From 817fec9e3d4b01be17356d4478db0719b8ef12cd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 22 Sep 2021 00:44:52 +0100 Subject: [PATCH 001/710] EducationSettingsPacket: safeguard against purity issue reported by PHPStan while annoying, PHPStan is right to complain about this, because putBool() is impure, meaning that these fields could have been mutated in the call. We know they didn't, but PHPStan doesn't, and we can't mark the method as pure because .. well .. it isn't. --- .../network/mcpe/protocol/EducationSettingsPacket.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/network/mcpe/protocol/EducationSettingsPacket.php b/src/pocketmine/network/mcpe/protocol/EducationSettingsPacket.php index a53f687ed..cb8f35d53 100644 --- a/src/pocketmine/network/mcpe/protocol/EducationSettingsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/EducationSettingsPacket.php @@ -133,9 +133,10 @@ class EducationSettingsPacket extends DataPacket{ $this->putBool($this->disableLegacyTitleBar); $this->putString($this->postProcessFilter); $this->putString($this->screenshotBorderResourcePath); - if($this->agentCapabilities !== null){ + $agentCapabilities = $this->agentCapabilities; + if($agentCapabilities !== null){ $this->putBool(true); - $this->agentCapabilities->write($this); + $agentCapabilities->write($this); }else{ $this->putBool(false); } @@ -144,9 +145,10 @@ class EducationSettingsPacket extends DataPacket{ $this->putString($this->codeBuilderOverrideUri); } $this->putBool($this->hasQuiz); - if($this->linkSettings !== null){ + $linkSettings = $this->linkSettings; + if($linkSettings !== null){ $this->putBool(true); - $this->linkSettings->write($this); + $linkSettings->write($this); }else{ $this->putBool(false); } From b3601c93900e1d579b32897d67ae9e93773b2b5c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 22 Sep 2021 00:45:07 +0100 Subject: [PATCH 002/710] Regenerate PHPStan baselines --- .../check-explicit-mixed-baseline.neon | 22 +++++++++---------- tests/phpstan/configs/l7-baseline.neon | 7 +++++- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/tests/phpstan/configs/check-explicit-mixed-baseline.neon b/tests/phpstan/configs/check-explicit-mixed-baseline.neon index 7c9cc5451..9c7492962 100644 --- a/tests/phpstan/configs/check-explicit-mixed-baseline.neon +++ b/tests/phpstan/configs/check-explicit-mixed-baseline.neon @@ -42,7 +42,7 @@ parameters: - message: "#^Parameter \\#1 \\$string of function base64_decode expects string, mixed given\\.$#" - count: 5 + count: 6 path: ../../../src/pocketmine/Player.php - @@ -51,27 +51,32 @@ parameters: path: ../../../src/pocketmine/Player.php - - message: "#^Parameter \\#10 \\$persona of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" + message: "#^Parameter \\#10 \\$capeId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" count: 1 path: ../../../src/pocketmine/Player.php - - message: "#^Parameter \\#11 \\$personaCapeOnClassic of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" + message: "#^Parameter \\#12 \\$armSize of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" count: 1 path: ../../../src/pocketmine/Player.php - - message: "#^Parameter \\#12 \\$capeId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" + message: "#^Parameter \\#13 \\$skinColor of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" count: 1 path: ../../../src/pocketmine/Player.php - - message: "#^Parameter \\#14 \\$armSize of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" + message: "#^Parameter \\#17 \\$premium of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" count: 1 path: ../../../src/pocketmine/Player.php - - message: "#^Parameter \\#15 \\$skinColor of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" + message: "#^Parameter \\#18 \\$persona of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#19 \\$personaCapeOnClassic of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" count: 1 path: ../../../src/pocketmine/Player.php @@ -85,11 +90,6 @@ parameters: count: 2 path: ../../../src/pocketmine/Player.php - - - message: "#^Parameter \\#9 \\$premium of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - message: "#^Cannot access offset 'git' on mixed\\.$#" count: 2 diff --git a/tests/phpstan/configs/l7-baseline.neon b/tests/phpstan/configs/l7-baseline.neon index 8da59e251..0f6f063c1 100644 --- a/tests/phpstan/configs/l7-baseline.neon +++ b/tests/phpstan/configs/l7-baseline.neon @@ -41,7 +41,12 @@ parameters: path: ../../../src/pocketmine/Player.php - - message: "#^Parameter \\#8 \\$animationData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" + message: "#^Parameter \\#8 \\$geometryDataEngineVersion of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#9 \\$animationData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" count: 1 path: ../../../src/pocketmine/Player.php From 352162a6e6ac7b4641d2fc200ed3ba5908292eda Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 22 Sep 2021 00:50:00 +0100 Subject: [PATCH 003/710] Fixed PHP 7.4 build --- tests/phpstan/configs/php7.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpstan/configs/php7.neon b/tests/phpstan/configs/php7.neon index e98ee2176..f02766677 100644 --- a/tests/phpstan/configs/php7.neon +++ b/tests/phpstan/configs/php7.neon @@ -12,7 +12,7 @@ parameters: - message: "#^Parameter \\#1 \\$str of function base64_decode expects string, mixed given\\.$#" - count: 5 + count: 6 path: ../../../src/pocketmine/Player.php - From 43ac3fbf3e47ecda48c3d95aff2068a4ceec8c08 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 22 Sep 2021 00:51:06 +0100 Subject: [PATCH 004/710] actions: use newer PHP versions --- .github/workflows/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0c2f95b9b..74d55641a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: image: [ubuntu-20.04] - php: [7.4.22, 8.0.9] + php: [7.4.23, 8.0.10] steps: - uses: actions/checkout@v2 #needed for build.sh @@ -37,10 +37,10 @@ jobs: fail-fast: false matrix: include: - - php: 8.0.9 + - php: 8.0.10 config: phpstan.neon.dist image: ubuntu-20.04 - - php: 7.4.22 + - php: 7.4.23 config: phpstan.php7.neon image: ubuntu-20.04 @@ -92,7 +92,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [7.4.22, 8.0.9] + php: [7.4.23, 8.0.10] steps: - uses: actions/checkout@v2 @@ -142,7 +142,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [7.4.22, 8.0.9] + php: [7.4.23, 8.0.10] steps: - uses: actions/checkout@v2 @@ -194,7 +194,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [7.4.22, 8.0.9] + php: [7.4.23, 8.0.10] steps: - uses: actions/checkout@v2 From 14fba366364eca9f13a30b955c702edbd8e66267 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 22 Sep 2021 01:00:50 +0100 Subject: [PATCH 005/710] Release 3.23.1 --- changelogs/3.23.md | 3 +++ src/pocketmine/VersionInfo.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/changelogs/3.23.md b/changelogs/3.23.md index 216ac2f95..91a871ef5 100644 --- a/changelogs/3.23.md +++ b/changelogs/3.23.md @@ -9,3 +9,6 @@ Plugin developers should **only** update their required API to this version if y # 3.23.0 - Added support for Minecraft: Bedrock Edition 1.17.30. - Removed compatibility with earlier versions. + +# 3.23.1 +- Fixed broken build of 3.23.0. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 7b8ea6fe0..975afa23d 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,6 +34,6 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.23.1"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = ""; +const BUILD_CHANNEL = "stable"; From d455188d036797d7bebdb29e104194a7dda8cdc9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 22 Sep 2021 01:00:50 +0100 Subject: [PATCH 006/710] 3.23.2 is next --- src/pocketmine/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 975afa23d..ce905e803 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.23.1"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.23.2"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = "stable"; +const BUILD_CHANNEL = ""; From a11cf8c2965f9ef712687ef6b74c32fc6d610709 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 28 Sep 2021 20:52:40 +0100 Subject: [PATCH 007/710] Update PHP versions used by GitHub Actions --- .github/workflows/main.yml | 12 ++++++------ tests/gh-actions/build.sh | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 74d55641a..ae5ecd62f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: image: [ubuntu-20.04] - php: [7.4.23, 8.0.10] + php: [7.4.24, 8.0.11] steps: - uses: actions/checkout@v2 #needed for build.sh @@ -37,10 +37,10 @@ jobs: fail-fast: false matrix: include: - - php: 8.0.10 + - php: 8.0.11 config: phpstan.neon.dist image: ubuntu-20.04 - - php: 7.4.23 + - php: 7.4.24 config: phpstan.php7.neon image: ubuntu-20.04 @@ -92,7 +92,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [7.4.23, 8.0.10] + php: [7.4.24, 8.0.11] steps: - uses: actions/checkout@v2 @@ -142,7 +142,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [7.4.23, 8.0.10] + php: [7.4.24, 8.0.11] steps: - uses: actions/checkout@v2 @@ -194,7 +194,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [7.4.23, 8.0.10] + php: [7.4.24, 8.0.11] steps: - uses: actions/checkout@v2 diff --git a/tests/gh-actions/build.sh b/tests/gh-actions/build.sh index a8703e8d2..4dd13b8fe 100755 --- a/tests/gh-actions/build.sh +++ b/tests/gh-actions/build.sh @@ -17,7 +17,7 @@ INSTALL_DIR="$(pwd)/bin/php7" export CFLAGS="$CFLAGS -march=x86-64" export CXXFLAGS="$CXXFLAGS -march=x86-64" -git clone https://github.com/php-build/php-build.git +git clone https://github.com/pmmp/php-build.git cd php-build ./install-dependencies.sh echo '"pthreads",,"https://github.com/pmmp/pthreads.git",,,"extension",' >> share/php-build/extension/definition From 65e468e3c23908455533e4a7da3b2a5a7a622a59 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 28 Sep 2021 21:00:13 +0100 Subject: [PATCH 008/710] Updated build/php submodule to pmmp/php-build-scripts@6aac46e5008a6e3701c537d7e9d0669079523fc6 --- build/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/php b/build/php index e55c60f17..6aac46e50 160000 --- a/build/php +++ b/build/php @@ -1 +1 @@ -Subproject commit e55c60f1760a019662e0fa139210975e8a160d31 +Subproject commit 6aac46e5008a6e3701c537d7e9d0669079523fc6 From d417b1e2f5bc2c303668f7a3d702785cce94464a Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 28 Sep 2021 16:03:03 -0400 Subject: [PATCH 009/710] Projectile: fixed move() not using the given parameters (#4481) it was using this->motion instead, which usually would be the same, but maybe not. --- src/pocketmine/entity/projectile/Projectile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/projectile/Projectile.php b/src/pocketmine/entity/projectile/Projectile.php index 1921ebb55..5e0ddf1f9 100644 --- a/src/pocketmine/entity/projectile/Projectile.php +++ b/src/pocketmine/entity/projectile/Projectile.php @@ -180,7 +180,7 @@ abstract class Projectile extends Entity{ Timings::$entityMoveTimer->startTiming(); $start = $this->asVector3(); - $end = $start->add($this->motion); + $end = $start->add($dx, $dy, $dz); $blockHit = null; $entityHit = null; From 003c002208d575f4b6c3b10b2885e936fb96ebc8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Sep 2021 21:04:11 +0100 Subject: [PATCH 010/710] Bump phpunit/phpunit from 9.5.9 to 9.5.10 (#4482) Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.9 to 9.5.10. - [Release notes](https://github.com/sebastianbergmann/phpunit/releases) - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.9...9.5.10) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 74 +++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/composer.lock b/composer.lock index a79360e76..7cedb4812 100644 --- a/composer.lock +++ b/composer.lock @@ -617,16 +617,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.12.0", + "version": "v4.13.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143" + "reference": "50953a2691a922aa1769461637869a0a2faa3f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", + "reference": "50953a2691a922aa1769461637869a0a2faa3f53", "shasum": "" }, "require": { @@ -667,9 +667,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" }, - "time": "2021-07-21T10:44:31+00:00" + "time": "2021-09-20T12:20:58+00:00" }, { "name": "phar-io/manifest", @@ -893,16 +893,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/30f38bffc6f24293dadd1823936372dfa9e86e2f", + "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f", "shasum": "" }, "require": { @@ -910,7 +910,8 @@ "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "*" + "ext-tokenizer": "*", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -936,39 +937,39 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.0" }, - "time": "2020-09-17T18:55:26+00:00" + "time": "2021-09-17T15:28:14+00:00" }, { "name": "phpspec/prophecy", - "version": "1.13.0", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", + "php": "^7.2 || ~8.0, <8.2", "phpdocumentor/reflection-docblock": "^5.2", "sebastian/comparator": "^3.0 || ^4.0", "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^6.0", + "phpspec/phpspec": "^6.0 || ^7.0", "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -1003,9 +1004,9 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.13.0" + "source": "https://github.com/phpspec/prophecy/tree/1.14.0" }, - "time": "2021-03-17T13:42:18+00:00" + "time": "2021-09-10T09:02:12+00:00" }, { "name": "phpstan/phpstan", @@ -1177,23 +1178,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.6", + "version": "9.2.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f6293e1b30a2354e8428e004689671b83871edde" + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", - "reference": "f6293e1b30a2354e8428e004689671b83871edde", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", + "nikic/php-parser": "^4.12.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -1242,7 +1243,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" }, "funding": [ { @@ -1250,7 +1251,7 @@ "type": "github" } ], - "time": "2021-03-28T07:26:59+00:00" + "time": "2021-09-17T05:39:03+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1495,16 +1496,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.9", + "version": "9.5.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b" + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", - "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a", + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a", "shasum": "" }, "require": { @@ -1520,7 +1521,7 @@ "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-code-coverage": "^9.2.7", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -1582,7 +1583,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.9" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10" }, "funding": [ { @@ -1594,7 +1595,7 @@ "type": "github" } ], - "time": "2021-08-31T06:47:40+00:00" + "time": "2021-09-25T07:38:51+00:00" }, { "name": "sebastian/cli-parser", @@ -2449,7 +2450,6 @@ "type": "github" } ], - "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { From afa3349c04822e07705ff6908e0a6a583f6b513e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 21:09:53 +0100 Subject: [PATCH 011/710] Acknowledge the presence of capabilities field in resource pack manifest closes #4485 --- src/resourcepacks/json/Manifest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/resourcepacks/json/Manifest.php b/src/resourcepacks/json/Manifest.php index 31c68973e..dad99a861 100644 --- a/src/resourcepacks/json/Manifest.php +++ b/src/resourcepacks/json/Manifest.php @@ -40,4 +40,7 @@ final class Manifest{ public array $modules; public ?ManifestMetadata $metadata = null; + + /** @var string[] */ + public ?array $capabilities = null; } From 349f37b15fccfa1efca17272328580fad0d632d8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 21:14:28 +0100 Subject: [PATCH 012/710] resource packs: manifest may also contain a list of dependencies ... which we should be verifying the presence of, as the server. --- src/resourcepacks/json/Manifest.php | 3 ++ .../json/ManifestDependencyEntry.php | 37 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/resourcepacks/json/ManifestDependencyEntry.php diff --git a/src/resourcepacks/json/Manifest.php b/src/resourcepacks/json/Manifest.php index dad99a861..cd6f1c913 100644 --- a/src/resourcepacks/json/Manifest.php +++ b/src/resourcepacks/json/Manifest.php @@ -43,4 +43,7 @@ final class Manifest{ /** @var string[] */ public ?array $capabilities = null; + + /** @var ManifestDependencyEntry[] */ + public ?array $dependencies = null; } diff --git a/src/resourcepacks/json/ManifestDependencyEntry.php b/src/resourcepacks/json/ManifestDependencyEntry.php new file mode 100644 index 000000000..f7dd76abc --- /dev/null +++ b/src/resourcepacks/json/ManifestDependencyEntry.php @@ -0,0 +1,37 @@ + Date: Fri, 1 Oct 2021 21:39:26 +0100 Subject: [PATCH 013/710] RakLib 0.14.1 --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 667f2f983..baa3a8c3e 100644 --- a/composer.lock +++ b/composer.lock @@ -671,16 +671,16 @@ }, { "name": "pocketmine/raklib", - "version": "0.14.0", + "version": "0.14.1", "source": { "type": "git", "url": "https://github.com/pmmp/RakLib.git", - "reference": "ed27bfd83f4de5ff32f71ec7611a66c4857a82ce" + "reference": "2d7bac3d593219880696ca2ca254f083f1e71850" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/RakLib/zipball/ed27bfd83f4de5ff32f71ec7611a66c4857a82ce", - "reference": "ed27bfd83f4de5ff32f71ec7611a66c4857a82ce", + "url": "https://api.github.com/repos/pmmp/RakLib/zipball/2d7bac3d593219880696ca2ca254f083f1e71850", + "reference": "2d7bac3d593219880696ca2ca254f083f1e71850", "shasum": "" }, "require": { @@ -708,9 +708,9 @@ "description": "A RakNet server implementation written in PHP", "support": { "issues": "https://github.com/pmmp/RakLib/issues", - "source": "https://github.com/pmmp/RakLib/tree/0.14.0" + "source": "https://github.com/pmmp/RakLib/tree/0.14.1" }, - "time": "2021-09-20T21:53:31+00:00" + "time": "2021-10-01T20:35:44+00:00" }, { "name": "pocketmine/raklib-ipc", From aee4a00a5030cce602ec20702495284f7319050f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 21:40:31 +0100 Subject: [PATCH 014/710] Updated dependencies --- composer.lock | 301 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 235 insertions(+), 66 deletions(-) diff --git a/composer.lock b/composer.lock index baa3a8c3e..d79f12428 100644 --- a/composer.lock +++ b/composer.lock @@ -63,16 +63,16 @@ }, { "name": "brick/math", - "version": "0.9.2", + "version": "0.9.3", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", "shasum": "" }, "require": { @@ -82,7 +82,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.3.2" + "vimeo/psalm": "4.9.2" }, "type": "library", "autoload": { @@ -107,15 +107,19 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.2" + "source": "https://github.com/brick/math/tree/0.9.3" }, "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/brick/math", "type": "tidelift" } ], - "time": "2021-01-20T22:51:39+00:00" + "time": "2021-08-15T20:50:18+00:00" }, { "name": "fgrosse/phpasn1", @@ -832,20 +836,21 @@ }, { "name": "ramsey/collection", - "version": "1.1.3", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/ramsey/collection.git", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1" + "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/collection/zipball/28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", - "reference": "28a5c4ab2f5111db6a60b2b4ec84057e0f43b9c1", + "url": "https://api.github.com/repos/ramsey/collection/zipball/eaca1dc1054ddd10cbd83c1461907bee6fb528fa", + "reference": "eaca1dc1054ddd10cbd83c1461907bee6fb528fa", "shasum": "" }, "require": { - "php": "^7.2 || ^8" + "php": "^7.3 || ^8", + "symfony/polyfill-php81": "^1.23" }, "require-dev": { "captainhook/captainhook": "^5.3", @@ -855,6 +860,7 @@ "hamcrest/hamcrest-php": "^2", "jangregor/phpstan-prophecy": "^0.8", "mockery/mockery": "^1.3", + "phpspec/prophecy-phpunit": "^2.0", "phpstan/extension-installer": "^1", "phpstan/phpstan": "^0.12.32", "phpstan/phpstan-mockery": "^0.12.5", @@ -882,7 +888,7 @@ "homepage": "https://benramsey.com" } ], - "description": "A PHP 7.2+ library for representing and manipulating collections.", + "description": "A PHP library for representing and manipulating collections.", "keywords": [ "array", "collection", @@ -893,7 +899,7 @@ ], "support": { "issues": "https://github.com/ramsey/collection/issues", - "source": "https://github.com/ramsey/collection/tree/1.1.3" + "source": "https://github.com/ramsey/collection/tree/1.2.1" }, "funding": [ { @@ -905,28 +911,29 @@ "type": "tidelift" } ], - "time": "2021-01-21T17:40:04+00:00" + "time": "2021-08-06T03:41:06+00:00" }, { "name": "ramsey/uuid", - "version": "4.2.1", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae" + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/fe665a03df4f056aa65af552a96e1976df8c8dae", - "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", "shasum": "" }, "require": { "brick/math": "^0.8 || ^0.9", "ext-json": "*", - "php": "^7.2 || ^8", + "php": "^7.2 || ^8.0", "ramsey/collection": "^1.0", - "symfony/polyfill-ctype": "^1.8" + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php80": "^1.14" }, "replace": { "rhumsaa/uuid": "self.version" @@ -990,7 +997,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.2.1" + "source": "https://github.com/ramsey/uuid/tree/4.2.3" }, "funding": [ { @@ -1002,7 +1009,7 @@ "type": "tidelift" } ], - "time": "2021-08-11T01:06:55+00:00" + "time": "2021-09-25T23:10:38+00:00" }, { "name": "respect/stringifier", @@ -1209,16 +1216,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1" + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2df51500adbaebdc4c38dea4c89a2e131c45c8a1", - "reference": "2df51500adbaebdc4c38dea4c89a2e131c45c8a1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", + "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", "shasum": "" }, "require": { @@ -1269,7 +1276,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" }, "funding": [ { @@ -1285,7 +1292,169 @@ "type": "tidelift" } ], - "time": "2021-05-27T09:27:20+00:00" + "time": "2021-05-27T12:26:48+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.23.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/1100343ed1a92e3a38f9ae122fc0eb21602547be", + "reference": "1100343ed1a92e3a38f9ae122fc0eb21602547be", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-07-28T13:41:28+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "e66119f3de95efc359483f810c4c3e6436279436" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/e66119f3de95efc359483f810c4c3e6436279436", + "reference": "e66119f3de95efc359483f810c4c3e6436279436", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-05-21T13:25:03+00:00" }, { "name": "webmozart/assert", @@ -1526,16 +1695,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.12.0", + "version": "v4.13.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143" + "reference": "50953a2691a922aa1769461637869a0a2faa3f53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143", - "reference": "6608f01670c3cc5079e18c1dab1104e002579143", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", + "reference": "50953a2691a922aa1769461637869a0a2faa3f53", "shasum": "" }, "require": { @@ -1576,9 +1745,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" }, - "time": "2021-07-21T10:44:31+00:00" + "time": "2021-09-20T12:20:58+00:00" }, { "name": "phar-io/manifest", @@ -1802,16 +1971,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/30f38bffc6f24293dadd1823936372dfa9e86e2f", + "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f", "shasum": "" }, "require": { @@ -1819,7 +1988,8 @@ "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "ext-tokenizer": "*" + "ext-tokenizer": "*", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -1845,39 +2015,39 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.0" }, - "time": "2020-09-17T18:55:26+00:00" + "time": "2021-09-17T15:28:14+00:00" }, { "name": "phpspec/prophecy", - "version": "1.13.0", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", - "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", "shasum": "" }, "require": { "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", + "php": "^7.2 || ~8.0, <8.2", "phpdocumentor/reflection-docblock": "^5.2", "sebastian/comparator": "^3.0 || ^4.0", "sebastian/recursion-context": "^3.0 || ^4.0" }, "require-dev": { - "phpspec/phpspec": "^6.0", + "phpspec/phpspec": "^6.0 || ^7.0", "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { @@ -1912,9 +2082,9 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.13.0" + "source": "https://github.com/phpspec/prophecy/tree/1.14.0" }, - "time": "2021-03-17T13:42:18+00:00" + "time": "2021-09-10T09:02:12+00:00" }, { "name": "phpstan/phpstan", @@ -2086,23 +2256,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.6", + "version": "9.2.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f6293e1b30a2354e8428e004689671b83871edde" + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f6293e1b30a2354e8428e004689671b83871edde", - "reference": "f6293e1b30a2354e8428e004689671b83871edde", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", + "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", + "nikic/php-parser": "^4.12.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -2151,7 +2321,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.6" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" }, "funding": [ { @@ -2159,7 +2329,7 @@ "type": "github" } ], - "time": "2021-03-28T07:26:59+00:00" + "time": "2021-09-17T05:39:03+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2404,16 +2574,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.9", + "version": "9.5.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b" + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", - "reference": "ea8c2dfb1065eb35a79b3681eee6e6fb0a6f273b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a", + "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a", "shasum": "" }, "require": { @@ -2429,7 +2599,7 @@ "phar-io/version": "^3.0.2", "php": ">=7.3", "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-code-coverage": "^9.2.7", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -2491,7 +2661,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.9" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10" }, "funding": [ { @@ -2503,7 +2673,7 @@ "type": "github" } ], - "time": "2021-08-31T06:47:40+00:00" + "time": "2021-09-25T07:38:51+00:00" }, { "name": "sebastian/cli-parser", @@ -3358,7 +3528,6 @@ "type": "github" } ], - "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { From 42bf9578ce4d0d3858a2a580b5362df0d3401224 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 22:05:03 +0100 Subject: [PATCH 015/710] Remove unused constants --- src/block/Bell.php | 2 -- src/world/format/io/FastChunkSerializer.php | 1 - 2 files changed, 3 deletions(-) diff --git a/src/block/Bell.php b/src/block/Bell.php index 1cffd606b..2b33610b6 100644 --- a/src/block/Bell.php +++ b/src/block/Bell.php @@ -37,8 +37,6 @@ use pocketmine\world\BlockTransaction; use pocketmine\world\sound\BellRingSound; final class Bell extends Transparent{ - private const BELL_RINGING_REPEAT_TICKS = 20; - use HorizontalFacingTrait; private BellAttachmentType $attachmentType; diff --git a/src/world/format/io/FastChunkSerializer.php b/src/world/format/io/FastChunkSerializer.php index ca6d4ea50..8dfaf76b0 100644 --- a/src/world/format/io/FastChunkSerializer.php +++ b/src/world/format/io/FastChunkSerializer.php @@ -41,7 +41,6 @@ use function unpack; * The serialization format **is not intended for permanent storage** and may change without warning. */ final class FastChunkSerializer{ - private const FLAG_GENERATED = 1 << 0; private const FLAG_POPULATED = 1 << 1; private const FLAG_HAS_LIGHT = 1 << 2; From 5b818827dbce69faa82b6426e24261118c28c580 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 22:17:28 +0100 Subject: [PATCH 016/710] Chunk: stop exposing SplFixedArray to the API this fixes a large number of PHPStan errors, and also brings us a step closer to negative-build-height readiness. --- .../mcpe/serializer/ChunkSerializer.php | 2 +- src/world/format/Chunk.php | 8 +-- src/world/format/io/FastChunkSerializer.php | 2 +- src/world/light/SkyLightUpdate.php | 5 +- .../configs/spl-fixed-array-sucks.neon | 70 ++----------------- 5 files changed, 14 insertions(+), 73 deletions(-) diff --git a/src/network/mcpe/serializer/ChunkSerializer.php b/src/network/mcpe/serializer/ChunkSerializer.php index fe8253e4c..6fe392b67 100644 --- a/src/network/mcpe/serializer/ChunkSerializer.php +++ b/src/network/mcpe/serializer/ChunkSerializer.php @@ -46,7 +46,7 @@ final class ChunkSerializer{ * Chunks are sent in a stack, so every chunk below the top non-empty one must be sent. */ public static function getSubChunkCount(Chunk $chunk) : int{ - for($count = $chunk->getSubChunks()->count(); $count > 0; --$count){ + for($count = count($chunk->getSubChunks()); $count > 0; --$count){ if($chunk->getSubChunk($count - 1)->isEmptyFast()){ continue; } diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index 3691b4dbd..c90c18482 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -299,11 +299,11 @@ class Chunk{ } /** - * @return \SplFixedArray|SubChunk[] - * @phpstan-return \SplFixedArray + * @return SubChunk[] + * @phpstan-return array */ - public function getSubChunks() : \SplFixedArray{ - return $this->subChunks; + public function getSubChunks() : array{ + return $this->subChunks->toArray(); } /** diff --git a/src/world/format/io/FastChunkSerializer.php b/src/world/format/io/FastChunkSerializer.php index 8dfaf76b0..4e65c414f 100644 --- a/src/world/format/io/FastChunkSerializer.php +++ b/src/world/format/io/FastChunkSerializer.php @@ -67,7 +67,7 @@ final class FastChunkSerializer{ //subchunks $subChunks = $chunk->getSubChunks(); - $count = $subChunks->count(); + $count = count($subChunks); $stream->putByte($count); foreach($subChunks as $y => $subChunk){ diff --git a/src/world/light/SkyLightUpdate.php b/src/world/light/SkyLightUpdate.php index e9507c153..42d12be17 100644 --- a/src/world/light/SkyLightUpdate.php +++ b/src/world/light/SkyLightUpdate.php @@ -30,6 +30,7 @@ use pocketmine\world\format\SubChunk; use pocketmine\world\utils\SubChunkExplorer; use pocketmine\world\utils\SubChunkExplorerStatus; use pocketmine\world\World; +use function count; use function max; class SkyLightUpdate extends LightUpdate{ @@ -114,7 +115,7 @@ class SkyLightUpdate extends LightUpdate{ //have to avoid filling full light for any subchunk that contains a heightmap Y coordinate $highestHeightMapPlusOne = max($chunk->getHeightMapArray()) + 1; $lowestClearSubChunk = ($highestHeightMapPlusOne >> SubChunk::COORD_BIT_SIZE) + (($highestHeightMapPlusOne & SubChunk::COORD_MASK) !== 0 ? 1 : 0); - $chunkHeight = $chunk->getSubChunks()->count(); + $chunkHeight = count($chunk->getSubChunks()); for($y = 0; $y < $lowestClearSubChunk && $y < $chunkHeight; $y++){ $chunk->getSubChunk($y)->setBlockSkyLightArray(LightArray::fill(0)); } @@ -173,7 +174,7 @@ class SkyLightUpdate extends LightUpdate{ * @phpstan-param \SplFixedArray $directSkyLightBlockers */ private static function recalculateHeightMap(Chunk $chunk, \SplFixedArray $directSkyLightBlockers) : HeightArray{ - $maxSubChunkY = $chunk->getSubChunks()->count() - 1; + $maxSubChunkY = count($chunk->getSubChunks()) - 1; for(; $maxSubChunkY >= 0; $maxSubChunkY--){ if(!$chunk->getSubChunk($maxSubChunkY)->isEmptyFast()){ break; diff --git a/tests/phpstan/configs/spl-fixed-array-sucks.neon b/tests/phpstan/configs/spl-fixed-array-sucks.neon index f984dc555..d69e0a6e4 100644 --- a/tests/phpstan/configs/spl-fixed-array-sucks.neon +++ b/tests/phpstan/configs/spl-fixed-array-sucks.neon @@ -1,77 +1,17 @@ parameters: ignoreErrors: - - - message: "#^Cannot call method getFullBlock\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/World.php - - - - message: "#^Cannot call method isEmptyFast\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/World.php - - message: "#^Cannot call method collectGarbage\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" count: 1 path: ../../../src/world/format/Chunk.php + - + message: "#^Method pocketmine\\\\world\\\\format\\\\Chunk\\:\\:getSubChunks\\(\\) should return array\\ but returns array\\\\.$#" + count: 1 + path: ../../../src/world/format/Chunk.php + - message: "#^Method pocketmine\\\\world\\\\format\\\\HeightArray\\:\\:getValues\\(\\) should return array\\ but returns array\\\\.$#" count: 1 path: ../../../src/world/format/HeightArray.php - - - message: "#^Cannot call method getBlockLayers\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/format/io/FastChunkSerializer.php - - - - message: "#^Cannot call method getBlockLightArray\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/format/io/FastChunkSerializer.php - - - - message: "#^Cannot call method getBlockSkyLightArray\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/format/io/FastChunkSerializer.php - - - - message: "#^Cannot call method getEmptyBlockId\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/format/io/FastChunkSerializer.php - - - - message: "#^Cannot call method getBlockLayers\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/format/io/leveldb/LevelDB.php - - - - message: "#^Cannot call method isEmptyAuthoritative\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/format/io/leveldb/LevelDB.php - - - - message: "#^Cannot call method getBlockLayers\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/light/BlockLightUpdate.php - - - - message: "#^Cannot call method setBlockLightArray\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/light/BlockLightUpdate.php - - - - message: "#^Parameter \\#1 \\$subChunk of method pocketmine\\\\world\\\\light\\\\BlockLightUpdate\\:\\:scanForLightEmittingBlocks\\(\\) expects pocketmine\\\\world\\\\format\\\\SubChunk, pocketmine\\\\world\\\\format\\\\SubChunk\\|null given\\.$#" - count: 1 - path: ../../../src/world/light/BlockLightUpdate.php - - - - message: "#^Cannot call method getBlockLightArray\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/light/LightPopulationTask.php - - - - message: "#^Cannot call method getBlockSkyLightArray\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" - count: 1 - path: ../../../src/world/light/LightPopulationTask.php - From 32f8b8163e8632ef5a65531b647c741c1c320b65 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 22:19:36 +0100 Subject: [PATCH 017/710] Clean out PHPStan l7 baseline --- tests/phpstan/configs/l7-baseline.neon | 83 ++------------------------ 1 file changed, 4 insertions(+), 79 deletions(-) diff --git a/tests/phpstan/configs/l7-baseline.neon b/tests/phpstan/configs/l7-baseline.neon index 4f82f4aff..ae390b9de 100644 --- a/tests/phpstan/configs/l7-baseline.neon +++ b/tests/phpstan/configs/l7-baseline.neon @@ -260,14 +260,9 @@ parameters: count: 1 path: ../../../src/block/Leaves.php - - - message: "#^Parameter \\#1 \\$blockX of method pocketmine\\\\block\\\\Liquid\\:\\:calculateFlowCost\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/block/Liquid.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 23 + count: 11 path: ../../../src/block/Liquid.php - @@ -275,19 +270,9 @@ parameters: count: 1 path: ../../../src/block/Liquid.php - - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/block/Liquid.php - - - - message: "#^Parameter \\#2 \\$blockY of method pocketmine\\\\block\\\\Liquid\\:\\:calculateFlowCost\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/block/Liquid.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 23 + count: 11 path: ../../../src/block/Liquid.php - @@ -295,19 +280,9 @@ parameters: count: 1 path: ../../../src/block/Liquid.php - - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/block/Liquid.php - - - - message: "#^Parameter \\#3 \\$blockZ of method pocketmine\\\\block\\\\Liquid\\:\\:calculateFlowCost\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/block/Liquid.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 23 + count: 11 path: ../../../src/block/Liquid.php - @@ -315,11 +290,6 @@ parameters: count: 1 path: ../../../src/block/Liquid.php - - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/block/Liquid.php - - message: "#^Parameter \\#1 \\$min of function mt_rand expects int, float\\|int given\\.$#" count: 3 @@ -610,38 +580,18 @@ parameters: count: 1 path: ../../../src/utils/Timezone.php - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" count: 1 path: ../../../src/world/Explosion.php - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:setBlockAt\\(\\) expects int, float\\|int given\\.$#" count: 1 path: ../../../src/world/Explosion.php - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:updateAllLight\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/world/Explosion.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" count: 1 path: ../../../src/world/Explosion.php @@ -650,28 +600,13 @@ parameters: count: 1 path: ../../../src/world/Explosion.php - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:setBlockAt\\(\\) expects int, float\\|int given\\.$#" count: 1 path: ../../../src/world/Explosion.php - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:updateAllLight\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/world/Explosion.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" count: 1 path: ../../../src/world/Explosion.php @@ -680,24 +615,14 @@ parameters: count: 1 path: ../../../src/world/Explosion.php - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:setBlockAt\\(\\) expects int, float\\|int given\\.$#" count: 1 path: ../../../src/world/Explosion.php - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:updateAllLight\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/Explosion.php - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 2 + count: 1 path: ../../../src/world/Explosion.php - From e6f6a036ef523cba75013745cf804cd6ddb81858 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 22:34:11 +0100 Subject: [PATCH 018/710] LightPopulationTask: do not copy existing light arrays this task wipes out the light arrays and recalculates them from scratch, so it's pointless to copy any preexisting light arrays anyway. --- src/world/light/LightPopulationTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/light/LightPopulationTask.php b/src/world/light/LightPopulationTask.php index d7cdce64a..a2d607e0e 100644 --- a/src/world/light/LightPopulationTask.php +++ b/src/world/light/LightPopulationTask.php @@ -51,7 +51,7 @@ class LightPopulationTask extends AsyncTask{ * @phpstan-param \Closure(array $blockLight, array $skyLight, array $heightMap) : void $onCompletion */ public function __construct(Chunk $chunk, \Closure $onCompletion){ - $this->chunk = FastChunkSerializer::serialize($chunk); + $this->chunk = FastChunkSerializer::serializeWithoutLight($chunk); $this->storeLocal(self::TLS_KEY_COMPLETION_CALLBACK, $onCompletion); } From 8de30e8162e8c46f94b8c6e166e9d191044aa3f2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 22:57:22 +0100 Subject: [PATCH 019/710] FastChunkSerializer no longer serializes light by default the core doesn't use this anywhere. serializeWithoutLight() has been renamed to serializeTerrain() to more accurately describe what it does. --- src/network/mcpe/ChunkRequestTask.php | 4 +-- src/world/format/io/FastChunkSerializer.php | 36 +++------------------ src/world/generator/PopulationTask.php | 16 ++++----- src/world/light/LightPopulationTask.php | 4 +-- 4 files changed, 16 insertions(+), 44 deletions(-) diff --git a/src/network/mcpe/ChunkRequestTask.php b/src/network/mcpe/ChunkRequestTask.php index ec7b0adf7..676a480a9 100644 --- a/src/network/mcpe/ChunkRequestTask.php +++ b/src/network/mcpe/ChunkRequestTask.php @@ -58,7 +58,7 @@ class ChunkRequestTask extends AsyncTask{ public function __construct(int $chunkX, int $chunkZ, Chunk $chunk, CompressBatchPromise $promise, Compressor $compressor, ?\Closure $onError = null){ $this->compressor = $compressor; - $this->chunk = FastChunkSerializer::serializeWithoutLight($chunk); + $this->chunk = FastChunkSerializer::serializeTerrain($chunk); $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; $this->tiles = ChunkSerializer::serializeTiles($chunk); @@ -68,7 +68,7 @@ class ChunkRequestTask extends AsyncTask{ } public function onRun() : void{ - $chunk = FastChunkSerializer::deserialize($this->chunk); + $chunk = FastChunkSerializer::deserializeTerrain($this->chunk); $subCount = ChunkSerializer::getSubChunkCount($chunk); $encoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()); $payload = ChunkSerializer::serializeFullChunk($chunk, RuntimeBlockMapping::getInstance(), $encoderContext, $this->tiles); diff --git a/src/world/format/io/FastChunkSerializer.php b/src/world/format/io/FastChunkSerializer.php index 4e65c414f..cc8544411 100644 --- a/src/world/format/io/FastChunkSerializer.php +++ b/src/world/format/io/FastChunkSerializer.php @@ -26,8 +26,6 @@ namespace pocketmine\world\format\io; use pocketmine\utils\BinaryStream; use pocketmine\world\format\BiomeArray; use pocketmine\world\format\Chunk; -use pocketmine\world\format\HeightArray; -use pocketmine\world\format\LightArray; use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\format\SubChunk; use function array_values; @@ -42,26 +40,18 @@ use function unpack; */ final class FastChunkSerializer{ private const FLAG_POPULATED = 1 << 1; - private const FLAG_HAS_LIGHT = 1 << 2; private function __construct(){ //NOOP } - public static function serializeWithoutLight(Chunk $chunk) : string{ - return self::serialize($chunk, false); - } - /** * Fast-serializes the chunk for passing between threads * TODO: tiles and entities */ - public static function serialize(Chunk $chunk, bool $includeLight = true) : string{ - $includeLight = $includeLight && $chunk->isLightPopulated() === true; - + public static function serializeTerrain(Chunk $chunk) : string{ $stream = new BinaryStream(); $stream->putByte( - ($includeLight ? self::FLAG_HAS_LIGHT : 0) | ($chunk->isPopulated() ? self::FLAG_POPULATED : 0) ); @@ -85,18 +75,10 @@ final class FastChunkSerializer{ $stream->putInt(strlen($serialPalette)); $stream->put($serialPalette); } - - if($includeLight){ - $stream->put($subChunk->getBlockSkyLightArray()->getData()); - $stream->put($subChunk->getBlockLightArray()->getData()); - } } //biomes $stream->put($chunk->getBiomeIdArray()); - if($includeLight){ - $stream->put(pack("S*", ...$chunk->getHeightMapArray())); - } return $stream->getBuffer(); } @@ -104,15 +86,13 @@ final class FastChunkSerializer{ /** * Deserializes a fast-serialized chunk */ - public static function deserialize(string $data) : Chunk{ + public static function deserializeTerrain(string $data) : Chunk{ $stream = new BinaryStream($data); $flags = $stream->getByte(); - $lightPopulated = (bool) ($flags & self::FLAG_HAS_LIGHT); $terrainPopulated = (bool) ($flags & self::FLAG_POPULATED); $subChunks = []; - $heightMap = null; $count = $stream->getByte(); for($subCount = 0; $subCount < $count; ++$subCount){ @@ -130,21 +110,13 @@ final class FastChunkSerializer{ $layers[] = PalettedBlockArray::fromData($bitsPerBlock, $words, $palette); } - $subChunks[$y] = new SubChunk( - $airBlockId, $layers, $lightPopulated ? new LightArray($stream->get(2048)) : null, $lightPopulated ? new LightArray($stream->get(2048)) : null - ); + $subChunks[$y] = new SubChunk($airBlockId, $layers); } $biomeIds = new BiomeArray($stream->get(256)); - if($lightPopulated){ - /** @var int[] $unpackedHeightMap */ - $unpackedHeightMap = unpack("S*", $stream->get(512)); //unpack() will never fail here - $heightMap = new HeightArray(array_values($unpackedHeightMap)); - } - $chunk = new Chunk($subChunks, $biomeIds, $heightMap); + $chunk = new Chunk($subChunks, $biomeIds); $chunk->setPopulated($terrainPopulated); - $chunk->setLightPopulated($lightPopulated); $chunk->clearTerrainDirtyFlags(); return $chunk; diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 87222664e..2af1a452b 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -68,10 +68,10 @@ class PopulationTask extends AsyncTask{ $this->worldId = $world->getId(); $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; - $this->chunk = $chunk !== null ? FastChunkSerializer::serializeWithoutLight($chunk) : null; + $this->chunk = $chunk !== null ? FastChunkSerializer::serializeTerrain($chunk) : null; foreach($world->getAdjacentChunks($chunkX, $chunkZ) as $i => $c){ - $this->{"chunk$i"} = $c !== null ? FastChunkSerializer::serializeWithoutLight($c) : null; + $this->{"chunk$i"} = $c !== null ? FastChunkSerializer::serializeTerrain($c) : null; } $this->storeLocal(self::TLS_KEY_WORLD, $world); @@ -88,7 +88,7 @@ class PopulationTask extends AsyncTask{ /** @var Chunk[] $chunks */ $chunks = []; - $chunk = $this->chunk !== null ? FastChunkSerializer::deserialize($this->chunk) : null; + $chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : null; for($i = 0; $i < 9; ++$i){ if($i === 4){ @@ -98,7 +98,7 @@ class PopulationTask extends AsyncTask{ if($ck === null){ $chunks[$i] = null; }else{ - $chunks[$i] = FastChunkSerializer::deserialize($ck); + $chunks[$i] = FastChunkSerializer::deserializeTerrain($ck); } } @@ -135,10 +135,10 @@ class PopulationTask extends AsyncTask{ $chunk = $manager->getChunk($this->chunkX, $this->chunkZ); $chunk->setPopulated(); - $this->chunk = FastChunkSerializer::serializeWithoutLight($chunk); + $this->chunk = FastChunkSerializer::serializeTerrain($chunk); foreach($chunks as $i => $c){ - $this->{"chunk$i"} = $c->isTerrainDirty() ? FastChunkSerializer::serializeWithoutLight($c) : null; + $this->{"chunk$i"} = $c->isTerrainDirty() ? FastChunkSerializer::serializeTerrain($c) : null; } } @@ -146,7 +146,7 @@ class PopulationTask extends AsyncTask{ /** @var World $world */ $world = $this->fetchLocal(self::TLS_KEY_WORLD); if($world->isLoaded()){ - $chunk = $this->chunk !== null ? FastChunkSerializer::deserialize($this->chunk) : null; + $chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : null; for($i = 0; $i < 9; ++$i){ if($i === 4){ @@ -157,7 +157,7 @@ class PopulationTask extends AsyncTask{ $xx = -1 + $i % 3; $zz = -1 + intdiv($i, 3); - $c = FastChunkSerializer::deserialize($c); + $c = FastChunkSerializer::deserializeTerrain($c); $world->generateChunkCallback($this->chunkX + $xx, $this->chunkZ + $zz, $c); } } diff --git a/src/world/light/LightPopulationTask.php b/src/world/light/LightPopulationTask.php index a2d607e0e..97d6344ed 100644 --- a/src/world/light/LightPopulationTask.php +++ b/src/world/light/LightPopulationTask.php @@ -51,12 +51,12 @@ class LightPopulationTask extends AsyncTask{ * @phpstan-param \Closure(array $blockLight, array $skyLight, array $heightMap) : void $onCompletion */ public function __construct(Chunk $chunk, \Closure $onCompletion){ - $this->chunk = FastChunkSerializer::serializeWithoutLight($chunk); + $this->chunk = FastChunkSerializer::serializeTerrain($chunk); $this->storeLocal(self::TLS_KEY_COMPLETION_CALLBACK, $onCompletion); } public function onRun() : void{ - $chunk = FastChunkSerializer::deserialize($this->chunk); + $chunk = FastChunkSerializer::deserializeTerrain($this->chunk); $manager = new SimpleChunkManager(World::Y_MIN, World::Y_MAX); $manager->setChunk(0, 0, $chunk); From 88f799da2ceb88e290a3fe7a992fc3cdf2d40058 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 23:05:48 +0100 Subject: [PATCH 020/710] more AssumptionFailedError hacks for PHPStan :( the code in this class is really horrible --- src/world/generator/PopulationTask.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 2af1a452b..6c96b1c27 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -133,6 +133,9 @@ class PopulationTask extends AsyncTask{ $generator->populateChunk($manager, $this->chunkX, $this->chunkZ); $chunk = $manager->getChunk($this->chunkX, $this->chunkZ); + if($chunk === null){ + throw new AssumptionFailedError("We just generated this chunk, so it must exist"); + } $chunk->setPopulated(); $this->chunk = FastChunkSerializer::serializeTerrain($chunk); From c7e913899498fccb9d62284ade3503f7260428f7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 23:18:56 +0100 Subject: [PATCH 021/710] PopulationTask: reduce code duplication --- src/world/generator/PopulationTask.php | 37 +++++++++++--------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 6c96b1c27..5af9ed650 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -102,32 +102,13 @@ class PopulationTask extends AsyncTask{ } } - $manager->setChunk($this->chunkX, $this->chunkZ, $chunk ?? new Chunk()); - if($chunk === null){ - $generator->generateChunk($manager, $this->chunkX, $this->chunkZ); - $chunk = $manager->getChunk($this->chunkX, $this->chunkZ); - if($chunk === null){ - throw new AssumptionFailedError("We just set this chunk, so it must exist"); - } - $chunk->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN, true); - $chunk->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_BIOMES, true); - } + self::setOrGenerateChunk($manager, $generator, $this->chunkX, $this->chunkZ, $chunk); $resultChunks = []; //this is just to keep phpstan's type inference happy foreach($chunks as $i => $c){ $cX = (-1 + $i % 3) + $this->chunkX; $cZ = (-1 + intdiv($i, 3)) + $this->chunkZ; - $manager->setChunk($cX, $cZ, $c ?? new Chunk()); - if($c === null){ - $generator->generateChunk($manager, $cX, $cZ); - $c = $manager->getChunk($cX, $cZ); - if($c === null){ - throw new AssumptionFailedError("We just set this chunk, so it must exist"); - } - $c->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN, true); - $c->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_BIOMES, true); - } - $resultChunks[$i] = $c; + $resultChunks[$i] = self::setOrGenerateChunk($manager, $generator, $cX, $cZ, $c); } $chunks = $resultChunks; @@ -145,6 +126,20 @@ class PopulationTask extends AsyncTask{ } } + private static function setOrGenerateChunk(SimpleChunkManager $manager, Generator $generator, int $chunkX, int $chunkZ, ?Chunk $chunk) : Chunk{ + $manager->setChunk($chunkX, $chunkZ, $chunk ?? new Chunk()); + if($chunk === null){ + $generator->generateChunk($manager, $chunkX, $chunkZ); + $chunk = $manager->getChunk($chunkX, $chunkZ); + if($chunk === null){ + throw new AssumptionFailedError("We just set this chunk, so it must exist"); + } + $chunk->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN, true); + $chunk->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_BIOMES, true); + } + return $chunk; + } + public function onCompletion() : void{ /** @var World $world */ $world = $this->fetchLocal(self::TLS_KEY_WORLD); From 81d5598e96ecf776c6d312a403d9bcd6f0b3b502 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 1 Oct 2021 23:27:58 +0100 Subject: [PATCH 022/710] UPnP: Fixed server crash on failure to find UPnP device https://crash.pmmp.io/view/5241010 --- src/network/upnp/UPnPNetworkInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/upnp/UPnPNetworkInterface.php b/src/network/upnp/UPnPNetworkInterface.php index f261cc401..06634d018 100644 --- a/src/network/upnp/UPnPNetworkInterface.php +++ b/src/network/upnp/UPnPNetworkInterface.php @@ -50,9 +50,9 @@ final class UPnPNetworkInterface implements NetworkInterface{ public function start() : void{ $this->logger->info("Attempting to portforward..."); - $this->serviceURL = UPnP::getServiceUrl(); try{ + $this->serviceURL = UPnP::getServiceUrl(); UPnP::portForward($this->serviceURL, Internet::getInternalIP(), $this->port, $this->port); $this->logger->info("Forwarded $this->ip:$this->port to external port $this->port"); }catch(UPnPException $e){ From f26f06316411767a3b404fbe5bc45be68e09d9b1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 00:52:14 +0100 Subject: [PATCH 023/710] UPnP: catch InternetException when attempting portforward we might fail to get the internal IP for some reason, which shouldn't crash the server. --- src/network/upnp/UPnPNetworkInterface.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/upnp/UPnPNetworkInterface.php b/src/network/upnp/UPnPNetworkInterface.php index 06634d018..45e8a1171 100644 --- a/src/network/upnp/UPnPNetworkInterface.php +++ b/src/network/upnp/UPnPNetworkInterface.php @@ -25,6 +25,7 @@ namespace pocketmine\network\upnp; use pocketmine\network\NetworkInterface; use pocketmine\utils\Internet; +use pocketmine\utils\InternetException; final class UPnPNetworkInterface implements NetworkInterface{ @@ -55,7 +56,7 @@ final class UPnPNetworkInterface implements NetworkInterface{ $this->serviceURL = UPnP::getServiceUrl(); UPnP::portForward($this->serviceURL, Internet::getInternalIP(), $this->port, $this->port); $this->logger->info("Forwarded $this->ip:$this->port to external port $this->port"); - }catch(UPnPException $e){ + }catch(UPnPException | InternetException $e){ $this->logger->error("UPnP portforward failed: " . $e->getMessage()); } } From c6b2c63a9b69e9b7a89881064ae9e54d030d7b2e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 00:52:47 +0100 Subject: [PATCH 024/710] Remove a couple more dead errors from PHPStan baseline --- tests/phpstan/configs/l8-baseline.neon | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/phpstan/configs/l8-baseline.neon b/tests/phpstan/configs/l8-baseline.neon index cb21fad4e..2c4824f43 100644 --- a/tests/phpstan/configs/l8-baseline.neon +++ b/tests/phpstan/configs/l8-baseline.neon @@ -275,16 +275,6 @@ parameters: count: 1 path: ../../../src/world/format/HeightArray.php - - - message: "#^Cannot call method setPopulated\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/world/generator/PopulationTask.php - - - - message: "#^Parameter \\#1 \\$chunk of static method pocketmine\\\\world\\\\format\\\\io\\\\FastChunkSerializer\\:\\:serializeWithoutLight\\(\\) expects pocketmine\\\\world\\\\format\\\\Chunk, pocketmine\\\\world\\\\format\\\\Chunk\\|null given\\.$#" - count: 1 - path: ../../../src/world/generator/PopulationTask.php - - message: "#^Method pocketmine\\\\world\\\\generator\\\\biome\\\\BiomeSelector\\:\\:pickBiome\\(\\) should return pocketmine\\\\world\\\\biome\\\\Biome but returns pocketmine\\\\world\\\\biome\\\\Biome\\|null\\.$#" count: 1 From f5266ec81658809025e88aaffffc93faf46d0624 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 12:33:46 +0100 Subject: [PATCH 025/710] World: remove dead code leftover from 34f01a3ce3c02f41cfebfc81d34b755cfed62811 fixes #4486 --- src/world/World.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 05ff4dcd8..0eea2c7bc 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2289,10 +2289,6 @@ class World implements ChunkManager{ } } $pos = $entity->getPosition()->asVector3(); - $chunk = $this->getOrLoadChunkAtPosition($pos); - if($chunk === null){ - throw new \InvalidArgumentException("Cannot add an Entity in an ungenerated chunk"); - } $this->entitiesByChunk[World::chunkHash($pos->getFloorX() >> Chunk::COORD_BIT_SIZE, $pos->getFloorZ() >> Chunk::COORD_BIT_SIZE)][$entity->getId()] = $entity; $this->entityLastKnownPositions[$entity->getId()] = $pos; From 54174eefa026123a9eedebbd4917f88e1326377c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 15:27:11 +0100 Subject: [PATCH 026/710] Make sure COMPOSER_AUTOLOADER_PATH is always declared Sacrifice dynamic composer autoloader path to do this, because we don't need it anyway - it was a misconceived feature from the days when I used the same workspace for PM3 and PM4 both. --- src/CoreConstants.php | 1 + src/PocketMine.php | 13 +++---------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/CoreConstants.php b/src/CoreConstants.php index bf88306f1..63913e941 100644 --- a/src/CoreConstants.php +++ b/src/CoreConstants.php @@ -35,3 +35,4 @@ define('pocketmine\_CORE_CONSTANTS_INCLUDED', true); define('pocketmine\PATH', dirname(__DIR__) . '/'); define('pocketmine\RESOURCE_PATH', dirname(__DIR__) . '/resources/'); +define('pocketmine\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__) . '/vendor/autoload.php'); diff --git a/src/PocketMine.php b/src/PocketMine.php index afac6fd8d..88029b5df 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -214,20 +214,13 @@ JIT_WARNING error_reporting(-1); set_ini_entries(); - $opts = getopt("", ["bootstrap:"]); - if(isset($opts["bootstrap"])){ - $bootstrap = ($real = realpath($opts["bootstrap"])) !== false ? $real : $opts["bootstrap"]; - }else{ - $bootstrap = dirname(__FILE__, 2) . '/vendor/autoload.php'; - } - - if($bootstrap === false or !is_file($bootstrap)){ + $bootstrap = dirname(__FILE__, 2) . '/vendor/autoload.php'; + if(!is_file($bootstrap)){ critical_error("Composer autoloader not found at " . $bootstrap); critical_error("Please install/update Composer dependencies or use provided builds."); exit(1); } - define('pocketmine\COMPOSER_AUTOLOADER_PATH', $bootstrap); - require_once(\pocketmine\COMPOSER_AUTOLOADER_PATH); + require_once($bootstrap); $composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp'); if($composerGitHash !== null){ From 2566123e49deacc915512594d09c6b4f71f822ac Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 16:34:38 +0100 Subject: [PATCH 027/710] Remove unnecessary constant from PHPStan bootstrap --- tests/phpstan/bootstrap.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/phpstan/bootstrap.php b/tests/phpstan/bootstrap.php index ba8ccd3fc..6e25be8c3 100644 --- a/tests/phpstan/bootstrap.php +++ b/tests/phpstan/bootstrap.php @@ -28,6 +28,3 @@ if(!defined('LEVELDB_ZLIB_RAW_COMPRESSION')){ if(!extension_loaded('libdeflate')){ function libdeflate_deflate_compress(string $data, int $level = 6) : string{} } - -//TODO: these need to be defined properly or removed -define('pocketmine\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__, 2) . '/vendor/autoload.php'); From dd0c2fed8201ea7e76fc68c9d754f5a9187e9fed Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 16:56:24 +0100 Subject: [PATCH 028/710] Process: add subprocess parameter to kill() fix CommandReader subprocess lingering on a crash and fucking up the console --- src/PocketMine.php | 2 +- src/Server.php | 4 ++-- src/utils/Process.php | 7 +++++-- src/utils/ServerKiller.php | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/PocketMine.php b/src/PocketMine.php index 88029b5df..44b7ebdd6 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -300,7 +300,7 @@ JIT_WARNING if(ThreadManager::getInstance()->stopAll() > 0){ $logger->debug("Some threads could not be stopped, performing a force-kill"); - Process::kill(Process::pid()); + Process::kill(Process::pid(), true); } }while(false); diff --git a/src/Server.php b/src/Server.php index f76235d57..7b22fabf3 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1371,7 +1371,7 @@ class Server{ }catch(\Throwable $e){ $this->logger->logException($e); $this->logger->emergency("Crashed while crashing, killing process"); - @Process::kill(Process::pid()); + @Process::kill(Process::pid(), true); } } @@ -1501,7 +1501,7 @@ class Server{ echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL; sleep($spacing); } - @Process::kill(Process::pid()); + @Process::kill(Process::pid(), true); exit(1); } diff --git a/src/utils/Process.php b/src/utils/Process.php index f433300fe..a24550c5c 100644 --- a/src/utils/Process.php +++ b/src/utils/Process.php @@ -125,18 +125,21 @@ final class Process{ return count(ThreadManager::getInstance()->getAll()) + 2; //MainLogger + Main Thread } - public static function kill(int $pid) : void{ + public static function kill(int $pid, bool $subprocesses) : void{ $logger = \GlobalLogger::get(); if($logger instanceof MainLogger){ $logger->syncFlushBuffer(); } switch(Utils::getOS()){ case Utils::OS_WINDOWS: - exec("taskkill.exe /F /PID $pid > NUL"); + exec("taskkill.exe /F " . ($subprocesses ? "/T " : "") . "/PID $pid"); break; case Utils::OS_MACOS: case Utils::OS_LINUX: default: + if($subprocesses){ + $pid = -$pid; + } if(function_exists("posix_kill")){ posix_kill($pid, 9); //SIGKILL }else{ diff --git a/src/utils/ServerKiller.php b/src/utils/ServerKiller.php index 78d83f654..24f8eb37a 100644 --- a/src/utils/ServerKiller.php +++ b/src/utils/ServerKiller.php @@ -50,7 +50,7 @@ class ServerKiller extends Thread{ }); if(time() - $start >= $this->time){ echo "\nTook too long to stop, server was killed forcefully!\n"; - @Process::kill(Process::pid()); + @Process::kill(Process::pid(), true); } } From 0108888450e094263934b6f5959ba0cbc8873bff Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 17:23:26 +0100 Subject: [PATCH 029/710] Process: silence taskkill complaining that it can't commit suicide since taskkill is a subprocess of the server process, it gets included in taskkill's own attempted killing spree, but taskkill (wisely) won't kill itself. --- src/utils/Process.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Process.php b/src/utils/Process.php index a24550c5c..8e93f9b1c 100644 --- a/src/utils/Process.php +++ b/src/utils/Process.php @@ -132,7 +132,7 @@ final class Process{ } switch(Utils::getOS()){ case Utils::OS_WINDOWS: - exec("taskkill.exe /F " . ($subprocesses ? "/T " : "") . "/PID $pid"); + exec("taskkill.exe /F " . ($subprocesses ? "/T " : "") . "/PID $pid > NUL 2> NUL"); break; case Utils::OS_MACOS: case Utils::OS_LINUX: From d63b9d1648583e4be2ee379bbaca3e5b5c06cacd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 20:33:32 +0100 Subject: [PATCH 030/710] WorldManager: localize strings for world loading, generation and conversion --- resources/locale | 2 +- src/lang/KnownTranslationFactory.php | 45 ++++++++++++++++++++++++++++ src/lang/KnownTranslationKeys.php | 7 +++++ src/world/WorldManager.php | 22 ++++++++++---- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/resources/locale b/resources/locale index 4a322da43..6023e8b3b 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit 4a322da43eb9beef727bd36be3d6b641b8316591 +Subproject commit 6023e8b3bf089eb7c25a5ddc7b29e9ef81520e7e diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 62577ee16..62bc5d289 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -573,6 +573,12 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::COMMANDS_WHITELIST_USAGE, []); } + public static function death_attack_anvil(Translatable|string $param0) : Translatable{ + return new Translatable(KnownTranslationKeys::DEATH_ATTACK_ANVIL, [ + 0 => $param0, + ]); + } + public static function death_attack_arrow(Translatable|string $param0, Translatable|string $param1) : Translatable{ return new Translatable(KnownTranslationKeys::DEATH_ATTACK_ARROW, [ 0 => $param0, @@ -1490,6 +1496,25 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_level_conversion_finish(Translatable|string $worldName, Translatable|string $backupPath) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_CONVERSION_FINISH, [ + "worldName" => $worldName, + "backupPath" => $backupPath, + ]); + } + + public static function pocketmine_level_conversion_start(Translatable|string $worldName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_CONVERSION_START, [ + "worldName" => $worldName, + ]); + } + + public static function pocketmine_level_corrupted(Translatable|string $details) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_CORRUPTED, [ + "details" => $details, + ]); + } + public static function pocketmine_level_defaultError() : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_DEFAULTERROR, []); } @@ -1520,16 +1545,36 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_level_spawnTerrainGenerationProgress(Translatable|string $done, Translatable|string $total, Translatable|string $percentageDone) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_SPAWNTERRAINGENERATIONPROGRESS, [ + "done" => $done, + "total" => $total, + "percentageDone" => $percentageDone, + ]); + } + public static function pocketmine_level_unknownFormat() : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_UNKNOWNFORMAT, []); } + public static function pocketmine_level_unknownGenerator(Translatable|string $generatorName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_UNKNOWNGENERATOR, [ + "generatorName" => $generatorName, + ]); + } + public static function pocketmine_level_unloading(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_UNLOADING, [ 0 => $param0, ]); } + public static function pocketmine_level_unsupportedFormat(Translatable|string $details) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_UNSUPPORTEDFORMAT, [ + "details" => $details, + ]); + } + public static function pocketmine_player_invalidEntity(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLAYER_INVALIDENTITY, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 5c3d5bfa3..62ead25d9 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -128,6 +128,7 @@ final class KnownTranslationKeys{ public const COMMANDS_WHITELIST_REMOVE_SUCCESS = "commands.whitelist.remove.success"; public const COMMANDS_WHITELIST_REMOVE_USAGE = "commands.whitelist.remove.usage"; public const COMMANDS_WHITELIST_USAGE = "commands.whitelist.usage"; + public const DEATH_ATTACK_ANVIL = "death.attack.anvil"; public const DEATH_ATTACK_ARROW = "death.attack.arrow"; public const DEATH_ATTACK_ARROW_ITEM = "death.attack.arrow.item"; public const DEATH_ATTACK_CACTUS = "death.attack.cactus"; @@ -324,13 +325,19 @@ final class KnownTranslationKeys{ public const POCKETMINE_LEVEL_AMBIGUOUSFORMAT = "pocketmine.level.ambiguousFormat"; public const POCKETMINE_LEVEL_BACKGROUNDGENERATION = "pocketmine.level.backgroundGeneration"; public const POCKETMINE_LEVEL_BADDEFAULTFORMAT = "pocketmine.level.badDefaultFormat"; + public const POCKETMINE_LEVEL_CONVERSION_FINISH = "pocketmine.level.conversion.finish"; + public const POCKETMINE_LEVEL_CONVERSION_START = "pocketmine.level.conversion.start"; + public const POCKETMINE_LEVEL_CORRUPTED = "pocketmine.level.corrupted"; public const POCKETMINE_LEVEL_DEFAULTERROR = "pocketmine.level.defaultError"; public const POCKETMINE_LEVEL_GENERATIONERROR = "pocketmine.level.generationError"; public const POCKETMINE_LEVEL_LOADERROR = "pocketmine.level.loadError"; public const POCKETMINE_LEVEL_NOTFOUND = "pocketmine.level.notFound"; public const POCKETMINE_LEVEL_PREPARING = "pocketmine.level.preparing"; + public const POCKETMINE_LEVEL_SPAWNTERRAINGENERATIONPROGRESS = "pocketmine.level.spawnTerrainGenerationProgress"; public const POCKETMINE_LEVEL_UNKNOWNFORMAT = "pocketmine.level.unknownFormat"; + public const POCKETMINE_LEVEL_UNKNOWNGENERATOR = "pocketmine.level.unknownGenerator"; public const POCKETMINE_LEVEL_UNLOADING = "pocketmine.level.unloading"; + public const POCKETMINE_LEVEL_UNSUPPORTEDFORMAT = "pocketmine.level.unsupportedFormat"; public const POCKETMINE_PLAYER_INVALIDENTITY = "pocketmine.player.invalidEntity"; public const POCKETMINE_PLAYER_INVALIDMOVE = "pocketmine.player.invalidMove"; public const POCKETMINE_PLAYER_LOGIN = "pocketmine.player.logIn"; diff --git a/src/world/WorldManager.php b/src/world/WorldManager.php index 452e5a125..d79eee0b6 100644 --- a/src/world/WorldManager.php +++ b/src/world/WorldManager.php @@ -50,6 +50,7 @@ use function iterator_to_array; use function microtime; use function round; use function sprintf; +use function strval; use function trim; class WorldManager{ @@ -207,28 +208,37 @@ class WorldManager{ try{ $provider = $providerClass->fromPath($path); }catch(CorruptedWorldException $e){ - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError($name, "Corruption detected: " . $e->getMessage()))); + $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError( + $name, + KnownTranslationFactory::pocketmine_level_corrupted($e->getMessage()) + ))); return false; }catch(UnsupportedWorldFormatException $e){ - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError($name, "Unsupported format: " . $e->getMessage()))); + $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError( + $name, + KnownTranslationFactory::pocketmine_level_unsupportedFormat($e->getMessage()) + ))); return false; } try{ GeneratorManager::getInstance()->getGenerator($provider->getWorldData()->getGenerator(), true); }catch(\InvalidArgumentException $e){ - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError($name, "Unknown generator \"" . $provider->getWorldData()->getGenerator() . "\""))); + $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError( + $name, + KnownTranslationFactory::pocketmine_level_unknownGenerator($provider->getWorldData()->getGenerator()) + ))); return false; } if(!($provider instanceof WritableWorldProvider)){ if(!$autoUpgrade){ throw new UnsupportedWorldFormatException("World \"$name\" is in an unsupported format and needs to be upgraded"); } - $this->server->getLogger()->notice("Upgrading world \"$name\" to new format. This may take a while."); + $this->server->getLogger()->notice($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_conversion_start($name))); $converter = new FormatConverter($provider, $this->providerManager->getDefault(), Path::join($this->server->getDataPath(), "backups", "worlds"), $this->server->getLogger()); $provider = $converter->execute(); - $this->server->getLogger()->notice("Upgraded world \"$name\" to new format successfully. Backed up pre-conversion world at " . $converter->getBackupPath()); + $this->server->getLogger()->notice($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_conversion_finish($name, $converter->getBackupPath()))); } $world = new World($this->server, $name, $provider, $this->server->getAsyncPool()); @@ -282,7 +292,7 @@ class WorldManager{ $oldProgress = (int) floor(($done / $total) * 100); $newProgress = (int) floor((++$done / $total) * 100); if(intdiv($oldProgress, 10) !== intdiv($newProgress, 10) || $done === $total || $done === 1){ - $world->getLogger()->info("Generating spawn terrain chunks: $done / $total ($newProgress%)"); + $world->getLogger()->info($world->getServer()->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_spawnTerrainGenerationProgress(strval($done), strval($total), strval($newProgress)))); } }, static function() : void{ From 05dc675d5be8a245bba4250a4de1ca529d56b4c0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 20:42:59 +0100 Subject: [PATCH 031/710] Replace commands.generic.notFound with a custom PM version this also fixes #4379. --- resources/locale | 2 +- src/Server.php | 8 +------ src/command/SimpleCommandMap.php | 32 +++++++++++++--------------- src/lang/KnownTranslationFactory.php | 7 ++++++ src/lang/KnownTranslationKeys.php | 1 + 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/resources/locale b/resources/locale index 6023e8b3b..73fb74ffc 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit 6023e8b3bf089eb7c25a5ddc7b29e9ef81520e7e +Subproject commit 73fb74ffce2b633b87fc82039d1fb3c2cf0d5ac7 diff --git a/src/Server.php b/src/Server.php index 7b22fabf3..def42ef92 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1293,13 +1293,7 @@ class Server{ $commandLine = $ev->getCommand(); } - if($this->commandMap->dispatch($sender, $commandLine)){ - return true; - } - - $sender->sendMessage(KnownTranslationFactory::commands_generic_notFound()->prefix(TextFormat::RED)); - - return false; + return $this->commandMap->dispatch($sender, $commandLine); } /** diff --git a/src/command/SimpleCommandMap.php b/src/command/SimpleCommandMap.php index 638e10740..6b8f392e6 100644 --- a/src/command/SimpleCommandMap.php +++ b/src/command/SimpleCommandMap.php @@ -67,6 +67,7 @@ use pocketmine\command\defaults\WhitelistCommand; use pocketmine\command\utils\InvalidCommandSyntaxException; use pocketmine\lang\KnownTranslationFactory; use pocketmine\Server; +use pocketmine\utils\TextFormat; use function array_shift; use function count; use function explode; @@ -210,26 +211,23 @@ class SimpleCommandMap implements CommandMap{ } } } + $sentCommandLabel = array_shift($args); - if($sentCommandLabel === null){ - return false; - } - $target = $this->getCommand($sentCommandLabel); - if($target === null){ - return false; + if($sentCommandLabel !== null && ($target = $this->getCommand($sentCommandLabel)) !== null){ + $target->timings->startTiming(); + + try{ + $target->execute($sender, $sentCommandLabel, $args); + }catch(InvalidCommandSyntaxException $e){ + $sender->sendMessage($sender->getLanguage()->translate(KnownTranslationFactory::commands_generic_usage($target->getUsage()))); + }finally{ + $target->timings->stopTiming(); + } + return true; } - $target->timings->startTiming(); - - try{ - $target->execute($sender, $sentCommandLabel, $args); - }catch(InvalidCommandSyntaxException $e){ - $sender->sendMessage($sender->getLanguage()->translate(KnownTranslationFactory::commands_generic_usage($target->getUsage()))); - }finally{ - $target->timings->stopTiming(); - } - - return true; + $sender->sendMessage(KnownTranslationFactory::pocketmine_command_notFound($sentCommandLabel ?? "", "/help")->prefix(TextFormat::RED)); + return false; } public function clearCommands() : void{ diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 62bc5d289..a36417c81 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1185,6 +1185,13 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_ME_DESCRIPTION, []); } + public static function pocketmine_command_notFound(Translatable|string $commandName, Translatable|string $helpCommand) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_NOTFOUND, [ + "commandName" => $commandName, + "helpCommand" => $helpCommand, + ]); + } + public static function pocketmine_command_op_description() : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_OP_DESCRIPTION, []); } diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 62ead25d9..65a3c9a76 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -260,6 +260,7 @@ final class KnownTranslationKeys{ public const POCKETMINE_COMMAND_KILL_USAGE = "pocketmine.command.kill.usage"; public const POCKETMINE_COMMAND_LIST_DESCRIPTION = "pocketmine.command.list.description"; public const POCKETMINE_COMMAND_ME_DESCRIPTION = "pocketmine.command.me.description"; + public const POCKETMINE_COMMAND_NOTFOUND = "pocketmine.command.notFound"; public const POCKETMINE_COMMAND_OP_DESCRIPTION = "pocketmine.command.op.description"; public const POCKETMINE_COMMAND_PARTICLE_DESCRIPTION = "pocketmine.command.particle.description"; public const POCKETMINE_COMMAND_PARTICLE_USAGE = "pocketmine.command.particle.usage"; From 30e10c38b6933dd1e6b7c935e70fc7c5b1e7dae4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 20:59:36 +0100 Subject: [PATCH 032/710] Localize /help --- resources/locale | 2 +- src/command/defaults/HelpCommand.php | 13 ++++++++----- src/lang/KnownTranslationFactory.php | 18 ++++++++++++++++++ src/lang/KnownTranslationKeys.php | 3 +++ 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/resources/locale b/resources/locale index 73fb74ffc..73439bd44 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit 73fb74ffce2b633b87fc82039d1fb3c2cf0d5ac7 +Subproject commit 73439bd4492a3fb3c3ed11eb6e654cf4a282b20c diff --git a/src/command/defaults/HelpCommand.php b/src/command/defaults/HelpCommand.php index 77bc98d0e..f16049a69 100644 --- a/src/command/defaults/HelpCommand.php +++ b/src/command/defaults/HelpCommand.php @@ -105,17 +105,20 @@ class HelpCommand extends VanillaCommand{ $lang = $sender->getLanguage(); $description = $cmd->getDescription(); $descriptionString = $description instanceof Translatable ? $lang->translate($description) : $description; - $message = TextFormat::YELLOW . "--------- " . TextFormat::WHITE . " Help: /" . $cmd->getName() . TextFormat::YELLOW . " ---------\n"; - $message .= TextFormat::GOLD . "Description: " . TextFormat::WHITE . $descriptionString . "\n"; + $sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_header($commandName) + ->format(TextFormat::YELLOW . "--------- " . TextFormat::WHITE, TextFormat::YELLOW . " ---------")); + $sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_description(TextFormat::WHITE . $descriptionString) + ->prefix(TextFormat::GOLD)); + $usage = $cmd->getUsage(); $usageString = $usage instanceof Translatable ? $lang->translate($usage) : $usage; - $message .= TextFormat::GOLD . "Usage: " . TextFormat::WHITE . implode("\n" . TextFormat::WHITE, explode("\n", $usageString)) . "\n"; - $sender->sendMessage($message); + $sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_usage(TextFormat::WHITE . implode("\n" . TextFormat::WHITE, explode("\n", $usageString))) + ->prefix(TextFormat::GOLD)); return true; } } - $sender->sendMessage(TextFormat::RED . "No help for " . strtolower($commandName)); + $sender->sendMessage(KnownTranslationFactory::pocketmine_command_notFound($commandName, "/help")->prefix(TextFormat::RED)); return true; } diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index a36417c81..1150e1d51 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1165,6 +1165,24 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_HELP_DESCRIPTION, []); } + public static function pocketmine_command_help_specificCommand_description(Translatable|string $description) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_DESCRIPTION, [ + "description" => $description, + ]); + } + + public static function pocketmine_command_help_specificCommand_header(Translatable|string $commandName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_HEADER, [ + "commandName" => $commandName, + ]); + } + + public static function pocketmine_command_help_specificCommand_usage(Translatable|string $usage) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_USAGE, [ + "usage" => $usage, + ]); + } + public static function pocketmine_command_kick_description() : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_KICK_DESCRIPTION, []); } diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 65a3c9a76..88807b997 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -255,6 +255,9 @@ final class KnownTranslationKeys{ public const POCKETMINE_COMMAND_GIVE_DESCRIPTION = "pocketmine.command.give.description"; public const POCKETMINE_COMMAND_GIVE_USAGE = "pocketmine.command.give.usage"; public const POCKETMINE_COMMAND_HELP_DESCRIPTION = "pocketmine.command.help.description"; + public const POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_DESCRIPTION = "pocketmine.command.help.specificCommand.description"; + public const POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_HEADER = "pocketmine.command.help.specificCommand.header"; + public const POCKETMINE_COMMAND_HELP_SPECIFICCOMMAND_USAGE = "pocketmine.command.help.specificCommand.usage"; public const POCKETMINE_COMMAND_KICK_DESCRIPTION = "pocketmine.command.kick.description"; public const POCKETMINE_COMMAND_KILL_DESCRIPTION = "pocketmine.command.kill.description"; public const POCKETMINE_COMMAND_KILL_USAGE = "pocketmine.command.kill.usage"; From fb570970a8384cf0cea1a2c2659c62b5a68fc805 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 2 Oct 2021 21:22:54 +0100 Subject: [PATCH 033/710] Localize gamemode command errors --- resources/locale | 2 +- src/command/defaults/DefaultGamemodeCommand.php | 2 +- src/command/defaults/GamemodeCommand.php | 4 ++-- src/lang/KnownTranslationFactory.php | 12 ++++++++++++ src/lang/KnownTranslationKeys.php | 2 ++ 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/resources/locale b/resources/locale index 73439bd44..cb47518ae 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit 73439bd4492a3fb3c3ed11eb6e654cf4a282b20c +Subproject commit cb47518ae37ce834b612b2efe2df841852d07a31 diff --git a/src/command/defaults/DefaultGamemodeCommand.php b/src/command/defaults/DefaultGamemodeCommand.php index f7752319e..d2ae848ae 100644 --- a/src/command/defaults/DefaultGamemodeCommand.php +++ b/src/command/defaults/DefaultGamemodeCommand.php @@ -53,7 +53,7 @@ class DefaultGamemodeCommand extends VanillaCommand{ $gameMode = GameMode::fromString($args[0]); if($gameMode === null){ - $sender->sendMessage("Unknown game mode"); + $sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_unknown($args[0])); return true; } diff --git a/src/command/defaults/GamemodeCommand.php b/src/command/defaults/GamemodeCommand.php index e01150875..86658de6d 100644 --- a/src/command/defaults/GamemodeCommand.php +++ b/src/command/defaults/GamemodeCommand.php @@ -55,7 +55,7 @@ class GamemodeCommand extends VanillaCommand{ $gameMode = GameMode::fromString($args[0]); if($gameMode === null){ - $sender->sendMessage("Unknown game mode"); + $sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_unknown($args[0])); return true; } @@ -74,7 +74,7 @@ class GamemodeCommand extends VanillaCommand{ $target->setGamemode($gameMode); if(!$gameMode->equals($target->getGamemode())){ - $sender->sendMessage("Game mode change for " . $target->getName() . " failed!"); + $sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_failure($target->getName())); }else{ if($target === $sender){ Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_gamemode_success_self($gameMode->getTranslatableName())); diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 1150e1d51..9fc1fc67b 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1121,6 +1121,18 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_GAMEMODE_DESCRIPTION, []); } + public static function pocketmine_command_gamemode_failure(Translatable|string $playerName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_GAMEMODE_FAILURE, [ + "playerName" => $playerName, + ]); + } + + public static function pocketmine_command_gamemode_unknown(Translatable|string $gameModeName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_GAMEMODE_UNKNOWN, [ + "gameModeName" => $gameModeName, + ]); + } + public static function pocketmine_command_gc_chunks(Translatable|string $chunksCollected) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_GC_CHUNKS, [ "chunksCollected" => $chunksCollected, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 88807b997..0814c5ddd 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -246,6 +246,8 @@ final class KnownTranslationKeys{ public const POCKETMINE_COMMAND_ENCHANT_DESCRIPTION = "pocketmine.command.enchant.description"; public const POCKETMINE_COMMAND_EXCEPTION = "pocketmine.command.exception"; public const POCKETMINE_COMMAND_GAMEMODE_DESCRIPTION = "pocketmine.command.gamemode.description"; + public const POCKETMINE_COMMAND_GAMEMODE_FAILURE = "pocketmine.command.gamemode.failure"; + public const POCKETMINE_COMMAND_GAMEMODE_UNKNOWN = "pocketmine.command.gamemode.unknown"; public const POCKETMINE_COMMAND_GC_CHUNKS = "pocketmine.command.gc.chunks"; public const POCKETMINE_COMMAND_GC_CYCLES = "pocketmine.command.gc.cycles"; public const POCKETMINE_COMMAND_GC_DESCRIPTION = "pocketmine.command.gc.description"; From 6332af3e5925c15b7bc71a068aeb4c69fcdef347 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 4 Oct 2021 21:50:11 +0100 Subject: [PATCH 034/710] Require RakLib 0.14.2 minimum --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 12ff5f393..ee6bccdcc 100644 --- a/composer.json +++ b/composer.json @@ -44,7 +44,7 @@ "pocketmine/log-pthreads": "^0.2.0", "pocketmine/math": "^0.3.0", "pocketmine/nbt": "^0.3.0", - "pocketmine/raklib": "^0.14.0", + "pocketmine/raklib": "^0.14.2", "pocketmine/raklib-ipc": "^0.1.0", "pocketmine/snooze": "^0.3.0", "pocketmine/spl": "dev-master", diff --git a/composer.lock b/composer.lock index d79f12428..e2b12903f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bd5d7fc81a75739bfd2ef04b38220b84", + "content-hash": "77f899b35819bca38246a665fd0233f3", "packages": [ { "name": "adhocore/json-comment", @@ -675,16 +675,16 @@ }, { "name": "pocketmine/raklib", - "version": "0.14.1", + "version": "0.14.2", "source": { "type": "git", "url": "https://github.com/pmmp/RakLib.git", - "reference": "2d7bac3d593219880696ca2ca254f083f1e71850" + "reference": "e3a861187470e1facc6625040128f447ebbcbaec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/RakLib/zipball/2d7bac3d593219880696ca2ca254f083f1e71850", - "reference": "2d7bac3d593219880696ca2ca254f083f1e71850", + "url": "https://api.github.com/repos/pmmp/RakLib/zipball/e3a861187470e1facc6625040128f447ebbcbaec", + "reference": "e3a861187470e1facc6625040128f447ebbcbaec", "shasum": "" }, "require": { @@ -712,9 +712,9 @@ "description": "A RakNet server implementation written in PHP", "support": { "issues": "https://github.com/pmmp/RakLib/issues", - "source": "https://github.com/pmmp/RakLib/tree/0.14.1" + "source": "https://github.com/pmmp/RakLib/tree/0.14.2" }, - "time": "2021-10-01T20:35:44+00:00" + "time": "2021-10-04T20:39:11+00:00" }, { "name": "pocketmine/raklib-ipc", From 356a49d225ca9b735fd16cf1b5c9d3c7d1e9de0c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 4 Oct 2021 22:12:58 +0100 Subject: [PATCH 035/710] NetworkSession: account for possibility of syncGameMode() being called before the player is ready to receive it close #4323 --- src/network/mcpe/NetworkSession.php | 6 ++++-- tests/phpstan/configs/l8-baseline.neon | 7 +------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 45d6daaa6..3020484b2 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -754,8 +754,10 @@ class NetworkSession{ public function syncGameMode(GameMode $mode, bool $isRollback = false) : void{ $this->sendDataPacket(SetPlayerGameTypePacket::create(TypeConverter::getInstance()->coreGameModeToProtocol($mode))); - $this->syncAdventureSettings($this->player); - if(!$isRollback){ + if($this->player !== null){ + $this->syncAdventureSettings($this->player); + } + if(!$isRollback && $this->invManager !== null){ $this->invManager->syncCreative(); } } diff --git a/tests/phpstan/configs/l8-baseline.neon b/tests/phpstan/configs/l8-baseline.neon index 2c4824f43..c97b63728 100644 --- a/tests/phpstan/configs/l8-baseline.neon +++ b/tests/phpstan/configs/l8-baseline.neon @@ -125,11 +125,6 @@ parameters: count: 1 path: ../../../src/network/mcpe/NetworkSession.php - - - message: "#^Cannot call method syncCreative\\(\\) on pocketmine\\\\network\\\\mcpe\\\\InventoryManager\\|null\\.$#" - count: 1 - path: ../../../src/network/mcpe/NetworkSession.php - - message: "#^Parameter \\#1 \\$clientPub of class pocketmine\\\\network\\\\mcpe\\\\encryption\\\\PrepareEncryptionTask constructor expects string, string\\|null given\\.$#" count: 1 @@ -147,7 +142,7 @@ parameters: - message: "#^Parameter \\#1 \\$for of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:syncAdventureSettings\\(\\) expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#" - count: 3 + count: 2 path: ../../../src/network/mcpe/NetworkSession.php - From bb6ea8cbdc3f457c85f31f73a6efeab98d0d295a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 4 Oct 2021 22:36:50 +0100 Subject: [PATCH 036/710] Do not call PlayerLoginEvent during the Player constructor this closes a lot of loopholes in the login sequence that plugins were using to cause crashes. --- src/Server.php | 26 +++++++++++++++++++++++++- src/network/mcpe/NetworkSession.php | 4 ++++ src/player/Player.php | 23 ----------------------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/Server.php b/src/Server.php index def42ef92..c99ac010e 100644 --- a/src/Server.php +++ b/src/Server.php @@ -40,6 +40,7 @@ use pocketmine\entity\Location; use pocketmine\event\HandlerListManager; use pocketmine\event\player\PlayerCreationEvent; use pocketmine\event\player\PlayerDataSaveEvent; +use pocketmine\event\player\PlayerLoginEvent; use pocketmine\event\server\CommandEvent; use pocketmine\event\server\DataPacketSendEvent; use pocketmine\event\server\QueryRegenerateEvent; @@ -1521,7 +1522,28 @@ class Server{ } } - public function addOnlinePlayer(Player $player) : void{ + public function addOnlinePlayer(Player $player) : bool{ + $ev = new PlayerLoginEvent($player, "Plugin reason"); + $ev->call(); + if($ev->isCancelled() or !$player->isConnected()){ + $player->disconnect($ev->getKickMessage()); + + return false; + } + + $session = $player->getNetworkSession(); + $position = $player->getPosition(); + $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_player_logIn( + TextFormat::AQUA . $player->getName() . TextFormat::WHITE, + $session->getIp(), + (string) $session->getPort(), + (string) $player->getId(), + $position->getWorld()->getDisplayName(), + (string) round($position->x, 4), + (string) round($position->y, 4), + (string) round($position->z, 4) + ))); + foreach($this->playerList as $p){ $p->getNetworkSession()->onPlayerAdded($player); } @@ -1531,6 +1553,8 @@ class Server{ if($this->sendUsageTicker > 0){ $this->uniquePlayers[$rawUUID] = $rawUUID; } + + return true; } public function removeOnlinePlayer(Player $player) : void{ diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 3020484b2..cff5b3ee9 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -234,6 +234,10 @@ class NetworkSession{ return; } $this->player = $player; + if(!$this->server->addOnlinePlayer($player)){ + return; + } + $this->invManager = new InventoryManager($this->player, $this); $effectManager = $this->player->getEffects(); diff --git a/src/player/Player.php b/src/player/Player.php index 14a6b205a..bd7222af0 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -63,7 +63,6 @@ use pocketmine\event\player\PlayerItemUseEvent; use pocketmine\event\player\PlayerJoinEvent; use pocketmine\event\player\PlayerJumpEvent; use pocketmine\event\player\PlayerKickEvent; -use pocketmine\event\player\PlayerLoginEvent; use pocketmine\event\player\PlayerMoveEvent; use pocketmine\event\player\PlayerQuitEvent; use pocketmine\event\player\PlayerRespawnEvent; @@ -133,7 +132,6 @@ use function max; use function microtime; use function min; use function preg_match; -use function round; use function spl_object_id; use function sqrt; use function strlen; @@ -277,27 +275,6 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->usedChunks[World::chunkHash($spawnLocation->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawnLocation->getFloorZ() >> Chunk::COORD_BIT_SIZE)] = UsedChunkStatus::NEEDED(); parent::__construct($spawnLocation, $this->playerInfo->getSkin(), $namedtag); - - $ev = new PlayerLoginEvent($this, "Plugin reason"); - $ev->call(); - if($ev->isCancelled() or !$this->isConnected()){ - $this->disconnect($ev->getKickMessage()); - - return; - } - - $this->server->getLogger()->info($this->getServer()->getLanguage()->translate(KnownTranslationFactory::pocketmine_player_logIn( - TextFormat::AQUA . $this->username . TextFormat::WHITE, - $session->getIp(), - (string) $session->getPort(), - (string) $this->id, - $this->getWorld()->getDisplayName(), - (string) round($this->location->x, 4), - (string) round($this->location->y, 4), - (string) round($this->location->z, 4) - ))); - - $this->server->addOnlinePlayer($this); } protected function initHumanData(CompoundTag $nbt) : void{ From f2d60596134c51fb061797c5c06b0e7d3b21e64b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 4 Oct 2021 22:51:31 +0100 Subject: [PATCH 037/710] NetworkSession: Sync world spawn on world change --- src/network/mcpe/NetworkSession.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index cff5b3ee9..abf2a7c77 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -756,6 +756,11 @@ class NetworkSession{ $this->sendDataPacket(SetSpawnPositionPacket::playerSpawn($x, $y, $z, DimensionIds::OVERWORLD, $x, $y, $z)); } + public function syncWorldSpawnPoint(Position $newSpawn) : void{ + [$x, $y, $z] = [$newSpawn->getFloorX(), $newSpawn->getFloorY(), $newSpawn->getFloorZ()]; + $this->sendDataPacket(SetSpawnPositionPacket::worldSpawn($x, $y, $z, DimensionIds::OVERWORLD, $x, $y, $z)); + } + public function syncGameMode(GameMode $mode, bool $isRollback = false) : void{ $this->sendDataPacket(SetPlayerGameTypePacket::create(TypeConverter::getInstance()->coreGameModeToProtocol($mode))); if($this->player !== null){ @@ -939,8 +944,8 @@ class NetworkSession{ $world = $this->player->getWorld(); $this->syncWorldTime($world->getTime()); $this->syncWorldDifficulty($world->getDifficulty()); + $this->syncWorldSpawnPoint($world->getSpawnLocation()); //TODO: weather needs to be synced here (when implemented) - //TODO: world spawn needs to be synced here } } From 5b26abcb0ec730334e46b326a2d17e91a9e205c0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 01:02:15 +0100 Subject: [PATCH 038/710] NetworkSession: fixed code copy pasta these are not, in fact, equivalent. --- src/network/mcpe/NetworkSession.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index abf2a7c77..be4ea440a 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -757,8 +757,7 @@ class NetworkSession{ } public function syncWorldSpawnPoint(Position $newSpawn) : void{ - [$x, $y, $z] = [$newSpawn->getFloorX(), $newSpawn->getFloorY(), $newSpawn->getFloorZ()]; - $this->sendDataPacket(SetSpawnPositionPacket::worldSpawn($x, $y, $z, DimensionIds::OVERWORLD, $x, $y, $z)); + $this->sendDataPacket(SetSpawnPositionPacket::worldSpawn($newSpawn->getFloorX(), $newSpawn->getFloorY(), $newSpawn->getFloorZ(), DimensionIds::OVERWORLD)); } public function syncGameMode(GameMode $mode, bool $isRollback = false) : void{ From a27c14c00c184d2bbbb7350c4bcc6c38a77b60cb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 00:14:21 +0000 Subject: [PATCH 039/710] phpstan: exclude build/php from analysis in case I built PHP in there, I don't want the install_data getting analysed and screwing up the analysis. --- phpstan.neon.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e4a50aca4..9240471d4 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -33,6 +33,7 @@ parameters: - tests/plugins/TesterPlugin excludePaths: analyseAndScan: + - build/php - build/preprocessor dynamicConstantNames: - pocketmine\DEBUG From 7d06b76aafce64f6d0121b41eb6a4a6f6ef69824 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 18:36:00 +0100 Subject: [PATCH 040/710] PluginManager: account for possible invalid format of API version we're seeing a lot of crashes because of this. --- resources/locale | 2 +- src/lang/KnownTranslationFactory.php | 6 ++++++ src/lang/KnownTranslationKeys.php | 1 + src/plugin/PluginManager.php | 11 +++++++++++ src/utils/VersionString.php | 4 ++++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/resources/locale b/resources/locale index cb47518ae..cf184a00f 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit cb47518ae37ce834b612b2efe2df841852d07a31 +Subproject commit cf184a00f886a49dd91c2acb69384c630d3ac102 diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 9fc1fc67b..c66c5e35d 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1734,6 +1734,12 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_plugin_invalidAPI(Translatable|string $apiVersion) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_INVALIDAPI, [ + "apiVersion" => $apiVersion, + ]); + } + public static function pocketmine_plugin_load(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_LOAD, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 0814c5ddd..3171445be 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -362,6 +362,7 @@ final class KnownTranslationKeys{ public const POCKETMINE_PLUGIN_INCOMPATIBLEOS = "pocketmine.plugin.incompatibleOS"; public const POCKETMINE_PLUGIN_INCOMPATIBLEPHPVERSION = "pocketmine.plugin.incompatiblePhpVersion"; public const POCKETMINE_PLUGIN_INCOMPATIBLEPROTOCOL = "pocketmine.plugin.incompatibleProtocol"; + public const POCKETMINE_PLUGIN_INVALIDAPI = "pocketmine.plugin.invalidAPI"; public const POCKETMINE_PLUGIN_LOAD = "pocketmine.plugin.load"; public const POCKETMINE_PLUGIN_LOADERROR = "pocketmine.plugin.loadError"; public const POCKETMINE_PLUGIN_RESTRICTEDNAME = "pocketmine.plugin.restrictedName"; diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index c646a4dff..2ab687525 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -40,6 +40,7 @@ use pocketmine\Server; use pocketmine\timings\TimingsHandler; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Utils; +use pocketmine\utils\VersionString; use Webmozart\PathUtil\Path; use function array_intersect; use function array_merge; @@ -268,6 +269,16 @@ class PluginManager{ continue; } + foreach($description->getCompatibleApis() as $api){ + if(!VersionString::isValidBaseVersion($api)){ + $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( + $name, + KnownTranslationFactory::pocketmine_plugin_invalidAPI($api) + ))); + continue 2; + } + } + if(!ApiVersion::isCompatible($this->server->getApiVersion(), $description->getCompatibleApis())){ $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( $name, diff --git a/src/utils/VersionString.php b/src/utils/VersionString.php index 1dd666c9f..7dae029b5 100644 --- a/src/utils/VersionString.php +++ b/src/utils/VersionString.php @@ -63,6 +63,10 @@ class VersionString{ $this->suffix = $matches[4] ?? ""; } + public static function isValidBaseVersion(string $baseVersion) : bool{ + return preg_match('/^\d+\.\d+\.\d+(?:-(.*))?$/', $baseVersion, $matches) === 1; + } + public function getNumber() : int{ return (($this->major << 9) | ($this->minor << 5) | $this->patch); } From 2db79cf58d5a66cc2ff280e4d5430799f8d45a46 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 18:41:47 +0100 Subject: [PATCH 041/710] Fix build --- src/lang/KnownTranslationFactory.php | 6 ++++++ src/lang/KnownTranslationKeys.php | 1 + 2 files changed, 7 insertions(+) diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index c66c5e35d..e4aea7df6 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1109,6 +1109,12 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_ENCHANT_DESCRIPTION, []); } + public static function pocketmine_command_error_playerNotFound(Translatable|string $playerName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_ERROR_PLAYERNOTFOUND, [ + "playerName" => $playerName, + ]); + } + public static function pocketmine_command_exception(Translatable|string $param0, Translatable|string $param1, Translatable|string $param2) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_EXCEPTION, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 3171445be..4b8d87c64 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -244,6 +244,7 @@ final class KnownTranslationKeys{ public const POCKETMINE_COMMAND_DIFFICULTY_DESCRIPTION = "pocketmine.command.difficulty.description"; public const POCKETMINE_COMMAND_EFFECT_DESCRIPTION = "pocketmine.command.effect.description"; public const POCKETMINE_COMMAND_ENCHANT_DESCRIPTION = "pocketmine.command.enchant.description"; + public const POCKETMINE_COMMAND_ERROR_PLAYERNOTFOUND = "pocketmine.command.error.playerNotFound"; public const POCKETMINE_COMMAND_EXCEPTION = "pocketmine.command.exception"; public const POCKETMINE_COMMAND_GAMEMODE_DESCRIPTION = "pocketmine.command.gamemode.description"; public const POCKETMINE_COMMAND_GAMEMODE_FAILURE = "pocketmine.command.gamemode.failure"; From dbeaf27cb7485a422f1ab5a7748baf3a29639c8f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 19:09:22 +0100 Subject: [PATCH 042/710] Document that Item::setNamedTag() may cause NbtException to be thrown if the NBT is bogus for some reason in PM3, these kinds of bugs wouldn't show up until/unless the item NBT was actually used, but on PM4, we decode it ahead of time, so the errors always show up immediately. --- src/item/Item.php | 6 ++++++ src/item/ItemFactory.php | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/item/Item.php b/src/item/Item.php index b28bf9066..f37015ba9 100644 --- a/src/item/Item.php +++ b/src/item/Item.php @@ -37,6 +37,7 @@ use pocketmine\math\Vector3; use pocketmine\nbt\LittleEndianNbtSerializer; use pocketmine\nbt\NBT; use pocketmine\nbt\NbtDataException; +use pocketmine\nbt\NbtException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ShortTag; @@ -240,6 +241,7 @@ class Item implements \JsonSerializable{ * Sets the Item's NBT from the supplied CompoundTag object. * * @return $this + * @throws NbtException */ public function setNamedTag(CompoundTag $tag) : Item{ if($tag->getCount() === 0){ @@ -255,6 +257,7 @@ class Item implements \JsonSerializable{ /** * Removes the Item's NBT. * @return $this + * @throws NbtException */ public function clearNamedTag() : Item{ $this->nbt = new CompoundTag(); @@ -262,6 +265,9 @@ class Item implements \JsonSerializable{ return $this; } + /** + * @throws NbtException + */ protected function deserializeCompoundTag(CompoundTag $tag) : void{ $this->customName = ""; $this->lore = []; diff --git a/src/item/ItemFactory.php b/src/item/ItemFactory.php index 5fb7438a1..0e1a710ce 100644 --- a/src/item/ItemFactory.php +++ b/src/item/ItemFactory.php @@ -41,6 +41,7 @@ use pocketmine\entity\Villager; use pocketmine\entity\Zombie; use pocketmine\inventory\ArmorInventory; use pocketmine\math\Vector3; +use pocketmine\nbt\NbtException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\utils\SingletonTrait; use pocketmine\world\World; @@ -444,6 +445,7 @@ class ItemFactory{ * Deserializes an item from the provided legacy ID, legacy meta, count and NBT. * * @throws \InvalidArgumentException + * @throws NbtException */ public function get(int $id, int $meta = 0, int $count = 1, ?CompoundTag $tags = null) : Item{ /** @var Item|null $item */ From fef8297907b22baec072708c162cf76aa0a1db89 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 19:09:46 +0100 Subject: [PATCH 043/710] GiveCommand: don't crash on bogus item NBT --- src/command/defaults/GiveCommand.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/command/defaults/GiveCommand.php b/src/command/defaults/GiveCommand.php index 34814f207..8fd5c4298 100644 --- a/src/command/defaults/GiveCommand.php +++ b/src/command/defaults/GiveCommand.php @@ -32,6 +32,7 @@ use pocketmine\item\StringToItemParser; use pocketmine\lang\KnownTranslationFactory; use pocketmine\nbt\JsonNbtParser; use pocketmine\nbt\NbtDataException; +use pocketmine\nbt\NbtException; use pocketmine\permission\DefaultPermissionNames; use pocketmine\utils\TextFormat; use function array_slice; @@ -86,7 +87,12 @@ class GiveCommand extends VanillaCommand{ return true; } - $item->setNamedTag($tags); + try{ + $item->setNamedTag($tags); + }catch(NbtException $e){ + $sender->sendMessage(KnownTranslationFactory::commands_give_tagError($e->getMessage())); + return true; + } } //TODO: overflow From 817ab88c70b5bc574908e82f88284e81f5a91fe2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 19:10:55 +0100 Subject: [PATCH 044/710] Properly handle errors decoding network item NBT since the NBT is now decoded immediately now, any incorrect NBT will cause exceptions to be thrown that we weren't handling, causing server crashes. --- src/network/mcpe/convert/TypeConverter.php | 46 +++++++++++++------ .../mcpe/handler/InGamePacketHandler.php | 5 +- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/network/mcpe/convert/TypeConverter.php b/src/network/mcpe/convert/TypeConverter.php index c523eac10..d878423f6 100644 --- a/src/network/mcpe/convert/TypeConverter.php +++ b/src/network/mcpe/convert/TypeConverter.php @@ -37,6 +37,7 @@ use pocketmine\item\Durable; use pocketmine\item\Item; use pocketmine\item\ItemFactory; use pocketmine\item\ItemIds; +use pocketmine\nbt\NbtException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; use pocketmine\network\mcpe\InventoryManager; @@ -183,6 +184,9 @@ class TypeConverter{ ); } + /** + * @throws TypeConversionException + */ public function netItemStackToCore(ItemStack $itemStack) : Item{ if($itemStack->getId() === 0){ return ItemFactory::getInstance()->get(ItemIds::AIR, 0, 0); @@ -214,12 +218,16 @@ class TypeConverter{ } } - return ItemFactory::getInstance()->get( - $id, - $meta, - $itemStack->getCount(), - $compound - ); + try{ + return ItemFactory::getInstance()->get( + $id, + $meta, + $itemStack->getCount(), + $compound + ); + }catch(NbtException $e){ + throw TypeConversionException::wrap($e, "Bad itemstack NBT data"); + } } /** @@ -239,15 +247,23 @@ class TypeConverter{ } /** - * @throws \UnexpectedValueException + * @throws TypeConversionException */ public function createInventoryAction(NetworkInventoryAction $action, Player $player, InventoryManager $inventoryManager) : ?InventoryAction{ if($action->oldItem->getItemStack()->equals($action->newItem->getItemStack())){ //filter out useless noise in 1.13 return null; } - $old = $this->netItemStackToCore($action->oldItem->getItemStack()); - $new = $this->netItemStackToCore($action->newItem->getItemStack()); + try{ + $old = $this->netItemStackToCore($action->oldItem->getItemStack()); + }catch(TypeConversionException $e){ + throw TypeConversionException::wrap($e, "Inventory action: oldItem"); + } + try{ + $new = $this->netItemStackToCore($action->newItem->getItemStack()); + }catch(TypeConversionException $e){ + throw TypeConversionException::wrap($e, "Inventory action: newItem"); + } switch($action->sourceType){ case NetworkInventoryAction::SOURCE_CONTAINER: if($action->windowId === ContainerIds::UI and $action->inventorySlot > 0){ @@ -273,7 +289,7 @@ class TypeConverter{ fn(Inventory $i) => $i instanceof LoomInventory); } if($mapped === null){ - throw new \UnexpectedValueException("Unmatched UI inventory slot offset $pSlot"); + throw new TypeConversionException("Unmatched UI inventory slot offset $pSlot"); } [$slot, $window] = $mapped; }else{ @@ -284,10 +300,10 @@ class TypeConverter{ return new SlotChangeAction($window, $slot, $old, $new); } - throw new \UnexpectedValueException("No open container with window ID $action->windowId"); + throw new TypeConversionException("No open container with window ID $action->windowId"); case NetworkInventoryAction::SOURCE_WORLD: if($action->inventorySlot !== NetworkInventoryAction::ACTION_MAGIC_SLOT_DROP_ITEM){ - throw new \UnexpectedValueException("Only expecting drop-item world actions from the client!"); + throw new TypeConversionException("Only expecting drop-item world actions from the client!"); } return new DropItemAction($new); @@ -298,7 +314,7 @@ class TypeConverter{ case NetworkInventoryAction::ACTION_MAGIC_SLOT_CREATIVE_CREATE_ITEM: return new CreateItemAction($old); default: - throw new \UnexpectedValueException("Unexpected creative action type $action->inventorySlot"); + throw new TypeConversionException("Unexpected creative action type $action->inventorySlot"); } case NetworkInventoryAction::SOURCE_TODO: @@ -310,9 +326,9 @@ class TypeConverter{ } //TODO: more stuff - throw new \UnexpectedValueException("No open container with window ID $action->windowId"); + throw new TypeConversionException("No open container with window ID $action->windowId"); default: - throw new \UnexpectedValueException("Unknown inventory source type $action->sourceType"); + throw new TypeConversionException("Unknown inventory source type $action->sourceType"); } } } diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index c36510d02..65d294ae8 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -42,6 +42,7 @@ use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\convert\SkinAdapterSingleton; +use pocketmine\network\mcpe\convert\TypeConversionException; use pocketmine\network\mcpe\convert\TypeConverter; use pocketmine\network\mcpe\InventoryManager; use pocketmine\network\mcpe\NetworkSession; @@ -271,8 +272,8 @@ class InGamePacketHandler extends PacketHandler{ if($action !== null){ $actions[] = $action; } - }catch(\UnexpectedValueException $e){ - $this->session->getLogger()->debug("Unhandled inventory action: " . $e->getMessage()); + }catch(TypeConversionException $e){ + $this->session->getLogger()->debug("Error unpacking inventory action: " . $e->getMessage()); return false; } } From 13178a47a5eed4a72b7854c44134d5bbd12c6bf5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 19:11:10 +0100 Subject: [PATCH 045/710] fuck you git --- .../mcpe/convert/TypeConversionException.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/network/mcpe/convert/TypeConversionException.php diff --git a/src/network/mcpe/convert/TypeConversionException.php b/src/network/mcpe/convert/TypeConversionException.php new file mode 100644 index 000000000..fb24fefd3 --- /dev/null +++ b/src/network/mcpe/convert/TypeConversionException.php @@ -0,0 +1,35 @@ +getMessage(), 0, $previous); + } +} From 7245d15abe045983588c7d812e79b2ba2020b458 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 19:57:26 +0100 Subject: [PATCH 046/710] PermissionParser: Throw more specific exceptions --- src/permission/PermissionParser.php | 7 +++-- src/permission/PermissionParserException.php | 31 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 src/permission/PermissionParserException.php diff --git a/src/permission/PermissionParser.php b/src/permission/PermissionParser.php index 7115a5536..c7733a49c 100644 --- a/src/permission/PermissionParser.php +++ b/src/permission/PermissionParser.php @@ -55,7 +55,7 @@ class PermissionParser{ /** * @param bool|string $value * - * @throws \InvalidArgumentException + * @throws PermissionParserException */ public static function defaultFromString($value) : string{ if(is_bool($value)){ @@ -70,7 +70,7 @@ class PermissionParser{ return self::DEFAULT_STRING_MAP[$lower]; } - throw new \InvalidArgumentException("Unknown permission default name \"$value\""); + throw new PermissionParserException("Unknown permission default name \"$value\""); } /** @@ -79,6 +79,7 @@ class PermissionParser{ * * @return Permission[][] * @phpstan-return array> + * @throws PermissionParserException */ public static function loadPermissions(array $data, string $default = self::DEFAULT_FALSE) : array{ $result = []; @@ -89,7 +90,7 @@ class PermissionParser{ } if(isset($entry["children"])){ - throw new \InvalidArgumentException("Nested permission declarations are no longer supported. Declare each permission separately."); + throw new PermissionParserException("Nested permission declarations are no longer supported. Declare each permission separately."); } if(isset($entry["description"])){ diff --git a/src/permission/PermissionParserException.php b/src/permission/PermissionParserException.php new file mode 100644 index 000000000..a0231f805 --- /dev/null +++ b/src/permission/PermissionParserException.php @@ -0,0 +1,31 @@ + Date: Tue, 5 Oct 2021 20:28:43 +0100 Subject: [PATCH 047/710] Gracefully handle errors loading plugin manifest this isn't perfect, but it covers the common cases. Now, the server won't spam crashdumps just because some plugin declared nested permissions. --- src/lang/KnownTranslationFactory.php | 6 ++++++ src/lang/KnownTranslationKeys.php | 1 + src/plugin/PluginDescription.php | 15 ++++++++++----- src/plugin/PluginLoader.php | 1 + src/plugin/PluginManager.php | 7 +++++++ 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index e4aea7df6..756d623de 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1746,6 +1746,12 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_plugin_invalidManifest(Translatable|string $details) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_INVALIDMANIFEST, [ + "details" => $details, + ]); + } + public static function pocketmine_plugin_load(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_LOAD, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 4b8d87c64..7f1eb2658 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -364,6 +364,7 @@ final class KnownTranslationKeys{ public const POCKETMINE_PLUGIN_INCOMPATIBLEPHPVERSION = "pocketmine.plugin.incompatiblePhpVersion"; public const POCKETMINE_PLUGIN_INCOMPATIBLEPROTOCOL = "pocketmine.plugin.incompatibleProtocol"; public const POCKETMINE_PLUGIN_INVALIDAPI = "pocketmine.plugin.invalidAPI"; + public const POCKETMINE_PLUGIN_INVALIDMANIFEST = "pocketmine.plugin.invalidManifest"; public const POCKETMINE_PLUGIN_LOAD = "pocketmine.plugin.load"; public const POCKETMINE_PLUGIN_LOADERROR = "pocketmine.plugin.loadError"; public const POCKETMINE_PLUGIN_RESTRICTEDNAME = "pocketmine.plugin.restrictedName"; diff --git a/src/plugin/PluginDescription.php b/src/plugin/PluginDescription.php index 9ae463093..090be61b1 100644 --- a/src/plugin/PluginDescription.php +++ b/src/plugin/PluginDescription.php @@ -25,6 +25,7 @@ namespace pocketmine\plugin; use pocketmine\permission\Permission; use pocketmine\permission\PermissionParser; +use pocketmine\permission\PermissionParserException; use function array_map; use function array_values; use function is_array; @@ -99,20 +100,20 @@ class PluginDescription{ /** * @param mixed[] $plugin - * @throws PluginException + * @throws PluginDescriptionParseException */ private function loadMap(array $plugin) : void{ $this->map = $plugin; $this->name = $plugin["name"]; if(preg_match('/^[A-Za-z0-9 _.-]+$/', $this->name) === 0){ - throw new PluginException("Invalid Plugin name"); + throw new PluginDescriptionParseException("Invalid Plugin name"); } $this->name = str_replace(" ", "_", $this->name); $this->version = (string) $plugin["version"]; $this->main = $plugin["main"]; if(stripos($this->main, "pocketmine\\") === 0){ - throw new PluginException("Invalid Plugin main, cannot start within the PocketMine namespace"); + throw new PluginDescriptionParseException("Invalid Plugin main, cannot start within the PocketMine namespace"); } $this->srcNamespacePrefix = $plugin["src-namespace-prefix"] ?? ""; @@ -153,7 +154,7 @@ class PluginDescription{ if(isset($plugin["load"])){ $order = PluginEnableOrder::fromString($plugin["load"]); if($order === null){ - throw new PluginException("Invalid Plugin \"load\""); + throw new PluginDescriptionParseException("Invalid Plugin \"load\""); } $this->order = $order; }else{ @@ -175,7 +176,11 @@ class PluginDescription{ } if(isset($plugin["permissions"])){ - $this->permissions = PermissionParser::loadPermissions($plugin["permissions"]); + try{ + $this->permissions = PermissionParser::loadPermissions($plugin["permissions"]); + }catch(PermissionParserException $e){ + throw new PluginDescriptionParseException("Invalid Plugin \"permissions\": " . $e->getMessage(), 0, $e); + } } } diff --git a/src/plugin/PluginLoader.php b/src/plugin/PluginLoader.php index 2bf603dde..7e4787fa6 100644 --- a/src/plugin/PluginLoader.php +++ b/src/plugin/PluginLoader.php @@ -40,6 +40,7 @@ interface PluginLoader{ /** * Gets the PluginDescription from the file + * @throws PluginDescriptionParseException */ public function getPluginDescription(string $file) : ?PluginDescription; diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 2ab687525..3a58e3bc4 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -246,6 +246,13 @@ class PluginManager{ } try{ $description = $loader->getPluginDescription($file); + }catch(PluginDescriptionParseException $e){ + $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_fileError( + $file, + $directory, + KnownTranslationFactory::pocketmine_plugin_invalidManifest($e->getMessage()) + ))); + continue; }catch(\RuntimeException $e){ //TODO: more specific exception handling $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_fileError($file, $directory, $e->getMessage()))); $this->server->getLogger()->logException($e); From fec48003d92297e4b9f66e0b611ea789c687efa9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 20:29:24 +0100 Subject: [PATCH 048/710] ..... --- resources/locale | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/locale b/resources/locale index cf184a00f..dcfe3ff18 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit cf184a00f886a49dd91c2acb69384c630d3ac102 +Subproject commit dcfe3ff1888b2d3adecc00c14870717ed55824cc From a101d1cdf90c4d855bf43f756efeeb56442b1b03 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Oct 2021 23:31:00 +0100 Subject: [PATCH 049/710] Drop pocketmine.plugin.fileError in favour of pocketmine.plugin.loadError fileError was unnecessarily noisy, putting the directory path on the console twice. This conveys just as much information but with less wasted space. --- resources/locale | 2 +- src/lang/KnownTranslationFactory.php | 8 -------- src/lang/KnownTranslationKeys.php | 1 - src/plugin/PluginManager.php | 5 ++--- 4 files changed, 3 insertions(+), 13 deletions(-) diff --git a/resources/locale b/resources/locale index dcfe3ff18..c940b9f17 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit dcfe3ff1888b2d3adecc00c14870717ed55824cc +Subproject commit c940b9f17188548f78d0dc5fdd4e607c703b7952 diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 756d623de..43d3ce3b1 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1702,14 +1702,6 @@ final class KnownTranslationFactory{ ]); } - public static function pocketmine_plugin_fileError(Translatable|string $param0, Translatable|string $param1, Translatable|string $param2) : Translatable{ - return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_FILEERROR, [ - 0 => $param0, - 1 => $param1, - 2 => $param2, - ]); - } - public static function pocketmine_plugin_genericLoadError(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_GENERICLOADERROR, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 7f1eb2658..e4301fa24 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -357,7 +357,6 @@ final class KnownTranslationKeys{ public const POCKETMINE_PLUGIN_DISABLE = "pocketmine.plugin.disable"; public const POCKETMINE_PLUGIN_DUPLICATEERROR = "pocketmine.plugin.duplicateError"; public const POCKETMINE_PLUGIN_ENABLE = "pocketmine.plugin.enable"; - public const POCKETMINE_PLUGIN_FILEERROR = "pocketmine.plugin.fileError"; public const POCKETMINE_PLUGIN_GENERICLOADERROR = "pocketmine.plugin.genericLoadError"; public const POCKETMINE_PLUGIN_INCOMPATIBLEAPI = "pocketmine.plugin.incompatibleAPI"; public const POCKETMINE_PLUGIN_INCOMPATIBLEOS = "pocketmine.plugin.incompatibleOS"; diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 3a58e3bc4..1e849bc53 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -247,14 +247,13 @@ class PluginManager{ try{ $description = $loader->getPluginDescription($file); }catch(PluginDescriptionParseException $e){ - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_fileError( + $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( $file, - $directory, KnownTranslationFactory::pocketmine_plugin_invalidManifest($e->getMessage()) ))); continue; }catch(\RuntimeException $e){ //TODO: more specific exception handling - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_fileError($file, $directory, $e->getMessage()))); + $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError($file, $e->getMessage()))); $this->server->getLogger()->logException($e); continue; } From 5061bbbc25797c1b5efc04202f0d47fec7c7676f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 01:01:20 +0100 Subject: [PATCH 050/710] fuck you git x2 --- .../PluginDescriptionParseException.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/plugin/PluginDescriptionParseException.php diff --git a/src/plugin/PluginDescriptionParseException.php b/src/plugin/PluginDescriptionParseException.php new file mode 100644 index 000000000..ad98342f0 --- /dev/null +++ b/src/plugin/PluginDescriptionParseException.php @@ -0,0 +1,31 @@ + Date: Wed, 6 Oct 2021 01:12:02 +0100 Subject: [PATCH 051/710] PluginBase: remove special true/false handling for command permissions these aren't accepted as permission names anymore, and they never worked properly anyway. --- src/plugin/PluginBase.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugin/PluginBase.php b/src/plugin/PluginBase.php index ac7b0036f..c4fd5bb6b 100644 --- a/src/plugin/PluginBase.php +++ b/src/plugin/PluginBase.php @@ -195,9 +195,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{ } if(isset($data["permission"])){ - if(is_bool($data["permission"])){ - $newCmd->setPermission($data["permission"] ? "true" : "false"); - }elseif(is_string($data["permission"])){ + if(is_string($data["permission"])){ $newCmd->setPermission($data["permission"]); }else{ $this->logger->error("Permission must be a string, " . gettype($data["permission"]) . " given for command $key"); From 31a176286d7a33306f8ce8457fa64fed5a2b4d75 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 01:18:14 +0100 Subject: [PATCH 052/710] Do not register plugin commands without valid permissions this could lead to harmful results, e.g. if a developer typo'd while writing the plugin.yml, an admin-only command could become accessible to everyone, since commands are by default accessible by everyone. --- src/plugin/PluginBase.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugin/PluginBase.php b/src/plugin/PluginBase.php index c4fd5bb6b..d5460cf37 100644 --- a/src/plugin/PluginBase.php +++ b/src/plugin/PluginBase.php @@ -199,7 +199,11 @@ abstract class PluginBase implements Plugin, CommandExecutor{ $newCmd->setPermission($data["permission"]); }else{ $this->logger->error("Permission must be a string, " . gettype($data["permission"]) . " given for command $key"); + continue; } + }else{ + $this->logger->error("No permission set for command $key"); + continue; } if(isset($data["permission-message"])){ From d07517fe8bcdf4da75471fafffa9d747eafbf1d6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 01:42:03 +0100 Subject: [PATCH 053/710] Use an object to represent command entries in plugin manifest --- src/plugin/PluginBase.php | 61 +++++++------------- src/plugin/PluginDescription.php | 28 +++++++-- src/plugin/PluginDescriptionCommandEntry.php | 53 +++++++++++++++++ 3 files changed, 98 insertions(+), 44 deletions(-) create mode 100644 src/plugin/PluginDescriptionCommandEntry.php diff --git a/src/plugin/PluginBase.php b/src/plugin/PluginBase.php index d5460cf37..db29c40da 100644 --- a/src/plugin/PluginBase.php +++ b/src/plugin/PluginBase.php @@ -38,10 +38,6 @@ use function dirname; use function fclose; use function file_exists; use function fopen; -use function gettype; -use function is_array; -use function is_bool; -use function is_string; use function mkdir; use function rtrim; use function stream_copy_to_stream; @@ -171,47 +167,34 @@ abstract class PluginBase implements Plugin, CommandExecutor{ $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_commandError($key, $this->getDescription()->getFullName()))); continue; } - if(is_array($data)){ //TODO: error out if it isn't - $newCmd = new PluginCommand($key, $this, $this); - if(isset($data["description"])){ - $newCmd->setDescription($data["description"]); - } - if(isset($data["usage"])){ - $newCmd->setUsage($data["usage"]); - } + $newCmd = new PluginCommand($key, $this, $this); + if(($description = $data->getDescription()) !== null){ + $newCmd->setDescription($description); + } - if(isset($data["aliases"]) and is_array($data["aliases"])){ - $aliasList = []; - foreach($data["aliases"] as $alias){ - if(strpos($alias, ":") !== false){ - $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_aliasError($alias, $this->getDescription()->getFullName()))); - continue; - } - $aliasList[] = $alias; - } + if(($usageMessage = $data->getUsageMessage()) !== null){ + $newCmd->setUsage($usageMessage); + } - $newCmd->setAliases($aliasList); - } - - if(isset($data["permission"])){ - if(is_string($data["permission"])){ - $newCmd->setPermission($data["permission"]); - }else{ - $this->logger->error("Permission must be a string, " . gettype($data["permission"]) . " given for command $key"); - continue; - } - }else{ - $this->logger->error("No permission set for command $key"); + $aliasList = []; + foreach($data->getAliases() as $alias){ + if(strpos($alias, ":") !== false){ + $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_aliasError($alias, $this->getDescription()->getFullName()))); continue; } - - if(isset($data["permission-message"])){ - $newCmd->setPermissionMessage($data["permission-message"]); - } - - $pluginCmds[] = $newCmd; + $aliasList[] = $alias; } + + $newCmd->setAliases($aliasList); + + $newCmd->setPermission($data->getPermission()); + + if(($permissionDeniedMessage = $data->getPermissionDeniedMessage()) !== null){ + $newCmd->setPermissionMessage($permissionDeniedMessage); + } + + $pluginCmds[] = $newCmd; } if(count($pluginCmds) > 0){ diff --git a/src/plugin/PluginDescription.php b/src/plugin/PluginDescription.php index 090be61b1..0e34da74a 100644 --- a/src/plugin/PluginDescription.php +++ b/src/plugin/PluginDescription.php @@ -29,6 +29,7 @@ use pocketmine\permission\PermissionParserException; use function array_map; use function array_values; use function is_array; +use function is_string; use function phpversion; use function preg_match; use function str_replace; @@ -70,8 +71,8 @@ class PluginDescription{ /** @var string */ private $version; /** - * @var mixed[][] - * @phpstan-var array> + * @var PluginDescriptionCommandEntry[] + * @phpstan-var array */ private $commands = []; /** @var string */ @@ -123,7 +124,24 @@ class PluginDescription{ $this->compatibleOperatingSystems = array_map("\strval", (array) ($plugin["os"] ?? [])); if(isset($plugin["commands"]) and is_array($plugin["commands"])){ - $this->commands = $plugin["commands"]; + foreach($plugin["commands"] as $commandName => $commandData){ + if(!is_string($commandName)){ + throw new PluginDescriptionParseException("Invalid Plugin commands, key must be the name of the command"); + } + if(!is_array($commandData)){ + throw new PluginDescriptionParseException("Command $commandName has invalid properties"); + } + if(!isset($commandData["permission"]) || !is_string($commandData["permission"])){ + throw new PluginDescriptionParseException("Command $commandName does not have a permission set"); + } + $this->commands[$commandName] = new PluginDescriptionCommandEntry( + $commandData["description"] ?? null, + $commandData["usage"] ?? null, + $commandData["aliases"] ?? [], + $commandData["permission"], + $commandData["permission-message"] ?? null + ); + } } if(isset($plugin["depend"])){ @@ -221,8 +239,8 @@ class PluginDescription{ } /** - * @return mixed[][] - * @phpstan-return array> + * @return PluginDescriptionCommandEntry[] + * @phpstan-return array */ public function getCommands() : array{ return $this->commands; diff --git a/src/plugin/PluginDescriptionCommandEntry.php b/src/plugin/PluginDescriptionCommandEntry.php new file mode 100644 index 000000000..b9b618e8a --- /dev/null +++ b/src/plugin/PluginDescriptionCommandEntry.php @@ -0,0 +1,53 @@ + $aliases + */ + public function __construct( + private ?string $description, + private ?string $usageMessage, + private array $aliases, + private string $permission, + private ?string $permissionDeniedMessage, + ){} + + public function getDescription() : ?string{ return $this->description; } + + public function getUsageMessage() : ?string{ return $this->usageMessage; } + + /** + * @return string[] + * @phpstan-return list + */ + public function getAliases() : array{ return $this->aliases; } + + public function getPermission() : string{ return $this->permission; } + + public function getPermissionDeniedMessage() : ?string{ return $this->permissionDeniedMessage; } +} From 258c38f9cd55c2f84c33b8f9d98d86cc35288b23 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 01:45:40 +0100 Subject: [PATCH 054/710] PluginDescription: loosen invalid permission message (it might be wrong type as well as not existing) --- src/plugin/PluginDescription.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugin/PluginDescription.php b/src/plugin/PluginDescription.php index 0e34da74a..889823d84 100644 --- a/src/plugin/PluginDescription.php +++ b/src/plugin/PluginDescription.php @@ -132,7 +132,7 @@ class PluginDescription{ throw new PluginDescriptionParseException("Command $commandName has invalid properties"); } if(!isset($commandData["permission"]) || !is_string($commandData["permission"])){ - throw new PluginDescriptionParseException("Command $commandName does not have a permission set"); + throw new PluginDescriptionParseException("Command $commandName does not have a valid permission set"); } $this->commands[$commandName] = new PluginDescriptionCommandEntry( $commandData["description"] ?? null, From 10b3596eef37d84eaaac312b792dac5bf3e9ae5d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 02:00:55 +0100 Subject: [PATCH 055/710] PluginDescription: use typed properties --- src/plugin/PluginDescription.php | 43 +++++++++++++------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/src/plugin/PluginDescription.php b/src/plugin/PluginDescription.php index 889823d84..895097cb5 100644 --- a/src/plugin/PluginDescription.php +++ b/src/plugin/PluginDescription.php @@ -44,53 +44,46 @@ class PluginDescription{ * @var mixed[] * @phpstan-var array */ - private $map; + private array $map; - /** @var string */ - private $name; - /** @var string */ - private $main; + private string $name; + private string $main; private string $srcNamespacePrefix = ""; /** @var string[] */ - private $api; + private array $api; /** @var int[] */ - private $compatibleMcpeProtocols = []; + private array $compatibleMcpeProtocols = []; /** @var string[] */ - private $compatibleOperatingSystems = []; + private array $compatibleOperatingSystems = []; /** * @var string[][] * @phpstan-var array> */ - private $extensions = []; + private array $extensions = []; /** @var string[] */ - private $depend = []; + private array $depend = []; /** @var string[] */ - private $softDepend = []; + private array $softDepend = []; /** @var string[] */ - private $loadBefore = []; - /** @var string */ - private $version; + private array $loadBefore = []; + private string $version; /** * @var PluginDescriptionCommandEntry[] * @phpstan-var array */ - private $commands = []; - /** @var string */ - private $description = ""; + private array $commands = []; + private string $description = ""; /** @var string[] */ - private $authors = []; - /** @var string */ - private $website = ""; - /** @var string */ - private $prefix = ""; - /** @var PluginEnableOrder */ - private $order; + private array $authors = []; + private string $website = ""; + private string $prefix = ""; + private PluginEnableOrder $order; /** * @var Permission[][] * @phpstan-var array> */ - private $permissions = []; + private array $permissions = []; /** * @param string|mixed[] $yamlString From 4b00465e2435ad8115c3bb44683937e1fcf43b31 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 02:14:30 +0100 Subject: [PATCH 056/710] Clean PHPStan baselines --- .../configs/check-explicit-mixed-baseline.neon | 15 --------------- tests/phpstan/configs/l7-baseline.neon | 5 ----- tests/phpstan/configs/runtime-type-checks.neon | 5 ----- 3 files changed, 25 deletions(-) diff --git a/tests/phpstan/configs/check-explicit-mixed-baseline.neon b/tests/phpstan/configs/check-explicit-mixed-baseline.neon index 56654cf26..cffdf0a1c 100644 --- a/tests/phpstan/configs/check-explicit-mixed-baseline.neon +++ b/tests/phpstan/configs/check-explicit-mixed-baseline.neon @@ -80,21 +80,6 @@ parameters: count: 1 path: ../../../src/permission/PermissionParser.php - - - message: "#^Parameter \\#1 \\$description of method pocketmine\\\\command\\\\Command\\:\\:setDescription\\(\\) expects pocketmine\\\\lang\\\\Translatable\\|string, mixed given\\.$#" - count: 1 - path: ../../../src/plugin/PluginBase.php - - - - message: "#^Parameter \\#1 \\$permissionMessage of method pocketmine\\\\command\\\\Command\\:\\:setPermissionMessage\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/plugin/PluginBase.php - - - - message: "#^Parameter \\#1 \\$usage of method pocketmine\\\\command\\\\Command\\:\\:setUsage\\(\\) expects pocketmine\\\\lang\\\\Translatable\\|string, mixed given\\.$#" - count: 1 - path: ../../../src/plugin/PluginBase.php - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" count: 1 diff --git a/tests/phpstan/configs/l7-baseline.neon b/tests/phpstan/configs/l7-baseline.neon index ae390b9de..4cd255836 100644 --- a/tests/phpstan/configs/l7-baseline.neon +++ b/tests/phpstan/configs/l7-baseline.neon @@ -35,11 +35,6 @@ parameters: count: 1 path: ../../../src/PocketMine.php - - - message: "#^Parameter \\#1 \\$path of function realpath expects string, array\\\\|string\\|false given\\.$#" - count: 1 - path: ../../../src/PocketMine.php - - message: "#^Parameter \\#1 \\$path of function realpath expects string, string\\|false given\\.$#" count: 2 diff --git a/tests/phpstan/configs/runtime-type-checks.neon b/tests/phpstan/configs/runtime-type-checks.neon index 12e59f585..fb1e456b7 100644 --- a/tests/phpstan/configs/runtime-type-checks.neon +++ b/tests/phpstan/configs/runtime-type-checks.neon @@ -10,8 +10,3 @@ parameters: count: 1 path: ../../../src/network/mcpe/handler/InGamePacketHandler.php - - - message: "#^Call to function is_array\\(\\) with array\\ will always evaluate to true\\.$#" - count: 1 - path: ../../../src/plugin/PluginBase.php - From 90800a4124f99b11ad7d609d4b8b78cc311cd585 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 21:07:57 +0100 Subject: [PATCH 057/710] Config: Try to coerce types, similar to YAML --- src/utils/Config.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/utils/Config.php b/src/utils/Config.php index 841b7f860..2e10ad5e2 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -557,6 +557,13 @@ class Config{ case "no": $v = false; break; + default: + $v = match($v){ + (string) ((int) $v) => (int) $v, + (string) ((float) $v) => (float) $v, + default => $v, + }; + break; } if(isset($result[$k])){ \GlobalLogger::get()->debug("[Config] Repeated property " . $k . " on file " . $this->file); From e032b8fe208a053441c9fbd377209740008cddb8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 22:20:27 +0100 Subject: [PATCH 058/710] Server: fixed stats reporting checking a nonexistent pocketmine.yml property this was originally worked around by 47f7af6739537af7a4d356a08aa00eb7feefd1ed. However, that commit was just duct tape, and I never bothered to investigate if the config was being checked somewhere else. Here's to a years-old bug finally getting fixed. --- src/pocketmine/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 50df4e0bf..f097ad243 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1961,7 +1961,7 @@ class Server{ $this->network->blockAddress($entry->getName(), -1); } - if((bool) $this->getProperty("settings.send-usage", true)){ + if((bool) $this->getProperty("anonymous-statistics.enabled", true)){ $this->sendUsageTicker = 6000; $this->sendUsage(SendUsageTask::TYPE_OPEN); } From 8e3772ceef672b406cb75676e6c74ccc01327dbd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 23:16:03 +0100 Subject: [PATCH 059/710] Block: fixed incorrect behaviour of isSameState() for multi-ID blocks fixes #4492 --- src/block/Block.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/block/Block.php b/src/block/Block.php index 7006db1ca..1ef2ccee0 100644 --- a/src/block/Block.php +++ b/src/block/Block.php @@ -179,7 +179,7 @@ class Block{ * Returns whether the given block has the same type and properties as this block. */ public function isSameState(Block $other) : bool{ - return $this->isSameType($other) and $this->writeStateToMeta() === $other->writeStateToMeta(); + return $this->getFullId() === $other->getFullId(); } /** From 9e6d7405709560c0025e072324602983213276dd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 23:49:13 +0100 Subject: [PATCH 060/710] Release 4.0.0-BETA4 --- changelogs/4.0.md | 59 +++++++++++++++++++++++++++++++++++++++++++++ src/VersionInfo.php | 4 +-- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 644550657..0f3851543 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1332,3 +1332,62 @@ Released 10th September 2021. - `Liquid->getMinAdjacentSourcesToFormSource()`: returns how many adjacent source blocks of the same liquid must be present in order for the current block to become a source itself - `Player->getPlayerInfo()` - `Liquid` minimum-cost flow calculation code has been extracted to `MinimumCostFlowCalculator`. + +# 4.0.0-BETA4 +Released 6th October 2021. + +## General +- Improved performance of lighting calculation by avoiding copies of useless data from the main thread. +- Resource pack loading now accepts `dependencies` and `capabilities` fields in the `manifest.json` (although it doesn't currently check them). +- `/help` is now localized according to language set in `server.properties`. +- Various messages related to world loading, generation and conversion are now localized according to the language set in `server.properties`. +- Compasses now point to the correct (current) world's spawn point after teleporting players to a different world. Previously, they would continue to point to the spawn of the world that the player initially spawned in. +- The `--bootstrap` CLI option has been removed. +- RakLib 0.14.2 is now required. This fixes the following issues: + - Fixed incorrect handling of sessions on client disconnect (leading to timeout debug messages). + - Fixed transferring players often not working correctly. + - Fixed disconnect screens sometimes not displaying. + +## Fixes +- Fixed server crash when UPnP encounters an error. +- Fixed server crash when clients sent items with bad NBT in inventory transactions. +- Fixed server crash when loading a plugin with legacy nested permission structure (now the plugin will fail to load, but the server won't crash). +- Fixed server crash when using `/give` with bad NBT on any item. +- Fixed server crash when loading a plugin with improperly formatted API version (now the plugin will fail to load, but the server won't crash). +- Fixed server crash when changing player gamemode during `PlayerLoginEvent`. +- Incorrect structure of `commands` in plugin manifest is now detected earlier and handled more gracefully. +- Fixed console reader subprocess lingering on server crash on Windows and screwing up the terminal. +- Fixed `Player` object memory leak when kicking players during `PlayerLoginEvent` (this caused the `World` to report warnings about leaked entities on shutdown). +- Fixed `Projectile->move()` ignoring the `dx`/`dy`/`dz` parameters given and using its own `motion` instead. +- Fixed `BlockFactory->get()` erroneously accepting meta values of `16`. +- Fixed `Block->isSameState()` false negatives for some types of slabs. +- Fixed being unable to place slabs of the same type on top of each other to create double slabs. + +## API changes +- Plugin commands in `plugin.yml` must now declare `permission` for each command. Previously, the `permission` key was optional, causing anyone to be able to use the command. + - This behaviour was removed because of the potential for security issues - a typo in `plugin.yml` could lead to dangerous functionality being exposed to everyone. + - If you want to make a command that everyone can use, declare a permission with a `default` of `true` and assign it to the command. +- Plugin permissions in `plugin.yml` must now declare `default` for each permission. Previously, the `default` key was optional, causing the permission to silently be denied to everyone (PM4) or granted to ops implicitly (PM3). + +### Block +- Added the following classes: + - `pocketmine\block\utils\LeverFacing` +- Added the following API methods: + - `pocketmine\block\Lever->isActivated()` + - `pocketmine\block\Lever->setActivated()` + - `pocketmine\block\Lever->getFacing()` + - `pocketmine\block\Lever->setFacing()` + +### World +- The following API methods have signature changes: + - `Chunk->getSubChunks()` now returns `array` instead of `SplFixedArray`. +- The following API methods have been removed: + - `FastChunkSerializer::serialize()` + - `FastChunkSerializer::deserialize()` +- The following API methods have been added: + - `FastChunkSerializer::serializeTerrain()`: serializes blocks and biomes only + - `FastChunkSerializer::deserializeTerrain()`: deserializes the output of `serializeTerrain()` + +### Utils +- The following API methods have signature changes: + - `Process::kill()` now requires an additional `bool $subprocesses` parameter. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index dedf0f3ae..2bebe456a 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,9 +30,9 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA4"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; - public const BUILD_CHANNEL = ""; + public const BUILD_CHANNEL = "beta"; private function __construct(){ //NOOP From 847e24fc41852510e7d2c5928a125d370a5b2873 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 6 Oct 2021 23:49:30 +0100 Subject: [PATCH 061/710] 4.0.0-BETA5 is next --- src/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 2bebe456a..8b9fb420b 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,10 +29,10 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA4"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA5"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; - public const BUILD_CHANNEL = "beta"; + public const BUILD_CHANNEL = ""; private function __construct(){ //NOOP From dc2e8e7e8f13e23882c4df27ac0d1b397f7746b1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 20:02:21 +0100 Subject: [PATCH 062/710] ServerConfigGroup: do not assume that values are always bool|string --- src/ServerConfigGroup.php | 18 +++++++++++------- .../configs/check-explicit-mixed-baseline.neon | 5 ----- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/ServerConfigGroup.php b/src/ServerConfigGroup.php index 1965e0d7f..37df7e9a7 100644 --- a/src/ServerConfigGroup.php +++ b/src/ServerConfigGroup.php @@ -110,16 +110,20 @@ final class ServerConfigGroup{ }else{ $value = $this->serverProperties->exists($variable) ? $this->serverProperties->get($variable) : $defaultValue; } - if(is_bool($value)){ return $value; } - switch(strtolower($value)){ - case "on": - case "true": - case "1": - case "yes": - return true; + if(is_int($value)){ + return $value !== 0; + } + if(is_string($value)){ + switch(strtolower($value)){ + case "on": + case "true": + case "1": + case "yes": + return true; + } } return false; diff --git a/tests/phpstan/configs/check-explicit-mixed-baseline.neon b/tests/phpstan/configs/check-explicit-mixed-baseline.neon index cffdf0a1c..cb0893173 100644 --- a/tests/phpstan/configs/check-explicit-mixed-baseline.neon +++ b/tests/phpstan/configs/check-explicit-mixed-baseline.neon @@ -40,11 +40,6 @@ parameters: count: 2 path: ../../../src/ServerConfigGroup.php - - - message: "#^Parameter \\#1 \\$string of function strtolower expects string, mixed given\\.$#" - count: 1 - path: ../../../src/ServerConfigGroup.php - - message: "#^Cannot access offset 'git' on mixed\\.$#" count: 2 From 32fd9879e5ab8b58d82f2ec30a5c55a6188aea0f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 20:16:54 +0100 Subject: [PATCH 063/710] fix CS --- src/ServerConfigGroup.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ServerConfigGroup.php b/src/ServerConfigGroup.php index 37df7e9a7..f69990cf8 100644 --- a/src/ServerConfigGroup.php +++ b/src/ServerConfigGroup.php @@ -27,6 +27,8 @@ use pocketmine\utils\Config; use function array_key_exists; use function getopt; use function is_bool; +use function is_int; +use function is_string; use function strtolower; final class ServerConfigGroup{ From 1be9b2f037ba446c003b14c661bb959c1ddf9f1d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 20:30:56 +0100 Subject: [PATCH 064/710] Config: drop packing of arrays we don't handle arrays on decode, so there's no reason to support them on encode either. --- src/utils/Config.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/Config.php b/src/utils/Config.php index 2e10ad5e2..db0b8c464 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -529,8 +529,6 @@ class Config{ foreach($this->config as $k => $v){ if(is_bool($v)){ $v = $v ? "on" : "off"; - }elseif(is_array($v)){ - $v = implode(";", $v); } $content .= $k . "=" . $v . "\r\n"; } From a555f21b181dcc889e1c8749e551d8587717df38 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 20:32:02 +0100 Subject: [PATCH 065/710] MainLogger: write messages before calling logger attachments --- src/utils/MainLogger.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/utils/MainLogger.php b/src/utils/MainLogger.php index ebce6012e..29c64e974 100644 --- a/src/utils/MainLogger.php +++ b/src/utils/MainLogger.php @@ -244,12 +244,11 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ $this->synchronized(function() use ($message, $level, $time) : void{ Terminal::writeLine($message); + $this->logWriterThread->write($time->format("Y-m-d") . " " . TextFormat::clean($message) . PHP_EOL); foreach($this->attachments as $attachment){ $attachment->call($level, $message); } - - $this->logWriterThread->write($time->format("Y-m-d") . " " . TextFormat::clean($message) . PHP_EOL); }); } From dd0aaf59b5a269259cd2f922ca3f7d2bad8a3d06 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 20:40:20 +0100 Subject: [PATCH 066/710] MainLogger: Log exceptions as a single block message --- src/utils/MainLogger.php | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/utils/MainLogger.php b/src/utils/MainLogger.php index 29c64e974..b5b9dd7ef 100644 --- a/src/utils/MainLogger.php +++ b/src/utils/MainLogger.php @@ -140,18 +140,20 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ $trace = $e->getTrace(); } - $this->buffer(function() use ($e, $trace) : void{ - $this->critical(self::printExceptionMessage($e)); - foreach(Utils::printableTrace($trace) as $line){ - $this->critical($line); + $lines = [self::printExceptionMessage($e)]; + $lines[] = "--- Stack trace ---"; + foreach(Utils::printableTrace($trace) as $line){ + $lines[] = " " . $line; + } + for($prev = $e->getPrevious(); $prev !== null; $prev = $prev->getPrevious()){ + $lines[] = "--- Previous ---"; + $lines[] = self::printExceptionMessage($prev); + foreach(Utils::printableTrace($prev->getTrace()) as $line){ + $lines[] = " " . $line; } - for($prev = $e->getPrevious(); $prev !== null; $prev = $prev->getPrevious()){ - $this->critical("Previous: " . self::printExceptionMessage($prev)); - foreach(Utils::printableTrace($prev->getTrace()) as $line){ - $this->critical(" " . $line); - } - } - }); + } + $lines[] = "--- End of exception information ---"; + $this->critical(implode("\n", $lines)); $this->syncFlushBuffer(); } From 5115387feb7f6c16735f8a82f8d46e5dea38107b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 20:43:55 +0100 Subject: [PATCH 067/710] fix CS (again) --- src/utils/MainLogger.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/MainLogger.php b/src/utils/MainLogger.php index b5b9dd7ef..67ab82a62 100644 --- a/src/utils/MainLogger.php +++ b/src/utils/MainLogger.php @@ -28,6 +28,7 @@ use pocketmine\errorhandler\ErrorTypeToStringMap; use pocketmine\thread\Thread; use pocketmine\thread\Worker; use function get_class; +use function implode; use function is_int; use function preg_replace; use function sprintf; From 2a3a57c5195ffe3094ef6c6862ce0b73e7cd1fc3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 20:53:15 +0100 Subject: [PATCH 068/710] Enable parsing/emitting .properties without creating a Config object this is useful when the contents are just going to get passed straight into a model, making Config object redundant anyway. --- src/utils/Config.php | 22 ++++++++++--------- .../check-explicit-mixed-baseline.neon | 5 +++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/utils/Config.php b/src/utils/Config.php index db0b8c464..9449f768d 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -170,7 +170,7 @@ class Config{ $config = null; switch($this->type){ case Config::PROPERTIES: - $config = $this->parseProperties($content); + $config = self::parseProperties($content); break; case Config::JSON: $config = json_decode($content, true); @@ -211,7 +211,7 @@ class Config{ $content = null; switch($this->type){ case Config::PROPERTIES: - $content = $this->writeProperties(); + $content = self::writeProperties($this->config); break; case Config::JSON: $content = json_encode($this->config, $this->jsonOptions); @@ -524,9 +524,13 @@ class Config{ return $result; } - private function writeProperties() : string{ + /** + * @param string[]|int[]|float[]|bool[] $config + * @phpstan-param array $config + */ + public static function writeProperties(array $config) : string{ $content = "#Properties Config file\r\n#" . date("D M j H:i:s T Y") . "\r\n"; - foreach($this->config as $k => $v){ + foreach($config as $k => $v){ if(is_bool($v)){ $v = $v ? "on" : "off"; } @@ -537,9 +541,10 @@ class Config{ } /** - * @return mixed[] + * @return string[]|int[]|float[]|bool[] + * @phpstan-return array */ - private function parseProperties(string $content) : array{ + public static function parseProperties(string $content) : array{ $result = []; if(preg_match_all('/^\s*([a-zA-Z0-9\-_\.]+)[ \t]*=([^\r\n]*)/um', $content, $matches) > 0){ //false or 0 matches foreach($matches[1] as $i => $k){ @@ -563,10 +568,7 @@ class Config{ }; break; } - if(isset($result[$k])){ - \GlobalLogger::get()->debug("[Config] Repeated property " . $k . " on file " . $this->file); - } - $result[$k] = $v; + $result[(string) $k] = $v; } } diff --git a/tests/phpstan/configs/check-explicit-mixed-baseline.neon b/tests/phpstan/configs/check-explicit-mixed-baseline.neon index cb0893173..a13bb3a1b 100644 --- a/tests/phpstan/configs/check-explicit-mixed-baseline.neon +++ b/tests/phpstan/configs/check-explicit-mixed-baseline.neon @@ -165,6 +165,11 @@ parameters: count: 1 path: ../../../src/timings/TimingsHandler.php + - + message: "#^Parameter \\#1 \\$config of static method pocketmine\\\\utils\\\\Config\\:\\:writeProperties\\(\\) expects array\\, array\\ given\\.$#" + count: 1 + path: ../../../src/utils/Config.php + - message: "#^Parameter \\#2 \\$offset of function substr expects int, mixed given\\.$#" count: 1 From d5f02a0bf84d3918087df8392e0ab18ba77e8d5c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 21:18:42 +0100 Subject: [PATCH 069/710] Config: expose APIs to parse/emit list configs --- src/utils/Config.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/utils/Config.php b/src/utils/Config.php index 9449f768d..e611d1f03 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -183,7 +183,7 @@ class Config{ $config = unserialize($content); break; case Config::ENUM: - $config = self::parseList($content); + $config = array_fill_keys(self::parseList($content), true); break; default: throw new \InvalidStateException("Config type is unknown"); @@ -223,7 +223,7 @@ class Config{ $content = serialize($this->config); break; case Config::ENUM: - $content = implode("\r\n", array_keys($this->config)); + $content = self::writeList(array_keys($this->config)); break; default: throw new \InvalidStateException("Config type is unknown, has not been set or not detected"); @@ -509,21 +509,29 @@ class Config{ } /** - * @return true[] - * @phpstan-return array + * @return string[] + * @phpstan-return list */ - private static function parseList(string $content) : array{ + public static function parseList(string $content) : array{ $result = []; foreach(explode("\n", trim(str_replace("\r\n", "\n", $content))) as $v){ $v = trim($v); - if($v == ""){ + if($v === ""){ continue; } - $result[$v] = true; + $result[] = $v; } return $result; } + /** + * @param string[] $entries + * @phpstan-param list $entries + */ + public static function writeList(array $entries) : string{ + return implode("\n", array_keys($entries)); + } + /** * @param string[]|int[]|float[]|bool[] $config * @phpstan-param array $config From e0d2e24698c531a0ff4cdad372709d67f568e13a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 21:19:44 +0100 Subject: [PATCH 070/710] fix CS (again\!) --- src/utils/Config.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/Config.php b/src/utils/Config.php index e611d1f03..6923db588 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -25,6 +25,7 @@ namespace pocketmine\utils; use Webmozart\PathUtil\Path; use function array_change_key_case; +use function array_fill_keys; use function array_keys; use function array_shift; use function count; From 4910250a81eae7a8955437b2c04d8a0f1ef4accb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 7 Oct 2021 21:47:09 +0100 Subject: [PATCH 071/710] Config: fixed writeList() --- src/utils/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Config.php b/src/utils/Config.php index 6923db588..696269a1b 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -530,7 +530,7 @@ class Config{ * @phpstan-param list $entries */ public static function writeList(array $entries) : string{ - return implode("\n", array_keys($entries)); + return implode("\n", $entries); } /** From 308d7c126a6609c36ce2de886a408ff492369351 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 8 Oct 2021 23:39:25 +0100 Subject: [PATCH 072/710] Fixed world data ::generate() functions putting level.dat in the wrong place if the world path didn't end with a / --- src/world/format/io/data/BedrockWorldData.php | 3 ++- src/world/format/io/data/JavaWorldData.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/world/format/io/data/BedrockWorldData.php b/src/world/format/io/data/BedrockWorldData.php index e59c066d5..50a4184fe 100644 --- a/src/world/format/io/data/BedrockWorldData.php +++ b/src/world/format/io/data/BedrockWorldData.php @@ -39,6 +39,7 @@ use pocketmine\world\generator\Generator; use pocketmine\world\generator\GeneratorManager; use pocketmine\world\World; use pocketmine\world\WorldCreationOptions; +use Webmozart\PathUtil\Path; use function file_get_contents; use function file_put_contents; use function strlen; @@ -101,7 +102,7 @@ class BedrockWorldData extends BaseNbtWorldData{ $nbt = new LittleEndianNbtSerializer(); $buffer = $nbt->write(new TreeRoot($worldData)); - file_put_contents($path . "level.dat", Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer); + file_put_contents(Path::join($path, "level.dat"), Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer); } protected function load() : CompoundTag{ diff --git a/src/world/format/io/data/JavaWorldData.php b/src/world/format/io/data/JavaWorldData.php index 356579979..c2f488876 100644 --- a/src/world/format/io/data/JavaWorldData.php +++ b/src/world/format/io/data/JavaWorldData.php @@ -33,6 +33,7 @@ use pocketmine\world\format\io\exception\CorruptedWorldException; use pocketmine\world\generator\GeneratorManager; use pocketmine\world\World; use pocketmine\world\WorldCreationOptions; +use Webmozart\PathUtil\Path; use function ceil; use function file_get_contents; use function file_put_contents; @@ -68,7 +69,7 @@ class JavaWorldData extends BaseNbtWorldData{ $nbt = new BigEndianNbtSerializer(); $buffer = zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag("Data", $worldData))), ZLIB_ENCODING_GZIP); - file_put_contents($path . "level.dat", $buffer); + file_put_contents(Path::join($path, "level.dat"), $buffer); } protected function load() : CompoundTag{ From ccc881ee5808a747bb197dfee19a2d2cd3a47341 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Oct 2021 00:57:15 +0100 Subject: [PATCH 073/710] Switch to custom permission denied message closes #4494 --- resources/locale | 2 +- src/command/Command.php | 2 +- src/lang/KnownTranslationFactory.php | 6 ++++++ src/lang/KnownTranslationKeys.php | 1 + 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/resources/locale b/resources/locale index c940b9f17..299927cf8 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit c940b9f17188548f78d0dc5fdd4e607c703b7952 +Subproject commit 299927cf85ef6b19d9a159e0bde66ef50e1c143d diff --git a/src/command/Command.php b/src/command/Command.php index ff08620f1..ea324a933 100644 --- a/src/command/Command.php +++ b/src/command/Command.php @@ -117,7 +117,7 @@ abstract class Command{ } if($this->permissionMessage === null){ - $target->sendMessage(KnownTranslationFactory::commands_generic_permission()->prefix(TextFormat::RED)); + $target->sendMessage(KnownTranslationFactory::pocketmine_command_error_permission($this->name)->prefix(TextFormat::RED)); }elseif($this->permissionMessage !== ""){ $target->sendMessage(str_replace("", $permission ?? $this->permission, $this->permissionMessage)); } diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 43d3ce3b1..78f0abe6e 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1109,6 +1109,12 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_ENCHANT_DESCRIPTION, []); } + public static function pocketmine_command_error_permission(Translatable|string $commandName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_ERROR_PERMISSION, [ + "commandName" => $commandName, + ]); + } + public static function pocketmine_command_error_playerNotFound(Translatable|string $playerName) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_COMMAND_ERROR_PLAYERNOTFOUND, [ "playerName" => $playerName, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index e4301fa24..039642a96 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -244,6 +244,7 @@ final class KnownTranslationKeys{ public const POCKETMINE_COMMAND_DIFFICULTY_DESCRIPTION = "pocketmine.command.difficulty.description"; public const POCKETMINE_COMMAND_EFFECT_DESCRIPTION = "pocketmine.command.effect.description"; public const POCKETMINE_COMMAND_ENCHANT_DESCRIPTION = "pocketmine.command.enchant.description"; + public const POCKETMINE_COMMAND_ERROR_PERMISSION = "pocketmine.command.error.permission"; public const POCKETMINE_COMMAND_ERROR_PLAYERNOTFOUND = "pocketmine.command.error.playerNotFound"; public const POCKETMINE_COMMAND_EXCEPTION = "pocketmine.command.exception"; public const POCKETMINE_COMMAND_GAMEMODE_DESCRIPTION = "pocketmine.command.gamemode.description"; From 58a95f88366568fea531df30ff898fd881b3d43d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Oct 2021 19:18:32 +0100 Subject: [PATCH 074/710] Updated transitive composer dependencies --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 7cedb4812..34065f3a8 100644 --- a/composer.lock +++ b/composer.lock @@ -893,16 +893,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f" + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/30f38bffc6f24293dadd1823936372dfa9e86e2f", - "reference": "30f38bffc6f24293dadd1823936372dfa9e86e2f", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", "shasum": "" }, "require": { @@ -937,9 +937,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" }, - "time": "2021-09-17T15:28:14+00:00" + "time": "2021-10-02T14:08:47+00:00" }, { "name": "phpspec/prophecy", From e38866c4ba90f8efd5630dbe674fd7ca15f586ff Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Oct 2021 19:33:43 +0100 Subject: [PATCH 075/710] phpstan 0.12.99 --- composer.json | 2 +- composer.lock | 14 +++---- phpstan.neon.dist | 4 +- src/pocketmine/utils/Internet.php | 1 + tests/phpstan/configs/l7-baseline.neon | 5 --- tests/phpstan/configs/l8-baseline.neon | 5 --- tests/phpstan/configs/phpstan-bugs.neon | 50 ++++++++++++++++++++++--- 7 files changed, 56 insertions(+), 25 deletions(-) diff --git a/composer.json b/composer.json index 89758d393..911b036f5 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "pocketmine/spl": "^0.4.0" }, "require-dev": { - "phpstan/phpstan": "0.12.98", + "phpstan/phpstan": "0.12.99", "phpstan/phpstan-phpunit": "^0.12.6", "phpstan/phpstan-strict-rules": "^0.12.2", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index 34065f3a8..68576adf1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8fc787ba6d9029fb6daa3e8c112b76c5", + "content-hash": "f3f0ef9944d96c5b71b7e32aac5118cd", "packages": [ { "name": "adhocore/json-comment", @@ -1010,16 +1010,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.12.98", + "version": "0.12.99", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00" + "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/3bb7cc246c057405dd5e290c3ecc62ab51d57e00", - "reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b4d40f1d759942f523be267a1bab6884f46ca3f7", + "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7", "shasum": "" }, "require": { @@ -1050,7 +1050,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.98" + "source": "https://github.com/phpstan/phpstan/tree/0.12.99" }, "funding": [ { @@ -1070,7 +1070,7 @@ "type": "tidelift" } ], - "time": "2021-09-02T12:33:01+00:00" + "time": "2021-09-12T20:09:55+00:00" }, { "name": "phpstan/phpstan-phpunit", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 9240471d4..f2fd04b9b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -49,7 +49,7 @@ parameters: #variadics don't work for this - mixed probably shouldn't work either, but for now it does #what we actually need is something that accepts an infinite number of parameters, but in the absence of that, #we'll just fill it with 10 - it's very unlikely to encounter a callable with 10 parameters anyway. - anyCallable: 'callable(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed' - anyClosure: '\Closure(mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed, mixed) : mixed' + anyCallable: 'callable(never, never, never, never, never, never, never, never, never, never) : mixed' + anyClosure: '\Closure(never, never, never, never, never, never, never, never, never, never) : mixed' PhpSocket: '\Socket' PhpCurlHandle: '\CurlHandle' diff --git a/src/pocketmine/utils/Internet.php b/src/pocketmine/utils/Internet.php index 26b393061..4979aa4e8 100644 --- a/src/pocketmine/utils/Internet.php +++ b/src/pocketmine/utils/Internet.php @@ -233,6 +233,7 @@ class Internet{ } if(!is_string($raw)) throw new AssumptionFailedError("curl_exec() should return string|false when CURLOPT_RETURNTRANSFER is set"); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if(!is_int($httpCode)) throw new AssumptionFailedError("curl_getinfo(CURLINFO_HTTP_CODE) always returns int"); $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $rawHeaders = substr($raw, 0, $headerSize); $body = substr($raw, $headerSize); diff --git a/tests/phpstan/configs/l7-baseline.neon b/tests/phpstan/configs/l7-baseline.neon index 0f6f063c1..52ea0cd26 100644 --- a/tests/phpstan/configs/l7-baseline.neon +++ b/tests/phpstan/configs/l7-baseline.neon @@ -75,11 +75,6 @@ parameters: count: 2 path: ../../../src/pocketmine/PocketMine.php - - - message: "#^Cannot cast array\\\\|string\\|false to int\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - message: "#^Cannot cast array\\\\|string\\|false to string\\.$#" count: 1 diff --git a/tests/phpstan/configs/l8-baseline.neon b/tests/phpstan/configs/l8-baseline.neon index 03641bb01..636f93250 100644 --- a/tests/phpstan/configs/l8-baseline.neon +++ b/tests/phpstan/configs/l8-baseline.neon @@ -260,11 +260,6 @@ parameters: count: 1 path: ../../../src/pocketmine/block/BaseRail.php - - - message: "#^Parameter \\#1 \\$constraint of method pocketmine\\\\block\\\\BaseRail\\:\\:getPossibleConnectionDirectionsOneConstraint\\(\\) expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BaseRail.php - - message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" count: 1 diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index c98712cb1..d538a89ca 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -1,15 +1,60 @@ parameters: ignoreErrors: + - + message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\Player\\)\\: bool given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(string\\)\\: bool given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + - message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#" count: 3 path: ../../../src/pocketmine/command/CommandReader.php + - + message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\Player\\)\\: bool given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/ListCommand.php + + - + message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\entity\\\\Attribute\\)\\: bool given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/AttributeMap.php + + - + message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\item\\\\Item\\)\\: bool given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Human.php + - message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#" count: 1 path: ../../../src/pocketmine/entity/projectile/Projectile.php + - + message: "#^Parameter \\#2 \\$callback of function usort expects callable\\(mixed, mixed\\)\\: int, array\\('pocketmine\\\\\\\\inventory\\\\\\\\CraftingManager', 'sort'\\) given\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/CraftingManager.php + + - + message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(string\\)\\: bool given\\.$#" + count: 1 + path: ../../../src/pocketmine/lang/BaseLang.php + + - + message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\entity\\\\Entity\\)\\: bool given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/Chunk.php + + - + message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(string\\)\\: bool given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + - message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#" count: 2 @@ -25,11 +70,6 @@ parameters: count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/DataPacket.php - - - message: "#^Parameter \\#1 \\$ of closure expects TMemberType, TMemberType given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - message: "#^Strict comparison using \\=\\=\\= between string and false will always evaluate to false\\.$#" count: 1 From 289553fa46fc26b03db73db23481a98d6ddb12a5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Oct 2021 19:50:07 +0100 Subject: [PATCH 076/710] CS again --- src/pocketmine/utils/Internet.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/utils/Internet.php b/src/pocketmine/utils/Internet.php index 4979aa4e8..5bdd65881 100644 --- a/src/pocketmine/utils/Internet.php +++ b/src/pocketmine/utils/Internet.php @@ -31,6 +31,7 @@ use function curl_getinfo; use function curl_init; use function curl_setopt_array; use function explode; +use function is_int; use function is_string; use function preg_match; use function socket_close; From 974d08efd62c52c1c8ac92cb1b67ac157908fd71 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Oct 2021 20:09:42 +0100 Subject: [PATCH 077/710] Bump PHP minimum requirement to 8.0 PHPStan failed on 7.4 after updating to 0.12.99, and I figured it was less hassle to just do this than fix the build. In any case, we stopped shipping 7.4 months ago, and warned at 3.22 release that 7.4 support would soon be dropped. --- .github/workflows/main.yml | 19 ++-- .github/workflows/update-php-versions.php | 2 - BUILDING.md | 6 +- composer.json | 4 +- composer.lock | 6 +- phpstan.neon.dist | 3 - phpstan.php7.neon | 9 -- src/pocketmine/PocketMine.php | 2 +- src/pocketmine/network/rcon/RCON.php | 15 +-- src/pocketmine/network/rcon/RCONInstance.php | 37 ++---- src/pocketmine/utils/Internet.php | 2 +- src/pocketmine/utils/Timezone.php | 3 - src/pocketmine/utils/Utils.php | 3 +- tests/phpstan/configs/php7.neon | 112 ------------------- tests/phpstan/configs/php74-compat.neon | 11 -- 15 files changed, 29 insertions(+), 205 deletions(-) delete mode 100644 phpstan.php7.neon delete mode 100644 tests/phpstan/configs/php7.neon delete mode 100644 tests/phpstan/configs/php74-compat.neon diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ae5ecd62f..79f39f899 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: image: [ubuntu-20.04] - php: [7.4.24, 8.0.11] + php: [8.0.11] steps: - uses: actions/checkout@v2 #needed for build.sh @@ -36,13 +36,8 @@ jobs: strategy: fail-fast: false matrix: - include: - - php: 8.0.11 - config: phpstan.neon.dist - image: ubuntu-20.04 - - php: 7.4.24 - config: phpstan.php7.neon - image: ubuntu-20.04 + image: [ubuntu-20.04] + php: [8.0.11] steps: - uses: actions/checkout@v2 @@ -82,7 +77,7 @@ jobs: run: php composer.phar install --prefer-dist --no-interaction - name: Run PHPStan - run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G -c ${{ matrix.config }} + run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G phpunit: name: PHPUnit tests @@ -92,7 +87,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [7.4.24, 8.0.11] + php: [8.0.11] steps: - uses: actions/checkout@v2 @@ -142,7 +137,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [7.4.24, 8.0.11] + php: [8.0.11] steps: - uses: actions/checkout@v2 @@ -194,7 +189,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [7.4.24, 8.0.11] + php: [8.0.11] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/update-php-versions.php b/.github/workflows/update-php-versions.php index 8b24812c8..0ba7382cf 100644 --- a/.github/workflows/update-php-versions.php +++ b/.github/workflows/update-php-versions.php @@ -22,8 +22,6 @@ declare(strict_types=1); const VERSIONS = [ - "7.3", - "7.4", "8.0" ]; diff --git a/BUILDING.md b/BUILDING.md index 1c5aa8e59..37b7a4a8f 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -2,13 +2,13 @@ ## Pre-requisites - A bash shell (git bash is sufficient for Windows) - [`git`](https://git-scm.com) available in your shell -- PHP 7.4 or newer available in your shell +- PHP 8.0 or newer available in your shell - [`composer`](https://getcomposer.org) available in your shell ## Custom PHP binaries Because PocketMine-MP requires several non-standard PHP extensions and configuration, PMMP provides scripts to build custom binaries for running PocketMine-MP, as well as prebuilt binaries. -- [Prebuilt binaries](https://jenkins.pmmp.io/job/PHP-7.4-Aggregate) +- [Prebuilt binaries](https://jenkins.pmmp.io/job/PHP-8.0-Aggregate) - [Compile scripts](https://github.com/pmmp/php-build-scripts) are provided as a submodule in the path `build/php` If you use a custom binary, you'll need to replace `composer` usages in this guide with `path/to/your/php path/to/your/composer.phar`. @@ -38,7 +38,7 @@ There is a bug in PHP that might cause an error which looks like this: ``` Fatal error: Uncaught BadMethodCallException: unable to create temporary file in PocketMine-MP/build/server-phar.php:119 ``` -You can work around it by setting `ulimit -n` to some bigger number, e.g. `8192`, or by updating your PHP version to at least 7.4.16 or 8.0.3. +You can work around it by setting `ulimit -n` to some bigger number, e.g. `8192`, or by updating your PHP version to at least 8.0.3. ## Running PocketMine-MP from source code Run `src/pocketmine/PocketMine.php` using your preferred PHP binary. diff --git a/composer.json b/composer.json index 911b036f5..262d67a10 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "homepage": "https://pmmp.io", "license": "LGPL-3.0", "require": { - "php": "^7.4 || ^8.0", + "php": "^8.0", "php-64bit": "*", "ext-ctype": "*", "ext-curl": "*", @@ -60,7 +60,7 @@ }, "config": { "platform": { - "php": "7.4.0" + "php": "8.0.0" }, "sort-packages": true }, diff --git a/composer.lock b/composer.lock index 68576adf1..838f72322 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f3f0ef9944d96c5b71b7e32aac5118cd", + "content-hash": "cfba71d2ad0dd961ed00520b5d52e4d7", "packages": [ { "name": "adhocore/json-comment", @@ -2755,7 +2755,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.4 || ^8.0", + "php": "^8.0", "php-64bit": "*", "ext-ctype": "*", "ext-curl": "*", @@ -2778,7 +2778,7 @@ }, "platform-dev": [], "platform-overrides": { - "php": "7.4.0" + "php": "8.0.0" }, "plugin-api-version": "2.1.0" } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index f2fd04b9b..0dee95aa2 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -5,7 +5,6 @@ includes: - tests/phpstan/configs/l7-baseline.neon - tests/phpstan/configs/l8-baseline.neon - tests/phpstan/configs/php-bugs.neon - - tests/phpstan/configs/php74-compat.neon - tests/phpstan/configs/phpstan-bugs.neon - tests/phpstan/configs/phpunit-wiring-tests.neon - tests/phpstan/configs/pthreads-bugs.neon @@ -51,5 +50,3 @@ parameters: #we'll just fill it with 10 - it's very unlikely to encounter a callable with 10 parameters anyway. anyCallable: 'callable(never, never, never, never, never, never, never, never, never, never) : mixed' anyClosure: '\Closure(never, never, never, never, never, never, never, never, never, never) : mixed' - PhpSocket: '\Socket' - PhpCurlHandle: '\CurlHandle' diff --git a/phpstan.php7.neon b/phpstan.php7.neon deleted file mode 100644 index e16e7b8c3..000000000 --- a/phpstan.php7.neon +++ /dev/null @@ -1,9 +0,0 @@ -includes: - - phpstan.neon.dist - - tests/phpstan/configs/php7.neon - -parameters: - phpVersion: 70400 - typeAliases: - PhpSocket: resource - PhpCurlHandle: resource diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index f425d7267..fd648140d 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -36,7 +36,7 @@ namespace pocketmine { require_once __DIR__ . '/VersionInfo.php'; - const MIN_PHP_VERSION = "7.4.0"; + const MIN_PHP_VERSION = "8.0.0"; /** * @param string $message diff --git a/src/pocketmine/network/rcon/RCON.php b/src/pocketmine/network/rcon/RCON.php index 87ccab802..13dec46cb 100644 --- a/src/pocketmine/network/rcon/RCON.php +++ b/src/pocketmine/network/rcon/RCON.php @@ -57,24 +57,15 @@ use const SOL_TCP; class RCON{ /** @var Server */ private $server; - /** - * @var \Socket|resource - * @phpstan-var PhpSocket - */ + /** @var \Socket */ private $socket; /** @var RCONInstance */ private $instance; - /** - * @var \Socket|resource - * @phpstan-var PhpSocket - */ + /** @var \Socket */ private $ipcMainSocket; - /** - * @var resource - * @phpstan-var PhpSocket - */ + /** @var \Socket */ private $ipcThreadSocket; public function __construct(Server $server, string $password, int $port = 19132, string $interface = "0.0.0.0", int $maxClients = 50){ diff --git a/src/pocketmine/network/rcon/RCONInstance.php b/src/pocketmine/network/rcon/RCONInstance.php index 42212f6d3..ab60c745f 100644 --- a/src/pocketmine/network/rcon/RCONInstance.php +++ b/src/pocketmine/network/rcon/RCONInstance.php @@ -60,10 +60,7 @@ class RCONInstance extends Thread{ /** @var bool */ private $stop; - /** - * @var \Socket|resource - * @phpstan-var PhpSocket - */ + /** @var \Socket */ private $socket; /** @var string */ private $password; @@ -71,21 +68,12 @@ class RCONInstance extends Thread{ private $maxClients; /** @var \ThreadedLogger */ private $logger; - /** - * @var \Socket|resource - * @phpstan-var PhpSocket - */ + /** @var \Socket */ private $ipcSocket; /** @var SleeperNotifier|null */ private $notifier; - /** - * @param \Socket|resource $socket - * @param \Socket|resource $ipcSocket - * @phpstan-param PhpSocket $socket - * @phpstan-param PhpSocket $ipcSocket - */ - public function __construct($socket, string $password, int $maxClients, \ThreadedLogger $logger, $ipcSocket, ?SleeperNotifier $notifier){ + public function __construct(\Socket $socket, string $password, int $maxClients, \ThreadedLogger $logger, \Socket $ipcSocket, ?SleeperNotifier $notifier){ $this->stop = false; $this->cmd = ""; $this->response = ""; @@ -100,12 +88,9 @@ class RCONInstance extends Thread{ } /** - * @param \Socket|resource $client - * @phpstan-param PhpSocket $client - * * @return int|false */ - private function writePacket($client, int $requestID, int $packetType, string $payload){ + private function writePacket(\Socket $client, int $requestID, int $packetType, string $payload){ $pk = Binary::writeLInt($requestID) . Binary::writeLInt($packetType) . $payload @@ -114,15 +99,13 @@ class RCONInstance extends Thread{ } /** - * @param \Socket|resource $client * @param int $requestID reference parameter * @param int $packetType reference parameter * @param string $payload reference parameter - * @phpstan-param PhpSocket $client * * @return bool */ - private function readPacket($client, ?int &$requestID, ?int &$packetType, ?string &$payload){ + private function readPacket(\Socket $client, ?int &$requestID, ?int &$packetType, ?string &$payload){ $d = @socket_read($client, 4); socket_getpeername($client, $ip, $port); @@ -176,8 +159,8 @@ class RCONInstance extends Thread{ $this->registerClassLoader(); /** - * @var \Socket[]|resource[] $clients - * @phpstan-var array $clients + * @var \Socket[] $clients + * @phpstan-var array $clients */ $clients = []; /** @var bool[] $authenticated */ @@ -277,11 +260,7 @@ class RCONInstance extends Thread{ } } - /** - * @param \Socket|resource $client - * @phpstan-param PhpSocket $client - */ - private function disconnectClient($client) : void{ + private function disconnectClient(\Socket $client) : void{ socket_getpeername($client, $ip, $port); @socket_set_option($client, SOL_SOCKET, SO_LINGER, ["l_onoff" => 1, "l_linger" => 1]); @socket_shutdown($client, 2); diff --git a/src/pocketmine/utils/Internet.php b/src/pocketmine/utils/Internet.php index 5bdd65881..5c3f06329 100644 --- a/src/pocketmine/utils/Internet.php +++ b/src/pocketmine/utils/Internet.php @@ -197,7 +197,7 @@ class Internet{ * @param callable|null $onSuccess function to be called if there is no error. Accepts a resource argument as the cURL handle. * @phpstan-param array $extraOpts * @phpstan-param list $extraHeaders - * @phpstan-param (callable(PhpCurlHandle) : void)|null $onSuccess + * @phpstan-param (callable(\CurlHandle) : void)|null $onSuccess * * @return array a plain array of three [result body : string, headers : string[][], HTTP response code : int]. Headers are grouped by requests with strtolower(header name) as keys and header value as values * @phpstan-return array{string, list>, int} diff --git a/src/pocketmine/utils/Timezone.php b/src/pocketmine/utils/Timezone.php index 8d883e582..08a7c78bf 100644 --- a/src/pocketmine/utils/Timezone.php +++ b/src/pocketmine/utils/Timezone.php @@ -201,9 +201,6 @@ abstract class Timezone{ } $parsed = date_parse($offset); - if($parsed === false){ - return false; - } $offset = $parsed['hour'] * 3600 + $parsed['minute'] * 60 + $parsed['second']; //After date_parse is done, put the sign back diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 1b81ad3b8..c92fc373a 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -454,7 +454,7 @@ class Utils{ * @param callable|null $onSuccess function to be called if there is no error. Accepts a resource argument as the cURL handle. * @phpstan-param array $extraOpts * @phpstan-param list $extraHeaders - * @phpstan-param (callable(PhpCurlHandle) : void)|null $onSuccess + * @phpstan-param (callable(\CurlHandle) : void)|null $onSuccess * * @return array a plain array of three [result body : string, headers : string[][], HTTP response code : int]. Headers are grouped by requests with strtolower(header name) as keys and header value as values * @phpstan-return array{string, list>, int} @@ -642,7 +642,6 @@ class Utils{ preg_match_all('/(*ANYCRLF)^[\t ]*(?:\* )?@([a-zA-Z]+)(?:[\t ]+(.+?))?[\t ]*$/m', $rawDocComment, $matches); $result = array_combine($matches[1], $matches[2]); - if($result === false) throw new AssumptionFailedError("array_combine() doesn't return false with two equal-sized arrays"); return $result; } diff --git a/tests/phpstan/configs/php7.neon b/tests/phpstan/configs/php7.neon deleted file mode 100644 index f02766677..000000000 --- a/tests/phpstan/configs/php7.neon +++ /dev/null @@ -1,112 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Parameter \\#1 \\$fp of function fclose expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - - - - message: "#^Parameter \\#1 \\$fp of function fwrite expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - - - - message: "#^Parameter \\#1 \\$str of function base64_decode expects string, mixed given\\.$#" - count: 6 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#1 \\$input of function array_filter expects array, array\\\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$str of function strtolower expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$number of function round expects float, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/StatusCommand.php - - - - message: "#^Parameter \\#1 \\$fp of function fclose expects resource, resource\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Parameter \\#1 \\$fp of function fseek expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Parameter \\#1 \\$source of function stream_get_contents expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Parameter \\#1 \\$argument of class ReflectionClass constructor expects class\\-string\\\\|T of object, string given\\.$#" - count: 1 - path: ../../../src/pocketmine/event/HandlerList.php - - - - message: "#^Parameter \\#2 \\$input1 of function array_map expects array, array\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/lang/BaseLang.php - - - - message: "#^Parameter \\#2 \\$str of function explode expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php - - - - message: "#^Parameter \\#1 \\$input of function array_filter expects array, array\\\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Parameter \\#1 \\$str of function str_split expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Parameter \\#1 \\$str of function mb_strtoupper expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#1 \\$variable_representation of function unserialize expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/AsyncTask.php - - - - message: "#^Parameter \\#1 \\$str of function strtolower expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Parameter \\#2 \\$timestamp of function date expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Parameter \\#2 \\$start of function substr expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#3 \\$length of function substr expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#2 \\$input1 of function array_map expects array, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Method ReflectionMethod\\:\\:getClosure\\(\\) invoked with 0 parameters, 1 required\\.$#" - count: 1 - path: ../../phpunit/network/mcpe/StupidJsonDecodeTest.php - diff --git a/tests/phpstan/configs/php74-compat.neon b/tests/phpstan/configs/php74-compat.neon deleted file mode 100644 index c5aaf4443..000000000 --- a/tests/phpstan/configs/php74-compat.neon +++ /dev/null @@ -1,11 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Strict comparison using \\=\\=\\= between array\\ and false will always evaluate to false\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Strict comparison using \\=\\=\\= between array and false will always evaluate to false\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php From b54854529f8a1366e156f8ec32e02635ec670e95 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Oct 2021 20:20:37 +0100 Subject: [PATCH 078/710] Release 3.24.0 --- changelogs/3.24.md | 12 ++++++++++++ src/pocketmine/VersionInfo.php | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 changelogs/3.24.md diff --git a/changelogs/3.24.md b/changelogs/3.24.md new file mode 100644 index 000000000..2d97a8fb6 --- /dev/null +++ b/changelogs/3.24.md @@ -0,0 +1,12 @@ +**For Minecraft: Bedrock Edition 1.17.30** + +### Note about API versions +Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps. +Plugin developers should **only** update their required API to this version if you need the changes in this build. + +**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do. + +# 3.24.0 +- PHP 8.0 is now required as a minimum. +- Fixed stats reporting checking the wrong `pocketmine.yml` property. +- Fixed `Projectile->move()` not respecting the given `dx`/`dy`/`dz` and using its own motion instead. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index ce905e803..dc37bf9c4 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.23.2"; -const IS_DEVELOPMENT_BUILD = true; +const BASE_VERSION = "3.24.0"; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = ""; +const BUILD_CHANNEL = "stable"; From 13068ba3a77a7e59d373532248387bd2e340ece4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Oct 2021 20:20:41 +0100 Subject: [PATCH 079/710] 3.24.1 is next --- src/pocketmine/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index dc37bf9c4..a13e9cce1 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.24.0"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.24.1"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = "stable"; +const BUILD_CHANNEL = ""; From 09715906c8850088ceb34718530c876bf2985986 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 9 Oct 2021 23:51:46 +0200 Subject: [PATCH 080/710] StructureGrowEvent: added API to get the player who caused the growth (#4445) --- src/block/Bamboo.php | 10 +++++----- src/block/BambooSapling.php | 8 ++++---- src/block/Sapling.php | 8 ++++---- src/event/block/StructureGrowEvent.php | 13 ++++++++++++- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/block/Bamboo.php b/src/block/Bamboo.php index fc5182cfb..171491406 100644 --- a/src/block/Bamboo.php +++ b/src/block/Bamboo.php @@ -145,12 +145,12 @@ class Bamboo extends Transparent{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($item instanceof Fertilizer){ $top = $this->seekToTop(); - if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2))){ + if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2), $player)){ $item->pop(); return true; } }elseif($item instanceof ItemBamboo){ - if($this->seekToTop()->grow(PHP_INT_MAX, 1)){ + if($this->seekToTop()->grow(PHP_INT_MAX, 1, $player)){ $item->pop(); return true; } @@ -165,7 +165,7 @@ class Bamboo extends Transparent{ } } - private function grow(int $maxHeight, int $growAmount) : bool{ + private function grow(int $maxHeight, int $growAmount, ?Player $player) : bool{ $world = $this->position->getWorld(); if(!$world->getBlock($this->position->up())->canBeReplaced()){ return false; @@ -212,7 +212,7 @@ class Bamboo extends Transparent{ $tx->addBlock($this->position->subtract(0, $idx - $growAmount, 0), $newBlock); } - $ev = new StructureGrowEvent($this, $tx); + $ev = new StructureGrowEvent($this, $tx, $player); $ev->call(); if($ev->isCancelled()){ return false; @@ -229,7 +229,7 @@ class Bamboo extends Transparent{ $world = $this->position->getWorld(); if($this->ready){ $this->ready = false; - if($world->getFullLight($this->position) < 9 || !$this->grow(self::getMaxHeight($this->position->getFloorX(), $this->position->getFloorZ()), 1)){ + if($world->getFullLight($this->position) < 9 || !$this->grow(self::getMaxHeight($this->position->getFloorX(), $this->position->getFloorZ()), 1, null)){ $world->setBlock($this->position, $this); } }elseif($world->getBlock($this->position->up())->canBeReplaced()){ diff --git a/src/block/BambooSapling.php b/src/block/BambooSapling.php index b617236ed..3da1e593a 100644 --- a/src/block/BambooSapling.php +++ b/src/block/BambooSapling.php @@ -73,7 +73,7 @@ final class BambooSapling extends Flowable{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($item instanceof Fertilizer || $item instanceof ItemBamboo){ - if($this->grow()){ + if($this->grow($player)){ $item->pop(); return true; } @@ -87,7 +87,7 @@ final class BambooSapling extends Flowable{ } } - private function grow() : bool{ + private function grow(?Player $player) : bool{ $world = $this->position->getWorld(); if(!$world->getBlock($this->position->up())->canBeReplaced()){ return false; @@ -98,7 +98,7 @@ final class BambooSapling extends Flowable{ $tx->addBlock($this->position, $bamboo) ->addBlock($this->position->up(), (clone $bamboo)->setLeafSize(Bamboo::SMALL_LEAVES)); - $ev = new StructureGrowEvent($this, $tx); + $ev = new StructureGrowEvent($this, $tx, $player); $ev->call(); if($ev->isCancelled()){ return false; @@ -115,7 +115,7 @@ final class BambooSapling extends Flowable{ $world = $this->position->getWorld(); if($this->ready){ $this->ready = false; - if($world->getFullLight($this->position) < 9 || !$this->grow()){ + if($world->getFullLight($this->position) < 9 || !$this->grow(null)){ $world->setBlock($this->position, $this); } }elseif($world->getBlock($this->position->up())->canBeReplaced()){ diff --git a/src/block/Sapling.php b/src/block/Sapling.php index cb9d36b02..169cb9a32 100644 --- a/src/block/Sapling.php +++ b/src/block/Sapling.php @@ -77,7 +77,7 @@ class Sapling extends Flowable{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($item instanceof Fertilizer){ - $this->grow(); + $this->grow($player); $item->pop(); @@ -100,7 +100,7 @@ class Sapling extends Flowable{ public function onRandomTick() : void{ if($this->position->getWorld()->getFullLightAt($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ()) >= 8 and mt_rand(1, 7) === 1){ if($this->ready){ - $this->grow(); + $this->grow(null); }else{ $this->ready = true; $this->position->getWorld()->setBlock($this->position, $this); @@ -108,7 +108,7 @@ class Sapling extends Flowable{ } } - private function grow() : void{ + private function grow(?Player $player) : void{ $random = new Random(mt_rand()); $tree = TreeFactory::get($random, $this->treeType); $transaction = $tree?->getBlockTransaction($this->position->getWorld(), $this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ(), $random); @@ -116,7 +116,7 @@ class Sapling extends Flowable{ return; } - $ev = new StructureGrowEvent($this, $transaction); + $ev = new StructureGrowEvent($this, $transaction, $player); $ev->call(); if($ev->isCancelled()){ return; diff --git a/src/event/block/StructureGrowEvent.php b/src/event/block/StructureGrowEvent.php index 88fd54ae8..30d7c7ceb 100644 --- a/src/event/block/StructureGrowEvent.php +++ b/src/event/block/StructureGrowEvent.php @@ -7,6 +7,7 @@ namespace pocketmine\event\block; use pocketmine\block\Block; use pocketmine\event\Cancellable; use pocketmine\event\CancellableTrait; +use pocketmine\player\Player; use pocketmine\world\BlockTransaction; /** @@ -17,13 +18,23 @@ class StructureGrowEvent extends BlockEvent implements Cancellable{ use CancellableTrait; private BlockTransaction $transaction; + private ?Player $player; - public function __construct(Block $block, BlockTransaction $transaction){ + public function __construct(Block $block, BlockTransaction $transaction, ?Player $player){ parent::__construct($block); $this->transaction = $transaction; + $this->player = $player; } public function getTransaction() : BlockTransaction{ return $this->transaction; } + + /** + * It returns the player which grows the structure. + * It returns null when the structure grows by itself. + */ + public function getPlayer() : ?Player{ + return $this->player; + } } \ No newline at end of file From c1f843a42ca073e2ff096d1a64f02903790b78dc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Oct 2021 23:55:36 +0100 Subject: [PATCH 081/710] GarbageCollectorCommand: fixed duplicate MB suffix --- src/command/defaults/GarbageCollectorCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/defaults/GarbageCollectorCommand.php b/src/command/defaults/GarbageCollectorCommand.php index 1081ac52e..2e85ed093 100644 --- a/src/command/defaults/GarbageCollectorCommand.php +++ b/src/command/defaults/GarbageCollectorCommand.php @@ -68,7 +68,7 @@ class GarbageCollectorCommand extends VanillaCommand{ $sender->sendMessage(KnownTranslationFactory::pocketmine_command_gc_entities(TextFormat::RED . number_format($entitiesCollected))->prefix(TextFormat::GOLD)); $sender->sendMessage(KnownTranslationFactory::pocketmine_command_gc_cycles(TextFormat::RED . number_format($cyclesCollected))->prefix(TextFormat::GOLD)); - $sender->sendMessage(KnownTranslationFactory::pocketmine_command_gc_memoryFreed(TextFormat::RED . number_format(round((($memory - memory_get_usage()) / 1024) / 1024, 2), 2) . " MB")->prefix(TextFormat::GOLD)); + $sender->sendMessage(KnownTranslationFactory::pocketmine_command_gc_memoryFreed(TextFormat::RED . number_format(round((($memory - memory_get_usage()) / 1024) / 1024, 2), 2))->prefix(TextFormat::GOLD)); return true; } } From aa53dc670982d05c5235ef26cc55586bc08d4b52 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 9 Oct 2021 23:56:49 +0100 Subject: [PATCH 082/710] Entity: fixed network properties not updating when fireTicks changes another bug that LBSG knew about, but didn't report. :/ --- src/entity/Entity.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index b1680fdb2..8bab76480 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -681,10 +681,12 @@ abstract class Entity{ throw new \InvalidArgumentException("Fire ticks must be in range 0 ... " . 0x7fff . ", got $fireTicks"); } $this->fireTicks = $fireTicks; + $this->networkPropertiesDirty = true; } public function extinguish() : void{ $this->fireTicks = 0; + $this->networkPropertiesDirty = true; } public function isFireProof() : bool{ From fd2df637b60871fd6f0ae47d10ec47cf126c5eb3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 10 Oct 2021 22:35:38 +0100 Subject: [PATCH 083/710] Block: rename getPositionOffset() -> getModelPositionOffset() this gives a better idea of what the function does, and is also much less annoying for auto complete. --- src/block/Bamboo.php | 2 +- src/block/Block.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/block/Bamboo.php b/src/block/Bamboo.php index 171491406..08817d12d 100644 --- a/src/block/Bamboo.php +++ b/src/block/Bamboo.php @@ -115,7 +115,7 @@ class Bamboo extends Transparent{ return 12 + (self::getOffsetSeed($x, 0, $z) % 5); } - public function getPositionOffset() : ?Vector3{ + public function getModelPositionOffset() : ?Vector3{ $seed = self::getOffsetSeed($this->position->getFloorX(), 0, $this->position->getFloorZ()); $retX = (($seed % 12) + 1) / 16; $retZ = ((($seed >> 8) % 12) + 1) / 16; diff --git a/src/block/Block.php b/src/block/Block.php index 1ef2ccee0..2de12ce58 100644 --- a/src/block/Block.php +++ b/src/block/Block.php @@ -577,7 +577,7 @@ class Block{ final public function getCollisionBoxes() : array{ if($this->collisionBoxes === null){ $this->collisionBoxes = $this->recalculateCollisionBoxes(); - $extraOffset = $this->getPositionOffset(); + $extraOffset = $this->getModelPositionOffset(); $offset = $extraOffset !== null ? $this->position->addVector($extraOffset) : $this->position; foreach($this->collisionBoxes as $bb){ $bb->offset($offset->x, $offset->y, $offset->z); @@ -588,10 +588,10 @@ class Block{ } /** - * Returns an additional fractional vector to shift the block's effective position by based on the current position. + * Returns an additional fractional vector to shift the block model's position by based on the current position. * Used to randomize position of things like bamboo canes and tall grass. */ - public function getPositionOffset() : ?Vector3{ + public function getModelPositionOffset() : ?Vector3{ return null; } From 912e612743485d48612eece46162038a071dc120 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 10 Oct 2021 23:27:09 +0100 Subject: [PATCH 084/710] Utils: allow validateCallableSignature() to accept a manually constructed CallbackType instead of a closure this allows more fine-grained control without PHPStan yelling at us. --- src/utils/Utils.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/utils/Utils.php b/src/utils/Utils.php index 72192e6ee..9e33fc8a7 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -488,17 +488,20 @@ final class Utils{ * Verifies that the given callable is compatible with the desired signature. Throws a TypeError if they are * incompatible. * - * @param callable $signature Dummy callable with the required parameters and return type - * @param callable $subject Callable to check the signature of - * @phpstan-param anyCallable $signature - * @phpstan-param anyCallable $subject + * @param callable|CallbackType $signature Dummy callable with the required parameters and return type + * @param callable $subject Callable to check the signature of + * @phpstan-param anyCallable|CallbackType $signature + * @phpstan-param anyCallable $subject * * @throws \DaveRandom\CallbackValidator\InvalidCallbackException * @throws \TypeError */ - public static function validateCallableSignature(callable $signature, callable $subject) : void{ - if(!($sigType = CallbackType::createFromCallable($signature))->isSatisfiedBy($subject)){ - throw new \TypeError("Declaration of callable `" . CallbackType::createFromCallable($subject) . "` must be compatible with `" . $sigType . "`"); + public static function validateCallableSignature(callable|CallbackType $signature, callable $subject) : void{ + if(!($signature instanceof CallbackType)){ + $signature = CallbackType::createFromCallable($signature); + } + if(!$signature->isSatisfiedBy($subject)){ + throw new \TypeError("Declaration of callable `" . CallbackType::createFromCallable($subject) . "` must be compatible with `" . $signature . "`"); } } From 2696698926bd7651ca344b36ae63357057c1596c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 10 Oct 2021 23:31:57 +0100 Subject: [PATCH 085/710] ClosureTask: relax closure checks to allow arrow functions without return typehints nobody uses return typehints on arrow functions anyway .. they just waste space. --- src/scheduler/ClosureTask.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/scheduler/ClosureTask.php b/src/scheduler/ClosureTask.php index 45e30212e..74bf85a00 100644 --- a/src/scheduler/ClosureTask.php +++ b/src/scheduler/ClosureTask.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\scheduler; +use DaveRandom\CallbackValidator\CallbackType; +use DaveRandom\CallbackValidator\ReturnType; use pocketmine\utils\Utils; /** @@ -49,7 +51,7 @@ class ClosureTask extends Task{ * @phpstan-param \Closure() : void $closure */ public function __construct(\Closure $closure){ - Utils::validateCallableSignature(function() : void{}, $closure); + Utils::validateCallableSignature(new CallbackType(new ReturnType()), $closure); $this->closure = $closure; } From 5bae458a91d13871d3624c636fbd7ae3078a4966 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 10 Oct 2021 23:32:40 +0100 Subject: [PATCH 086/710] changelog: mention that Entity->setPosition(AndRotation)() are now protected --- changelogs/4.0.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 0f3851543..e5194d5b0 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -329,6 +329,8 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - The following methods have signature changes: - `Entity->entityBaseTick()` is now `protected`. - `Entity->move()` is now `protected`. + - `Entity->setPosition()` is now `protected` (use `Entity->teleport()` instead). + - `Entity->setPositionAndRotation()` is now `protected` (use `Entity->teleport()` instead). - `Living->knockBack()` now accepts `float, float, float` (the first two parameters have been removed). - `Living->getEffects()` now returns `EffectManager` instead of `Effect[]`. - The following classes have been added: From 965a16d19d053f9499838a4c66836d317f7ea0e7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 00:49:32 +0100 Subject: [PATCH 087/710] PluginManager: Extract deterministic plugin loadability checks into a separate method --- src/plugin/PluginManager.php | 101 ++++++++++++++++------------------- 1 file changed, 47 insertions(+), 54 deletions(-) diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 1e849bc53..064780653 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -32,6 +32,7 @@ use pocketmine\event\plugin\PluginDisableEvent; use pocketmine\event\plugin\PluginEnableEvent; use pocketmine\event\RegisteredListener; use pocketmine\lang\KnownTranslationFactory; +use pocketmine\lang\Translatable; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\permission\DefaultPermissions; use pocketmine\permission\PermissionManager; @@ -128,6 +129,47 @@ class PluginManager{ return Path::join(dirname($pluginPath), $pluginName); } + private function checkPluginLoadability(PluginDescription $description) : Translatable|string|null{ + $name = $description->getName(); + if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){ + return KnownTranslationFactory::pocketmine_plugin_restrictedName(); + } + + foreach($description->getCompatibleApis() as $api){ + if(!VersionString::isValidBaseVersion($api)){ + return KnownTranslationFactory::pocketmine_plugin_invalidAPI($api); + } + } + + if(!ApiVersion::isCompatible($this->server->getApiVersion(), $description->getCompatibleApis())){ + return KnownTranslationFactory::pocketmine_plugin_incompatibleAPI(implode(", ", $description->getCompatibleApis())); + } + + $ambiguousVersions = ApiVersion::checkAmbiguousVersions($description->getCompatibleApis()); + if(count($ambiguousVersions) > 0){ + return KnownTranslationFactory::pocketmine_plugin_ambiguousMinAPI(implode(", ", $ambiguousVersions)); + } + + if(count($description->getCompatibleOperatingSystems()) > 0 and !in_array(Utils::getOS(), $description->getCompatibleOperatingSystems(), true)) { + return KnownTranslationFactory::pocketmine_plugin_incompatibleOS(implode(", ", $description->getCompatibleOperatingSystems())); + } + + if(count($pluginMcpeProtocols = $description->getCompatibleMcpeProtocols()) > 0){ + $serverMcpeProtocols = [ProtocolInfo::CURRENT_PROTOCOL]; + if(count(array_intersect($pluginMcpeProtocols, $serverMcpeProtocols)) === 0){ + return KnownTranslationFactory::pocketmine_plugin_incompatibleProtocol(implode(", ", $pluginMcpeProtocols)); + } + } + + try{ + $description->checkRequiredExtensions(); + }catch(PluginException $ex){ + return $ex->getMessage(); + } + + return null; + } + /** * @param PluginLoader[] $loaders */ @@ -137,12 +179,6 @@ class PluginManager{ $description = $loader->getPluginDescription($path); if($description instanceof PluginDescription){ $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName()))); - try{ - $description->checkRequiredExtensions(); - }catch(PluginException $ex){ - $this->server->getLogger()->error($ex->getMessage()); - return null; - } $dataFolder = $this->getDataDirectory($path, $description->getName()); if(file_exists($dataFolder) and !is_dir($dataFolder)){ @@ -262,62 +298,19 @@ class PluginManager{ } $name = $description->getName(); - if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){ - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError($name, KnownTranslationFactory::pocketmine_plugin_restrictedName()))); + + if(($loadabilityError = $this->checkPluginLoadability($description)) !== null){ + $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError($name, $loadabilityError))); continue; } - if(strpos($name, " ") !== false){ - $this->server->getLogger()->warning($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_spacesDiscouraged($name))); - } if(isset($plugins[$name]) or $this->getPlugin($name) instanceof Plugin){ $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_duplicateError($name))); continue; } - foreach($description->getCompatibleApis() as $api){ - if(!VersionString::isValidBaseVersion($api)){ - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( - $name, - KnownTranslationFactory::pocketmine_plugin_invalidAPI($api) - ))); - continue 2; - } - } - - if(!ApiVersion::isCompatible($this->server->getApiVersion(), $description->getCompatibleApis())){ - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( - $name, - KnownTranslationFactory::pocketmine_plugin_incompatibleAPI(implode(", ", $description->getCompatibleApis())) - ))); - continue; - } - $ambiguousVersions = ApiVersion::checkAmbiguousVersions($description->getCompatibleApis()); - if(count($ambiguousVersions) > 0){ - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( - $name, - KnownTranslationFactory::pocketmine_plugin_ambiguousMinAPI(implode(", ", $ambiguousVersions)) - ))); - continue; - } - - if(count($description->getCompatibleOperatingSystems()) > 0 and !in_array(Utils::getOS(), $description->getCompatibleOperatingSystems(), true)) { - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( - $name, - KnownTranslationFactory::pocketmine_plugin_incompatibleOS(implode(", ", $description->getCompatibleOperatingSystems())) - ))); - continue; - } - - if(count($pluginMcpeProtocols = $description->getCompatibleMcpeProtocols()) > 0){ - $serverMcpeProtocols = [ProtocolInfo::CURRENT_PROTOCOL]; - if(count(array_intersect($pluginMcpeProtocols, $serverMcpeProtocols)) === 0){ - $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( - $name, - KnownTranslationFactory::pocketmine_plugin_incompatibleProtocol(implode(", ", $pluginMcpeProtocols)) - ))); - continue; - } + if(strpos($name, " ") !== false){ + $this->server->getLogger()->warning($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_spacesDiscouraged($name))); } if($this->graylist !== null and !$this->graylist->isAllowed($name)){ From e1ee320c8d4b5eaf355e7696b12786257190b23d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 00:58:33 +0100 Subject: [PATCH 088/710] PluginManager: Localize plugin loading error messages --- resources/locale | 2 +- src/lang/KnownTranslationFactory.php | 52 ++++++++++++++++++++++++++++ src/lang/KnownTranslationKeys.php | 9 +++++ src/plugin/PluginManager.php | 20 +++++++---- 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/resources/locale b/resources/locale index 299927cf8..d9b2c17b2 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit 299927cf85ef6b19d9a159e0bde66ef50e1c143d +Subproject commit d9b2c17b20e4eaf5538b179ab57c5568bb818359 diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 78f0abe6e..e02f95370 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1671,6 +1671,12 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_plugin_badDataFolder(Translatable|string $dataFolder) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_BADDATAFOLDER, [ + "dataFolder" => $dataFolder, + ]); + } + public static function pocketmine_plugin_circularDependency() : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_CIRCULARDEPENDENCY, []); } @@ -1696,18 +1702,39 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_plugin_disallowedByBlacklist() : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_DISALLOWEDBYBLACKLIST, []); + } + + public static function pocketmine_plugin_disallowedByWhitelist() : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_DISALLOWEDBYWHITELIST, []); + } + public static function pocketmine_plugin_duplicateError(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_DUPLICATEERROR, [ 0 => $param0, ]); } + public static function pocketmine_plugin_emptyExtensionVersionConstraint(Translatable|string $constraintIndex, Translatable|string $extensionName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_EMPTYEXTENSIONVERSIONCONSTRAINT, [ + "constraintIndex" => $constraintIndex, + "extensionName" => $extensionName, + ]); + } + public static function pocketmine_plugin_enable(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_ENABLE, [ 0 => $param0, ]); } + public static function pocketmine_plugin_extensionNotLoaded(Translatable|string $extensionName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_EXTENSIONNOTLOADED, [ + "extensionName" => $extensionName, + ]); + } + public static function pocketmine_plugin_genericLoadError(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_GENERICLOADERROR, [ 0 => $param0, @@ -1720,6 +1747,14 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_plugin_incompatibleExtensionVersion(Translatable|string $extensionVersion, Translatable|string $extensionName, Translatable|string $pluginRequirement) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_INCOMPATIBLEEXTENSIONVERSION, [ + "extensionVersion" => $extensionVersion, + "extensionName" => $extensionName, + "pluginRequirement" => $pluginRequirement, + ]); + } + public static function pocketmine_plugin_incompatibleOS(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_INCOMPATIBLEOS, [ 0 => $param0, @@ -1744,6 +1779,13 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_plugin_invalidExtensionVersionConstraint(Translatable|string $versionConstraint, Translatable|string $extensionName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_INVALIDEXTENSIONVERSIONCONSTRAINT, [ + "versionConstraint" => $versionConstraint, + "extensionName" => $extensionName, + ]); + } + public static function pocketmine_plugin_invalidManifest(Translatable|string $details) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_INVALIDMANIFEST, [ "details" => $details, @@ -1763,6 +1805,16 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_plugin_mainClassNotFound() : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_MAINCLASSNOTFOUND, []); + } + + public static function pocketmine_plugin_mainClassWrongType(Translatable|string $pluginInterface) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_MAINCLASSWRONGTYPE, [ + "pluginInterface" => $pluginInterface, + ]); + } + public static function pocketmine_plugin_restrictedName() : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_RESTRICTEDNAME, []); } diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 039642a96..238b4f806 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -352,21 +352,30 @@ final class KnownTranslationKeys{ public const POCKETMINE_PLAYER_LOGOUT = "pocketmine.player.logOut"; public const POCKETMINE_PLUGIN_ALIASERROR = "pocketmine.plugin.aliasError"; public const POCKETMINE_PLUGIN_AMBIGUOUSMINAPI = "pocketmine.plugin.ambiguousMinAPI"; + public const POCKETMINE_PLUGIN_BADDATAFOLDER = "pocketmine.plugin.badDataFolder"; public const POCKETMINE_PLUGIN_CIRCULARDEPENDENCY = "pocketmine.plugin.circularDependency"; public const POCKETMINE_PLUGIN_COMMANDERROR = "pocketmine.plugin.commandError"; public const POCKETMINE_PLUGIN_DEPRECATEDEVENT = "pocketmine.plugin.deprecatedEvent"; public const POCKETMINE_PLUGIN_DISABLE = "pocketmine.plugin.disable"; + public const POCKETMINE_PLUGIN_DISALLOWEDBYBLACKLIST = "pocketmine.plugin.disallowedByBlacklist"; + public const POCKETMINE_PLUGIN_DISALLOWEDBYWHITELIST = "pocketmine.plugin.disallowedByWhitelist"; public const POCKETMINE_PLUGIN_DUPLICATEERROR = "pocketmine.plugin.duplicateError"; + public const POCKETMINE_PLUGIN_EMPTYEXTENSIONVERSIONCONSTRAINT = "pocketmine.plugin.emptyExtensionVersionConstraint"; public const POCKETMINE_PLUGIN_ENABLE = "pocketmine.plugin.enable"; + public const POCKETMINE_PLUGIN_EXTENSIONNOTLOADED = "pocketmine.plugin.extensionNotLoaded"; public const POCKETMINE_PLUGIN_GENERICLOADERROR = "pocketmine.plugin.genericLoadError"; public const POCKETMINE_PLUGIN_INCOMPATIBLEAPI = "pocketmine.plugin.incompatibleAPI"; + public const POCKETMINE_PLUGIN_INCOMPATIBLEEXTENSIONVERSION = "pocketmine.plugin.incompatibleExtensionVersion"; public const POCKETMINE_PLUGIN_INCOMPATIBLEOS = "pocketmine.plugin.incompatibleOS"; public const POCKETMINE_PLUGIN_INCOMPATIBLEPHPVERSION = "pocketmine.plugin.incompatiblePhpVersion"; public const POCKETMINE_PLUGIN_INCOMPATIBLEPROTOCOL = "pocketmine.plugin.incompatibleProtocol"; public const POCKETMINE_PLUGIN_INVALIDAPI = "pocketmine.plugin.invalidAPI"; + public const POCKETMINE_PLUGIN_INVALIDEXTENSIONVERSIONCONSTRAINT = "pocketmine.plugin.invalidExtensionVersionConstraint"; public const POCKETMINE_PLUGIN_INVALIDMANIFEST = "pocketmine.plugin.invalidManifest"; public const POCKETMINE_PLUGIN_LOAD = "pocketmine.plugin.load"; public const POCKETMINE_PLUGIN_LOADERROR = "pocketmine.plugin.loadError"; + public const POCKETMINE_PLUGIN_MAINCLASSNOTFOUND = "pocketmine.plugin.mainClassNotFound"; + public const POCKETMINE_PLUGIN_MAINCLASSWRONGTYPE = "pocketmine.plugin.mainClassWrongType"; public const POCKETMINE_PLUGIN_RESTRICTEDNAME = "pocketmine.plugin.restrictedName"; public const POCKETMINE_PLUGIN_SPACESDISCOURAGED = "pocketmine.plugin.spacesDiscouraged"; public const POCKETMINE_PLUGIN_UNKNOWNDEPENDENCY = "pocketmine.plugin.unknownDependency"; diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 064780653..7b963af7e 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -178,11 +178,15 @@ class PluginManager{ if($loader->canLoadPlugin($path)){ $description = $loader->getPluginDescription($path); if($description instanceof PluginDescription){ + $language = $this->server->getLanguage(); $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName()))); $dataFolder = $this->getDataDirectory($path, $description->getName()); if(file_exists($dataFolder) and !is_dir($dataFolder)){ - $this->server->getLogger()->error("Projected dataFolder '" . $dataFolder . "' for " . $description->getName() . " exists and is not a directory"); + $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( + $description->getName(), + KnownTranslationFactory::pocketmine_plugin_badDataFolder($dataFolder) + ))); return null; } if(!file_exists($dataFolder)){ @@ -194,11 +198,17 @@ class PluginManager{ $mainClass = $description->getMain(); if(!class_exists($mainClass, true)){ - $this->server->getLogger()->error("Main class for plugin " . $description->getName() . " not found"); + $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( + $description->getName(), + KnownTranslationFactory::pocketmine_plugin_mainClassNotFound() + ))); return null; } if(!is_a($mainClass, Plugin::class, true)){ - $this->server->getLogger()->error("Main class for plugin " . $description->getName() . " is not an instance of " . Plugin::class); + $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( + $description->getName(), + KnownTranslationFactory::pocketmine_plugin_mainClassWrongType(Plugin::class) + ))); return null; } @@ -316,7 +326,7 @@ class PluginManager{ if($this->graylist !== null and !$this->graylist->isAllowed($name)){ $this->server->getLogger()->notice($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( $name, - "Disallowed by graylist" + $this->graylist->isWhitelist() ? KnownTranslationFactory::pocketmine_plugin_disallowedByWhitelist() : KnownTranslationFactory::pocketmine_plugin_disallowedByBlacklist() ))); continue; } @@ -381,8 +391,6 @@ class PluginManager{ $loadedThisLoop++; if(($plugin = $this->loadPlugin($file, $loaders)) instanceof Plugin){ $loadedPlugins[$name] = $plugin; - }else{ - $this->server->getLogger()->critical($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_genericLoadError($name))); } } } From 6d728e8d98d7910856d21b6fdc7193ba08968bbb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 01:11:59 +0100 Subject: [PATCH 089/710] PluginManager: Improved startup performance when loading many plugins for some reason we were reading and parsing the plugin.yml at least twice for every plugin loaded. We were repeating work already done by the initial loadPlugins() triage (discovering correct loader, loading plugin.yml from disk, parsing plugin.yml, validating plugin.yml) every time loadPlugin() was called with that plugin. --- src/plugin/PluginLoadTriageEntry.php | 42 ++++++++ src/plugin/PluginManager.php | 152 ++++++++++++++------------- 2 files changed, 120 insertions(+), 74 deletions(-) create mode 100644 src/plugin/PluginLoadTriageEntry.php diff --git a/src/plugin/PluginLoadTriageEntry.php b/src/plugin/PluginLoadTriageEntry.php new file mode 100644 index 000000000..5a1a875de --- /dev/null +++ b/src/plugin/PluginLoadTriageEntry.php @@ -0,0 +1,42 @@ +file; } + + public function getLoader() : PluginLoader{ return $this->loader; } + + public function getDescription() : PluginDescription{ return $this->description; } +} \ No newline at end of file diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 7b963af7e..63a444233 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -178,77 +178,7 @@ class PluginManager{ if($loader->canLoadPlugin($path)){ $description = $loader->getPluginDescription($path); if($description instanceof PluginDescription){ - $language = $this->server->getLanguage(); - $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName()))); - - $dataFolder = $this->getDataDirectory($path, $description->getName()); - if(file_exists($dataFolder) and !is_dir($dataFolder)){ - $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( - $description->getName(), - KnownTranslationFactory::pocketmine_plugin_badDataFolder($dataFolder) - ))); - return null; - } - if(!file_exists($dataFolder)){ - mkdir($dataFolder, 0777, true); - } - - $prefixed = $loader->getAccessProtocol() . $path; - $loader->loadPlugin($prefixed); - - $mainClass = $description->getMain(); - if(!class_exists($mainClass, true)){ - $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( - $description->getName(), - KnownTranslationFactory::pocketmine_plugin_mainClassNotFound() - ))); - return null; - } - if(!is_a($mainClass, Plugin::class, true)){ - $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( - $description->getName(), - KnownTranslationFactory::pocketmine_plugin_mainClassWrongType(Plugin::class) - ))); - return null; - } - - $permManager = PermissionManager::getInstance(); - $opRoot = $permManager->getPermission(DefaultPermissions::ROOT_OPERATOR); - $everyoneRoot = $permManager->getPermission(DefaultPermissions::ROOT_USER); - foreach($description->getPermissions() as $default => $perms){ - foreach($perms as $perm){ - $permManager->addPermission($perm); - switch($default){ - case PermissionParser::DEFAULT_TRUE: - $everyoneRoot->addChild($perm->getName(), true); - break; - case PermissionParser::DEFAULT_OP: - $opRoot->addChild($perm->getName(), true); - break; - case PermissionParser::DEFAULT_NOT_OP: - //TODO: I don't think anyone uses this, and it currently relies on some magic inside PermissibleBase - //to ensure that the operator override actually applies. - //Explore getting rid of this. - //The following grants this permission to anyone who has the "everyone" root permission. - //However, if the operator root node (which has higher priority) is present, the - //permission will be denied instead. - $everyoneRoot->addChild($perm->getName(), true); - $opRoot->addChild($perm->getName(), false); - break; - default: - break; - } - } - } - - /** - * @var Plugin $plugin - * @see Plugin::__construct() - */ - $plugin = new $mainClass($loader, $this->server, $description, $dataFolder, $prefixed, new DiskResourceProvider($prefixed . "/resources/")); - $this->plugins[$plugin->getDescription()->getName()] = $plugin; - - return $plugin; + $this->internalLoadPlugin($path, $loader, $description); } } } @@ -256,6 +186,80 @@ class PluginManager{ return null; } + private function internalLoadPlugin(string $path, PluginLoader $loader, PluginDescription $description) : ?Plugin{ + $language = $this->server->getLanguage(); + $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName()))); + + $dataFolder = $this->getDataDirectory($path, $description->getName()); + if(file_exists($dataFolder) and !is_dir($dataFolder)){ + $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( + $description->getName(), + KnownTranslationFactory::pocketmine_plugin_badDataFolder($dataFolder) + ))); + return null; + } + if(!file_exists($dataFolder)){ + mkdir($dataFolder, 0777, true); + } + + $prefixed = $loader->getAccessProtocol() . $path; + $loader->loadPlugin($prefixed); + + $mainClass = $description->getMain(); + if(!class_exists($mainClass, true)){ + $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( + $description->getName(), + KnownTranslationFactory::pocketmine_plugin_mainClassNotFound() + ))); + return null; + } + if(!is_a($mainClass, Plugin::class, true)){ + $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( + $description->getName(), + KnownTranslationFactory::pocketmine_plugin_mainClassWrongType(Plugin::class) + ))); + return null; + } + + $permManager = PermissionManager::getInstance(); + $opRoot = $permManager->getPermission(DefaultPermissions::ROOT_OPERATOR); + $everyoneRoot = $permManager->getPermission(DefaultPermissions::ROOT_USER); + foreach($description->getPermissions() as $default => $perms){ + foreach($perms as $perm){ + $permManager->addPermission($perm); + switch($default){ + case PermissionParser::DEFAULT_TRUE: + $everyoneRoot->addChild($perm->getName(), true); + break; + case PermissionParser::DEFAULT_OP: + $opRoot->addChild($perm->getName(), true); + break; + case PermissionParser::DEFAULT_NOT_OP: + //TODO: I don't think anyone uses this, and it currently relies on some magic inside PermissibleBase + //to ensure that the operator override actually applies. + //Explore getting rid of this. + //The following grants this permission to anyone who has the "everyone" root permission. + //However, if the operator root node (which has higher priority) is present, the + //permission will be denied instead. + $everyoneRoot->addChild($perm->getName(), true); + $opRoot->addChild($perm->getName(), false); + break; + default: + break; + } + } + } + + /** + * @var Plugin $plugin + * @see Plugin::__construct() + */ + $plugin = new $mainClass($loader, $this->server, $description, $dataFolder, $prefixed, new DiskResourceProvider($prefixed . "/resources/")); + $this->plugins[$plugin->getDescription()->getName()] = $plugin; + + return $plugin; + } + /** * @param string[]|null $newLoaders * @phpstan-param list> $newLoaders @@ -330,7 +334,7 @@ class PluginManager{ ))); continue; } - $plugins[$name] = $file; + $plugins[$name] = new PluginLoadTriageEntry($file, $loader, $description); $softDependencies[$name] = array_merge($softDependencies[$name] ?? [], $description->getSoftDepend()); $dependencies[$name] = $description->getDepend(); @@ -347,7 +351,7 @@ class PluginManager{ while(count($plugins) > 0){ $loadedThisLoop = 0; - foreach($plugins as $name => $file){ + foreach($plugins as $name => $entry){ if(isset($dependencies[$name])){ foreach($dependencies[$name] as $key => $dependency){ if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ @@ -389,7 +393,7 @@ class PluginManager{ if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){ unset($plugins[$name]); $loadedThisLoop++; - if(($plugin = $this->loadPlugin($file, $loaders)) instanceof Plugin){ + if(($plugin = $this->internalLoadPlugin($entry->getFile(), $entry->getLoader(), $entry->getDescription())) instanceof Plugin){ $loadedPlugins[$name] = $plugin; } } From 19a66a8d037d0d02d046cc73e36bc1212bc00f73 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 01:14:00 +0100 Subject: [PATCH 090/710] committing the new strings would have helped ... --- resources/locale | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/locale b/resources/locale index d9b2c17b2..0fe963d08 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit d9b2c17b20e4eaf5538b179ab57c5568bb818359 +Subproject commit 0fe963d087c1408b1dffa82f33e67f34ad8deaf5 From 8ac16345a3bc099b62c1f5cfbf3b736e621c3f76 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 15:05:08 +0100 Subject: [PATCH 091/710] TypeConverter: account for items without properly mapped IDs fixes #4459 --- src/network/mcpe/convert/ItemTranslator.php | 17 +++++-- src/network/mcpe/convert/TypeConverter.php | 52 +++++++++++++++------ 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index d1a7c3a58..1af9adba2 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -142,10 +142,10 @@ final class ItemTranslator{ } /** - * @return int[] - * @phpstan-return array{int, int} + * @return int[]|null + * @phpstan-return array{int, int}|null */ - public function toNetworkId(int $internalId, int $internalMeta) : array{ + public function toNetworkIdQuiet(int $internalId, int $internalMeta) : ?array{ if($internalMeta === -1){ $internalMeta = 0x7fff; } @@ -156,7 +156,16 @@ final class ItemTranslator{ return [$this->simpleCoreToNetMapping[$internalId], $internalMeta]; } - throw new \InvalidArgumentException("Unmapped ID/metadata combination $internalId:$internalMeta"); + return null; + } + + /** + * @return int[] + * @phpstan-return array{int, int} + */ + public function toNetworkId(int $internalId, int $internalMeta) : array{ + return $this->toNetworkIdQuiet($internalId, $internalMeta) ?? + throw new \InvalidArgumentException("Unmapped ID/metadata combination $internalId:$internalMeta"); } /** diff --git a/src/network/mcpe/convert/TypeConverter.php b/src/network/mcpe/convert/TypeConverter.php index d878423f6..21b3ab749 100644 --- a/src/network/mcpe/convert/TypeConverter.php +++ b/src/network/mcpe/convert/TypeConverter.php @@ -58,6 +58,7 @@ class TypeConverter{ private const DAMAGE_TAG = "Damage"; //TAG_Int private const DAMAGE_TAG_CONFLICT_RESOLUTION = "___Damage_ProtocolCollisionResolution___"; + private const PM_ID_TAG = "___Id___"; private const PM_META_TAG = "___Meta___"; /** @var int */ @@ -143,26 +144,40 @@ class TypeConverter{ } $isBlockItem = $itemStack->getId() < 256; - if($itemStack instanceof Durable and $itemStack->getDamage() > 0){ - if($nbt !== null){ - if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){ - $nbt->removeTag(self::DAMAGE_TAG); - $nbt->setTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION, $existing); - } - }else{ - $nbt = new CompoundTag(); - } - $nbt->setInt(self::DAMAGE_TAG, $itemStack->getDamage()); - }elseif($isBlockItem && $itemStack->getMeta() !== 0){ - //TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the - //client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata - //client-side. Aside from being very annoying, this also breaks various server-side behaviours. + + $idMeta = ItemTranslator::getInstance()->toNetworkIdQuiet($itemStack->getId(), $itemStack->getMeta()); + if($idMeta === null){ + //Display unmapped items as INFO_UPDATE, but stick something in their NBT to make sure they don't stack with + //other unmapped items. + [$id, $meta] = ItemTranslator::getInstance()->toNetworkId(ItemIds::INFO_UPDATE, 0); if($nbt === null){ $nbt = new CompoundTag(); } + $nbt->setInt(self::PM_ID_TAG, $itemStack->getId()); $nbt->setInt(self::PM_META_TAG, $itemStack->getMeta()); + }else{ + [$id, $meta] = $idMeta; + + if($itemStack instanceof Durable and $itemStack->getDamage() > 0){ + if($nbt !== null){ + if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){ + $nbt->removeTag(self::DAMAGE_TAG); + $nbt->setTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION, $existing); + } + }else{ + $nbt = new CompoundTag(); + } + $nbt->setInt(self::DAMAGE_TAG, $itemStack->getDamage()); + }elseif($isBlockItem && $itemStack->getMeta() !== 0){ + //TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the + //client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata + //client-side. Aside from being very annoying, this also breaks various server-side behaviours. + if($nbt === null){ + $nbt = new CompoundTag(); + } + $nbt->setInt(self::PM_META_TAG, $itemStack->getMeta()); + } } - [$id, $meta] = ItemTranslator::getInstance()->toNetworkId($itemStack->getId(), $itemStack->getMeta()); $blockRuntimeId = 0; if($isBlockItem){ @@ -197,6 +212,13 @@ class TypeConverter{ if($compound !== null){ $compound = clone $compound; + if(($idTag = $compound->getTag(self::PM_ID_TAG)) instanceof IntTag){ + $id = $idTag->getValue(); + $compound->removeTag(self::PM_ID_TAG); + if($compound->count() === 0){ + $compound = null; + } + } if(($damageTag = $compound->getTag(self::DAMAGE_TAG)) instanceof IntTag){ $meta = $damageTag->getValue(); $compound->removeTag(self::DAMAGE_TAG); From 500c298aafeb2d551bcd3b2154de96db773c7c9a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 15:12:16 +0100 Subject: [PATCH 092/710] Disallow the use of @handleCancelled on non-cancellable events closes #3464 --- src/plugin/PluginManager.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 63a444233..3fceaa710 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\plugin; +use pocketmine\event\Cancellable; use pocketmine\event\Event; use pocketmine\event\EventPriority; use pocketmine\event\HandlerListManager; @@ -60,6 +61,7 @@ use function is_subclass_of; use function iterator_to_array; use function mkdir; use function shuffle; +use function sprintf; use function stripos; use function strpos; use function strtolower; @@ -528,6 +530,14 @@ class PluginManager{ $handleCancelled = false; if(isset($tags[ListenerMethodTags::HANDLE_CANCELLED])){ + if(!is_a($eventClass, Cancellable::class, true)){ + throw new PluginException(sprintf( + "Event handler %s() declares @%s for non-cancellable event of type %s", + Utils::getNiceClosureName($handlerClosure), + ListenerMethodTags::HANDLE_CANCELLED, + $eventClass + )); + } switch(strtolower($tags[ListenerMethodTags::HANDLE_CANCELLED])){ case "true": case "": From e62794e4cfc12e47f73dee94e4134392254fc928 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 15:17:32 +0100 Subject: [PATCH 093/710] TypeConverter: fixed PHPStan errors --- src/network/mcpe/convert/TypeConverter.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/network/mcpe/convert/TypeConverter.php b/src/network/mcpe/convert/TypeConverter.php index 21b3ab749..38bbe359a 100644 --- a/src/network/mcpe/convert/TypeConverter.php +++ b/src/network/mcpe/convert/TypeConverter.php @@ -215,9 +215,6 @@ class TypeConverter{ if(($idTag = $compound->getTag(self::PM_ID_TAG)) instanceof IntTag){ $id = $idTag->getValue(); $compound->removeTag(self::PM_ID_TAG); - if($compound->count() === 0){ - $compound = null; - } } if(($damageTag = $compound->getTag(self::DAMAGE_TAG)) instanceof IntTag){ $meta = $damageTag->getValue(); @@ -225,8 +222,6 @@ class TypeConverter{ if(($conflicted = $compound->getTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION)) !== null){ $compound->removeTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION); $compound->setTag(self::DAMAGE_TAG, $conflicted); - }elseif($compound->count() === 0){ - $compound = null; } }elseif(($metaTag = $compound->getTag(self::PM_META_TAG)) instanceof IntTag){ //TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the @@ -234,9 +229,9 @@ class TypeConverter{ //client-side. Aside from being very annoying, this also breaks various server-side behaviours. $meta = $metaTag->getValue(); $compound->removeTag(self::PM_META_TAG); - if($compound->count() === 0){ - $compound = null; - } + } + if($compound->count() === 0){ + $compound = null; } } From 7b6632941de7756676b96227ea43a2a06b63eb3f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 16:04:36 +0100 Subject: [PATCH 094/710] GeneratorManager::getGenerator() now returns null for unknown generator aliases instead of returning Normal::class (indistinguishable from successful match) or throwing an exception (pain in the ass to handle). --- src/Server.php | 5 +++-- src/world/World.php | 3 ++- src/world/WorldManager.php | 5 ++--- src/world/format/io/FormatConverter.php | 5 ++++- src/world/generator/GeneratorManager.php | 17 ++++------------- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/Server.php b/src/Server.php index c99ac010e..172aaf643 100644 --- a/src/Server.php +++ b/src/Server.php @@ -106,6 +106,7 @@ use pocketmine\world\format\io\WorldProviderManager; use pocketmine\world\format\io\WritableWorldProviderManagerEntry; use pocketmine\world\generator\Generator; use pocketmine\world\generator\GeneratorManager; +use pocketmine\world\generator\normal\Normal; use pocketmine\world\World; use pocketmine\world\WorldCreationOptions; use pocketmine\world\WorldManager; @@ -979,7 +980,7 @@ class Server{ if(isset($options["generator"])){ $generatorOptions = explode(":", $options["generator"]); - $creationOptions->setGeneratorClass(GeneratorManager::getInstance()->getGenerator(array_shift($generatorOptions))); + $creationOptions->setGeneratorClass(GeneratorManager::getInstance()->getGenerator(array_shift($generatorOptions)) ?? Normal::class); if(count($generatorOptions) > 0){ $creationOptions->setGeneratorOptions(implode(":", $generatorOptions)); } @@ -1010,7 +1011,7 @@ class Server{ } if(!$this->worldManager->loadWorld($default, true)){ $creationOptions = WorldCreationOptions::create() - ->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($this->configGroup->getConfigString("level-type"))) + ->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($this->configGroup->getConfigString("level-type")) ?? Normal::class) ->setGeneratorOptions($this->configGroup->getConfigString("generator-settings")); $convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed")); if($convertedSeed !== null){ diff --git a/src/world/World.php b/src/world/World.php index 0eea2c7bc..9b953b3d4 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -411,7 +411,8 @@ class World implements ChunkManager{ $this->maxY = $this->provider->getWorldMaxY(); $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_preparing($this->displayName))); - $this->generator = GeneratorManager::getInstance()->getGenerator($this->provider->getWorldData()->getGenerator(), true); + $this->generator = GeneratorManager::getInstance()->getGenerator($this->provider->getWorldData()->getGenerator()) ?? + throw new AssumptionFailedError("WorldManager should already have checked that the generator exists"); //TODO: validate generator options $this->chunkPopulationRequestQueue = new \SplQueue(); $this->addOnUnloadCallback(function() : void{ diff --git a/src/world/WorldManager.php b/src/world/WorldManager.php index d79eee0b6..ff2c7ca12 100644 --- a/src/world/WorldManager.php +++ b/src/world/WorldManager.php @@ -220,9 +220,8 @@ class WorldManager{ ))); return false; } - try{ - GeneratorManager::getInstance()->getGenerator($provider->getWorldData()->getGenerator(), true); - }catch(\InvalidArgumentException $e){ + + if(GeneratorManager::getInstance()->getGenerator($provider->getWorldData()->getGenerator()) === null){ $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError( $name, KnownTranslationFactory::pocketmine_level_unknownGenerator($provider->getWorldData()->getGenerator()) diff --git a/src/world/format/io/FormatConverter.php b/src/world/format/io/FormatConverter.php index 5ee6ea3a8..6931d3b5f 100644 --- a/src/world/format/io/FormatConverter.php +++ b/src/world/format/io/FormatConverter.php @@ -25,6 +25,7 @@ namespace pocketmine\world\format\io; use pocketmine\utils\Filesystem; use pocketmine\world\generator\GeneratorManager; +use pocketmine\world\generator\normal\Normal; use pocketmine\world\WorldCreationOptions; use Webmozart\PathUtil\Path; use function basename; @@ -112,7 +113,9 @@ class FormatConverter{ Filesystem::recursiveUnlink($convertedOutput); } $this->newProvider->generate($convertedOutput, $data->getName(), WorldCreationOptions::create() - ->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($data->getGenerator())) + //TODO: defaulting to NORMAL here really isn't very good behaviour, but it's consistent with what we already + //did previously; besides, WorldManager checks for unknown generators before this is reached anyway. + ->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($data->getGenerator()) ?? Normal::class) ->setGeneratorOptions($data->getGeneratorOptions()) ->setSeed($data->getSeed()) ->setSpawnPosition($data->getSpawn()) diff --git a/src/world/generator/GeneratorManager.php b/src/world/generator/GeneratorManager.php index 58811f05f..1415906c9 100644 --- a/src/world/generator/GeneratorManager.php +++ b/src/world/generator/GeneratorManager.php @@ -79,20 +79,11 @@ final class GeneratorManager{ * * @param bool $throwOnMissing @deprecated this is for backwards compatibility only * - * @return string Name of class that extends Generator - * @phpstan-return class-string - * - * @throws \InvalidArgumentException if the generator type isn't registered + * @return string|null Name of class that extends Generator, or null if no generator is mapped to that name + * @phpstan-return class-string|null */ - public function getGenerator(string $name, bool $throwOnMissing = false){ - if(isset($this->list[$name = strtolower($name)])){ - return $this->list[$name]; - } - - if($throwOnMissing){ - throw new \InvalidArgumentException("Alias \"$name\" does not map to any known generator"); - } - return Normal::class; + public function getGenerator(string $name, bool $throwOnMissing = false) : ?string{ + return $this->list[strtolower($name)] ?? null; } /** From fa93a8d78f7aff607d72dcdd551ee60fd3773098 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 16:13:32 +0100 Subject: [PATCH 095/710] Server: Error on unknown generators when generating new worlds from config, instead of silently using DEFAULT this is consistent with the behaviour of loading worlds. --- src/Server.php | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/Server.php b/src/Server.php index 172aaf643..52bde0c2a 100644 --- a/src/Server.php +++ b/src/Server.php @@ -106,7 +106,6 @@ use pocketmine\world\format\io\WorldProviderManager; use pocketmine\world\format\io\WritableWorldProviderManagerEntry; use pocketmine\world\generator\Generator; use pocketmine\world\generator\GeneratorManager; -use pocketmine\world\generator\normal\Normal; use pocketmine\world\World; use pocketmine\world\WorldCreationOptions; use pocketmine\world\WorldManager; @@ -968,6 +967,17 @@ class Server{ $this->pluginManager->loadPlugins($this->pluginPath); $this->enablePlugins(PluginEnableOrder::STARTUP()); + $getGenerator = function(string $generatorName, string $worldName) : ?string{ + $generatorClass = GeneratorManager::getInstance()->getGenerator($generatorName); + if($generatorClass === null){ + $this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_level_generationError( + $worldName, + KnownTranslationFactory::pocketmine_level_unknownGenerator($generatorName) + ))); + } + return $generatorClass; + }; + foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){ if($options === null){ $options = []; @@ -980,7 +990,11 @@ class Server{ if(isset($options["generator"])){ $generatorOptions = explode(":", $options["generator"]); - $creationOptions->setGeneratorClass(GeneratorManager::getInstance()->getGenerator(array_shift($generatorOptions)) ?? Normal::class); + $generatorClass = $getGenerator(array_shift($generatorOptions), $name); + if($generatorClass === null){ + continue; + } + $creationOptions->setGeneratorClass($generatorClass); if(count($generatorOptions) > 0){ $creationOptions->setGeneratorOptions(implode(":", $generatorOptions)); } @@ -1010,14 +1024,17 @@ class Server{ $this->configGroup->setConfigString("level-name", "world"); } if(!$this->worldManager->loadWorld($default, true)){ - $creationOptions = WorldCreationOptions::create() - ->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($this->configGroup->getConfigString("level-type")) ?? Normal::class) - ->setGeneratorOptions($this->configGroup->getConfigString("generator-settings")); - $convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed")); - if($convertedSeed !== null){ - $creationOptions->setSeed($convertedSeed); + $generatorClass = $getGenerator($this->configGroup->getConfigString("level-type"), $default); + if($generatorClass !== null){ + $creationOptions = WorldCreationOptions::create() + ->setGeneratorClass($generatorClass) + ->setGeneratorOptions($this->configGroup->getConfigString("generator-settings")); + $convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed")); + if($convertedSeed !== null){ + $creationOptions->setSeed($convertedSeed); + } + $this->worldManager->generateWorld($default, $creationOptions); } - $this->worldManager->generateWorld($default, $creationOptions); } $world = $this->worldManager->getWorldByName($default); From 859cdfa5d2883d4ccebf5c0f6f6ff90802e88284 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 16:18:38 +0100 Subject: [PATCH 096/710] GeneratorManager: removed unused parameter from getGenerator() --- src/world/generator/GeneratorManager.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/world/generator/GeneratorManager.php b/src/world/generator/GeneratorManager.php index 1415906c9..0db15390e 100644 --- a/src/world/generator/GeneratorManager.php +++ b/src/world/generator/GeneratorManager.php @@ -77,12 +77,10 @@ final class GeneratorManager{ /** * Returns a class name of a registered Generator matching the given name. * - * @param bool $throwOnMissing @deprecated this is for backwards compatibility only - * * @return string|null Name of class that extends Generator, or null if no generator is mapped to that name * @phpstan-return class-string|null */ - public function getGenerator(string $name, bool $throwOnMissing = false) : ?string{ + public function getGenerator(string $name) : ?string{ return $this->list[strtolower($name)] ?? null; } From 70deea0ef992a572ec4ec9ddae63b2541b2de516 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 16:52:10 +0100 Subject: [PATCH 097/710] Flat: Move preset handling to a FlatGeneratorOptions unit --- src/world/generator/Flat.php | 84 ++---------- src/world/generator/FlatGeneratorOptions.php | 127 +++++++++++++++++++ 2 files changed, 137 insertions(+), 74 deletions(-) create mode 100644 src/world/generator/FlatGeneratorOptions.php diff --git a/src/world/generator/Flat.php b/src/world/generator/Flat.php index 1aba3ae13..3afab55db 100644 --- a/src/world/generator/Flat.php +++ b/src/world/generator/Flat.php @@ -39,32 +39,22 @@ use function preg_match; use function preg_match_all; class Flat extends Generator{ + /** @var Chunk */ private $chunk; /** @var Populator[] */ private $populators = []; - /** - * @var int[] - * @phpstan-var array - */ - private $structure; - /** @var int */ - private $biome; - /** - * @var mixed[] - * @phpstan-var array - */ - private array $options = []; + private FlatGeneratorOptions $options; /** * @throws InvalidGeneratorOptionsException */ public function __construct(int $seed, string $preset){ parent::__construct($seed, $preset !== "" ? $preset : "2;bedrock,2xdirt,grass;1;"); - $this->parsePreset(); + $this->options = FlatGeneratorOptions::parsePreset($this->preset); - if(isset($this->options["decoration"])){ + if(isset($this->options->getExtraOptions()["decoration"])){ $ores = new Ore(); $stone = VanillaBlocks::STONE(); $ores->setOreTypes([ @@ -83,76 +73,22 @@ class Flat extends Generator{ $this->generateBaseChunk(); } - /** - * @return int[] - * @phpstan-return array - * - * @throws InvalidGeneratorOptionsException - */ - public static function parseLayers(string $layers) : array{ - $result = []; - $split = array_map('\trim', explode(',', $layers)); - $y = 0; - $itemParser = LegacyStringToItemParser::getInstance(); - foreach($split as $line){ - preg_match('#^(?:(\d+)[x|*])?(.+)$#', $line, $matches); - if(count($matches) !== 3){ - throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\""); - } - - $cnt = $matches[1] !== "" ? (int) $matches[1] : 1; - try{ - $b = $itemParser->parse($matches[2])->getBlock(); - }catch(LegacyStringToItemParserException $e){ - throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\": " . $e->getMessage(), 0, $e); - } - for($cY = $y, $y += $cnt; $cY < $y; ++$cY){ - $result[$cY] = $b->getFullId(); - } - } - - return $result; - } - - protected function parsePreset() : void{ - $preset = explode(";", $this->preset); - $blocks = $preset[1] ?? ""; - $this->biome = (int) ($preset[2] ?? 1); - $options = $preset[3] ?? ""; - $this->structure = self::parseLayers($blocks); - - //TODO: more error checking - preg_match_all('#(([0-9a-z_]{1,})\(?([0-9a-z_ =:]{0,})\)?),?#', $options, $matches); - foreach($matches[2] as $i => $option){ - $params = true; - if($matches[3][$i] !== ""){ - $params = []; - $p = explode(" ", $matches[3][$i]); - foreach($p as $k){ - $k = explode("=", $k); - if(isset($k[1])){ - $params[$k[0]] = $k[1]; - } - } - } - $this->options[$option] = $params; - } - } - protected function generateBaseChunk() : void{ $this->chunk = new Chunk(); + $biomeId = $this->options->getBiomeId(); for($Z = 0; $Z < Chunk::EDGE_LENGTH; ++$Z){ for($X = 0; $X < Chunk::EDGE_LENGTH; ++$X){ - $this->chunk->setBiomeId($X, $Z, $this->biome); + $this->chunk->setBiomeId($X, $Z, $biomeId); } } - $count = count($this->structure); + $structure = $this->options->getStructure(); + $count = count($structure); for($sy = 0; $sy < $count; $sy += SubChunk::EDGE_LENGTH){ $subchunk = $this->chunk->getSubChunk($sy >> SubChunk::COORD_BIT_SIZE); - for($y = 0; $y < SubChunk::EDGE_LENGTH and isset($this->structure[$y | $sy]); ++$y){ - $id = $this->structure[$y | $sy]; + for($y = 0; $y < SubChunk::EDGE_LENGTH and isset($structure[$y | $sy]); ++$y){ + $id = $structure[$y | $sy]; for($Z = 0; $Z < SubChunk::EDGE_LENGTH; ++$Z){ for($X = 0; $X < SubChunk::EDGE_LENGTH; ++$X){ diff --git a/src/world/generator/FlatGeneratorOptions.php b/src/world/generator/FlatGeneratorOptions.php new file mode 100644 index 000000000..6c3f20a9c --- /dev/null +++ b/src/world/generator/FlatGeneratorOptions.php @@ -0,0 +1,127 @@ + $structure + * @phpstan-param array|true> $extraOptions + */ + public function __construct( + private array $structure, + private int $biomeId, + private array $extraOptions = [] + ){} + + /** + * @return int[] + * @phpstan-return array + */ + public function getStructure() : array{ return $this->structure; } + + public function getBiomeId() : int{ return $this->biomeId; } + + /** + * @return mixed[] + * @phpstan-return array|true> + */ + public function getExtraOptions() : array{ return $this->extraOptions; } + + + /** + * @return int[] + * @phpstan-return array + * + * @throws InvalidGeneratorOptionsException + */ + public static function parseLayers(string $layers) : array{ + $result = []; + $split = array_map('\trim', explode(',', $layers)); + $y = 0; + $itemParser = LegacyStringToItemParser::getInstance(); + foreach($split as $line){ + preg_match('#^(?:(\d+)[x|*])?(.+)$#', $line, $matches); + if(count($matches) !== 3){ + throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\""); + } + + $cnt = $matches[1] !== "" ? (int) $matches[1] : 1; + try{ + $b = $itemParser->parse($matches[2])->getBlock(); + }catch(LegacyStringToItemParserException $e){ + throw new InvalidGeneratorOptionsException("Invalid preset layer \"$line\": " . $e->getMessage(), 0, $e); + } + for($cY = $y, $y += $cnt; $cY < $y; ++$cY){ + $result[$cY] = $b->getFullId(); + } + } + + return $result; + } + + /** + * @throws InvalidGeneratorOptionsException + */ + public static function parsePreset(string $presetString) : self{ + $preset = explode(";", $presetString); + $blocks = $preset[1] ?? ""; + $biomeId = (int) ($preset[2] ?? 1); + $optionsString = $preset[3] ?? ""; + $structure = self::parseLayers($blocks); + + $options = []; + //TODO: more error checking + preg_match_all('#(([0-9a-z_]{1,})\(?([0-9a-z_ =:]{0,})\)?),?#', $optionsString, $matches); + foreach($matches[2] as $i => $option){ + $params = true; + if($matches[3][$i] !== ""){ + $params = []; + $p = explode(" ", $matches[3][$i]); + foreach($p as $k){ + $k = explode("=", $k); + if(isset($k[1])){ + $params[$k[0]] = $k[1]; + } + } + } + $options[(string) $option] = $params; + } + return new self($structure, $biomeId, $options); + } + +} \ No newline at end of file From 89d7b7198feecc21cf3efc613b0751f4686e75dd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 17:20:49 +0100 Subject: [PATCH 098/710] Server: drop support for tagging generator options onto the 'generator' key in pocketmine.yml the 'preset' key should be used for this purpose instead. This couldn't be dropped until now due to the shitty handling of unknown generators. --- src/Server.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Server.php b/src/Server.php index 52bde0c2a..3c8c2e4c6 100644 --- a/src/Server.php +++ b/src/Server.php @@ -989,15 +989,11 @@ class Server{ //TODO: error checking if(isset($options["generator"])){ - $generatorOptions = explode(":", $options["generator"]); - $generatorClass = $getGenerator(array_shift($generatorOptions), $name); + $generatorClass = $getGenerator($options["generator"], $name); if($generatorClass === null){ continue; } $creationOptions->setGeneratorClass($generatorClass); - if(count($generatorOptions) > 0){ - $creationOptions->setGeneratorOptions(implode(":", $generatorOptions)); - } } if(isset($options["difficulty"]) && is_string($options["difficulty"])){ $creationOptions->setDifficulty(World::getDifficultyFromString($options["difficulty"])); From 092aabeb97c06fb4228e83dd6075633cb3e83872 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 17:21:19 +0100 Subject: [PATCH 099/710] fix CS --- src/Server.php | 3 --- src/world/generator/Flat.php | 6 ------ src/world/generator/FlatGeneratorOptions.php | 1 - 3 files changed, 10 deletions(-) diff --git a/src/Server.php b/src/Server.php index 3c8c2e4c6..7168341f7 100644 --- a/src/Server.php +++ b/src/Server.php @@ -111,19 +111,16 @@ use pocketmine\world\WorldCreationOptions; use pocketmine\world\WorldManager; use Ramsey\Uuid\UuidInterface; use Webmozart\PathUtil\Path; -use function array_shift; use function array_sum; use function base64_encode; use function cli_set_process_title; use function copy; use function count; -use function explode; use function file_exists; use function file_get_contents; use function file_put_contents; use function filemtime; use function get_class; -use function implode; use function ini_set; use function is_array; use function is_string; diff --git a/src/world/generator/Flat.php b/src/world/generator/Flat.php index 3afab55db..fff96db94 100644 --- a/src/world/generator/Flat.php +++ b/src/world/generator/Flat.php @@ -24,19 +24,13 @@ declare(strict_types=1); namespace pocketmine\world\generator; use pocketmine\block\VanillaBlocks; -use pocketmine\item\LegacyStringToItemParser; -use pocketmine\item\LegacyStringToItemParserException; use pocketmine\world\ChunkManager; use pocketmine\world\format\Chunk; use pocketmine\world\format\SubChunk; use pocketmine\world\generator\object\OreType; use pocketmine\world\generator\populator\Ore; use pocketmine\world\generator\populator\Populator; -use function array_map; use function count; -use function explode; -use function preg_match; -use function preg_match_all; class Flat extends Generator{ diff --git a/src/world/generator/FlatGeneratorOptions.php b/src/world/generator/FlatGeneratorOptions.php index 6c3f20a9c..98d2f16a2 100644 --- a/src/world/generator/FlatGeneratorOptions.php +++ b/src/world/generator/FlatGeneratorOptions.php @@ -62,7 +62,6 @@ final class FlatGeneratorOptions{ */ public function getExtraOptions() : array{ return $this->extraOptions; } - /** * @return int[] * @phpstan-return array From 34f54750c82b614bcfe919adef46f9584358c61d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 17:37:47 +0100 Subject: [PATCH 100/710] Added support for creation-time validation of generator options, closes #2717 --- resources/locale | 2 +- src/Server.php | 44 +++++++++++------ src/lang/KnownTranslationFactory.php | 8 ++++ src/lang/KnownTranslationKeys.php | 1 + src/world/World.php | 5 +- src/world/format/io/FormatConverter.php | 2 +- src/world/generator/GeneratorManager.php | 47 +++++++++++------- src/world/generator/GeneratorManagerEntry.php | 48 +++++++++++++++++++ 8 files changed, 120 insertions(+), 37 deletions(-) create mode 100644 src/world/generator/GeneratorManagerEntry.php diff --git a/resources/locale b/resources/locale index 0fe963d08..17fc6a105 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit 0fe963d087c1408b1dffa82f33e67f34ad8deaf5 +Subproject commit 17fc6a10501c2cd48ec08f81ab41a640864f8d1d diff --git a/src/Server.php b/src/Server.php index 7168341f7..77e441c61 100644 --- a/src/Server.php +++ b/src/Server.php @@ -106,6 +106,7 @@ use pocketmine\world\format\io\WorldProviderManager; use pocketmine\world\format\io\WritableWorldProviderManagerEntry; use pocketmine\world\generator\Generator; use pocketmine\world\generator\GeneratorManager; +use pocketmine\world\generator\InvalidGeneratorOptionsException; use pocketmine\world\World; use pocketmine\world\WorldCreationOptions; use pocketmine\world\WorldManager; @@ -964,15 +965,25 @@ class Server{ $this->pluginManager->loadPlugins($this->pluginPath); $this->enablePlugins(PluginEnableOrder::STARTUP()); - $getGenerator = function(string $generatorName, string $worldName) : ?string{ - $generatorClass = GeneratorManager::getInstance()->getGenerator($generatorName); - if($generatorClass === null){ + $getGenerator = function(string $generatorName, string $generatorOptions, string $worldName) : ?string{ + $generatorEntry = GeneratorManager::getInstance()->getGenerator($generatorName); + if($generatorEntry === null){ $this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_level_generationError( $worldName, KnownTranslationFactory::pocketmine_level_unknownGenerator($generatorName) ))); + return null; } - return $generatorClass; + try{ + $generatorEntry->validateGeneratorOptions($generatorOptions); + }catch(InvalidGeneratorOptionsException $e){ + $this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_level_generationError( + $worldName, + KnownTranslationFactory::pocketmine_level_invalidGeneratorOptions($generatorOptions, $generatorName, $e->getMessage()) + ))); + return null; + } + return $generatorEntry->getGeneratorClass(); }; foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){ @@ -985,19 +996,20 @@ class Server{ $creationOptions = WorldCreationOptions::create(); //TODO: error checking - if(isset($options["generator"])){ - $generatorClass = $getGenerator($options["generator"], $name); - if($generatorClass === null){ - continue; - } - $creationOptions->setGeneratorClass($generatorClass); + $generatorName = $options["generator"] ?? "default"; + $generatorOptions = isset($options["preset"]) && is_string($options["preset"]) ? $options["preset"] : ""; + + $generatorClass = $getGenerator($generatorName, $generatorOptions, $name); + if($generatorClass === null){ + continue; } + $creationOptions->setGeneratorClass($generatorClass); + $creationOptions->setGeneratorOptions($generatorOptions); + if(isset($options["difficulty"]) && is_string($options["difficulty"])){ $creationOptions->setDifficulty(World::getDifficultyFromString($options["difficulty"])); } - if(isset($options["preset"]) && is_string($options["preset"])){ - $creationOptions->setGeneratorOptions($options["preset"]); - } + if(isset($options["seed"])){ $convertedSeed = Generator::convertSeed((string) ($options["seed"] ?? "")); if($convertedSeed !== null){ @@ -1017,11 +1029,13 @@ class Server{ $this->configGroup->setConfigString("level-name", "world"); } if(!$this->worldManager->loadWorld($default, true)){ - $generatorClass = $getGenerator($this->configGroup->getConfigString("level-type"), $default); + $generatorName = $this->configGroup->getConfigString("level-type"); + $generatorOptions = $this->configGroup->getConfigString("generator-settings"); + $generatorClass = $getGenerator($generatorName, $generatorOptions, $default); if($generatorClass !== null){ $creationOptions = WorldCreationOptions::create() ->setGeneratorClass($generatorClass) - ->setGeneratorOptions($this->configGroup->getConfigString("generator-settings")); + ->setGeneratorOptions($generatorOptions); $convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed")); if($convertedSeed !== null){ $creationOptions->setSeed($convertedSeed); diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index e02f95370..ce4f33c2b 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1575,6 +1575,14 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_level_invalidGeneratorOptions(Translatable|string $preset, Translatable|string $generatorName, Translatable|string $details) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_INVALIDGENERATOROPTIONS, [ + "preset" => $preset, + "generatorName" => $generatorName, + "details" => $details, + ]); + } + public static function pocketmine_level_loadError(Translatable|string $param0, Translatable|string $param1) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_LEVEL_LOADERROR, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 238b4f806..16f4d26f4 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -338,6 +338,7 @@ final class KnownTranslationKeys{ public const POCKETMINE_LEVEL_CORRUPTED = "pocketmine.level.corrupted"; public const POCKETMINE_LEVEL_DEFAULTERROR = "pocketmine.level.defaultError"; public const POCKETMINE_LEVEL_GENERATIONERROR = "pocketmine.level.generationError"; + public const POCKETMINE_LEVEL_INVALIDGENERATOROPTIONS = "pocketmine.level.invalidGeneratorOptions"; public const POCKETMINE_LEVEL_LOADERROR = "pocketmine.level.loadError"; public const POCKETMINE_LEVEL_NOTFOUND = "pocketmine.level.notFound"; public const POCKETMINE_LEVEL_PREPARING = "pocketmine.level.preparing"; diff --git a/src/world/World.php b/src/world/World.php index 9b953b3d4..f85320e34 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -411,9 +411,10 @@ class World implements ChunkManager{ $this->maxY = $this->provider->getWorldMaxY(); $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_preparing($this->displayName))); - $this->generator = GeneratorManager::getInstance()->getGenerator($this->provider->getWorldData()->getGenerator()) ?? + $generator = GeneratorManager::getInstance()->getGenerator($this->provider->getWorldData()->getGenerator()) ?? throw new AssumptionFailedError("WorldManager should already have checked that the generator exists"); - //TODO: validate generator options + $generator->validateGeneratorOptions($this->provider->getWorldData()->getGeneratorOptions()); + $this->generator = $generator->getGeneratorClass(); $this->chunkPopulationRequestQueue = new \SplQueue(); $this->addOnUnloadCallback(function() : void{ $this->logger->debug("Cancelling unfulfilled generation requests"); diff --git a/src/world/format/io/FormatConverter.php b/src/world/format/io/FormatConverter.php index 6931d3b5f..2599415c4 100644 --- a/src/world/format/io/FormatConverter.php +++ b/src/world/format/io/FormatConverter.php @@ -115,7 +115,7 @@ class FormatConverter{ $this->newProvider->generate($convertedOutput, $data->getName(), WorldCreationOptions::create() //TODO: defaulting to NORMAL here really isn't very good behaviour, but it's consistent with what we already //did previously; besides, WorldManager checks for unknown generators before this is reached anyway. - ->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($data->getGenerator()) ?? Normal::class) + ->setGeneratorClass(GeneratorManager::getInstance()->getGenerator($data->getGenerator())?->getGeneratorClass() ?? Normal::class) ->setGeneratorOptions($data->getGeneratorOptions()) ->setSeed($data->getSeed()) ->setSpawnPosition($data->getSpawn()) diff --git a/src/world/generator/GeneratorManager.php b/src/world/generator/GeneratorManager.php index 0db15390e..11fd02f3b 100644 --- a/src/world/generator/GeneratorManager.php +++ b/src/world/generator/GeneratorManager.php @@ -34,35 +34,49 @@ final class GeneratorManager{ use SingletonTrait; /** - * @var string[] name => classname mapping - * @phpstan-var array> + * @var GeneratorManagerEntry[] name => classname mapping + * @phpstan-var array */ private $list = []; public function __construct(){ - $this->addGenerator(Flat::class, "flat"); - $this->addGenerator(Normal::class, "normal"); - $this->addGenerator(Normal::class, "default"); - $this->addGenerator(Nether::class, "hell"); - $this->addGenerator(Nether::class, "nether"); + $this->addGenerator(Flat::class, "flat", \Closure::fromCallable(function(string $preset) : ?InvalidGeneratorOptionsException{ + if($preset === ""){ + return null; + } + try{ + FlatGeneratorOptions::parsePreset($preset); + return null; + }catch(InvalidGeneratorOptionsException $e){ + return $e; + } + })); + $this->addGenerator(Normal::class, "normal", fn() => null); + $this->addGenerator(Normal::class, "default", fn() => null); + $this->addGenerator(Nether::class, "hell", fn() => null); + $this->addGenerator(Nether::class, "nether", fn() => null); } /** - * @param string $class Fully qualified name of class that extends \pocketmine\world\generator\Generator - * @param string $name Alias for this generator type that can be written in configs - * @param bool $overwrite Whether to force overwriting any existing registered generator with the same name + * @param string $class Fully qualified name of class that extends \pocketmine\world\generator\Generator + * @param string $name Alias for this generator type that can be written in configs + * @param \Closure $presetValidator Callback to validate generator options for new worlds + * @param bool $overwrite Whether to force overwriting any existing registered generator with the same name + * + * @phpstan-param \Closure(string) : ?InvalidGeneratorOptionsException $presetValidator + * * @phpstan-param class-string $class * * @throws \InvalidArgumentException */ - public function addGenerator(string $class, string $name, bool $overwrite = false) : void{ + public function addGenerator(string $class, string $name, \Closure $presetValidator, bool $overwrite = false) : void{ Utils::testValidInstance($class, Generator::class); if(!$overwrite and isset($this->list[$name = strtolower($name)])){ throw new \InvalidArgumentException("Alias \"$name\" is already assigned"); } - $this->list[$name] = $class; + $this->list[$name] = new GeneratorManagerEntry($class, $presetValidator); } /** @@ -75,12 +89,9 @@ final class GeneratorManager{ } /** - * Returns a class name of a registered Generator matching the given name. - * - * @return string|null Name of class that extends Generator, or null if no generator is mapped to that name - * @phpstan-return class-string|null + * Returns the generator entry of a registered Generator matching the given name, or null if not found. */ - public function getGenerator(string $name) : ?string{ + public function getGenerator(string $name) : ?GeneratorManagerEntry{ return $this->list[strtolower($name)] ?? null; } @@ -95,7 +106,7 @@ final class GeneratorManager{ public function getGeneratorName(string $class) : string{ Utils::testValidInstance($class, Generator::class); foreach($this->list as $name => $c){ - if($c === $class){ + if($c->getGeneratorClass() === $class){ return $name; } } diff --git a/src/world/generator/GeneratorManagerEntry.php b/src/world/generator/GeneratorManagerEntry.php new file mode 100644 index 000000000..2f7bbc16c --- /dev/null +++ b/src/world/generator/GeneratorManagerEntry.php @@ -0,0 +1,48 @@ + $generatorClass + * @phpstan-param \Closure(string) : ?InvalidGeneratorOptionsException $presetValidator + */ + public function __construct( + private string $generatorClass, + private \Closure $presetValidator + ){} + + /** @phpstan-return class-string */ + public function getGeneratorClass() : string{ return $this->generatorClass; } + + /** + * @throws InvalidGeneratorOptionsException + */ + public function validateGeneratorOptions(string $generatorOptions) : void{ + if(($exception = ($this->presetValidator)($generatorOptions)) !== null){ + throw $exception; + } + } +} \ No newline at end of file From 8fd475f87b458b313b916f8ba73750dfc0de9d34 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 17:44:38 +0100 Subject: [PATCH 101/710] WorldManager: Check generator options of worlds before loading them, too --- src/world/WorldManager.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/world/WorldManager.php b/src/world/WorldManager.php index ff2c7ca12..aa906e4ab 100644 --- a/src/world/WorldManager.php +++ b/src/world/WorldManager.php @@ -38,6 +38,7 @@ use pocketmine\world\format\io\FormatConverter; use pocketmine\world\format\io\WorldProviderManager; use pocketmine\world\format\io\WritableWorldProvider; use pocketmine\world\generator\GeneratorManager; +use pocketmine\world\generator\InvalidGeneratorOptionsException; use Webmozart\PathUtil\Path; use function array_keys; use function array_shift; @@ -221,13 +222,27 @@ class WorldManager{ return false; } - if(GeneratorManager::getInstance()->getGenerator($provider->getWorldData()->getGenerator()) === null){ + $generatorEntry = GeneratorManager::getInstance()->getGenerator($provider->getWorldData()->getGenerator()); + if($generatorEntry === null){ $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError( $name, KnownTranslationFactory::pocketmine_level_unknownGenerator($provider->getWorldData()->getGenerator()) ))); return false; } + try{ + $generatorEntry->validateGeneratorOptions($provider->getWorldData()->getGeneratorOptions()); + }catch(InvalidGeneratorOptionsException $e){ + $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_loadError( + $name, + KnownTranslationFactory::pocketmine_level_invalidGeneratorOptions( + $provider->getWorldData()->getGeneratorOptions(), + $provider->getWorldData()->getGenerator(), + $e->getMessage() + ) + ))); + return false; + } if(!($provider instanceof WritableWorldProvider)){ if(!$autoUpgrade){ throw new UnsupportedWorldFormatException("World \"$name\" is in an unsupported format and needs to be upgraded"); From 01c06020430f8549fb2bfd2e7ad2c7a15abde4fe Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 17:48:08 +0100 Subject: [PATCH 102/710] Server: do not attempt to generate a new world if it already exists --- src/Server.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Server.php b/src/Server.php index 77e441c61..71374fc45 100644 --- a/src/Server.php +++ b/src/Server.php @@ -992,7 +992,7 @@ class Server{ }elseif(!is_array($options)){ continue; } - if(!$this->worldManager->loadWorld($name, true)){ + if(!$this->worldManager->loadWorld($name, true) && !$this->worldManager->isWorldGenerated($name)){ $creationOptions = WorldCreationOptions::create(); //TODO: error checking @@ -1028,7 +1028,7 @@ class Server{ $default = "world"; $this->configGroup->setConfigString("level-name", "world"); } - if(!$this->worldManager->loadWorld($default, true)){ + if(!$this->worldManager->loadWorld($default, true) && !$this->worldManager->isWorldGenerated($default)){ $generatorName = $this->configGroup->getConfigString("level-type"); $generatorOptions = $this->configGroup->getConfigString("generator-settings"); $generatorClass = $getGenerator($generatorName, $generatorOptions, $default); From 835e18ce6ea2f91564812b97261812f47fab4c73 Mon Sep 17 00:00:00 2001 From: ErikPDev <33035080+ErikPDev@users.noreply.github.com> Date: Mon, 11 Oct 2021 22:15:44 +0300 Subject: [PATCH 103/710] Changelog: Changed utils\Color to color\Color (#4502) [ci skip] --- changelogs/4.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index e5194d5b0..88914ea8a 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1147,7 +1147,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` #### Particles - `DestroyBlockParticle` has been renamed to `BlockBreakParticle` for consistency. -- `DustParticle->__construct()` now accepts a `pocketmine\utils\Color` object instead of `r, g, b, a`. +- `DustParticle->__construct()` now accepts a `pocketmine\color\Color` object instead of `r, g, b, a`. - `pocketmine\world\particle\Particle` no longer extends `pocketmine\math\Vector3`, and has been converted to an interface. - Added the following `Particle` classes: - `DragonEggTeleportParticle` From d73ea8efe4f0510b4b74ad12d1401c32b1a63874 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 21:32:03 +0100 Subject: [PATCH 104/710] FlatGeneratorOptions: Do not hardcode biome ID --- src/world/generator/FlatGeneratorOptions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/world/generator/FlatGeneratorOptions.php b/src/world/generator/FlatGeneratorOptions.php index 98d2f16a2..01ca4a914 100644 --- a/src/world/generator/FlatGeneratorOptions.php +++ b/src/world/generator/FlatGeneratorOptions.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\world\generator; +use pocketmine\data\bedrock\BiomeIds; use pocketmine\item\LegacyStringToItemParser; use pocketmine\item\LegacyStringToItemParserException; use function array_map; @@ -99,7 +100,7 @@ final class FlatGeneratorOptions{ public static function parsePreset(string $presetString) : self{ $preset = explode(";", $presetString); $blocks = $preset[1] ?? ""; - $biomeId = (int) ($preset[2] ?? 1); + $biomeId = (int) ($preset[2] ?? BiomeIds::PLAINS); $optionsString = $preset[3] ?? ""; $structure = self::parseLayers($blocks); From a5833327f0608135fc0e04666a2d09884d272dc8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 21:46:27 +0100 Subject: [PATCH 105/710] Inventory: added getAddableItemQuantity() this mostly reuses the code from canAddItem(). --- src/inventory/BaseInventory.php | 8 ++++++-- src/inventory/Inventory.php | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/inventory/BaseInventory.php b/src/inventory/BaseInventory.php index 4d79d7d94..c5b854a6d 100644 --- a/src/inventory/BaseInventory.php +++ b/src/inventory/BaseInventory.php @@ -169,6 +169,10 @@ abstract class BaseInventory implements Inventory{ } public function canAddItem(Item $item) : bool{ + return $this->getAddableItemQuantity($item) === $item->getCount(); + } + + public function getAddableItemQuantity(Item $item) : int{ $count = $item->getCount(); for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ $slot = $this->getItem($i); @@ -181,11 +185,11 @@ abstract class BaseInventory implements Inventory{ } if($count <= 0){ - return true; + return $item->getCount(); } } - return false; + return $item->getCount() - $count; } public function addItem(Item ...$slots) : array{ diff --git a/src/inventory/Inventory.php b/src/inventory/Inventory.php index 0a5e3b766..b1fad3904 100644 --- a/src/inventory/Inventory.php +++ b/src/inventory/Inventory.php @@ -63,6 +63,11 @@ interface Inventory{ */ public function canAddItem(Item $item) : bool; + /** + * Returns how many items from the given itemstack can be added to this inventory. + */ + public function getAddableItemQuantity(Item $item) : int; + /** * Removes the given Item from the inventory. * It will return the Items that couldn't be removed. From 62f11360ee1f3dc5c9c0f211a20e86b0778d7257 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 21:52:27 +0100 Subject: [PATCH 106/710] Added unit tests for getAddableItemQuantity() --- tests/phpunit/inventory/BaseInventoryTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/phpunit/inventory/BaseInventoryTest.php b/tests/phpunit/inventory/BaseInventoryTest.php index a0ae029ea..0354b2696 100644 --- a/tests/phpunit/inventory/BaseInventoryTest.php +++ b/tests/phpunit/inventory/BaseInventoryTest.php @@ -94,4 +94,18 @@ class BaseInventoryTest extends TestCase{ } self::assertSame(100, $count); } + + public function testGetAddableItemQuantityStacking() : void{ + $inventory = new SimpleInventory(1); + $inventory->addItem(VanillaItems::APPLE()->setCount(60)); + self::assertSame(2, $inventory->getAddableItemQuantity(VanillaItems::APPLE()->setCount(2))); + self::assertSame(4, $inventory->getAddableItemQuantity(VanillaItems::APPLE()->setCount(6))); + } + + public function testGetAddableItemQuantityEmptyStack() : void{ + $inventory = new SimpleInventory(1); + $item = VanillaItems::APPLE(); + $item->setCount($item->getMaxStackSize()); + self::assertSame($item->getMaxStackSize(), $inventory->getAddableItemQuantity($item)); + } } From 9b94a4661b1a0a773c5cff64b626adaaf068cbbb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 11 Oct 2021 22:17:40 +0100 Subject: [PATCH 107/710] ItemTranslator: Use LegacyItemIdToStringMap instead of reading files directly --- src/network/mcpe/convert/ItemTranslator.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index 1af9adba2..0302a6898 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\convert; +use pocketmine\data\bedrock\LegacyItemIdToStringIdMap; use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; @@ -76,10 +77,7 @@ final class ItemTranslator{ if($legacyStringToIntMapRaw === false){ throw new AssumptionFailedError("Missing required resource file"); } - $legacyStringToIntMap = json_decode($legacyStringToIntMapRaw, true); - if(!is_array($legacyStringToIntMap)){ - throw new AssumptionFailedError("Invalid mapping table format"); - } + $legacyStringToIntMap = LegacyItemIdToStringIdMap::getInstance(); /** @phpstan-var array $simpleMappings */ $simpleMappings = []; @@ -87,13 +85,14 @@ final class ItemTranslator{ if(!is_string($oldId) || !is_string($newId)){ throw new AssumptionFailedError("Invalid item table format"); } - if(!isset($legacyStringToIntMap[$oldId])){ + $intId = $legacyStringToIntMap->stringToLegacy($oldId); + if($intId === null){ //new item without a fixed legacy ID - we can't handle this right now continue; } - $simpleMappings[$newId] = $legacyStringToIntMap[$oldId]; + $simpleMappings[$newId] = $intId; } - foreach($legacyStringToIntMap as $stringId => $intId){ + foreach($legacyStringToIntMap->getStringToLegacyMap() as $stringId => $intId){ if(isset($simpleMappings[$stringId])){ throw new \UnexpectedValueException("Old ID $stringId collides with new ID"); } @@ -110,7 +109,12 @@ final class ItemTranslator{ if(!is_numeric($meta) || !is_string($newId)){ throw new AssumptionFailedError("Invalid item table format"); } - $complexMappings[$newId] = [$legacyStringToIntMap[$oldId], (int) $meta]; + $intId = $legacyStringToIntMap->stringToLegacy($oldId); + if($intId === null){ + //new item without a fixed legacy ID - we can't handle this right now + continue; + } + $complexMappings[$newId] = [$intId, (int) $meta]; } } From 49c1e4c06e3a1561501ef579d8e08be1740aa4b4 Mon Sep 17 00:00:00 2001 From: IceCruelStuff <50642756+IceCruelStuff@users.noreply.github.com> Date: Tue, 12 Oct 2021 13:21:05 -0700 Subject: [PATCH 108/710] Implement fletching table (#4501) --- src/block/BlockFactory.php | 2 +- src/block/FletchingTable.php | 30 +++++++++++++++++++ src/block/VanillaBlocks.php | 2 ++ src/item/StringToItemParser.php | 1 + .../block_factory_consistency_check.json | 2 +- 5 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/block/FletchingTable.php diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index ee2345f82..6390812a1 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -183,6 +183,7 @@ class BlockFactory{ $this->register(new EnderChest(new BID(Ids::ENDER_CHEST, 0, null, TileEnderChest::class), "Ender Chest", new BlockBreakInfo(22.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 3000.0))); $this->register(new Farmland(new BID(Ids::FARMLAND, 0), "Farmland", new BlockBreakInfo(0.6, BlockToolType::SHOVEL))); $this->register(new Fire(new BID(Ids::FIRE, 0), "Fire Block", BlockBreakInfo::instant())); + $this->register(new FletchingTable(new BID(Ids::FLETCHING_TABLE, 0), "Fletching Table", new BlockBreakInfo(2.5, BlockToolType::AXE, 0, 2.5))); $this->register(new Flower(new BID(Ids::DANDELION, 0), "Dandelion", BlockBreakInfo::instant())); $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ALLIUM), "Allium", BlockBreakInfo::instant())); $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_AZURE_BLUET), "Azure Bluet", BlockBreakInfo::instant())); @@ -567,7 +568,6 @@ class BlockFactory{ //TODO: minecraft:dropper //TODO: minecraft:end_gateway //TODO: minecraft:end_portal - //TODO: minecraft:fletching_table //TODO: minecraft:grindstone //TODO: minecraft:jigsaw //TODO: minecraft:kelp diff --git a/src/block/FletchingTable.php b/src/block/FletchingTable.php new file mode 100644 index 000000000..64a71ad97 --- /dev/null +++ b/src/block/FletchingTable.php @@ -0,0 +1,30 @@ +get(60, 0)); self::register("fern", $factory->get(31, 2)); self::register("fire", $factory->get(51, 0)); + self::register("fletching_table", $factory->get(456, 0)); self::register("flower_pot", $factory->get(140, 0)); self::register("frosted_ice", $factory->get(207, 0)); self::register("furnace", $factory->get(61, 2)); diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index 700ada9bf..75b6b81aa 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -530,6 +530,7 @@ final class StringToItemParser{ $result->registerBlock("fence_gate_spruce", fn() => VanillaBlocks::SPRUCE_FENCE_GATE()); $result->registerBlock("fern", fn() => VanillaBlocks::FERN()); $result->registerBlock("fire", fn() => VanillaBlocks::FIRE()); + $result->registerBlock("fletching_table", fn() => VanillaBlocks::FLETCHING_TABLE()); $result->registerBlock("flower_pot", fn() => VanillaBlocks::FLOWER_POT()); $result->registerBlock("flower_pot_block", fn() => VanillaBlocks::FLOWER_POT()); $result->registerBlock("flowing_lava", fn() => VanillaBlocks::LAVA()); diff --git a/tests/phpunit/block/block_factory_consistency_check.json b/tests/phpunit/block/block_factory_consistency_check.json index 28308e4a4..6df3cf098 100644 --- a/tests/phpunit/block/block_factory_consistency_check.json +++ b/tests/phpunit/block/block_factory_consistency_check.json @@ -1 +1 @@ -{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"284":7472,"285":7473,"286":7474,"287":7475,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"496":498,"499":498,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"800":805,"806":805,"807":805,"864":866,"865":866,"870":866,"871":866,"976":978,"977":978,"982":978,"983":978,"992":978,"993":978,"998":978,"999":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1200":1221,"1206":1221,"1207":1221,"1216":1221,"1222":1221,"1223":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1377":1376,"1378":1376,"1379":1376,"1440":1441,"1443":1441,"1479":1472,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2493":2481,"2494":2482,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2604":7476,"2605":7477,"2732":2720,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3230":3218,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3334":3328,"3335":3328,"3468":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3824":3829,"3830":3829,"3831":3829,"3955":3952,"4163":4160,"4179":4176,"4195":4192,"4211":4208,"4227":4224,"4243":4240,"6181":6176,"6182":6176,"6183":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7504":7218,"7505":7218,"7510":7218,"7511":7218}} \ No newline at end of file +{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7296":"Fletching Table","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"284":7472,"285":7473,"286":7474,"287":7475,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"496":498,"499":498,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"800":805,"806":805,"807":805,"864":866,"865":866,"870":866,"871":866,"976":978,"977":978,"982":978,"983":978,"992":978,"993":978,"998":978,"999":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1200":1221,"1206":1221,"1207":1221,"1216":1221,"1222":1221,"1223":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1377":1376,"1378":1376,"1379":1376,"1440":1441,"1443":1441,"1479":1472,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2493":2481,"2494":2482,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2604":7476,"2605":7477,"2732":2720,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3230":3218,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3334":3328,"3335":3328,"3468":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3824":3829,"3830":3829,"3831":3829,"3955":3952,"4163":4160,"4179":4176,"4195":4192,"4211":4208,"4227":4224,"4243":4240,"6181":6176,"6182":6176,"6183":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7504":7218,"7505":7218,"7510":7218,"7511":7218}} \ No newline at end of file From ec2699ffee7e29913dd9490fd5e6c5f5b752c030 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 12 Oct 2021 22:15:52 +0100 Subject: [PATCH 109/710] DefaultPermissions: fix description of timings command permission --- src/permission/DefaultPermissions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/permission/DefaultPermissions.php b/src/permission/DefaultPermissions.php index 371a970db..8e0bb5a01 100644 --- a/src/permission/DefaultPermissions.php +++ b/src/permission/DefaultPermissions.php @@ -105,7 +105,7 @@ abstract class DefaultPermissions{ self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_STATUS, "Allows the user to view the server performance"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_GC, "Allows the user to fire garbage collection tasks"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_DUMPMEMORY, "Allows the user to dump memory contents"), [$consoleRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TIMINGS, "Allows the user to records timings for all plugin events"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TIMINGS, "Allows the user to record timings to analyse server performance"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SPAWNPOINT, "Allows the user to change player's spawnpoint"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SETWORLDSPAWN, "Allows the user to change the world spawn"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TRANSFERSERVER, "Allows the user to transfer self to another server"), [$operatorRoot]); From aefa0afd7ca91d345ec903ba0abde8f1cd31f6f2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 12 Oct 2021 22:17:46 +0100 Subject: [PATCH 110/710] DefaultPermissions: Order registrations alphabetically --- src/permission/DefaultPermissions.php | 87 ++++++++++++--------------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/src/permission/DefaultPermissions.php b/src/permission/DefaultPermissions.php index 8e0bb5a01..3145fda58 100644 --- a/src/permission/DefaultPermissions.php +++ b/src/permission/DefaultPermissions.php @@ -51,65 +51,56 @@ abstract class DefaultPermissions{ self::registerPermission(new Permission(DefaultPermissionNames::BROADCAST_ADMIN, "Allows the user to receive administrative broadcasts"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::BROADCAST_USER, "Allows the user to receive user broadcasts"), [$everyoneRoot]); - - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_ADD, "Allows the user to add a player to the server whitelist"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_REMOVE, "Allows the user to remove a player from the server whitelist"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_RELOAD, "Allows the user to reload the server whitelist"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_ENABLE, "Allows the user to enable the server whitelist"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_DISABLE, "Allows the user to disable the server whitelist"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_LIST, "Allows the user to list all players on the server whitelist"), [$operatorRoot]); - - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_BAN_PLAYER, "Allows the user to ban players"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_BAN_IP, "Allows the user to ban IP addresses"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_BAN_LIST, "Allows the user to list banned players"), [$operatorRoot]); - - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_UNBAN_PLAYER, "Allows the user to unban players"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_UNBAN_IP, "Allows the user to unban IP addresses"), [$operatorRoot]); - + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_BAN_PLAYER, "Allows the user to ban players"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_CLEAR_OTHER, "Allows the user to clear inventory of other players"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_CLEAR_SELF, "Allows the user to clear their own inventory"), [$everyoneRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_DEFAULTGAMEMODE, "Allows the user to change the default gamemode"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_DIFFICULTY, "Allows the user to change the game difficulty"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_DUMPMEMORY, "Allows the user to dump memory contents"), [$consoleRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_EFFECT, "Allows the user to give/take potion effects"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_ENCHANT, "Allows the user to enchant items"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_GAMEMODE, "Allows the user to change the gamemode of players"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_GC, "Allows the user to fire garbage collection tasks"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_GIVE, "Allows the user to give items to players"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_HELP, "Allows the user to view the help menu"), [$everyoneRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_KICK, "Allows the user to kick players"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_KILL_OTHER, "Allows the user to kill other players"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_KILL_SELF, "Allows the user to commit suicide"), [$everyoneRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_LIST, "Allows the user to list all online players"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_ME, "Allows the user to perform a chat action"), [$everyoneRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_OP_GIVE, "Allows the user to give a player operator status"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_OP_TAKE, "Allows the user to take a player's operator status"), [$operatorRoot]); - - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SAVE_ENABLE, "Allows the user to enable automatic saving"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_PARTICLE, "Allows the user to create particle effects"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_PLUGINS, "Allows the user to view the list of plugins"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SAVE_DISABLE, "Allows the user to disable automatic saving"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SAVE_ENABLE, "Allows the user to enable automatic saving"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SAVE_PERFORM, "Allows the user to perform a manual save"), [$operatorRoot]); - + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SAY, "Allows the user to talk as the console"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SEED, "Allows the user to view the seed of the world"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SETWORLDSPAWN, "Allows the user to change the world spawn"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SPAWNPOINT, "Allows the user to change player's spawnpoint"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_STATUS, "Allows the user to view the server performance"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_STOP, "Allows the user to stop the server"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TELEPORT, "Allows the user to teleport players"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TELL, "Allows the user to privately message another player"), [$everyoneRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TIME_ADD, "Allows the user to fast-forward time"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TIME_QUERY, "Allows the user query the time"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TIME_SET, "Allows the user to change the time"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TIME_START, "Allows the user to restart the time"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TIME_STOP, "Allows the user to stop the time"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TIME_QUERY, "Allows the user query the time"), [$operatorRoot]); - - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_KILL_SELF, "Allows the user to commit suicide"), [$everyoneRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_KILL_OTHER, "Allows the user to kill other players"), [$operatorRoot]); - - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_CLEAR_SELF, "Allows the user to clear their own inventory"), [$everyoneRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_CLEAR_OTHER, "Allows the user to clear inventory of other players"), [$operatorRoot]); - - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_ME, "Allows the user to perform a chat action"), [$everyoneRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TELL, "Allows the user to privately message another player"), [$everyoneRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SAY, "Allows the user to talk as the console"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_GIVE, "Allows the user to give items to players"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_EFFECT, "Allows the user to give/take potion effects"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_ENCHANT, "Allows the user to enchant items"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_PARTICLE, "Allows the user to create particle effects"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TELEPORT, "Allows the user to teleport players"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_KICK, "Allows the user to kick players"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_STOP, "Allows the user to stop the server"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_LIST, "Allows the user to list all online players"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_HELP, "Allows the user to view the help menu"), [$everyoneRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_PLUGINS, "Allows the user to view the list of plugins"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_VERSION, "Allows the user to view the version of the server"), [$everyoneRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_GAMEMODE, "Allows the user to change the gamemode of players"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_DEFAULTGAMEMODE, "Allows the user to change the default gamemode"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SEED, "Allows the user to view the seed of the world"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_STATUS, "Allows the user to view the server performance"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_GC, "Allows the user to fire garbage collection tasks"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_DUMPMEMORY, "Allows the user to dump memory contents"), [$consoleRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TIMINGS, "Allows the user to record timings to analyse server performance"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SPAWNPOINT, "Allows the user to change player's spawnpoint"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_SETWORLDSPAWN, "Allows the user to change the world spawn"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TRANSFERSERVER, "Allows the user to transfer self to another server"), [$operatorRoot]); self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TITLE, "Allows the user to send a title to the specified player"), [$operatorRoot]); - self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_DIFFICULTY, "Allows the user to change the game difficulty"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_TRANSFERSERVER, "Allows the user to transfer self to another server"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_UNBAN_IP, "Allows the user to unban IP addresses"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_UNBAN_PLAYER, "Allows the user to unban players"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_VERSION, "Allows the user to view the version of the server"), [$everyoneRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_ADD, "Allows the user to add a player to the server whitelist"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_DISABLE, "Allows the user to disable the server whitelist"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_ENABLE, "Allows the user to enable the server whitelist"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_LIST, "Allows the user to list all players on the server whitelist"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_RELOAD, "Allows the user to reload the server whitelist"), [$operatorRoot]); + self::registerPermission(new Permission(DefaultPermissionNames::COMMAND_WHITELIST_REMOVE, "Allows the user to remove a player from the server whitelist"), [$operatorRoot]); } } From ead9aae23cdc8925313891a0ce13899df9ec086f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 12 Oct 2021 23:10:06 +0100 Subject: [PATCH 111/710] Updated build/php submodule to pmmp/php-build-scripts@fab0cbeaae7de58ea78a02c7505719d04a0325a3 --- build/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/php b/build/php index 6aac46e50..fab0cbeaa 160000 --- a/build/php +++ b/build/php @@ -1 +1 @@ -Subproject commit 6aac46e5008a6e3701c537d7e9d0669079523fc6 +Subproject commit fab0cbeaae7de58ea78a02c7505719d04a0325a3 From b65e89b605aeba5f7958d3cbb6db47e766cd6f9f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Oct 2021 00:01:56 +0100 Subject: [PATCH 112/710] Release 4.0.0-BETA5 --- changelogs/4.0.md | 50 +++++++++++++++++++++++++++++++++++++++++++++ src/VersionInfo.php | 4 ++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 88914ea8a..70add2c99 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1393,3 +1393,53 @@ Released 6th October 2021. ### Utils - The following API methods have signature changes: - `Process::kill()` now requires an additional `bool $subprocesses` parameter. + +# 4.0.0-BETA5 +Released 12th October 2021. + +## General +- Exception log format has been changed. Now, exception info is logged in one big block message. This saves space on the console and improves readability, as well as reducing the ability for bad `ThreadedLoggerAttachment`s to break exception output. +- Log messages are now pushed to `server.log` before calling logger attachment, instead of after. This fixes messages not being written to disk when an error occurs in a logger attachment. +- Improved startup performance when loading many plugins. +- The `worlds` config in `pocketmine.yml` no longer supports attaching the generator settings to the `generator` key (use the `preset` key instead). +- Using an unknown generator in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world. +- Using invalid/incorrect world generator options (presets) in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world. +- Generator options of existing worlds are now validated before loading them. If they are invalid, the server will fail to load them. +- Several more log messages have been localized, including plugin loading errors. + +## Fixes +- Fixed server crash when using `/give` to give an item by ID which doesn't exist in Minecraft. +- Fixed server crash when boolean `server.properties` options were given an integer value (e.g. `0` or `1` instead of `false` or `true`). +- Fixed stats reporting checking for a nonexistent `pocketmine.yml` setting. +- Fixed use of commands without the proper permission sending a message `commands.generic.permission` instead of the proper message. +- Fixed entities set on fire appearing to stay on fire, although not taking any damage. +- Fixed a duplicate `MB` suffix on the `Memory freed` output of `/gc`. +- Fixed the server attempting to generate a world if it failed to load. + +## API +### Block +- The following API methods have been renamed: + - `Block->getPositionOffset()` -> `Block->getModelPositionOffset()`. + +### Event +- `@handleCancelled` PhpDoc annotation can no longer be used on event handlers for non-cancellable events. +- The following API methods have been added: + - `StructureGrowEvent->getPlayer()` + +### Inventory +- The following API methods have been added: + - `Inventory->getAddableItemQuantity()` + +### Scheduler +- `ClosureTask` now permits closures without an explicit return type (useful for arrow functions). + +### Utils +- The following API methods have been added: + - `Config::parseProperties()` + - `Config::writeProperties()` + - `Config::parseList()` + - `Config::writeList()` + +### World +- The following API methods have signature changes: + - `GeneratorManager->registerGenerator()` now requires a `\Closure $presetValidator` parameter. This is used to check generator options of worlds and configs before attempting to use them. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 8b9fb420b..3cf7af10b 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,9 +30,9 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA5"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; - public const BUILD_CHANNEL = ""; + public const BUILD_CHANNEL = "beta"; private function __construct(){ //NOOP From ce8af4e3bca90b6778b6b0c47ec88b8a952e60d7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Oct 2021 00:02:01 +0100 Subject: [PATCH 113/710] 4.0.0-BETA6 is next --- src/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 3cf7af10b..9bae4e775 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,10 +29,10 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA5"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA6"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; - public const BUILD_CHANNEL = "beta"; + public const BUILD_CHANNEL = ""; private function __construct(){ //NOOP From 6284cd14c7d662e5afe3a50c09010949e5b3fe2c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Oct 2021 20:19:44 +0100 Subject: [PATCH 114/710] LegacyStringToItemParser: added getMappings() --- src/item/LegacyStringToItemParser.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/item/LegacyStringToItemParser.php b/src/item/LegacyStringToItemParser.php index 9edb37c19..6eb3888c6 100644 --- a/src/item/LegacyStringToItemParser.php +++ b/src/item/LegacyStringToItemParser.php @@ -84,6 +84,14 @@ final class LegacyStringToItemParser{ $this->map[$alias] = $id; } + /** + * @return int[] + * @phpstan-return array + */ + public function getMappings() : array{ + return $this->map; + } + /** * Tries to parse the specified string into Item types. * From b57032428824de5909a8854dc9e0d7952caed5c6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Oct 2021 20:29:18 +0100 Subject: [PATCH 115/710] LegacyStringToItemParser: rely exclusively on item_from_string_bc_map.json, do not interpret integers given as strings fixes #4507 --- resources/item_from_string_bc_map.json | 687 +++++++++++++++++++++++++ src/item/LegacyStringToItemParser.php | 8 +- 2 files changed, 690 insertions(+), 5 deletions(-) diff --git a/resources/item_from_string_bc_map.json b/resources/item_from_string_bc_map.json index 0edc1e7df..c12f00a24 100644 --- a/resources/item_from_string_bc_map.json +++ b/resources/item_from_string_bc_map.json @@ -1,4 +1,691 @@ { + "-10": -10, + "-100": -100, + "-101": -101, + "-102": -102, + "-103": -103, + "-104": -104, + "-105": -105, + "-106": -106, + "-107": -107, + "-108": -108, + "-109": -109, + "-11": -11, + "-110": -110, + "-111": -111, + "-112": -112, + "-113": -113, + "-114": -114, + "-115": -115, + "-116": -116, + "-117": -117, + "-118": -118, + "-119": -119, + "-12": -12, + "-120": -120, + "-121": -121, + "-122": -122, + "-123": -123, + "-124": -124, + "-125": -125, + "-126": -126, + "-127": -127, + "-128": -128, + "-129": -129, + "-13": -13, + "-130": -130, + "-131": -131, + "-132": -132, + "-133": -133, + "-134": -134, + "-135": -135, + "-136": -136, + "-137": -137, + "-138": -138, + "-139": -139, + "-14": -14, + "-140": -140, + "-141": -141, + "-142": -142, + "-143": -143, + "-144": -144, + "-145": -145, + "-146": -146, + "-147": -147, + "-148": -148, + "-149": -149, + "-15": -15, + "-150": -150, + "-151": -151, + "-152": -152, + "-153": -153, + "-154": -154, + "-155": -155, + "-156": -156, + "-157": -157, + "-159": -159, + "-16": -16, + "-160": -160, + "-161": -161, + "-162": -162, + "-163": -163, + "-164": -164, + "-165": -165, + "-166": -166, + "-167": -167, + "-168": -168, + "-169": -169, + "-17": -17, + "-170": -170, + "-171": -171, + "-172": -172, + "-173": -173, + "-174": -174, + "-175": -175, + "-176": -176, + "-177": -177, + "-178": -178, + "-179": -179, + "-18": -18, + "-180": -180, + "-181": -181, + "-182": -182, + "-183": -183, + "-184": -184, + "-185": -185, + "-186": -186, + "-187": -187, + "-188": -188, + "-189": -189, + "-19": -19, + "-190": -190, + "-191": -191, + "-192": -192, + "-193": -193, + "-194": -194, + "-195": -195, + "-196": -196, + "-197": -197, + "-198": -198, + "-199": -199, + "-2": -2, + "-20": -20, + "-200": -200, + "-201": -201, + "-202": -202, + "-203": -203, + "-204": -204, + "-206": -206, + "-207": -207, + "-208": -208, + "-209": -209, + "-21": -21, + "-210": -210, + "-211": -211, + "-213": -213, + "-214": -214, + "-22": -22, + "-23": -23, + "-24": -24, + "-25": -25, + "-26": -26, + "-27": -27, + "-28": -28, + "-29": -29, + "-3": -3, + "-30": -30, + "-31": -31, + "-32": -32, + "-33": -33, + "-34": -34, + "-35": -35, + "-36": -36, + "-37": -37, + "-38": -38, + "-39": -39, + "-4": -4, + "-40": -40, + "-41": -41, + "-42": -42, + "-43": -43, + "-44": -44, + "-45": -45, + "-46": -46, + "-47": -47, + "-48": -48, + "-49": -49, + "-5": -5, + "-50": -50, + "-51": -51, + "-52": -52, + "-53": -53, + "-54": -54, + "-55": -55, + "-56": -56, + "-57": -57, + "-58": -58, + "-59": -59, + "-6": -6, + "-60": -60, + "-61": -61, + "-62": -62, + "-63": -63, + "-64": -64, + "-65": -65, + "-66": -66, + "-67": -67, + "-68": -68, + "-69": -69, + "-7": -7, + "-70": -70, + "-71": -71, + "-72": -72, + "-73": -73, + "-74": -74, + "-75": -75, + "-76": -76, + "-77": -77, + "-78": -78, + "-79": -79, + "-8": -8, + "-80": -80, + "-81": -81, + "-82": -82, + "-83": -83, + "-84": -84, + "-85": -85, + "-86": -86, + "-87": -87, + "-88": -88, + "-89": -89, + "-9": -9, + "-90": -90, + "-91": -91, + "-92": -92, + "-93": -93, + "-94": -94, + "-95": -95, + "-96": -96, + "-97": -97, + "-98": -98, + "-99": -99, + "0": 0, + "1": 1, + "10": 10, + "100": 100, + "101": 101, + "102": 102, + "103": 103, + "104": 104, + "105": 105, + "106": 106, + "107": 107, + "108": 108, + "109": 109, + "11": 11, + "110": 110, + "111": 111, + "112": 112, + "113": 113, + "114": 114, + "115": 115, + "116": 116, + "117": 117, + "118": 118, + "119": 119, + "12": 12, + "120": 120, + "121": 121, + "122": 122, + "123": 123, + "124": 124, + "125": 125, + "126": 126, + "127": 127, + "128": 128, + "129": 129, + "13": 13, + "130": 130, + "131": 131, + "132": 132, + "133": 133, + "134": 134, + "135": 135, + "136": 136, + "137": 137, + "138": 138, + "139": 139, + "14": 14, + "140": 140, + "141": 141, + "142": 142, + "143": 143, + "144": 144, + "145": 145, + "146": 146, + "147": 147, + "148": 148, + "149": 149, + "15": 15, + "150": 150, + "151": 151, + "152": 152, + "153": 153, + "154": 154, + "155": 155, + "156": 156, + "157": 157, + "158": 158, + "159": 159, + "16": 16, + "160": 160, + "161": 161, + "162": 162, + "163": 163, + "164": 164, + "165": 165, + "166": 166, + "167": 167, + "168": 168, + "169": 169, + "17": 17, + "170": 170, + "171": 171, + "172": 172, + "173": 173, + "174": 174, + "175": 175, + "176": 176, + "177": 177, + "178": 178, + "179": 179, + "18": 18, + "180": 180, + "181": 181, + "182": 182, + "183": 183, + "184": 184, + "185": 185, + "186": 186, + "187": 187, + "188": 188, + "189": 189, + "19": 19, + "190": 190, + "191": 191, + "192": 192, + "193": 193, + "194": 194, + "195": 195, + "196": 196, + "197": 197, + "198": 198, + "199": 199, + "2": 2, + "20": 20, + "200": 200, + "201": 201, + "202": 202, + "203": 203, + "204": 204, + "205": 205, + "206": 206, + "207": 207, + "208": 208, + "209": 209, + "21": 21, + "213": 213, + "214": 214, + "215": 215, + "216": 216, + "218": 218, + "219": 219, + "22": 22, + "220": 220, + "221": 221, + "222": 222, + "223": 223, + "224": 224, + "225": 225, + "226": 226, + "227": 227, + "228": 228, + "229": 229, + "23": 23, + "231": 231, + "232": 232, + "233": 233, + "234": 234, + "235": 235, + "236": 236, + "237": 237, + "238": 238, + "239": 239, + "24": 24, + "240": 240, + "241": 241, + "243": 243, + "244": 244, + "245": 245, + "246": 246, + "247": 247, + "248": 248, + "249": 249, + "25": 25, + "250": 250, + "251": 251, + "252": 252, + "253": 253, + "254": 254, + "255": 255, + "256": 256, + "257": 257, + "258": 258, + "259": 259, + "26": 26, + "260": 260, + "261": 261, + "262": 262, + "263": 263, + "264": 264, + "265": 265, + "266": 266, + "267": 267, + "268": 268, + "269": 269, + "27": 27, + "270": 270, + "271": 271, + "272": 272, + "273": 273, + "274": 274, + "275": 275, + "276": 276, + "277": 277, + "278": 278, + "279": 279, + "28": 28, + "280": 280, + "281": 281, + "282": 282, + "283": 283, + "284": 284, + "285": 285, + "286": 286, + "287": 287, + "288": 288, + "289": 289, + "29": 29, + "290": 290, + "291": 291, + "292": 292, + "293": 293, + "294": 294, + "295": 295, + "296": 296, + "297": 297, + "298": 298, + "299": 299, + "3": 3, + "30": 30, + "300": 300, + "301": 301, + "302": 302, + "303": 303, + "304": 304, + "305": 305, + "306": 306, + "307": 307, + "308": 308, + "309": 309, + "31": 31, + "310": 310, + "311": 311, + "312": 312, + "313": 313, + "314": 314, + "315": 315, + "316": 316, + "317": 317, + "318": 318, + "319": 319, + "32": 32, + "320": 320, + "321": 321, + "322": 322, + "323": 323, + "324": 324, + "325": 325, + "328": 328, + "329": 329, + "33": 33, + "330": 330, + "331": 331, + "332": 332, + "333": 333, + "334": 334, + "335": 335, + "336": 336, + "337": 337, + "338": 338, + "339": 339, + "34": 34, + "340": 340, + "341": 341, + "342": 342, + "344": 344, + "345": 345, + "346": 346, + "347": 347, + "348": 348, + "349": 349, + "35": 35, + "350": 350, + "351": 351, + "352": 352, + "353": 353, + "354": 354, + "355": 355, + "356": 356, + "357": 357, + "358": 358, + "359": 359, + "36": 36, + "360": 360, + "361": 361, + "362": 362, + "363": 363, + "364": 364, + "365": 365, + "366": 366, + "367": 367, + "368": 368, + "369": 369, + "37": 37, + "370": 370, + "371": 371, + "372": 372, + "373": 373, + "374": 374, + "375": 375, + "376": 376, + "377": 377, + "378": 378, + "379": 379, + "38": 38, + "380": 380, + "381": 381, + "382": 382, + "383": 383, + "384": 384, + "385": 385, + "386": 386, + "387": 387, + "388": 388, + "389": 389, + "39": 39, + "390": 390, + "391": 391, + "392": 392, + "393": 393, + "394": 394, + "395": 395, + "396": 396, + "397": 397, + "398": 398, + "399": 399, + "4": 4, + "40": 40, + "400": 400, + "401": 401, + "402": 402, + "403": 403, + "404": 404, + "405": 405, + "406": 406, + "407": 407, + "408": 408, + "409": 409, + "41": 41, + "410": 410, + "411": 411, + "412": 412, + "413": 413, + "414": 414, + "415": 415, + "416": 416, + "417": 417, + "418": 418, + "419": 419, + "42": 42, + "420": 420, + "421": 421, + "422": 422, + "423": 423, + "424": 424, + "425": 425, + "426": 426, + "427": 427, + "428": 428, + "429": 429, + "43": 43, + "430": 430, + "431": 431, + "432": 432, + "433": 433, + "434": 434, + "437": 437, + "438": 438, + "44": 44, + "441": 441, + "442": 442, + "443": 443, + "444": 444, + "445": 445, + "446": 446, + "447": 447, + "448": 448, + "449": 449, + "45": 45, + "450": 450, + "451": 451, + "452": 452, + "453": 453, + "455": 455, + "457": 457, + "458": 458, + "459": 459, + "46": 46, + "460": 460, + "461": 461, + "462": 462, + "463": 463, + "464": 464, + "465": 465, + "466": 466, + "467": 467, + "468": 468, + "469": 469, + "47": 47, + "470": 470, + "471": 471, + "472": 472, + "473": 473, + "474": 474, + "475": 475, + "476": 476, + "477": 477, + "48": 48, + "49": 49, + "499": 499, + "5": 5, + "50": 50, + "500": 500, + "501": 501, + "502": 502, + "503": 503, + "504": 504, + "505": 505, + "506": 506, + "507": 507, + "508": 508, + "509": 509, + "51": 51, + "510": 510, + "511": 511, + "513": 513, + "52": 52, + "53": 53, + "54": 54, + "55": 55, + "56": 56, + "57": 57, + "58": 58, + "59": 59, + "6": 6, + "60": 60, + "61": 61, + "62": 62, + "63": 63, + "64": 64, + "65": 65, + "66": 66, + "67": 67, + "68": 68, + "69": 69, + "7": 7, + "70": 70, + "71": 71, + "72": 72, + "73": 73, + "74": 74, + "75": 75, + "76": 76, + "77": 77, + "78": 78, + "79": 79, + "8": 8, + "80": 80, + "81": 81, + "82": 82, + "83": 83, + "84": 84, + "85": 85, + "86": 86, + "87": 87, + "88": 88, + "89": 89, + "9": 9, + "90": 90, + "91": 91, + "92": 92, + "93": 93, + "94": 94, + "95": 95, + "96": 96, + "97": 97, + "98": 98, + "99": 99, "acacia_button": -140, "acacia_door": 430, "acacia_door_block": 196, diff --git a/src/item/LegacyStringToItemParser.php b/src/item/LegacyStringToItemParser.php index 6eb3888c6..afe22cd2d 100644 --- a/src/item/LegacyStringToItemParser.php +++ b/src/item/LegacyStringToItemParser.php @@ -63,8 +63,8 @@ final class LegacyStringToItemParser{ if(!is_array($mappings)) throw new AssumptionFailedError("Invalid mappings format, expected array"); foreach($mappings as $name => $id){ - if(!is_string($name) or !is_int($id)) throw new AssumptionFailedError("Invalid mappings format, expected string keys and int values"); - $result->addMapping($name, $id); + if(!is_int($id)) throw new AssumptionFailedError("Invalid mappings format, expected int values"); + $result->addMapping((string) $name, $id); } return $result; @@ -114,9 +114,7 @@ final class LegacyStringToItemParser{ throw new LegacyStringToItemParserException("Unable to parse \"" . $b[1] . "\" from \"" . $input . "\" as a valid meta value"); } - if(is_numeric($b[0])){ - $item = $this->itemFactory->get((int) $b[0], $meta); - }elseif(isset($this->map[strtolower($b[0])])){ + if(isset($this->map[strtolower($b[0])])){ $item = $this->itemFactory->get($this->map[strtolower($b[0])], $meta); }else{ throw new LegacyStringToItemParserException("Unable to resolve \"" . $input . "\" to a valid item"); From 8523f0fb0bcd83e7ed20ec20525b3a916be7fe45 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Oct 2021 20:31:24 +0100 Subject: [PATCH 116/710] CS fix --- src/item/LegacyStringToItemParser.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/item/LegacyStringToItemParser.php b/src/item/LegacyStringToItemParser.php index afe22cd2d..ccc824b0d 100644 --- a/src/item/LegacyStringToItemParser.php +++ b/src/item/LegacyStringToItemParser.php @@ -31,7 +31,6 @@ use function file_get_contents; use function is_array; use function is_int; use function is_numeric; -use function is_string; use function json_decode; use function str_replace; use function strtolower; From 2db53775e0f89512167db166303e05e7e24ef0f6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Oct 2021 21:01:59 +0100 Subject: [PATCH 117/710] Sort item_from_string_bc_map using SORT_NATURAL --- resources/item_from_string_bc_map.json | 1138 ++++++++++++------------ 1 file changed, 569 insertions(+), 569 deletions(-) diff --git a/resources/item_from_string_bc_map.json b/resources/item_from_string_bc_map.json index c12f00a24..c5c502e9a 100644 --- a/resources/item_from_string_bc_map.json +++ b/resources/item_from_string_bc_map.json @@ -1,129 +1,24 @@ { - "-10": -10, - "-100": -100, - "-101": -101, - "-102": -102, - "-103": -103, - "-104": -104, - "-105": -105, - "-106": -106, - "-107": -107, - "-108": -108, - "-109": -109, - "-11": -11, - "-110": -110, - "-111": -111, - "-112": -112, - "-113": -113, - "-114": -114, - "-115": -115, - "-116": -116, - "-117": -117, - "-118": -118, - "-119": -119, - "-12": -12, - "-120": -120, - "-121": -121, - "-122": -122, - "-123": -123, - "-124": -124, - "-125": -125, - "-126": -126, - "-127": -127, - "-128": -128, - "-129": -129, - "-13": -13, - "-130": -130, - "-131": -131, - "-132": -132, - "-133": -133, - "-134": -134, - "-135": -135, - "-136": -136, - "-137": -137, - "-138": -138, - "-139": -139, - "-14": -14, - "-140": -140, - "-141": -141, - "-142": -142, - "-143": -143, - "-144": -144, - "-145": -145, - "-146": -146, - "-147": -147, - "-148": -148, - "-149": -149, - "-15": -15, - "-150": -150, - "-151": -151, - "-152": -152, - "-153": -153, - "-154": -154, - "-155": -155, - "-156": -156, - "-157": -157, - "-159": -159, - "-16": -16, - "-160": -160, - "-161": -161, - "-162": -162, - "-163": -163, - "-164": -164, - "-165": -165, - "-166": -166, - "-167": -167, - "-168": -168, - "-169": -169, - "-17": -17, - "-170": -170, - "-171": -171, - "-172": -172, - "-173": -173, - "-174": -174, - "-175": -175, - "-176": -176, - "-177": -177, - "-178": -178, - "-179": -179, - "-18": -18, - "-180": -180, - "-181": -181, - "-182": -182, - "-183": -183, - "-184": -184, - "-185": -185, - "-186": -186, - "-187": -187, - "-188": -188, - "-189": -189, - "-19": -19, - "-190": -190, - "-191": -191, - "-192": -192, - "-193": -193, - "-194": -194, - "-195": -195, - "-196": -196, - "-197": -197, - "-198": -198, - "-199": -199, "-2": -2, + "-3": -3, + "-4": -4, + "-5": -5, + "-6": -6, + "-7": -7, + "-8": -8, + "-9": -9, + "-10": -10, + "-11": -11, + "-12": -12, + "-13": -13, + "-14": -14, + "-15": -15, + "-16": -16, + "-17": -17, + "-18": -18, + "-19": -19, "-20": -20, - "-200": -200, - "-201": -201, - "-202": -202, - "-203": -203, - "-204": -204, - "-206": -206, - "-207": -207, - "-208": -208, - "-209": -209, "-21": -21, - "-210": -210, - "-211": -211, - "-213": -213, - "-214": -214, "-22": -22, "-23": -23, "-24": -24, @@ -132,7 +27,6 @@ "-27": -27, "-28": -28, "-29": -29, - "-3": -3, "-30": -30, "-31": -31, "-32": -32, @@ -143,7 +37,6 @@ "-37": -37, "-38": -38, "-39": -39, - "-4": -4, "-40": -40, "-41": -41, "-42": -42, @@ -154,7 +47,6 @@ "-47": -47, "-48": -48, "-49": -49, - "-5": -5, "-50": -50, "-51": -51, "-52": -52, @@ -165,7 +57,6 @@ "-57": -57, "-58": -58, "-59": -59, - "-6": -6, "-60": -60, "-61": -61, "-62": -62, @@ -176,7 +67,6 @@ "-67": -67, "-68": -68, "-69": -69, - "-7": -7, "-70": -70, "-71": -71, "-72": -72, @@ -187,7 +77,6 @@ "-77": -77, "-78": -78, "-79": -79, - "-8": -8, "-80": -80, "-81": -81, "-82": -82, @@ -198,7 +87,6 @@ "-87": -87, "-88": -88, "-89": -89, - "-9": -9, "-90": -90, "-91": -91, "-92": -92, @@ -209,431 +97,170 @@ "-97": -97, "-98": -98, "-99": -99, + "-100": -100, + "-101": -101, + "-102": -102, + "-103": -103, + "-104": -104, + "-105": -105, + "-106": -106, + "-107": -107, + "-108": -108, + "-109": -109, + "-110": -110, + "-111": -111, + "-112": -112, + "-113": -113, + "-114": -114, + "-115": -115, + "-116": -116, + "-117": -117, + "-118": -118, + "-119": -119, + "-120": -120, + "-121": -121, + "-122": -122, + "-123": -123, + "-124": -124, + "-125": -125, + "-126": -126, + "-127": -127, + "-128": -128, + "-129": -129, + "-130": -130, + "-131": -131, + "-132": -132, + "-133": -133, + "-134": -134, + "-135": -135, + "-136": -136, + "-137": -137, + "-138": -138, + "-139": -139, + "-140": -140, + "-141": -141, + "-142": -142, + "-143": -143, + "-144": -144, + "-145": -145, + "-146": -146, + "-147": -147, + "-148": -148, + "-149": -149, + "-150": -150, + "-151": -151, + "-152": -152, + "-153": -153, + "-154": -154, + "-155": -155, + "-156": -156, + "-157": -157, + "-159": -159, + "-160": -160, + "-161": -161, + "-162": -162, + "-163": -163, + "-164": -164, + "-165": -165, + "-166": -166, + "-167": -167, + "-168": -168, + "-169": -169, + "-170": -170, + "-171": -171, + "-172": -172, + "-173": -173, + "-174": -174, + "-175": -175, + "-176": -176, + "-177": -177, + "-178": -178, + "-179": -179, + "-180": -180, + "-181": -181, + "-182": -182, + "-183": -183, + "-184": -184, + "-185": -185, + "-186": -186, + "-187": -187, + "-188": -188, + "-189": -189, + "-190": -190, + "-191": -191, + "-192": -192, + "-193": -193, + "-194": -194, + "-195": -195, + "-196": -196, + "-197": -197, + "-198": -198, + "-199": -199, + "-200": -200, + "-201": -201, + "-202": -202, + "-203": -203, + "-204": -204, + "-206": -206, + "-207": -207, + "-208": -208, + "-209": -209, + "-210": -210, + "-211": -211, + "-213": -213, + "-214": -214, "0": 0, "1": 1, - "10": 10, - "100": 100, - "101": 101, - "102": 102, - "103": 103, - "104": 104, - "105": 105, - "106": 106, - "107": 107, - "108": 108, - "109": 109, - "11": 11, - "110": 110, - "111": 111, - "112": 112, - "113": 113, - "114": 114, - "115": 115, - "116": 116, - "117": 117, - "118": 118, - "119": 119, - "12": 12, - "120": 120, - "121": 121, - "122": 122, - "123": 123, - "124": 124, - "125": 125, - "126": 126, - "127": 127, - "128": 128, - "129": 129, - "13": 13, - "130": 130, - "131": 131, - "132": 132, - "133": 133, - "134": 134, - "135": 135, - "136": 136, - "137": 137, - "138": 138, - "139": 139, - "14": 14, - "140": 140, - "141": 141, - "142": 142, - "143": 143, - "144": 144, - "145": 145, - "146": 146, - "147": 147, - "148": 148, - "149": 149, - "15": 15, - "150": 150, - "151": 151, - "152": 152, - "153": 153, - "154": 154, - "155": 155, - "156": 156, - "157": 157, - "158": 158, - "159": 159, - "16": 16, - "160": 160, - "161": 161, - "162": 162, - "163": 163, - "164": 164, - "165": 165, - "166": 166, - "167": 167, - "168": 168, - "169": 169, - "17": 17, - "170": 170, - "171": 171, - "172": 172, - "173": 173, - "174": 174, - "175": 175, - "176": 176, - "177": 177, - "178": 178, - "179": 179, - "18": 18, - "180": 180, - "181": 181, - "182": 182, - "183": 183, - "184": 184, - "185": 185, - "186": 186, - "187": 187, - "188": 188, - "189": 189, - "19": 19, - "190": 190, - "191": 191, - "192": 192, - "193": 193, - "194": 194, - "195": 195, - "196": 196, - "197": 197, - "198": 198, - "199": 199, "2": 2, - "20": 20, - "200": 200, - "201": 201, - "202": 202, - "203": 203, - "204": 204, - "205": 205, - "206": 206, - "207": 207, - "208": 208, - "209": 209, - "21": 21, - "213": 213, - "214": 214, - "215": 215, - "216": 216, - "218": 218, - "219": 219, - "22": 22, - "220": 220, - "221": 221, - "222": 222, - "223": 223, - "224": 224, - "225": 225, - "226": 226, - "227": 227, - "228": 228, - "229": 229, - "23": 23, - "231": 231, - "232": 232, - "233": 233, - "234": 234, - "235": 235, - "236": 236, - "237": 237, - "238": 238, - "239": 239, - "24": 24, - "240": 240, - "241": 241, - "243": 243, - "244": 244, - "245": 245, - "246": 246, - "247": 247, - "248": 248, - "249": 249, - "25": 25, - "250": 250, - "251": 251, - "252": 252, - "253": 253, - "254": 254, - "255": 255, - "256": 256, - "257": 257, - "258": 258, - "259": 259, - "26": 26, - "260": 260, - "261": 261, - "262": 262, - "263": 263, - "264": 264, - "265": 265, - "266": 266, - "267": 267, - "268": 268, - "269": 269, - "27": 27, - "270": 270, - "271": 271, - "272": 272, - "273": 273, - "274": 274, - "275": 275, - "276": 276, - "277": 277, - "278": 278, - "279": 279, - "28": 28, - "280": 280, - "281": 281, - "282": 282, - "283": 283, - "284": 284, - "285": 285, - "286": 286, - "287": 287, - "288": 288, - "289": 289, - "29": 29, - "290": 290, - "291": 291, - "292": 292, - "293": 293, - "294": 294, - "295": 295, - "296": 296, - "297": 297, - "298": 298, - "299": 299, "3": 3, - "30": 30, - "300": 300, - "301": 301, - "302": 302, - "303": 303, - "304": 304, - "305": 305, - "306": 306, - "307": 307, - "308": 308, - "309": 309, - "31": 31, - "310": 310, - "311": 311, - "312": 312, - "313": 313, - "314": 314, - "315": 315, - "316": 316, - "317": 317, - "318": 318, - "319": 319, - "32": 32, - "320": 320, - "321": 321, - "322": 322, - "323": 323, - "324": 324, - "325": 325, - "328": 328, - "329": 329, - "33": 33, - "330": 330, - "331": 331, - "332": 332, - "333": 333, - "334": 334, - "335": 335, - "336": 336, - "337": 337, - "338": 338, - "339": 339, - "34": 34, - "340": 340, - "341": 341, - "342": 342, - "344": 344, - "345": 345, - "346": 346, - "347": 347, - "348": 348, - "349": 349, - "35": 35, - "350": 350, - "351": 351, - "352": 352, - "353": 353, - "354": 354, - "355": 355, - "356": 356, - "357": 357, - "358": 358, - "359": 359, - "36": 36, - "360": 360, - "361": 361, - "362": 362, - "363": 363, - "364": 364, - "365": 365, - "366": 366, - "367": 367, - "368": 368, - "369": 369, - "37": 37, - "370": 370, - "371": 371, - "372": 372, - "373": 373, - "374": 374, - "375": 375, - "376": 376, - "377": 377, - "378": 378, - "379": 379, - "38": 38, - "380": 380, - "381": 381, - "382": 382, - "383": 383, - "384": 384, - "385": 385, - "386": 386, - "387": 387, - "388": 388, - "389": 389, - "39": 39, - "390": 390, - "391": 391, - "392": 392, - "393": 393, - "394": 394, - "395": 395, - "396": 396, - "397": 397, - "398": 398, - "399": 399, "4": 4, + "5": 5, + "6": 6, + "7": 7, + "8": 8, + "9": 9, + "10": 10, + "11": 11, + "12": 12, + "13": 13, + "14": 14, + "15": 15, + "16": 16, + "17": 17, + "18": 18, + "19": 19, + "20": 20, + "21": 21, + "22": 22, + "23": 23, + "24": 24, + "25": 25, + "26": 26, + "27": 27, + "28": 28, + "29": 29, + "30": 30, + "31": 31, + "32": 32, + "33": 33, + "34": 34, + "35": 35, + "36": 36, + "37": 37, + "38": 38, + "39": 39, "40": 40, - "400": 400, - "401": 401, - "402": 402, - "403": 403, - "404": 404, - "405": 405, - "406": 406, - "407": 407, - "408": 408, - "409": 409, "41": 41, - "410": 410, - "411": 411, - "412": 412, - "413": 413, - "414": 414, - "415": 415, - "416": 416, - "417": 417, - "418": 418, - "419": 419, "42": 42, - "420": 420, - "421": 421, - "422": 422, - "423": 423, - "424": 424, - "425": 425, - "426": 426, - "427": 427, - "428": 428, - "429": 429, "43": 43, - "430": 430, - "431": 431, - "432": 432, - "433": 433, - "434": 434, - "437": 437, - "438": 438, "44": 44, - "441": 441, - "442": 442, - "443": 443, - "444": 444, - "445": 445, - "446": 446, - "447": 447, - "448": 448, - "449": 449, "45": 45, - "450": 450, - "451": 451, - "452": 452, - "453": 453, - "455": 455, - "457": 457, - "458": 458, - "459": 459, "46": 46, - "460": 460, - "461": 461, - "462": 462, - "463": 463, - "464": 464, - "465": 465, - "466": 466, - "467": 467, - "468": 468, - "469": 469, "47": 47, - "470": 470, - "471": 471, - "472": 472, - "473": 473, - "474": 474, - "475": 475, - "476": 476, - "477": 477, "48": 48, "49": 49, - "499": 499, - "5": 5, "50": 50, - "500": 500, - "501": 501, - "502": 502, - "503": 503, - "504": 504, - "505": 505, - "506": 506, - "507": 507, - "508": 508, - "509": 509, "51": 51, - "510": 510, - "511": 511, - "513": 513, "52": 52, "53": 53, "54": 54, @@ -642,7 +269,6 @@ "57": 57, "58": 58, "59": 59, - "6": 6, "60": 60, "61": 61, "62": 62, @@ -653,7 +279,6 @@ "67": 67, "68": 68, "69": 69, - "7": 7, "70": 70, "71": 71, "72": 72, @@ -664,7 +289,6 @@ "77": 77, "78": 78, "79": 79, - "8": 8, "80": 80, "81": 81, "82": 82, @@ -675,7 +299,6 @@ "87": 87, "88": 88, "89": 89, - "9": 9, "90": 90, "91": 91, "92": 92, @@ -686,6 +309,383 @@ "97": 97, "98": 98, "99": 99, + "100": 100, + "101": 101, + "102": 102, + "103": 103, + "104": 104, + "105": 105, + "106": 106, + "107": 107, + "108": 108, + "109": 109, + "110": 110, + "111": 111, + "112": 112, + "113": 113, + "114": 114, + "115": 115, + "116": 116, + "117": 117, + "118": 118, + "119": 119, + "120": 120, + "121": 121, + "122": 122, + "123": 123, + "124": 124, + "125": 125, + "126": 126, + "127": 127, + "128": 128, + "129": 129, + "130": 130, + "131": 131, + "132": 132, + "133": 133, + "134": 134, + "135": 135, + "136": 136, + "137": 137, + "138": 138, + "139": 139, + "140": 140, + "141": 141, + "142": 142, + "143": 143, + "144": 144, + "145": 145, + "146": 146, + "147": 147, + "148": 148, + "149": 149, + "150": 150, + "151": 151, + "152": 152, + "153": 153, + "154": 154, + "155": 155, + "156": 156, + "157": 157, + "158": 158, + "159": 159, + "160": 160, + "161": 161, + "162": 162, + "163": 163, + "164": 164, + "165": 165, + "166": 166, + "167": 167, + "168": 168, + "169": 169, + "170": 170, + "171": 171, + "172": 172, + "173": 173, + "174": 174, + "175": 175, + "176": 176, + "177": 177, + "178": 178, + "179": 179, + "180": 180, + "181": 181, + "182": 182, + "183": 183, + "184": 184, + "185": 185, + "186": 186, + "187": 187, + "188": 188, + "189": 189, + "190": 190, + "191": 191, + "192": 192, + "193": 193, + "194": 194, + "195": 195, + "196": 196, + "197": 197, + "198": 198, + "199": 199, + "200": 200, + "201": 201, + "202": 202, + "203": 203, + "204": 204, + "205": 205, + "206": 206, + "207": 207, + "208": 208, + "209": 209, + "213": 213, + "214": 214, + "215": 215, + "216": 216, + "218": 218, + "219": 219, + "220": 220, + "221": 221, + "222": 222, + "223": 223, + "224": 224, + "225": 225, + "226": 226, + "227": 227, + "228": 228, + "229": 229, + "231": 231, + "232": 232, + "233": 233, + "234": 234, + "235": 235, + "236": 236, + "237": 237, + "238": 238, + "239": 239, + "240": 240, + "241": 241, + "243": 243, + "244": 244, + "245": 245, + "246": 246, + "247": 247, + "248": 248, + "249": 249, + "250": 250, + "251": 251, + "252": 252, + "253": 253, + "254": 254, + "255": 255, + "256": 256, + "257": 257, + "258": 258, + "259": 259, + "260": 260, + "261": 261, + "262": 262, + "263": 263, + "264": 264, + "265": 265, + "266": 266, + "267": 267, + "268": 268, + "269": 269, + "270": 270, + "271": 271, + "272": 272, + "273": 273, + "274": 274, + "275": 275, + "276": 276, + "277": 277, + "278": 278, + "279": 279, + "280": 280, + "281": 281, + "282": 282, + "283": 283, + "284": 284, + "285": 285, + "286": 286, + "287": 287, + "288": 288, + "289": 289, + "290": 290, + "291": 291, + "292": 292, + "293": 293, + "294": 294, + "295": 295, + "296": 296, + "297": 297, + "298": 298, + "299": 299, + "300": 300, + "301": 301, + "302": 302, + "303": 303, + "304": 304, + "305": 305, + "306": 306, + "307": 307, + "308": 308, + "309": 309, + "310": 310, + "311": 311, + "312": 312, + "313": 313, + "314": 314, + "315": 315, + "316": 316, + "317": 317, + "318": 318, + "319": 319, + "320": 320, + "321": 321, + "322": 322, + "323": 323, + "324": 324, + "325": 325, + "328": 328, + "329": 329, + "330": 330, + "331": 331, + "332": 332, + "333": 333, + "334": 334, + "335": 335, + "336": 336, + "337": 337, + "338": 338, + "339": 339, + "340": 340, + "341": 341, + "342": 342, + "344": 344, + "345": 345, + "346": 346, + "347": 347, + "348": 348, + "349": 349, + "350": 350, + "351": 351, + "352": 352, + "353": 353, + "354": 354, + "355": 355, + "356": 356, + "357": 357, + "358": 358, + "359": 359, + "360": 360, + "361": 361, + "362": 362, + "363": 363, + "364": 364, + "365": 365, + "366": 366, + "367": 367, + "368": 368, + "369": 369, + "370": 370, + "371": 371, + "372": 372, + "373": 373, + "374": 374, + "375": 375, + "376": 376, + "377": 377, + "378": 378, + "379": 379, + "380": 380, + "381": 381, + "382": 382, + "383": 383, + "384": 384, + "385": 385, + "386": 386, + "387": 387, + "388": 388, + "389": 389, + "390": 390, + "391": 391, + "392": 392, + "393": 393, + "394": 394, + "395": 395, + "396": 396, + "397": 397, + "398": 398, + "399": 399, + "400": 400, + "401": 401, + "402": 402, + "403": 403, + "404": 404, + "405": 405, + "406": 406, + "407": 407, + "408": 408, + "409": 409, + "410": 410, + "411": 411, + "412": 412, + "413": 413, + "414": 414, + "415": 415, + "416": 416, + "417": 417, + "418": 418, + "419": 419, + "420": 420, + "421": 421, + "422": 422, + "423": 423, + "424": 424, + "425": 425, + "426": 426, + "427": 427, + "428": 428, + "429": 429, + "430": 430, + "431": 431, + "432": 432, + "433": 433, + "434": 434, + "437": 437, + "438": 438, + "441": 441, + "442": 442, + "443": 443, + "444": 444, + "445": 445, + "446": 446, + "447": 447, + "448": 448, + "449": 449, + "450": 450, + "451": 451, + "452": 452, + "453": 453, + "455": 455, + "457": 457, + "458": 458, + "459": 459, + "460": 460, + "461": 461, + "462": 462, + "463": 463, + "464": 464, + "465": 465, + "466": 466, + "467": 467, + "468": 468, + "469": 469, + "470": 470, + "471": 471, + "472": 472, + "473": 473, + "474": 474, + "475": 475, + "476": 476, + "477": 477, + "499": 499, + "500": 500, + "501": 501, + "502": 502, + "503": 503, + "504": 504, + "505": 505, + "506": 506, + "507": 507, + "508": 508, + "509": 509, + "510": 510, + "511": 511, + "513": 513, "acacia_button": -140, "acacia_door": 430, "acacia_door_block": 196, @@ -913,27 +913,16 @@ "egg": 344, "element_0": 36, "element_1": -12, + "element_2": -13, + "element_3": -14, + "element_4": -15, + "element_5": -16, + "element_6": -17, + "element_7": -18, + "element_8": -19, + "element_9": -20, "element_10": -21, - "element_100": -111, - "element_101": -112, - "element_102": -113, - "element_103": -114, - "element_104": -115, - "element_105": -116, - "element_106": -117, - "element_107": -118, - "element_108": -119, - "element_109": -120, "element_11": -22, - "element_110": -121, - "element_111": -122, - "element_112": -123, - "element_113": -124, - "element_114": -125, - "element_115": -126, - "element_116": -127, - "element_117": -128, - "element_118": -129, "element_12": -23, "element_13": -24, "element_14": -25, @@ -942,7 +931,6 @@ "element_17": -28, "element_18": -29, "element_19": -30, - "element_2": -13, "element_20": -31, "element_21": -32, "element_22": -33, @@ -953,7 +941,6 @@ "element_27": -38, "element_28": -39, "element_29": -40, - "element_3": -14, "element_30": -41, "element_31": -42, "element_32": -43, @@ -964,7 +951,6 @@ "element_37": -48, "element_38": -49, "element_39": -50, - "element_4": -15, "element_40": -51, "element_41": -52, "element_42": -53, @@ -975,7 +961,6 @@ "element_47": -58, "element_48": -59, "element_49": -60, - "element_5": -16, "element_50": -61, "element_51": -62, "element_52": -63, @@ -986,7 +971,6 @@ "element_57": -68, "element_58": -69, "element_59": -70, - "element_6": -17, "element_60": -71, "element_61": -72, "element_62": -73, @@ -997,7 +981,6 @@ "element_67": -78, "element_68": -79, "element_69": -80, - "element_7": -18, "element_70": -81, "element_71": -82, "element_72": -83, @@ -1008,7 +991,6 @@ "element_77": -88, "element_78": -89, "element_79": -90, - "element_8": -19, "element_80": -91, "element_81": -92, "element_82": -93, @@ -1019,7 +1001,6 @@ "element_87": -98, "element_88": -99, "element_89": -100, - "element_9": -20, "element_90": -101, "element_91": -102, "element_92": -103, @@ -1030,6 +1011,25 @@ "element_97": -108, "element_98": -109, "element_99": -110, + "element_100": -111, + "element_101": -112, + "element_102": -113, + "element_103": -114, + "element_104": -115, + "element_105": -116, + "element_106": -117, + "element_107": -118, + "element_108": -119, + "element_109": -120, + "element_110": -121, + "element_111": -122, + "element_112": -123, + "element_113": -124, + "element_114": -125, + "element_115": -126, + "element_116": -127, + "element_117": -128, + "element_118": -129, "elytra": 444, "emerald": 388, "emerald_block": 133, @@ -1219,8 +1219,8 @@ "leather_pants": 300, "leather_tunic": 299, "leave": 18, - "leaves": 18, "leave2": 161, + "leaves": 18, "leaves2": 161, "lectern": -194, "lever": 69, From 0ac9f4fe61227df626ca00e8898436235ada171f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Oct 2021 22:26:51 +0100 Subject: [PATCH 118/710] BlockFactory: move SweetBerryBush to its proper place --- src/block/BlockFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index 6390812a1..70077b71a 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -403,6 +403,7 @@ class BlockFactory{ $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_STONE), "Stone", $stoneSlabBreakInfo)); $this->register(new Opaque(new BID(Ids::STONECUTTER, 0), "Stonecutter", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); $this->register(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BlockBreakInfo::instant())); + $this->register(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant())); $this->register(new TNT(new BID(Ids::TNT, 0), "TNT", BlockBreakInfo::instant())); $fern = new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_FERN), "Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)); @@ -584,7 +585,6 @@ class BlockFactory{ //TODO: minecraft:sticky_piston //TODO: minecraft:stonecutter_block //TODO: minecraft:structure_block - $this->register(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant())); //TODO: minecraft:turtle_egg //endregion From 321345fcc817d59475faead6ea2323b4f00e38de Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Oct 2021 23:00:38 +0100 Subject: [PATCH 119/710] Sapling: simplify condition --- src/block/Sapling.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/block/Sapling.php b/src/block/Sapling.php index 169cb9a32..d2ae0b5a7 100644 --- a/src/block/Sapling.php +++ b/src/block/Sapling.php @@ -118,11 +118,9 @@ class Sapling extends Flowable{ $ev = new StructureGrowEvent($this, $transaction, $player); $ev->call(); - if($ev->isCancelled()){ - return; + if(!$ev->isCancelled()){ + $transaction->apply(); } - - $transaction->apply(); } public function getFuelTime() : int{ From 34b13925983a92f9749c3fa1dda0237069574220 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Oct 2021 15:03:11 +0100 Subject: [PATCH 120/710] Cross-platform signal handler --- src/Server.php | 13 +++++- src/utils/SignalHandler.php | 79 +++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/utils/SignalHandler.php diff --git a/src/Server.php b/src/Server.php index abc24f8da..0a4aebf09 100644 --- a/src/Server.php +++ b/src/Server.php @@ -98,6 +98,7 @@ use pocketmine\utils\NotCloneable; use pocketmine\utils\NotSerializable; use pocketmine\utils\Process; use pocketmine\utils\Promise; +use pocketmine\utils\SignalHandler; use pocketmine\utils\Terminal; use pocketmine\utils\TextFormat; use pocketmine\utils\Utils; @@ -250,6 +251,8 @@ class Server{ /** @var Player[] */ private array $playerList = []; + private SignalHandler $signalHandler; + /** * @var CommandSender[][] * @phpstan-var array> @@ -743,6 +746,11 @@ class Server{ $this->autoloader = $autoloader; $this->logger = $logger; + $this->signalHandler = new SignalHandler(function() : void{ + $this->logger->info("Received signal interrupt, stopping the server"); + $this->shutdown(); + }); + try{ foreach([ $dataPath, @@ -1326,7 +1334,10 @@ class Server{ * Shuts the server down correctly */ public function shutdown() : void{ - $this->isRunning = false; + if($this->isRunning){ + $this->isRunning = false; + $this->signalHandler->unregister(); + } } public function forceShutdown() : void{ diff --git a/src/utils/SignalHandler.php b/src/utils/SignalHandler.php new file mode 100644 index 000000000..3f6d7b256 --- /dev/null +++ b/src/utils/SignalHandler.php @@ -0,0 +1,79 @@ +interruptCallback = $interruptCallback; + + if(function_exists('sapi_windows_set_ctrl_handler')){ + sapi_windows_set_ctrl_handler($this->interruptCallback = function(int $signo) use ($interruptCallback) : void{ + if($signo === PHP_WINDOWS_EVENT_CTRL_C || $signo === PHP_WINDOWS_EVENT_CTRL_BREAK){ + $interruptCallback(); + } + }); + }elseif(function_exists('pcntl_signal')){ + foreach([ + SIGTERM, + SIGINT, + SIGHUP + ] as $signal){ + pcntl_signal($signal, $this->interruptCallback = fn(int $signo) => $interruptCallback()); + } + pcntl_async_signals(true); + }else{ + //no supported signal handlers :( + } + } + + public function unregister() : void{ + if(function_exists('sapi_windows_set_ctrl_handler')){ + sapi_windows_set_ctrl_handler($this->interruptCallback, false); + }elseif(function_exists('pcntl_signal')){ + foreach([ + SIGTERM, + SIGINT, + SIGHUP + ] as $signal){ + pcntl_signal($signal, SIG_DFL); + } + } + } +} From 7a4af7a0bcb9b6904df5a7f1e53fd840eb0b7347 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Oct 2021 15:14:27 +0100 Subject: [PATCH 121/710] SignalHandler: fix CS AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA --- src/utils/SignalHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/SignalHandler.php b/src/utils/SignalHandler.php index 3f6d7b256..de81a2b67 100644 --- a/src/utils/SignalHandler.php +++ b/src/utils/SignalHandler.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\utils; use function function_exists; +use function pcntl_async_signals; use function pcntl_signal; use function sapi_windows_set_ctrl_handler; use const PHP_WINDOWS_EVENT_CTRL_BREAK; From bdbfa705582b91ed800563bb53c86ebbe4484345 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Oct 2021 15:44:18 +0100 Subject: [PATCH 122/710] Server: break some isolated stuff out of Server::__construct() --- src/Server.php | 227 ++++++++++++++++++++++++++----------------------- 1 file changed, 121 insertions(+), 106 deletions(-) diff --git a/src/Server.php b/src/Server.php index 0a4aebf09..b1b357907 100644 --- a/src/Server.php +++ b/src/Server.php @@ -973,115 +973,13 @@ class Server{ $this->pluginManager->loadPlugins($this->pluginPath); $this->enablePlugins(PluginEnableOrder::STARTUP()); - $getGenerator = function(string $generatorName, string $generatorOptions, string $worldName) : ?string{ - $generatorEntry = GeneratorManager::getInstance()->getGenerator($generatorName); - if($generatorEntry === null){ - $this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_level_generationError( - $worldName, - KnownTranslationFactory::pocketmine_level_unknownGenerator($generatorName) - ))); - return null; - } - try{ - $generatorEntry->validateGeneratorOptions($generatorOptions); - }catch(InvalidGeneratorOptionsException $e){ - $this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_level_generationError( - $worldName, - KnownTranslationFactory::pocketmine_level_invalidGeneratorOptions($generatorOptions, $generatorName, $e->getMessage()) - ))); - return null; - } - return $generatorEntry->getGeneratorClass(); - }; - - foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){ - if($options === null){ - $options = []; - }elseif(!is_array($options)){ - continue; - } - if(!$this->worldManager->loadWorld($name, true) && !$this->worldManager->isWorldGenerated($name)){ - $creationOptions = WorldCreationOptions::create(); - //TODO: error checking - - $generatorName = $options["generator"] ?? "default"; - $generatorOptions = isset($options["preset"]) && is_string($options["preset"]) ? $options["preset"] : ""; - - $generatorClass = $getGenerator($generatorName, $generatorOptions, $name); - if($generatorClass === null){ - continue; - } - $creationOptions->setGeneratorClass($generatorClass); - $creationOptions->setGeneratorOptions($generatorOptions); - - if(isset($options["difficulty"]) && is_string($options["difficulty"])){ - $creationOptions->setDifficulty(World::getDifficultyFromString($options["difficulty"])); - } - - if(isset($options["seed"])){ - $convertedSeed = Generator::convertSeed((string) ($options["seed"] ?? "")); - if($convertedSeed !== null){ - $creationOptions->setSeed($convertedSeed); - } - } - - $this->worldManager->generateWorld($name, $creationOptions); - } + if(!$this->startupPrepareWorlds()){ + return; } - - if($this->worldManager->getDefaultWorld() === null){ - $default = $this->configGroup->getConfigString("level-name", "world"); - if(trim($default) == ""){ - $this->getLogger()->warning("level-name cannot be null, using default"); - $default = "world"; - $this->configGroup->setConfigString("level-name", "world"); - } - if(!$this->worldManager->loadWorld($default, true) && !$this->worldManager->isWorldGenerated($default)){ - $generatorName = $this->configGroup->getConfigString("level-type"); - $generatorOptions = $this->configGroup->getConfigString("generator-settings"); - $generatorClass = $getGenerator($generatorName, $generatorOptions, $default); - if($generatorClass !== null){ - $creationOptions = WorldCreationOptions::create() - ->setGeneratorClass($generatorClass) - ->setGeneratorOptions($generatorOptions); - $convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed")); - if($convertedSeed !== null){ - $creationOptions->setSeed($convertedSeed); - } - $this->worldManager->generateWorld($default, $creationOptions); - } - } - - $world = $this->worldManager->getWorldByName($default); - if($world === null){ - $this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError())); - $this->forceShutdown(); - - return; - } - $this->worldManager->setDefaultWorld($world); - } - $this->enablePlugins(PluginEnableOrder::POSTWORLD()); - $useQuery = $this->configGroup->getConfigBool("enable-query", true); - if(!$this->network->registerInterface(new RakLibInterface($this)) && $useQuery){ - //RakLib would normally handle the transport for Query packets - //if it's not registered we need to make sure Query still works - $this->network->registerInterface(new DedicatedQueryNetworkInterface($this->getIp(), $this->getPort(), new \PrefixedLogger($this->logger, "Dedicated Query Interface"))); - } - $this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($this->getIp(), (string) $this->getPort()))); - - if($useQuery){ - $this->network->registerRawPacketHandler(new QueryHandler($this)); - } - - foreach($this->getIPBans()->getEntries() as $entry){ - $this->network->blockAddress($entry->getName(), -1); - } - - if($this->configGroup->getPropertyBool("network.upnp-forwarding", false)){ - $this->network->registerInterface(new UPnPNetworkInterface($this->logger, Internet::getInternalIP(), $this->getPort())); + if(!$this->startupPrepareNetworkInterfaces()){ + return; } if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){ @@ -1119,6 +1017,123 @@ class Server{ } } + private function startupPrepareWorlds() : bool{ + $getGenerator = function(string $generatorName, string $generatorOptions, string $worldName) : ?string{ + $generatorEntry = GeneratorManager::getInstance()->getGenerator($generatorName); + if($generatorEntry === null){ + $this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_level_generationError( + $worldName, + KnownTranslationFactory::pocketmine_level_unknownGenerator($generatorName) + ))); + return null; + } + try{ + $generatorEntry->validateGeneratorOptions($generatorOptions); + }catch(InvalidGeneratorOptionsException $e){ + $this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_level_generationError( + $worldName, + KnownTranslationFactory::pocketmine_level_invalidGeneratorOptions($generatorOptions, $generatorName, $e->getMessage()) + ))); + return null; + } + return $generatorEntry->getGeneratorClass(); + }; + + foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){ + if($options === null){ + $options = []; + }elseif(!is_array($options)){ + continue; + } + if(!$this->worldManager->loadWorld($name, true) && !$this->worldManager->isWorldGenerated($name)){ + $creationOptions = WorldCreationOptions::create(); + //TODO: error checking + + $generatorName = $options["generator"] ?? "default"; + $generatorOptions = isset($options["preset"]) && is_string($options["preset"]) ? $options["preset"] : ""; + + $generatorClass = $getGenerator($generatorName, $generatorOptions, $name); + if($generatorClass === null){ + continue; + } + $creationOptions->setGeneratorClass($generatorClass); + $creationOptions->setGeneratorOptions($generatorOptions); + + if(isset($options["difficulty"]) && is_string($options["difficulty"])){ + $creationOptions->setDifficulty(World::getDifficultyFromString($options["difficulty"])); + } + + if(isset($options["seed"])){ + $convertedSeed = Generator::convertSeed((string) ($options["seed"] ?? "")); + if($convertedSeed !== null){ + $creationOptions->setSeed($convertedSeed); + } + } + + $this->worldManager->generateWorld($name, $creationOptions); + } + } + + if($this->worldManager->getDefaultWorld() === null){ + $default = $this->configGroup->getConfigString("level-name", "world"); + if(trim($default) == ""){ + $this->getLogger()->warning("level-name cannot be null, using default"); + $default = "world"; + $this->configGroup->setConfigString("level-name", "world"); + } + if(!$this->worldManager->loadWorld($default, true) && !$this->worldManager->isWorldGenerated($default)){ + $generatorName = $this->configGroup->getConfigString("level-type"); + $generatorOptions = $this->configGroup->getConfigString("generator-settings"); + $generatorClass = $getGenerator($generatorName, $generatorOptions, $default); + if($generatorClass !== null){ + $creationOptions = WorldCreationOptions::create() + ->setGeneratorClass($generatorClass) + ->setGeneratorOptions($generatorOptions); + $convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed")); + if($convertedSeed !== null){ + $creationOptions->setSeed($convertedSeed); + } + $this->worldManager->generateWorld($default, $creationOptions); + } + } + + $world = $this->worldManager->getWorldByName($default); + if($world === null){ + $this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError())); + $this->forceShutdown(); + + return false; + } + $this->worldManager->setDefaultWorld($world); + } + + return true; + } + + private function startupPrepareNetworkInterfaces() : bool{ + $useQuery = $this->configGroup->getConfigBool("enable-query", true); + if(!$this->network->registerInterface(new RakLibInterface($this)) && $useQuery){ + //RakLib would normally handle the transport for Query packets + //if it's not registered we need to make sure Query still works + $this->network->registerInterface(new DedicatedQueryNetworkInterface($this->getIp(), $this->getPort(), new \PrefixedLogger($this->logger, "Dedicated Query Interface"))); + } + $this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($this->getIp(), (string) $this->getPort()))); + + if($useQuery){ + $this->network->registerRawPacketHandler(new QueryHandler($this)); + } + + foreach($this->getIPBans()->getEntries() as $entry){ + $this->network->blockAddress($entry->getName(), -1); + } + + if($this->configGroup->getPropertyBool("network.upnp-forwarding", false)){ + $this->network->registerInterface(new UPnPNetworkInterface($this->logger, Internet::getInternalIP(), $this->getPort())); + } + + return true; + } + /** * Subscribes to a particular message broadcast channel. * The channel ID can be any arbitrary string. From 06e7338ff915f3c95b2b2ef213a7ccb6836b58e0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Oct 2021 15:54:20 +0100 Subject: [PATCH 123/710] Move exception printing utilities from MainLogger to Utils where they can be useful to other stuff apart from just the logger --- src/utils/MainLogger.php | 42 +---------------- src/utils/Utils.php | 46 +++++++++++++++++++ .../check-explicit-mixed-baseline.neon | 15 ++++-- 3 files changed, 57 insertions(+), 46 deletions(-) diff --git a/src/utils/MainLogger.php b/src/utils/MainLogger.php index 67ab82a62..1e5c53044 100644 --- a/src/utils/MainLogger.php +++ b/src/utils/MainLogger.php @@ -24,15 +24,10 @@ declare(strict_types=1); namespace pocketmine\utils; use LogLevel; -use pocketmine\errorhandler\ErrorTypeToStringMap; use pocketmine\thread\Thread; use pocketmine\thread\Worker; -use function get_class; use function implode; -use function is_int; -use function preg_replace; use function sprintf; -use function trim; use const PHP_EOL; use const PTHREADS_INHERIT_NONE; @@ -137,46 +132,11 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ * @return void */ public function logException(\Throwable $e, $trace = null){ - if($trace === null){ - $trace = $e->getTrace(); - } - - $lines = [self::printExceptionMessage($e)]; - $lines[] = "--- Stack trace ---"; - foreach(Utils::printableTrace($trace) as $line){ - $lines[] = " " . $line; - } - for($prev = $e->getPrevious(); $prev !== null; $prev = $prev->getPrevious()){ - $lines[] = "--- Previous ---"; - $lines[] = self::printExceptionMessage($prev); - foreach(Utils::printableTrace($prev->getTrace()) as $line){ - $lines[] = " " . $line; - } - } - $lines[] = "--- End of exception information ---"; - $this->critical(implode("\n", $lines)); + $this->critical(implode("\n", Utils::printableExceptionInfo($e, $trace))); $this->syncFlushBuffer(); } - private static function printExceptionMessage(\Throwable $e) : string{ - $errstr = preg_replace('/\s+/', ' ', trim($e->getMessage())); - - $errno = $e->getCode(); - if(is_int($errno)){ - try{ - $errno = ErrorTypeToStringMap::get($errno); - }catch(\InvalidArgumentException $ex){ - //pass - } - } - - $errfile = Filesystem::cleanPath($e->getFile()); - $errline = $e->getLine(); - - return get_class($e) . ": \"$errstr\" ($errno) in \"$errfile\" at line $errline"; - } - public function log($level, $message){ switch($level){ case LogLevel::EMERGENCY: diff --git a/src/utils/Utils.php b/src/utils/Utils.php index 9e33fc8a7..e8add3c9c 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -28,6 +28,7 @@ declare(strict_types=1); namespace pocketmine\utils; use DaveRandom\CallbackValidator\CallbackType; +use pocketmine\errorhandler\ErrorTypeToStringMap; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; use function array_combine; @@ -46,6 +47,7 @@ use function file; use function file_exists; use function file_get_contents; use function function_exists; +use function get_class; use function get_current_user; use function get_loaded_extensions; use function getenv; @@ -53,6 +55,7 @@ use function gettype; use function implode; use function is_array; use function is_bool; +use function is_int; use function is_object; use function is_string; use function mb_check_encoding; @@ -384,6 +387,49 @@ final class Utils{ return -1; } + private static function printableExceptionMessage(\Throwable $e) : string{ + $errstr = preg_replace('/\s+/', ' ', trim($e->getMessage())); + + $errno = $e->getCode(); + if(is_int($errno)){ + try{ + $errno = ErrorTypeToStringMap::get($errno); + }catch(\InvalidArgumentException $ex){ + //pass + } + } + + $errfile = Filesystem::cleanPath($e->getFile()); + $errline = $e->getLine(); + + return get_class($e) . ": \"$errstr\" ($errno) in \"$errfile\" at line $errline"; + } + + /** + * @param mixed[] $trace + * @return string[] + */ + public static function printableExceptionInfo(\Throwable $e, $trace = null) : array{ + if($trace === null){ + $trace = $e->getTrace(); + } + + $lines = [self::printableExceptionMessage($e)]; + $lines[] = "--- Stack trace ---"; + foreach(Utils::printableTrace($trace) as $line){ + $lines[] = " " . $line; + } + for($prev = $e->getPrevious(); $prev !== null; $prev = $prev->getPrevious()){ + $lines[] = "--- Previous ---"; + $lines[] = self::printableExceptionMessage($prev); + foreach(Utils::printableTrace($prev->getTrace()) as $line){ + $lines[] = " " . $line; + } + } + $lines[] = "--- End of exception information ---"; + return $lines; + } + /** * @param mixed[][] $trace * @phpstan-param list> $trace diff --git a/tests/phpstan/configs/check-explicit-mixed-baseline.neon b/tests/phpstan/configs/check-explicit-mixed-baseline.neon index a13bb3a1b..2a0dd5404 100644 --- a/tests/phpstan/configs/check-explicit-mixed-baseline.neon +++ b/tests/phpstan/configs/check-explicit-mixed-baseline.neon @@ -180,21 +180,26 @@ parameters: count: 1 path: ../../../src/utils/Internet.php - - - message: "#^Part \\$errno \\(mixed\\) of encapsed string cannot be cast to string\\.$#" - count: 1 - path: ../../../src/utils/MainLogger.php - - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" count: 1 path: ../../../src/utils/Utils.php + - + message: "#^Parameter \\#1 \\$trace of static method pocketmine\\\\utils\\\\Utils\\:\\:printableTrace\\(\\) expects array\\\\>, array given\\.$#" + count: 1 + path: ../../../src/utils/Utils.php + - message: "#^Parameter \\#2 \\$array of function array_map expects array, mixed given\\.$#" count: 1 path: ../../../src/utils/Utils.php + - + message: "#^Part \\$errno \\(mixed\\) of encapsed string cannot be cast to string\\.$#" + count: 1 + path: ../../../src/utils/Utils.php + - message: "#^Parameter \\#1 \\$keys of function array_fill_keys expects array, mixed given\\.$#" count: 1 From 8c07748100d29f8c7f12680d02d0feefadc72a4a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Oct 2021 15:55:08 +0100 Subject: [PATCH 124/710] RakLibInterface: print packet exception info as a block using Utils::printableExceptionInfo() --- src/network/mcpe/raklib/RakLibInterface.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/network/mcpe/raklib/RakLibInterface.php b/src/network/mcpe/raklib/RakLibInterface.php index 9653a0d4e..55302b43a 100644 --- a/src/network/mcpe/raklib/RakLibInterface.php +++ b/src/network/mcpe/raklib/RakLibInterface.php @@ -192,10 +192,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{ $logger->error("Bad packet (error ID $errorId): " . $e->getMessage()); //intentionally doesn't use logException, we don't want spammy packet error traces to appear in release mode - $logger->debug("Origin: " . Filesystem::cleanPath($e->getFile()) . "(" . $e->getLine() . ")"); - foreach(Utils::printableTrace($e->getTrace()) as $frame){ - $logger->debug($frame); - } + $logger->debug(implode("\n", Utils::printableExceptionInfo($e))); $session->disconnect("Packet processing error (Error ID: $errorId)"); $this->interface->blockAddress($address, 5); } From 03482368608164acd202547854df9efabbc7f678 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Oct 2021 15:56:50 +0100 Subject: [PATCH 125/710] fucking CS again --- src/network/mcpe/raklib/RakLibInterface.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/network/mcpe/raklib/RakLibInterface.php b/src/network/mcpe/raklib/RakLibInterface.php index 55302b43a..927cdbd76 100644 --- a/src/network/mcpe/raklib/RakLibInterface.php +++ b/src/network/mcpe/raklib/RakLibInterface.php @@ -35,7 +35,6 @@ use pocketmine\network\Network; use pocketmine\network\PacketHandlingException; use pocketmine\Server; use pocketmine\snooze\SleeperNotifier; -use pocketmine\utils\Filesystem; use pocketmine\utils\Utils; use raklib\protocol\EncapsulatedPacket; use raklib\protocol\PacketReliability; From 48f809d3fa8b40e460352f11a9b527b4a123da3e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 15 Oct 2021 17:01:09 +0100 Subject: [PATCH 126/710] Removed another dead PHPStan error pattern this was actually a PHPStan bug fixed in 0.12.99. --- tests/phpstan/configs/check-explicit-mixed-baseline.neon | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/phpstan/configs/check-explicit-mixed-baseline.neon b/tests/phpstan/configs/check-explicit-mixed-baseline.neon index 2a0dd5404..5591d54c8 100644 --- a/tests/phpstan/configs/check-explicit-mixed-baseline.neon +++ b/tests/phpstan/configs/check-explicit-mixed-baseline.neon @@ -160,11 +160,6 @@ parameters: count: 1 path: ../../../src/thread/ThreadManager.php - - - message: "#^Method pocketmine\\\\timings\\\\TimingsHandler\\:\\:time\\(\\) should return TClosureReturn but returns TClosureReturn\\.$#" - count: 1 - path: ../../../src/timings/TimingsHandler.php - - message: "#^Parameter \\#1 \\$config of static method pocketmine\\\\utils\\\\Config\\:\\:writeProperties\\(\\) expects array\\, array\\ given\\.$#" count: 1 From 8db5732b44578a59c785e6e3c1d36c87c90ddeb4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 15 Oct 2021 17:15:46 +0100 Subject: [PATCH 127/710] Drop respect/validation it's not worth this turning into compatibility baggage just so that we can parse plugin_list.yml, especially when we have new ways to handle data parsing coming in the pipeline. For something as small as plugin_list.yml, it's easier (and in this case better too) to just validate it manually (respect/validation was anyway too strict considering it's YAML we're dealing with). --- composer.json | 1 - composer.lock | 206 +----------------- src/plugin/PluginGraylist.php | 42 ++-- .../check-explicit-mixed-baseline.neon | 5 - 4 files changed, 25 insertions(+), 229 deletions(-) diff --git a/composer.json b/composer.json index 05f575214..167149a72 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,6 @@ "pocketmine/snooze": "^0.3.0", "pocketmine/spl": "dev-master", "ramsey/uuid": "^4.1", - "respect/validation": "^2.0", "webmozart/path-util": "^2.3" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 4286906a6..fe195368c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c7a00c5a35d43f307fdba7a588029131", + "content-hash": "39ec9b1c108888c32a660f3bc2c400c4", "packages": [ { "name": "adhocore/json-comment", @@ -1011,130 +1011,6 @@ ], "time": "2021-09-25T23:10:38+00:00" }, - { - "name": "respect/stringifier", - "version": "0.2.0", - "source": { - "type": "git", - "url": "https://github.com/Respect/Stringifier.git", - "reference": "e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Respect/Stringifier/zipball/e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59", - "reference": "e55af3c8aeaeaa2abb5fa47a58a8e9688cc23b59", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.8", - "malukenho/docheader": "^0.1.7", - "phpunit/phpunit": "^6.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Respect\\Stringifier\\": "src/" - }, - "files": [ - "src/stringify.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Respect/Stringifier Contributors", - "homepage": "https://github.com/Respect/Stringifier/graphs/contributors" - } - ], - "description": "Converts any value to a string", - "homepage": "http://respect.github.io/Stringifier/", - "keywords": [ - "respect", - "stringifier", - "stringify" - ], - "support": { - "issues": "https://github.com/Respect/Stringifier/issues", - "source": "https://github.com/Respect/Stringifier/tree/0.2.0" - }, - "time": "2017-12-29T19:39:25+00:00" - }, - { - "name": "respect/validation", - "version": "2.2.3", - "source": { - "type": "git", - "url": "https://github.com/Respect/Validation.git", - "reference": "4c21a7ffc9a4915673cb2c2843963919e664e627" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Respect/Validation/zipball/4c21a7ffc9a4915673cb2c2843963919e664e627", - "reference": "4c21a7ffc9a4915673cb2c2843963919e664e627", - "shasum": "" - }, - "require": { - "php": "^7.3 || ^8.0", - "respect/stringifier": "^0.2.0", - "symfony/polyfill-mbstring": "^1.2" - }, - "require-dev": { - "egulias/email-validator": "^3.0", - "malukenho/docheader": "^0.1", - "mikey179/vfsstream": "^1.6", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-deprecation-rules": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^9.3", - "psr/http-message": "^1.0", - "respect/coding-standard": "^3.0", - "squizlabs/php_codesniffer": "^3.5", - "symfony/validator": "^3.0||^4.0", - "zendframework/zend-validator": "^2.1" - }, - "suggest": { - "egulias/email-validator": "Strict (RFC compliant) email validation", - "ext-bcmath": "Arbitrary Precision Mathematics", - "ext-fileinfo": "File Information", - "ext-mbstring": "Multibyte String Functions", - "symfony/validator": "Use Symfony validator through Respect\\Validation", - "zendframework/zend-validator": "Use Zend Framework validator through Respect\\Validation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Respect\\Validation\\": "library/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Respect/Validation Contributors", - "homepage": "https://github.com/Respect/Validation/graphs/contributors" - } - ], - "description": "The most awesome validation engine ever created for PHP", - "homepage": "http://respect.github.io/Validation/", - "keywords": [ - "respect", - "validation", - "validator" - ], - "support": { - "issues": "https://github.com/Respect/Validation/issues", - "source": "https://github.com/Respect/Validation/tree/2.2.3" - }, - "time": "2021-03-19T14:12:45+00:00" - }, { "name": "symfony/polyfill-ctype", "version": "v1.23.0", @@ -1214,86 +1090,6 @@ ], "time": "2021-02-19T12:13:01+00:00" }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.23.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9174a3d80210dca8daa7f31fec659150bbeabfc6", - "reference": "9174a3d80210dca8daa7f31fec659150bbeabfc6", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-05-27T12:26:48+00:00" - }, { "name": "symfony/polyfill-php80", "version": "v1.23.1", diff --git a/src/plugin/PluginGraylist.php b/src/plugin/PluginGraylist.php index 34aad55f1..cd6287f82 100644 --- a/src/plugin/PluginGraylist.php +++ b/src/plugin/PluginGraylist.php @@ -23,15 +23,11 @@ declare(strict_types=1); namespace pocketmine\plugin; -use Respect\Validation\Exceptions\NestedValidationException; -use Respect\Validation\Rules\AllOf; -use Respect\Validation\Rules\ArrayType; -use Respect\Validation\Rules\Each; -use Respect\Validation\Rules\In; -use Respect\Validation\Rules\Key; -use Respect\Validation\Rules\StringType; -use Respect\Validation\Validator; use function array_flip; +use function is_array; +use function is_float; +use function is_int; +use function is_string; class PluginGraylist{ @@ -70,17 +66,27 @@ class PluginGraylist{ * @param mixed[] $array */ public static function fromArray(array $array) : PluginGraylist{ - $validator = new Validator( - new Key("mode", new In(['whitelist', 'blacklist'], true), true), - new Key("plugins", new AllOf(new ArrayType(), new Each(new StringType())), true) - ); - $validator->setName('plugin_list.yml'); - try{ - $validator->assert($array); - }catch(NestedValidationException $e){ - throw new \InvalidArgumentException($e->getFullMessage(), 0, $e); + if(!isset($array["mode"]) || ($array["mode"] !== "whitelist" && $array["mode"] !== "blacklist")){ + throw new \InvalidArgumentException("\"mode\" must be set"); } - return new PluginGraylist($array["plugins"], $array["mode"] === 'whitelist'); + $isWhitelist = match($array["mode"]){ + "whitelist" => true, + "blacklist" => false, + default => throw new \InvalidArgumentException("\"mode\" must be either \"whitelist\" or \"blacklist\"") + }; + $plugins = []; + if(isset($array["plugins"])){ + if(!is_array($array["plugins"])){ + throw new \InvalidArgumentException("\"plugins\" must be an array"); + } + foreach($array["plugins"] as $k => $v){ + if(!is_string($v) && !is_int($v) && !is_float($v)){ + throw new \InvalidArgumentException("\"plugins\" contains invalid element at position $k"); + } + $plugins[] = (string) $v; + } + } + return new PluginGraylist($plugins, $isWhitelist); } /** diff --git a/tests/phpstan/configs/check-explicit-mixed-baseline.neon b/tests/phpstan/configs/check-explicit-mixed-baseline.neon index 5591d54c8..d8bb79fb2 100644 --- a/tests/phpstan/configs/check-explicit-mixed-baseline.neon +++ b/tests/phpstan/configs/check-explicit-mixed-baseline.neon @@ -135,11 +135,6 @@ parameters: count: 1 path: ../../../src/plugin/PluginDescription.php - - - message: "#^Parameter \\#1 \\$plugins of class pocketmine\\\\plugin\\\\PluginGraylist constructor expects array\\, mixed given\\.$#" - count: 1 - path: ../../../src/plugin/PluginGraylist.php - - message: "#^Parameter \\#2 \\$code of class pocketmine\\\\resourcepacks\\\\ResourcePackException constructor expects int, mixed given\\.$#" count: 1 From a794d24c81af0111a47a039f24b8ce64c88b0ccc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 17 Oct 2021 17:02:18 +0100 Subject: [PATCH 128/710] Added a tool to generate a Markdown document of all core permissions --- tools/generate-permission-doc.php | 100 ++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 tools/generate-permission-doc.php diff --git a/tools/generate-permission-doc.php b/tools/generate-permission-doc.php new file mode 100644 index 000000000..57fd04626 --- /dev/null +++ b/tools/generate-permission-doc.php @@ -0,0 +1,100 @@ +getPermissions(); +ksort($permissions, SORT_STRING); + +fwrite($doc, "# PocketMine-MP Core Permissions\n"); +fwrite($doc, "Generated from PocketMine-MP " . VersionInfo::VERSION()->getFullVersion() . "\n"); +fwrite($doc, "\n"); +fwrite($doc, "| Name | Description | Implied permissions |\n"); +fwrite($doc, "|:-----|:------------|:-------------------:|\n"); +foreach($permissions as $permission){ + $link = count($permission->getChildren()) === 0 ? "N/A" : "[Jump](#" . markdownify("Permissions implied by `" . $permission->getName() . "`") . ")"; + fwrite($doc, "| `" . $permission->getName() . "` | " . $permission->getDescription() . " | $link |\n"); +} + +fwrite($doc, "\n\n"); +fwrite($doc, "## Implied permissions\n"); +fwrite($doc, "Some permissions automatically grant (or deny) other permissions by default when granted. These are referred to as **implied permissions**.
\n"); +fwrite($doc, "Permissions may imply permissions which in turn imply other permissions (e.g. `pocketmine.group.operator` implies `pocketmine.group.user`, which in turn implies `pocketmine.command.help`).
\n"); +fwrite($doc, "Implied permissions can be overridden by explicit permissions from elsewhere.
\n"); +fwrite($doc, "**Note:** When explicitly denied, implied permissions are inverted. This means that \"granted\" becomes \"denied\" and vice versa.\n"); +fwrite($doc, "\n\n"); +foreach($permissions as $permission){ + if(count($permission->getChildren()) === 0){ + continue; + } + fwrite($doc, "### Permissions implied by `" . $permission->getName() . "`\n"); + fwrite($doc, "Users granted this permission will also be granted/denied the following permissions implicitly:\n\n"); + + fwrite($doc, "| Name | Type |\n"); + fwrite($doc, "|:-----|:----:|\n"); + $children = $permission->getChildren(); + ksort($children, SORT_STRING); + foreach($children as $childName => $isGranted){ + fwrite($doc, "| `$childName` | " . ($isGranted ? "Granted" : "Denied") . " |\n"); + } + fwrite($doc, "\n"); +} + +fclose($doc); +echo "Done.\n"; From c70b80c2730233b0551c11e6bafb996b708302d0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 17 Oct 2021 22:37:49 +0100 Subject: [PATCH 129/710] ItemEntity: implement partial itemstack pickups in the dumbest way possible Given the various limitations and flexibilities posed by EntityItemPickupEvent, I settled on this as the simplest way to deal with the problem. - EntityItemPickupEvent may have its destination inventory changed, so we can't cache the result of getAddableItemQuantity() to use after the event. - The item itself may have changed, so even if we thought we could add some items before the change, we might not be able to afterwards. Considering the above facts, it's better to just give the whole itemstack to EntityItemPickupEvent, and let plugins use getAddableItemQuantity() on their own to decide if their chosen inventory can accommodate the item or not. If it can't, then we'll just drop it on the ground. This also fixes a potential issue where plugins changing the item to a custom one might end up with their items and the actual items both just vanishing if the target inventory was full. closes #4499 --- src/entity/object/ItemEntity.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/entity/object/ItemEntity.php b/src/entity/object/ItemEntity.php index 7de765e65..2b16b7a11 100644 --- a/src/entity/object/ItemEntity.php +++ b/src/entity/object/ItemEntity.php @@ -227,8 +227,8 @@ class ItemEntity extends Entity{ $item = $this->getItem(); $playerInventory = match(true){ - $player->getOffHandInventory()->getItem(0)->canStackWith($item) and $player->getOffHandInventory()->canAddItem($item) => $player->getOffHandInventory(), - $player->getInventory()->canAddItem($item) => $player->getInventory(), + $player->getOffHandInventory()->getItem(0)->canStackWith($item) and $player->getOffHandInventory()->getAddableItemQuantity($item) > 0 => $player->getOffHandInventory(), + $player->getInventory()->getAddableItemQuantity($item) > 0 => $player->getInventory(), default => null }; @@ -246,7 +246,12 @@ class ItemEntity extends Entity{ $viewer->getNetworkSession()->onPlayerPickUpItem($player, $this); } - $ev->getInventory()?->addItem($ev->getItem()); + $inventory = $ev->getInventory(); + if($inventory !== null){ + foreach($inventory->addItem($ev->getItem()) as $remains){ + $this->getWorld()->dropItem($this->location, $remains, new Vector3(0, 0, 0)); + } + } $this->flagForDespawn(); } } From 70636f6eb4a7c487e2f43ee9673b338bcc88b94d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 19 Oct 2021 18:00:34 +0100 Subject: [PATCH 130/710] Protocol changes for 1.17.40 --- .../network/mcpe/NetworkSession.php | 14 ++- .../network/mcpe/protocol/PacketPool.php | 4 +- ...JumpPacket.php => PassengerJumpPacket.php} | 8 +- .../network/mcpe/protocol/ProtocolInfo.php | 10 +- .../network/mcpe/protocol/SubChunkPacket.php | 109 ++++++++++++++++++ .../mcpe/protocol/SubChunkRequestPacket.php | 72 ++++++++++++ .../types/SubChunkPacketHeightMapInfo.php | 89 ++++++++++++++ .../types/SubChunkPacketHeightMapType.php | 32 +++++ .../protocol/types/SubChunkRequestResult.php | 34 ++++++ src/pocketmine/resources/vanilla | 2 +- 10 files changed, 362 insertions(+), 12 deletions(-) rename src/pocketmine/network/mcpe/protocol/{RiderJumpPacket.php => PassengerJumpPacket.php} (83%) create mode 100644 src/pocketmine/network/mcpe/protocol/SubChunkPacket.php create mode 100644 src/pocketmine/network/mcpe/protocol/SubChunkRequestPacket.php create mode 100644 src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapInfo.php create mode 100644 src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapType.php create mode 100644 src/pocketmine/network/mcpe/protocol/types/SubChunkRequestResult.php diff --git a/src/pocketmine/network/mcpe/NetworkSession.php b/src/pocketmine/network/mcpe/NetworkSession.php index c0584ddb4..f505e1ec1 100644 --- a/src/pocketmine/network/mcpe/NetworkSession.php +++ b/src/pocketmine/network/mcpe/NetworkSession.php @@ -116,6 +116,7 @@ use pocketmine\network\mcpe\protocol\NpcDialoguePacket; use pocketmine\network\mcpe\protocol\NpcRequestPacket; use pocketmine\network\mcpe\protocol\OnScreenTextureAnimationPacket; use pocketmine\network\mcpe\protocol\PacketViolationWarningPacket; +use pocketmine\network\mcpe\protocol\PassengerJumpPacket; use pocketmine\network\mcpe\protocol\PhotoInfoRequestPacket; use pocketmine\network\mcpe\protocol\PhotoTransferPacket; use pocketmine\network\mcpe\protocol\PlayerActionPacket; @@ -144,7 +145,6 @@ use pocketmine\network\mcpe\protocol\ResourcePackDataInfoPacket; use pocketmine\network\mcpe\protocol\ResourcePacksInfoPacket; use pocketmine\network\mcpe\protocol\ResourcePackStackPacket; use pocketmine\network\mcpe\protocol\RespawnPacket; -use pocketmine\network\mcpe\protocol\RiderJumpPacket; use pocketmine\network\mcpe\protocol\ScriptCustomEventPacket; use pocketmine\network\mcpe\protocol\ServerSettingsRequestPacket; use pocketmine\network\mcpe\protocol\ServerSettingsResponsePacket; @@ -178,6 +178,8 @@ use pocketmine\network\mcpe\protocol\StopSoundPacket; use pocketmine\network\mcpe\protocol\StructureBlockUpdatePacket; use pocketmine\network\mcpe\protocol\StructureTemplateDataRequestPacket; use pocketmine\network\mcpe\protocol\StructureTemplateDataResponsePacket; +use pocketmine\network\mcpe\protocol\SubChunkPacket; +use pocketmine\network\mcpe\protocol\SubChunkRequestPacket; use pocketmine\network\mcpe\protocol\SubClientLoginPacket; use pocketmine\network\mcpe\protocol\SyncActorPropertyPacket; use pocketmine\network\mcpe\protocol\TakeItemActorPacket; @@ -272,7 +274,7 @@ abstract class NetworkSession{ return false; } - public function handleRiderJump(RiderJumpPacket $packet) : bool{ + public function handlePassengerJump(PassengerJumpPacket $packet) : bool{ return false; } @@ -871,4 +873,12 @@ abstract class NetworkSession{ public function handlePhotoInfoRequest(PhotoInfoRequestPacket $packet) : bool{ return false; } + + public function handleSubChunk(SubChunkPacket $packet) : bool{ + return false; + } + + public function handleSubChunkRequest(SubChunkRequestPacket $packet) : bool{ + return false; + } } diff --git a/src/pocketmine/network/mcpe/protocol/PacketPool.php b/src/pocketmine/network/mcpe/protocol/PacketPool.php index 531db9052..0ea0ff53a 100644 --- a/src/pocketmine/network/mcpe/protocol/PacketPool.php +++ b/src/pocketmine/network/mcpe/protocol/PacketPool.php @@ -54,7 +54,7 @@ class PacketPool{ static::registerPacket(new TakeItemActorPacket()); static::registerPacket(new MoveActorAbsolutePacket()); static::registerPacket(new MovePlayerPacket()); - static::registerPacket(new RiderJumpPacket()); + static::registerPacket(new PassengerJumpPacket()); static::registerPacket(new UpdateBlockPacket()); static::registerPacket(new AddPaintingPacket()); static::registerPacket(new TickSyncPacket()); @@ -204,6 +204,8 @@ class PacketPool{ static::registerPacket(new CreatePhotoPacket()); static::registerPacket(new UpdateSubChunkBlocksPacket()); static::registerPacket(new PhotoInfoRequestPacket()); + static::registerPacket(new SubChunkPacket()); + static::registerPacket(new SubChunkRequestPacket()); } /** diff --git a/src/pocketmine/network/mcpe/protocol/RiderJumpPacket.php b/src/pocketmine/network/mcpe/protocol/PassengerJumpPacket.php similarity index 83% rename from src/pocketmine/network/mcpe/protocol/RiderJumpPacket.php rename to src/pocketmine/network/mcpe/protocol/PassengerJumpPacket.php index ba108848c..11b286c99 100644 --- a/src/pocketmine/network/mcpe/protocol/RiderJumpPacket.php +++ b/src/pocketmine/network/mcpe/protocol/PassengerJumpPacket.php @@ -27,8 +27,8 @@ namespace pocketmine\network\mcpe\protocol; use pocketmine\network\mcpe\NetworkSession; -class RiderJumpPacket extends DataPacket{ - public const NETWORK_ID = ProtocolInfo::RIDER_JUMP_PACKET; +class PassengerJumpPacket extends DataPacket{ + public const NETWORK_ID = ProtocolInfo::PASSENGER_JUMP_PACKET; /** @var int */ public $jumpStrength; //percentage @@ -41,7 +41,7 @@ class RiderJumpPacket extends DataPacket{ $this->putVarInt($this->jumpStrength); } - public function handle(NetworkSession $session) : bool{ - return $session->handleRiderJump($this); + public function handle(NetworkSession $handler) : bool{ + return $handler->handlePassengerJump($this); } } diff --git a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php index 7d1cbc077..94012727b 100644 --- a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php +++ b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php @@ -37,11 +37,11 @@ interface ProtocolInfo{ */ /** Actual Minecraft: PE protocol version */ - public const CURRENT_PROTOCOL = 465; + public const CURRENT_PROTOCOL = 471; /** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */ - public const MINECRAFT_VERSION = 'v1.17.30'; + public const MINECRAFT_VERSION = 'v1.17.40'; /** Version number sent to clients in ping responses. */ - public const MINECRAFT_VERSION_NETWORK = '1.17.30'; + public const MINECRAFT_VERSION_NETWORK = '1.17.40'; public const LOGIN_PACKET = 0x01; public const PLAY_STATUS_PACKET = 0x02; @@ -62,7 +62,7 @@ interface ProtocolInfo{ public const TAKE_ITEM_ACTOR_PACKET = 0x11; public const MOVE_ACTOR_ABSOLUTE_PACKET = 0x12; public const MOVE_PLAYER_PACKET = 0x13; - public const RIDER_JUMP_PACKET = 0x14; + public const PASSENGER_JUMP_PACKET = 0x14; public const UPDATE_BLOCK_PACKET = 0x15; public const ADD_PAINTING_PACKET = 0x16; public const TICK_SYNC_PACKET = 0x17; @@ -216,5 +216,7 @@ interface ProtocolInfo{ public const CREATE_PHOTO_PACKET = 0xab; public const UPDATE_SUB_CHUNK_BLOCKS_PACKET = 0xac; public const PHOTO_INFO_REQUEST_PACKET = 0xad; + public const SUB_CHUNK_PACKET = 0xae; + public const SUB_CHUNK_REQUEST_PACKET = 0xaf; } diff --git a/src/pocketmine/network/mcpe/protocol/SubChunkPacket.php b/src/pocketmine/network/mcpe/protocol/SubChunkPacket.php new file mode 100644 index 000000000..35d4be5f4 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/SubChunkPacket.php @@ -0,0 +1,109 @@ + + +use pocketmine\network\mcpe\NetworkSession; +use pocketmine\network\mcpe\protocol\types\SubChunkPacketHeightMapInfo; +use pocketmine\network\mcpe\protocol\types\SubChunkPacketHeightMapType; + +class SubChunkPacket extends DataPacket{ + public const NETWORK_ID = ProtocolInfo::SUB_CHUNK_PACKET; + + private int $dimension; + private int $subChunkX; + private int $subChunkY; + private int $subChunkZ; + private string $data; + private int $requestResult; + private ?SubChunkPacketHeightMapInfo $heightMapData = null; + + public static function create(int $dimension, int $subChunkX, int $subChunkY, int $subChunkZ, string $data, int $requestResult, ?SubChunkPacketHeightMapInfo $heightMapData) : self{ + $result = new self; + $result->dimension = $dimension; + $result->subChunkX = $subChunkX; + $result->subChunkY = $subChunkY; + $result->subChunkZ = $subChunkZ; + $result->data = $data; + $result->requestResult = $requestResult; + $result->heightMapData = $heightMapData; + return $result; + } + + public function getDimension() : int{ return $this->dimension; } + + public function getSubChunkX() : int{ return $this->subChunkX; } + + public function getSubChunkY() : int{ return $this->subChunkY; } + + public function getSubChunkZ() : int{ return $this->subChunkZ; } + + public function getData() : string{ return $this->data; } + + public function getRequestResult() : int{ return $this->requestResult; } + + public function getHeightMapData() : ?SubChunkPacketHeightMapInfo{ return $this->heightMapData; } + + protected function decodePayload() : void{ + $this->dimension = $this->getVarInt(); + $this->subChunkX = $this->getVarInt(); + $this->subChunkY = $this->getVarInt(); + $this->subChunkZ = $this->getVarInt(); + $this->data = $this->getString(); + $this->requestResult = $this->getVarInt(); + $heightMapDataType = $this->getByte(); + $this->heightMapData = match($heightMapDataType){ + SubChunkPacketHeightMapType::NO_DATA => null, + SubChunkPacketHeightMapType::DATA => SubChunkPacketHeightMapInfo::read($this), + SubChunkPacketHeightMapType::ALL_TOO_HIGH => SubChunkPacketHeightMapInfo::allTooHigh(), + SubChunkPacketHeightMapType::ALL_TOO_LOW => SubChunkPacketHeightMapInfo::allTooLow(), + default => throw new \UnexpectedValueException("Unknown heightmap data type $heightMapDataType") + }; + } + + protected function encodePayload() : void{ + $this->putVarInt($this->dimension); + $this->putVarInt($this->subChunkX); + $this->putVarInt($this->subChunkY); + $this->putVarInt($this->subChunkZ); + $this->putString($this->data); + $this->putVarInt($this->requestResult); + if($this->heightMapData === null){ + $this->putByte(SubChunkPacketHeightMapType::NO_DATA); + }elseif($this->heightMapData->isAllTooLow()){ + $this->putByte(SubChunkPacketHeightMapType::ALL_TOO_LOW); + }elseif($this->heightMapData->isAllTooHigh()){ + $this->putByte(SubChunkPacketHeightMapType::ALL_TOO_HIGH); + }else{ + $heightMapData = $this->heightMapData; //avoid PHPStan purity issue + $this->putByte(SubChunkPacketHeightMapType::DATA); + $heightMapData->write($this); + } + } + + public function handle(NetworkSession $handler) : bool{ + return $handler->handleSubChunk($this); + } +} diff --git a/src/pocketmine/network/mcpe/protocol/SubChunkRequestPacket.php b/src/pocketmine/network/mcpe/protocol/SubChunkRequestPacket.php new file mode 100644 index 000000000..cd3594576 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/SubChunkRequestPacket.php @@ -0,0 +1,72 @@ + + +use pocketmine\network\mcpe\NetworkSession; + +class SubChunkRequestPacket extends DataPacket/* implements ServerboundPacket*/{ + public const NETWORK_ID = ProtocolInfo::SUB_CHUNK_REQUEST_PACKET; + + private int $dimension; + private int $subChunkX; + private int $subChunkY; + private int $subChunkZ; + + public static function create(int $dimension, int $subChunkX, int $subChunkY, int $subChunkZ) : self{ + $result = new self; + $result->dimension = $dimension; + $result->subChunkX = $subChunkX; + $result->subChunkY = $subChunkY; + $result->subChunkZ = $subChunkZ; + return $result; + } + + public function getDimension() : int{ return $this->dimension; } + + public function getSubChunkX() : int{ return $this->subChunkX; } + + public function getSubChunkY() : int{ return $this->subChunkY; } + + public function getSubChunkZ() : int{ return $this->subChunkZ; } + + protected function decodePayload() : void{ + $this->dimension = $this->getVarInt(); + $this->subChunkX = $this->getVarInt(); + $this->subChunkY = $this->getVarInt(); + $this->subChunkZ = $this->getVarInt(); + } + + protected function encodePayload() : void{ + $this->putVarInt($this->dimension); + $this->putVarInt($this->subChunkX); + $this->putVarInt($this->subChunkY); + $this->putVarInt($this->subChunkZ); + } + + public function handle(NetworkSession $handler) : bool{ + return $handler->handleSubChunkRequest($this); + } +} diff --git a/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapInfo.php b/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapInfo.php new file mode 100644 index 000000000..d8934d744 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapInfo.php @@ -0,0 +1,89 @@ + $heights + */ + public function __construct(private array $heights){ + if(count($heights) !== 256){ + throw new \InvalidArgumentException("Expected exactly 256 heightmap values"); + } + } + + /** @return int[] */ + public function getHeights() : array{ return $this->heights; } + + public function getHeight(int $x, int $z) : int{ + return $this->heights[(($z & 0xf) << 4) | ($x & 0xf)]; + } + + public static function read(NetworkBinaryStream $in) : self{ + $heights = []; + for($i = 0; $i < 256; ++$i){ + $heights[] = Binary::signByte($in->getByte()); + } + return new self($heights); + } + + public function write(NetworkBinaryStream $out) : void{ + for($i = 0; $i < 256; ++$i){ + $out->putByte(Binary::unsignByte($this->heights[$i])); + } + } + + public static function allTooLow() : self{ + return new self(array_fill(0, 256, -1)); + } + + public static function allTooHigh() : self{ + return new self(array_fill(0, 256, 16)); + } + + public function isAllTooLow() : bool{ + foreach($this->heights as $height){ + if($height >= 0){ + return false; + } + } + return true; + } + + public function isAllTooHigh() : bool{ + foreach($this->heights as $height){ + if($height <= 15){ + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapType.php b/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapType.php new file mode 100644 index 000000000..7b1d4105d --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapType.php @@ -0,0 +1,32 @@ + Date: Tue, 19 Oct 2021 18:27:26 +0100 Subject: [PATCH 131/710] Release 3.25.0 --- changelogs/3.25.md | 11 +++++++++++ src/pocketmine/VersionInfo.php | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 changelogs/3.25.md diff --git a/changelogs/3.25.md b/changelogs/3.25.md new file mode 100644 index 000000000..8c66ff9f3 --- /dev/null +++ b/changelogs/3.25.md @@ -0,0 +1,11 @@ +**For Minecraft: Bedrock Edition 1.17.40** + +### Note about API versions +Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps. +Plugin developers should **only** update their required API to this version if you need the changes in this build. + +**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do. + +# 3.25.0 +- Added support for Minecraft: Bedrock Edition 1.17.40. +- Removed compatibility with earlier versions. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index a13e9cce1..268ca7749 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.24.1"; -const IS_DEVELOPMENT_BUILD = true; +const BASE_VERSION = "3.25.0"; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = ""; +const BUILD_CHANNEL = "stable"; From 9c5cec77b177318e3559d4a37cf0d6da84bd265b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 19 Oct 2021 18:27:30 +0100 Subject: [PATCH 132/710] 3.25.1 is next --- src/pocketmine/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 268ca7749..82af4e6ce 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.25.0"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.25.1"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = "stable"; +const BUILD_CHANNEL = ""; From fee6478cbeed78e9c5aa010c39d6d3e48744885d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 19 Oct 2021 19:00:29 +0100 Subject: [PATCH 133/710] Updated BedrockData and BedrockProtocol for 1.17.40 support --- composer.json | 2 +- composer.lock | 16 ++++++++-------- resources/vanilla | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 167149a72..da7c87f62 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "adhocore/json-comment": "^1.1", "fgrosse/phpasn1": "^2.3", "netresearch/jsonmapper": "^4.0", - "pocketmine/bedrock-protocol": "2.0.0+bedrock1.17.30", + "pocketmine/bedrock-protocol": "3.0.0+bedrock1.17.40", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "dev-master", diff --git a/composer.lock b/composer.lock index fe195368c..3aa90d53b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "39ec9b1c108888c32a660f3bc2c400c4", + "content-hash": "ddffa959e1045fc084bb9142884f27a3", "packages": [ { "name": "adhocore/json-comment", @@ -249,22 +249,22 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "2.0.0+bedrock1.17.30", + "version": "3.0.0+bedrock1.17.40", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "faff7da904e68f69b1a9128956dac3122e87308a" + "reference": "ea9e22563b3d56f3b94b4a132c725912d029c101" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/faff7da904e68f69b1a9128956dac3122e87308a", - "reference": "faff7da904e68f69b1a9128956dac3122e87308a", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/ea9e22563b3d56f3b94b4a132c725912d029c101", + "reference": "ea9e22563b3d56f3b94b4a132c725912d029c101", "shasum": "" }, "require": { "ext-json": "*", "netresearch/jsonmapper": "^4.0", - "php": "^7.4 || ^8.0", + "php": "^8.0", "pocketmine/binaryutils": "^0.2.0", "pocketmine/color": "^0.2.0", "pocketmine/math": "^0.3.0", @@ -290,9 +290,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/bedrock-1.17.30" + "source": "https://github.com/pmmp/BedrockProtocol/tree/bedrock-1.17.40" }, - "time": "2021-09-21T23:25:51+00:00" + "time": "2021-10-19T17:28:41+00:00" }, { "name": "pocketmine/binaryutils", diff --git a/resources/vanilla b/resources/vanilla index 19569dd72..f29b7be8f 160000 --- a/resources/vanilla +++ b/resources/vanilla @@ -1 +1 @@ -Subproject commit 19569dd729970e161a24b574b41c06a5e064ab81 +Subproject commit f29b7be8fa3046d2ee4c6421485b97b3f5b07774 From 46920818b5de1632991c29620b4822fd87f7946b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 19 Oct 2021 19:13:43 +0100 Subject: [PATCH 134/710] Release 4.0.0-BETA6 --- changelogs/4.0.md | 17 +++++++++++++++++ src/VersionInfo.php | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 70add2c99..708822771 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1443,3 +1443,20 @@ Released 12th October 2021. ### World - The following API methods have signature changes: - `GeneratorManager->registerGenerator()` now requires a `\Closure $presetValidator` parameter. This is used to check generator options of worlds and configs before attempting to use them. + +# 4.0.0-BETA6 +Released 19th October 2021. + +## General +- Added support for Minecraft: Bedrock Edition 1.17.40. +- Removed support for earlier versions. +- CTRL+C signal handling has been restored, and is now supported on Windows. Pressing CTRL+C while the server is running will behave as if the `/stop` command was invoked. +- Added a script `tools/generate-permission-doc.php` to generate a Markdown file with a list of all permissions and their relationships. In the future, this will be used to maintain the official documentation, but plugin developers might find it useful for their own purposes too. +- [`respect/validation`](https://packagist.org/packages/respect/validation) is no longer a core dependency. + +## Fixes +- Fixed server crash when using `/give` to give an item with a too-large item ID, or `/clear` to clear an item that does not exist. + - Now, `LegacyStringToItemParser` is used exclusively, and numeric IDs are no longer parsed. + +## Gameplay +- Picking up some items from a dropped stack of items is now supported. This fixes various bugs with being unable to pick up items with an almost-full inventory. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 9bae4e775..c313f1193 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,9 +30,9 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA6"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; - public const BUILD_CHANNEL = ""; + public const BUILD_CHANNEL = "beta"; private function __construct(){ //NOOP From a3f8546ac442d6bbb44dfedc19eb6d3e639a50b6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 19 Oct 2021 19:13:43 +0100 Subject: [PATCH 135/710] 4.0.0-BETA7 is next --- src/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index c313f1193..701598a17 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,10 +29,10 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA6"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA7"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; - public const BUILD_CHANNEL = "beta"; + public const BUILD_CHANNEL = ""; private function __construct(){ //NOOP From 80b402e529fe3d47735aeb75676d5313ae453a20 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 14:01:39 +0100 Subject: [PATCH 136/710] ItemTranslator: throw the proper exceptions when failing to map network IDs --- src/network/mcpe/convert/ItemTranslator.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index 0302a6898..c7cba0226 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -175,11 +175,12 @@ final class ItemTranslator{ /** * @return int[] * @phpstan-return array{int, int} + * @throws TypeConversionException */ public function fromNetworkId(int $networkId, int $networkMeta, ?bool &$isComplexMapping = null) : array{ if(isset($this->complexNetToCoreMapping[$networkId])){ if($networkMeta !== 0){ - throw new \UnexpectedValueException("Unexpected non-zero network meta on complex item mapping"); + throw new TypeConversionException("Unexpected non-zero network meta on complex item mapping"); } $isComplexMapping = true; return $this->complexNetToCoreMapping[$networkId]; @@ -188,12 +189,13 @@ final class ItemTranslator{ if(isset($this->simpleNetToCoreMapping[$networkId])){ return [$this->simpleNetToCoreMapping[$networkId], $networkMeta]; } - throw new \UnexpectedValueException("Unmapped network ID/metadata combination $networkId:$networkMeta"); + throw new TypeConversionException("Unmapped network ID/metadata combination $networkId:$networkMeta"); } /** * @return int[] * @phpstan-return array{int, int} + * @throws TypeConversionException */ public function fromNetworkIdWithWildcardHandling(int $networkId, int $networkMeta) : array{ $isComplexMapping = false; From 09c840b66a6c6d35be4a2dcd1eec3c6d105132ae Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 16:19:20 +0100 Subject: [PATCH 137/710] Update transient composer dependencies --- composer.lock | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/composer.lock b/composer.lock index 3aa90d53b..95ceaa103 100644 --- a/composer.lock +++ b/composer.lock @@ -1711,16 +1711,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", "shasum": "" }, "require": { @@ -1731,7 +1731,8 @@ "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2" + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -1761,9 +1762,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" }, - "time": "2020-09-03T19:13:55+00:00" + "time": "2021-10-19T17:43:47+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -3324,6 +3325,7 @@ "type": "github" } ], + "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { From ec3986827c87f244e55ff7497d0c86a5b4f92f49 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 16:20:10 +0100 Subject: [PATCH 138/710] Update BedrockProtocol to 3.0.1, widen constraint to allow newer patch versions --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index da7c87f62..4a01020a7 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "adhocore/json-comment": "^1.1", "fgrosse/phpasn1": "^2.3", "netresearch/jsonmapper": "^4.0", - "pocketmine/bedrock-protocol": "3.0.0+bedrock1.17.40", + "pocketmine/bedrock-protocol": "^3.0.1+bedrock1.17.40", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "dev-master", diff --git a/composer.lock b/composer.lock index 95ceaa103..cb1287b83 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ddffa959e1045fc084bb9142884f27a3", + "content-hash": "bc2b425a6f436a01de4e423ea651dc84", "packages": [ { "name": "adhocore/json-comment", @@ -249,16 +249,16 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "3.0.0+bedrock1.17.40", + "version": "3.0.1+bedrock1.17.40", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "ea9e22563b3d56f3b94b4a132c725912d029c101" + "reference": "1add11e06366b983b97fa415fee55f31af3cb7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/ea9e22563b3d56f3b94b4a132c725912d029c101", - "reference": "ea9e22563b3d56f3b94b4a132c725912d029c101", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/1add11e06366b983b97fa415fee55f31af3cb7a9", + "reference": "1add11e06366b983b97fa415fee55f31af3cb7a9", "shasum": "" }, "require": { @@ -290,9 +290,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/bedrock-1.17.40" + "source": "https://github.com/pmmp/BedrockProtocol/tree/3.0.1+bedrock1.17.40" }, - "time": "2021-10-19T17:28:41+00:00" + "time": "2021-10-20T14:00:00+00:00" }, { "name": "pocketmine/binaryutils", From dc07ac33d33cf3a87b49ccf7983a9c0fb44db479 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 19:47:32 +0100 Subject: [PATCH 139/710] protocol: fixed missing field of CraftRecipeAuto --- .../CraftRecipeAutoStackRequestAction.php | 28 ++++++++++- .../CraftRecipeStackRequestAction.php | 21 ++++++++- .../CraftRecipeStackRequestActionTrait.php | 47 ------------------- 3 files changed, 47 insertions(+), 49 deletions(-) delete mode 100644 src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeStackRequestActionTrait.php diff --git a/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeAutoStackRequestAction.php b/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeAutoStackRequestAction.php index d5f10ee1f..e146afec0 100644 --- a/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeAutoStackRequestAction.php +++ b/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeAutoStackRequestAction.php @@ -23,12 +23,38 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest; +use pocketmine\network\mcpe\NetworkBinaryStream; + /** * Tells that the current transaction crafted the specified recipe, using the recipe book. This is effectively the same * as the regular crafting result action. */ final class CraftRecipeAutoStackRequestAction extends ItemStackRequestAction{ - use CraftRecipeStackRequestActionTrait; + + /** @var int */ + private $recipeId; + /** @var int */ + private $repetitions; + + final public function __construct(int $recipeId, int $repetitions){ + $this->recipeId = $recipeId; + $this->repetitions = $repetitions; + } + + public function getRecipeId() : int{ return $this->recipeId; } + + public function getRepetitions() : int{ return $this->repetitions; } public static function getTypeId() : int{ return ItemStackRequestActionType::CRAFTING_RECIPE_AUTO; } + + public static function read(NetworkBinaryStream $in) : self{ + $recipeId = $in->readGenericTypeNetworkId(); + $repetitions = $in->getByte(); + return new self($recipeId, $repetitions); + } + + public function write(NetworkBinaryStream $out) : void{ + $out->writeGenericTypeNetworkId($this->recipeId); + $out->putByte($this->repetitions); + } } diff --git a/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeStackRequestAction.php b/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeStackRequestAction.php index 6341aecc5..0a79642de 100644 --- a/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeStackRequestAction.php +++ b/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeStackRequestAction.php @@ -23,11 +23,30 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest; +use pocketmine\network\mcpe\NetworkBinaryStream; + /** * Tells that the current transaction crafted the specified recipe. */ final class CraftRecipeStackRequestAction extends ItemStackRequestAction{ - use CraftRecipeStackRequestActionTrait; + + /** @var int */ + private $recipeId; + + final public function __construct(int $recipeId){ + $this->recipeId = $recipeId; + } + + public function getRecipeId() : int{ return $this->recipeId; } public static function getTypeId() : int{ return ItemStackRequestActionType::CRAFTING_RECIPE; } + + public static function read(NetworkBinaryStream $in) : self{ + $recipeId = $in->readGenericTypeNetworkId(); + return new self($recipeId); + } + + public function write(NetworkBinaryStream $out) : void{ + $out->writeGenericTypeNetworkId($this->recipeId); + } } diff --git a/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeStackRequestActionTrait.php b/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeStackRequestActionTrait.php deleted file mode 100644 index 3690562cd..000000000 --- a/src/pocketmine/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeStackRequestActionTrait.php +++ /dev/null @@ -1,47 +0,0 @@ -recipeId = $recipeId; - } - - public function getRecipeId() : int{ return $this->recipeId; } - - public static function read(NetworkBinaryStream $in) : self{ - $recipeId = $in->readGenericTypeNetworkId(); - return new self($recipeId); - } - - public function write(NetworkBinaryStream $out) : void{ - $out->writeGenericTypeNetworkId($this->recipeId); - } -} From a7889545517a85e38574651d5ca0cdbb74268c91 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Wed, 20 Oct 2021 20:22:00 +0100 Subject: [PATCH 140/710] Fixed dependency handling across plugin loaders (#3971) --- src/plugin/PluginLoadTriage.php | 42 ++++++++ src/plugin/PluginManager.php | 165 +++++++++++++++++++++----------- tests/plugins/DevTools | 2 +- 3 files changed, 150 insertions(+), 59 deletions(-) create mode 100644 src/plugin/PluginLoadTriage.php diff --git a/src/plugin/PluginLoadTriage.php b/src/plugin/PluginLoadTriage.php new file mode 100644 index 000000000..c9c4fff77 --- /dev/null +++ b/src/plugin/PluginLoadTriage.php @@ -0,0 +1,42 @@ + + */ + public $plugins = []; + /** + * @var string[][] + * @phpstan-var array> + */ + public $dependencies = []; + /** + * @var string[][] + * @phpstan-var array> + */ + public $softDependencies = []; +} diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 3fceaa710..ae73c009f 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -44,7 +44,10 @@ use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Utils; use pocketmine\utils\VersionString; use Webmozart\PathUtil\Path; +use function array_diff_assoc; use function array_intersect; +use function array_key_exists; +use function array_keys; use function array_merge; use function class_exists; use function count; @@ -265,18 +268,12 @@ class PluginManager{ /** * @param string[]|null $newLoaders * @phpstan-param list> $newLoaders - * - * @return Plugin[] */ - public function loadPlugins(string $directory, ?array $newLoaders = null) : array{ + private function triagePlugins(string $directory, PluginLoadTriage $triage, ?array $newLoaders = null) : void{ if(!is_dir($directory)){ - return []; + return; } - $plugins = []; - $loadedPlugins = []; - $dependencies = []; - $softDependencies = []; if(is_array($newLoaders)){ $loaders = []; foreach($newLoaders as $key){ @@ -320,7 +317,7 @@ class PluginManager{ continue; } - if(isset($plugins[$name]) or $this->getPlugin($name) instanceof Plugin){ + if(isset($triage->plugins[$name]) or $this->getPlugin($name) instanceof Plugin){ $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_duplicateError($name))); continue; } @@ -336,77 +333,129 @@ class PluginManager{ ))); continue; } - $plugins[$name] = new PluginLoadTriageEntry($file, $loader, $description); - $softDependencies[$name] = array_merge($softDependencies[$name] ?? [], $description->getSoftDepend()); - $dependencies[$name] = $description->getDepend(); + $triage->plugins[$name] = new PluginLoadTriageEntry($file, $loader, $description); + + $triage->softDependencies[$name] = array_merge($triage->softDependencies[$name] ?? [], $description->getSoftDepend()); + $triage->dependencies[$name] = $description->getDepend(); foreach($description->getLoadBefore() as $before){ - if(isset($softDependencies[$before])){ - $softDependencies[$before][] = $name; + if(isset($triage->softDependencies[$before])){ + $triage->softDependencies[$before][] = $name; }else{ - $softDependencies[$before] = [$name]; + $triage->softDependencies[$before] = [$name]; } } } } + } - while(count($plugins) > 0){ + /** + * @param string[][] $dependencyLists + * @param Plugin[] $loadedPlugins + */ + private function checkDepsForTriage(string $pluginName, string $dependencyType, array &$dependencyLists, array $loadedPlugins, PluginLoadTriage $triage) : void{ + if(isset($dependencyLists[$pluginName])){ + foreach($dependencyLists[$pluginName] as $key => $dependency){ + if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ + $this->server->getLogger()->debug("Successfully resolved $dependencyType dependency \"$dependency\" for plugin \"$pluginName\""); + unset($dependencyLists[$pluginName][$key]); + }elseif(array_key_exists($dependency, $triage->plugins)){ + $this->server->getLogger()->debug("Deferring resolution of $dependencyType dependency \"$dependency\" for plugin \"$pluginName\" (found but not loaded yet)"); + } + } + + if(count($dependencyLists[$pluginName]) === 0){ + unset($dependencyLists[$pluginName]); + } + } + } + + /** + * @return Plugin[] + */ + public function loadPlugins(string $directory) : array{ + $triage = new PluginLoadTriage(); + $this->triagePlugins($directory, $triage); + + $loadedPlugins = []; + + while(count($triage->plugins) > 0){ $loadedThisLoop = 0; - foreach($plugins as $name => $entry){ - if(isset($dependencies[$name])){ - foreach($dependencies[$name] as $key => $dependency){ - if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ - unset($dependencies[$name][$key]); - }elseif(!isset($plugins[$dependency])){ - $this->server->getLogger()->critical($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( - $name, - KnownTranslationFactory::pocketmine_plugin_unknownDependency($dependency) - ))); - unset($plugins[$name]); - continue 2; - } - } + foreach($triage->plugins as $name => $entry){ + $this->checkDepsForTriage($name, "hard", $triage->dependencies, $loadedPlugins, $triage); + $this->checkDepsForTriage($name, "soft", $triage->softDependencies, $loadedPlugins, $triage); - if(count($dependencies[$name]) === 0){ - unset($dependencies[$name]); - } - } - - 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)"); - } - } - - if(count($softDependencies[$name]) === 0){ - unset($softDependencies[$name]); - } - } - - if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){ - unset($plugins[$name]); + if(!isset($triage->dependencies[$name]) and !isset($triage->softDependencies[$name])){ + unset($triage->plugins[$name]); $loadedThisLoop++; + + $oldRegisteredLoaders = $this->fileAssociations; if(($plugin = $this->internalLoadPlugin($entry->getFile(), $entry->getLoader(), $entry->getDescription())) instanceof Plugin){ $loadedPlugins[$name] = $plugin; + $diffLoaders = []; + foreach($this->fileAssociations as $k => $loader){ + if(!array_key_exists($k, $oldRegisteredLoaders)){ + $diffLoaders[] = $k; + } + } + if(count($diffLoaders) !== 0){ + $this->server->getLogger()->debug("Plugin $name registered a new plugin loader during load, scanning for new plugins"); + $plugins = $triage->plugins; + $this->triagePlugins($directory, $triage, $diffLoaders); + $diffPlugins = array_diff_assoc($triage->plugins, $plugins); + $this->server->getLogger()->debug("Re-triage found plugins: " . implode(", ", array_keys($diffPlugins))); + } } } } if($loadedThisLoop === 0){ //No plugins loaded :( - foreach($plugins as $name => $file){ + + //check for skippable soft dependencies first, in case the dependents could resolve hard dependencies + foreach($triage->plugins as $name => $file){ + if(isset($triage->softDependencies[$name]) && !isset($triage->dependencies[$name])){ + foreach($triage->softDependencies[$name] as $k => $dependency){ + if($this->getPlugin($dependency) === null && !array_key_exists($dependency, $triage->plugins)){ + $this->server->getLogger()->debug("Skipping resolution of missing soft dependency \"$dependency\" for plugin \"$name\""); + unset($triage->softDependencies[$name][$k]); + } + } + if(count($triage->softDependencies[$name]) === 0){ + unset($triage->softDependencies[$name]); + continue 2; //go back to the top and try again + } + } + } + + foreach($triage->plugins as $name => $file){ + if(isset($triage->dependencies[$name])){ + $unknownDependencies = []; + + foreach($triage->dependencies[$name] as $k => $dependency){ + if($this->getPlugin($dependency) === null && !array_key_exists($dependency, $triage->plugins)){ + //assume that the plugin is never going to be loaded + //by this point all soft dependencies have been ignored if they were able to be, so + //there's no chance of this dependency ever being resolved + $unknownDependencies[$dependency] = $dependency; + } + } + + if(count($unknownDependencies) > 0){ + $this->server->getLogger()->critical($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( + $name, + KnownTranslationFactory::pocketmine_plugin_unknownDependency(implode(", ", $unknownDependencies)) + ))); + unset($triage->plugins[$name]); + } + } + } + + foreach($triage->plugins as $name => $file){ $this->server->getLogger()->critical($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError($name, KnownTranslationFactory::pocketmine_plugin_circularDependency()))); } - $plugins = []; + break; } } diff --git a/tests/plugins/DevTools b/tests/plugins/DevTools index dfbea943e..db184c256 160000 --- a/tests/plugins/DevTools +++ b/tests/plugins/DevTools @@ -1 +1 @@ -Subproject commit dfbea943e1c64094358acac56013b89065884657 +Subproject commit db184c25636b1f984c6539fd4b1729b0b64b35d6 From 9646128d0176240c818dcefa57d39fb46af0de07 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 21:22:56 +0100 Subject: [PATCH 141/710] Updated resources/locale submodule to pmmp/Language@09c709f2426cb8d21d2a4851ad6df5a254a40fd4 --- resources/locale | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/locale b/resources/locale index 17fc6a105..09c709f24 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit 17fc6a10501c2cd48ec08f81ab41a640864f8d1d +Subproject commit 09c709f2426cb8d21d2a4851ad6df5a254a40fd4 From 03fcd844ebb8d563a54759ca6890ae694afd0e8a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 21:36:14 +0100 Subject: [PATCH 142/710] PluginManager::loadPlugins() now accepts files as well as directories loadPlugins() is now a superior option to loadPlugin(), since it enforces dependency checks and also supports automatic loading of plugins when new loaders are installed. --- src/plugin/PluginManager.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index ae73c009f..d39ee8335 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -269,11 +269,7 @@ class PluginManager{ * @param string[]|null $newLoaders * @phpstan-param list> $newLoaders */ - private function triagePlugins(string $directory, PluginLoadTriage $triage, ?array $newLoaders = null) : void{ - if(!is_dir($directory)){ - return; - } - + private function triagePlugins(string $path, PluginLoadTriage $triage, ?array $newLoaders = null) : void{ if(is_array($newLoaders)){ $loaders = []; foreach($newLoaders as $key){ @@ -285,8 +281,16 @@ class PluginManager{ $loaders = $this->fileAssociations; } - $files = iterator_to_array(new \FilesystemIterator($directory, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS)); - shuffle($files); //this prevents plugins implicitly relying on the filesystem name order when they should be using dependency properties + if(is_dir($path)){ + $files = iterator_to_array(new \FilesystemIterator($path, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS)); + shuffle($files); //this prevents plugins implicitly relying on the filesystem name order when they should be using dependency properties + }elseif(is_file($path)){ + $realPath = realpath($path); + if($realPath === false) throw new AssumptionFailedError("realpath() should not return false on an accessible, existing file"); + $files = [$realPath]; + }else{ + return; + } foreach($loaders as $loader){ foreach($files as $file){ if(!is_string($file)) throw new AssumptionFailedError("FilesystemIterator current should be string when using CURRENT_AS_PATHNAME"); @@ -374,9 +378,9 @@ class PluginManager{ /** * @return Plugin[] */ - public function loadPlugins(string $directory) : array{ + public function loadPlugins(string $path) : array{ $triage = new PluginLoadTriage(); - $this->triagePlugins($directory, $triage); + $this->triagePlugins($path, $triage); $loadedPlugins = []; @@ -402,7 +406,7 @@ class PluginManager{ if(count($diffLoaders) !== 0){ $this->server->getLogger()->debug("Plugin $name registered a new plugin loader during load, scanning for new plugins"); $plugins = $triage->plugins; - $this->triagePlugins($directory, $triage, $diffLoaders); + $this->triagePlugins($path, $triage, $diffLoaders); $diffPlugins = array_diff_assoc($triage->plugins, $plugins); $this->server->getLogger()->debug("Re-triage found plugins: " . implode(", ", array_keys($diffPlugins))); } From 76b4b23d98d5b17f09f6a918097fbb8ca8020099 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 21:52:19 +0100 Subject: [PATCH 143/710] PluginManager: remove loadPlugin() loadPlugins() is now the preferred option, since it does all the proper checks. In addition, the server now acknowledges that loading a single plugin may cause multiple plugins to be loaded, so returning only a single Plugin is not representative of what's actually happening. --- src/plugin/PluginManager.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index d39ee8335..fc560bf95 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -175,22 +175,6 @@ class PluginManager{ return null; } - /** - * @param PluginLoader[] $loaders - */ - public function loadPlugin(string $path, ?array $loaders = null) : ?Plugin{ - foreach($loaders ?? $this->fileAssociations as $loader){ - if($loader->canLoadPlugin($path)){ - $description = $loader->getPluginDescription($path); - if($description instanceof PluginDescription){ - $this->internalLoadPlugin($path, $loader, $description); - } - } - } - - return null; - } - private function internalLoadPlugin(string $path, PluginLoader $loader, PluginDescription $description) : ?Plugin{ $language = $this->server->getLanguage(); $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName()))); From 6d78a0b435ff0fc807a9d1e2bcdff2a2e72ac330 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 21:52:42 +0100 Subject: [PATCH 144/710] CS --- src/plugin/PluginManager.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index fc560bf95..8dc2b1092 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -59,10 +59,12 @@ use function in_array; use function is_a; use function is_array; use function is_dir; +use function is_file; use function is_string; use function is_subclass_of; use function iterator_to_array; use function mkdir; +use function realpath; use function shuffle; use function sprintf; use function stripos; From aa408c9a97ae737c6f98601106c09133b5047f15 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 21:54:57 +0100 Subject: [PATCH 145/710] Fixed 9646128d0176240c818dcefa57d39fb46af0de07 --- src/lang/KnownTranslationFactory.php | 4 ++++ src/lang/KnownTranslationKeys.php | 1 + 2 files changed, 5 insertions(+) diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index ce4f33c2b..a08e87f5c 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -2075,6 +2075,10 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::POTION_SATURATION, []); } + public static function potion_slowFalling() : Translatable{ + return new Translatable(KnownTranslationKeys::POTION_SLOWFALLING, []); + } + public static function potion_waterBreathing() : Translatable{ return new Translatable(KnownTranslationKeys::POTION_WATERBREATHING, []); } diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 16f4d26f4..cf4aca555 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -430,6 +430,7 @@ final class KnownTranslationKeys{ public const POTION_REGENERATION = "potion.regeneration"; public const POTION_RESISTANCE = "potion.resistance"; public const POTION_SATURATION = "potion.saturation"; + public const POTION_SLOWFALLING = "potion.slowFalling"; public const POTION_WATERBREATHING = "potion.waterBreathing"; public const POTION_WEAKNESS = "potion.weakness"; public const POTION_WITHER = "potion.wither"; From 44508a138f8ce7e0459571bc1a4249dde951bf1b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 22:13:30 +0100 Subject: [PATCH 146/710] Moved plugin extension requirement checks to PluginManager::checkPluginLoadability() these don't really belong in PluginDescription. --- src/plugin/PluginDescription.php | 38 -------------------------------- src/plugin/PluginManager.php | 35 ++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 43 deletions(-) diff --git a/src/plugin/PluginDescription.php b/src/plugin/PluginDescription.php index 895097cb5..c1ab144fe 100644 --- a/src/plugin/PluginDescription.php +++ b/src/plugin/PluginDescription.php @@ -30,13 +30,9 @@ use function array_map; use function array_values; use function is_array; use function is_string; -use function phpversion; use function preg_match; use function str_replace; use function stripos; -use function strlen; -use function substr; -use function version_compare; use function yaml_parse; class PluginDescription{ @@ -247,40 +243,6 @@ class PluginDescription{ return $this->extensions; } - /** - * Checks if the current PHP runtime has the extensions required by the plugin. - * - * @throws PluginException if there are required extensions missing or have incompatible version, or if the version constraint cannot be parsed - */ - public function checkRequiredExtensions() : void{ - foreach($this->extensions as $name => $versionConstrs){ - $gotVersion = phpversion($name); - if($gotVersion === false){ - throw new PluginException("Required extension $name not loaded"); - } - - foreach($versionConstrs as $constr){ // versionConstrs_loop - if($constr === "*"){ - continue; - } - if($constr === ""){ - throw new PluginException("One of the extension version constraints of $name is empty. Consider quoting the version string in plugin.yml"); - } - foreach(["<=", "le", "<>", "!=", "ne", "<", "lt", "==", "=", "eq", ">=", "ge", ">", "gt"] as $comparator){ - // warning: the > character should be quoted in YAML - if(substr($constr, 0, strlen($comparator)) === $comparator){ - $version = substr($constr, strlen($comparator)); - if(!version_compare($gotVersion, $version, $comparator)){ - throw new PluginException("Required extension $name has an incompatible version ($gotVersion not $constr)"); - } - continue 2; // versionConstrs_loop - } - } - throw new PluginException("Error parsing version constraint: $constr"); - } - } - } - /** * @return string[] */ diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 8dc2b1092..88e2d08b7 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -64,12 +64,16 @@ use function is_string; use function is_subclass_of; use function iterator_to_array; use function mkdir; +use function phpversion; use function realpath; use function shuffle; use function sprintf; use function stripos; +use function strlen; use function strpos; use function strtolower; +use function substr; +use function version_compare; /** * Manages all the plugins @@ -136,7 +140,7 @@ class PluginManager{ return Path::join(dirname($pluginPath), $pluginName); } - private function checkPluginLoadability(PluginDescription $description) : Translatable|string|null{ + private function checkPluginLoadability(PluginDescription $description) : Translatable|null{ $name = $description->getName(); if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){ return KnownTranslationFactory::pocketmine_plugin_restrictedName(); @@ -168,10 +172,31 @@ class PluginManager{ } } - try{ - $description->checkRequiredExtensions(); - }catch(PluginException $ex){ - return $ex->getMessage(); + foreach($description->getRequiredExtensions() as $extensionName => $versionConstrs){ + $gotVersion = phpversion($extensionName); + if($gotVersion === false){ + return KnownTranslationFactory::pocketmine_plugin_extensionNotLoaded($extensionName); + } + + foreach($versionConstrs as $k => $constr){ // versionConstrs_loop + if($constr === "*"){ + continue; + } + if($constr === ""){ + return KnownTranslationFactory::pocketmine_plugin_emptyExtensionVersionConstraint(extensionName: $extensionName, constraintIndex: "$k"); + } + foreach(["<=", "le", "<>", "!=", "ne", "<", "lt", "==", "=", "eq", ">=", "ge", ">", "gt"] as $comparator){ + // warning: the > character should be quoted in YAML + if(substr($constr, 0, strlen($comparator)) === $comparator){ + $version = substr($constr, strlen($comparator)); + if(!version_compare($gotVersion, $version, $comparator)){ + return KnownTranslationFactory::pocketmine_plugin_incompatibleExtensionVersion(extensionName: $extensionName, extensionVersion: $gotVersion, pluginRequirement: $constr); + } + continue 2; // versionConstrs_loop + } + } + return KnownTranslationFactory::pocketmine_plugin_invalidExtensionVersionConstraint(extensionName: $extensionName, versionConstraint: $constr); + } } return null; From 620874d902e91dca93f0ac5fbda83067a96e1e83 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 22:31:56 +0100 Subject: [PATCH 147/710] PluginManager: Extract checkPluginLoadability() to a PluginLoadabilityChecker unit this can be more easily unit-tested. --- src/plugin/PluginLoadabilityChecker.php | 108 ++++++++++++++++++++++++ src/plugin/PluginManager.php | 76 +---------------- 2 files changed, 111 insertions(+), 73 deletions(-) create mode 100644 src/plugin/PluginLoadabilityChecker.php diff --git a/src/plugin/PluginLoadabilityChecker.php b/src/plugin/PluginLoadabilityChecker.php new file mode 100644 index 000000000..9d3ca0387 --- /dev/null +++ b/src/plugin/PluginLoadabilityChecker.php @@ -0,0 +1,108 @@ +getName(); + if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){ + return KnownTranslationFactory::pocketmine_plugin_restrictedName(); + } + + foreach($description->getCompatibleApis() as $api){ + if(!VersionString::isValidBaseVersion($api)){ + return KnownTranslationFactory::pocketmine_plugin_invalidAPI($api); + } + } + + if(!ApiVersion::isCompatible($this->apiVersion, $description->getCompatibleApis())){ + return KnownTranslationFactory::pocketmine_plugin_incompatibleAPI(implode(", ", $description->getCompatibleApis())); + } + + $ambiguousVersions = ApiVersion::checkAmbiguousVersions($description->getCompatibleApis()); + if(count($ambiguousVersions) > 0){ + return KnownTranslationFactory::pocketmine_plugin_ambiguousMinAPI(implode(", ", $ambiguousVersions)); + } + + if(count($description->getCompatibleOperatingSystems()) > 0 and !in_array(Utils::getOS(), $description->getCompatibleOperatingSystems(), true)) { + return KnownTranslationFactory::pocketmine_plugin_incompatibleOS(implode(", ", $description->getCompatibleOperatingSystems())); + } + + if(count($pluginMcpeProtocols = $description->getCompatibleMcpeProtocols()) > 0){ + $serverMcpeProtocols = [ProtocolInfo::CURRENT_PROTOCOL]; + if(count(array_intersect($pluginMcpeProtocols, $serverMcpeProtocols)) === 0){ + return KnownTranslationFactory::pocketmine_plugin_incompatibleProtocol(implode(", ", $pluginMcpeProtocols)); + } + } + + foreach($description->getRequiredExtensions() as $extensionName => $versionConstrs){ + $gotVersion = phpversion($extensionName); + if($gotVersion === false){ + return KnownTranslationFactory::pocketmine_plugin_extensionNotLoaded($extensionName); + } + + foreach($versionConstrs as $k => $constr){ // versionConstrs_loop + if($constr === "*"){ + continue; + } + if($constr === ""){ + return KnownTranslationFactory::pocketmine_plugin_emptyExtensionVersionConstraint(extensionName: $extensionName, constraintIndex: "$k"); + } + foreach(["<=", "le", "<>", "!=", "ne", "<", "lt", "==", "=", "eq", ">=", "ge", ">", "gt"] as $comparator){ + // warning: the > character should be quoted in YAML + if(substr($constr, 0, strlen($comparator)) === $comparator){ + $version = substr($constr, strlen($comparator)); + if(!version_compare($gotVersion, $version, $comparator)){ + return KnownTranslationFactory::pocketmine_plugin_incompatibleExtensionVersion(extensionName: $extensionName, extensionVersion: $gotVersion, pluginRequirement: $constr); + } + continue 2; // versionConstrs_loop + } + } + return KnownTranslationFactory::pocketmine_plugin_invalidExtensionVersionConstraint(extensionName: $extensionName, versionConstraint: $constr); + } + } + + return null; + } +} \ No newline at end of file diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 88e2d08b7..f24488878 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -33,8 +33,6 @@ use pocketmine\event\plugin\PluginDisableEvent; use pocketmine\event\plugin\PluginEnableEvent; use pocketmine\event\RegisteredListener; use pocketmine\lang\KnownTranslationFactory; -use pocketmine\lang\Translatable; -use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\permission\DefaultPermissions; use pocketmine\permission\PermissionManager; use pocketmine\permission\PermissionParser; @@ -42,10 +40,8 @@ use pocketmine\Server; use pocketmine\timings\TimingsHandler; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Utils; -use pocketmine\utils\VersionString; use Webmozart\PathUtil\Path; use function array_diff_assoc; -use function array_intersect; use function array_key_exists; use function array_keys; use function array_merge; @@ -55,7 +51,6 @@ use function dirname; use function file_exists; use function get_class; use function implode; -use function in_array; use function is_a; use function is_array; use function is_dir; @@ -64,16 +59,11 @@ use function is_string; use function is_subclass_of; use function iterator_to_array; use function mkdir; -use function phpversion; use function realpath; use function shuffle; use function sprintf; -use function stripos; -use function strlen; use function strpos; use function strtolower; -use function substr; -use function version_compare; /** * Manages all the plugins @@ -140,68 +130,6 @@ class PluginManager{ return Path::join(dirname($pluginPath), $pluginName); } - private function checkPluginLoadability(PluginDescription $description) : Translatable|null{ - $name = $description->getName(); - if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){ - return KnownTranslationFactory::pocketmine_plugin_restrictedName(); - } - - foreach($description->getCompatibleApis() as $api){ - if(!VersionString::isValidBaseVersion($api)){ - return KnownTranslationFactory::pocketmine_plugin_invalidAPI($api); - } - } - - if(!ApiVersion::isCompatible($this->server->getApiVersion(), $description->getCompatibleApis())){ - return KnownTranslationFactory::pocketmine_plugin_incompatibleAPI(implode(", ", $description->getCompatibleApis())); - } - - $ambiguousVersions = ApiVersion::checkAmbiguousVersions($description->getCompatibleApis()); - if(count($ambiguousVersions) > 0){ - return KnownTranslationFactory::pocketmine_plugin_ambiguousMinAPI(implode(", ", $ambiguousVersions)); - } - - if(count($description->getCompatibleOperatingSystems()) > 0 and !in_array(Utils::getOS(), $description->getCompatibleOperatingSystems(), true)) { - return KnownTranslationFactory::pocketmine_plugin_incompatibleOS(implode(", ", $description->getCompatibleOperatingSystems())); - } - - if(count($pluginMcpeProtocols = $description->getCompatibleMcpeProtocols()) > 0){ - $serverMcpeProtocols = [ProtocolInfo::CURRENT_PROTOCOL]; - if(count(array_intersect($pluginMcpeProtocols, $serverMcpeProtocols)) === 0){ - return KnownTranslationFactory::pocketmine_plugin_incompatibleProtocol(implode(", ", $pluginMcpeProtocols)); - } - } - - foreach($description->getRequiredExtensions() as $extensionName => $versionConstrs){ - $gotVersion = phpversion($extensionName); - if($gotVersion === false){ - return KnownTranslationFactory::pocketmine_plugin_extensionNotLoaded($extensionName); - } - - foreach($versionConstrs as $k => $constr){ // versionConstrs_loop - if($constr === "*"){ - continue; - } - if($constr === ""){ - return KnownTranslationFactory::pocketmine_plugin_emptyExtensionVersionConstraint(extensionName: $extensionName, constraintIndex: "$k"); - } - foreach(["<=", "le", "<>", "!=", "ne", "<", "lt", "==", "=", "eq", ">=", "ge", ">", "gt"] as $comparator){ - // warning: the > character should be quoted in YAML - if(substr($constr, 0, strlen($comparator)) === $comparator){ - $version = substr($constr, strlen($comparator)); - if(!version_compare($gotVersion, $version, $comparator)){ - return KnownTranslationFactory::pocketmine_plugin_incompatibleExtensionVersion(extensionName: $extensionName, extensionVersion: $gotVersion, pluginRequirement: $constr); - } - continue 2; // versionConstrs_loop - } - } - return KnownTranslationFactory::pocketmine_plugin_invalidExtensionVersionConstraint(extensionName: $extensionName, versionConstraint: $constr); - } - } - - return null; - } - private function internalLoadPlugin(string $path, PluginLoader $loader, PluginDescription $description) : ?Plugin{ $language = $this->server->getLanguage(); $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName()))); @@ -302,6 +230,8 @@ class PluginManager{ }else{ return; } + + $loadabilityChecker = new PluginLoadabilityChecker($this->server->getApiVersion()); foreach($loaders as $loader){ foreach($files as $file){ if(!is_string($file)) throw new AssumptionFailedError("FilesystemIterator current should be string when using CURRENT_AS_PATHNAME"); @@ -327,7 +257,7 @@ class PluginManager{ $name = $description->getName(); - if(($loadabilityError = $this->checkPluginLoadability($description)) !== null){ + if(($loadabilityError = $loadabilityChecker->check($description)) !== null){ $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError($name, $loadabilityError))); continue; } From e2275cc8ec02b1d3b9dac8735f7e1060a913fb26 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 23:10:18 +0100 Subject: [PATCH 148/710] PluginManager: Prevent infinite recursion in loadPlugins() if a plugin calls loadPlugins(server->getPluginPath()) during its onLoad(), and it itself is in that plugin path, an infinite recursion will occur. --- src/plugin/PluginManager.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index f24488878..c46ad4a65 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -79,6 +79,8 @@ class PluginManager{ /** @var Plugin[] */ protected $enabledPlugins = []; + private bool $loadPluginsGuard = false; + /** * @var PluginLoader[] * @phpstan-var array, PluginLoader> @@ -320,6 +322,11 @@ class PluginManager{ * @return Plugin[] */ public function loadPlugins(string $path) : array{ + if($this->loadPluginsGuard){ + throw new \LogicException(__METHOD__ . "() cannot be called from within itself"); + } + $this->loadPluginsGuard = true; + $triage = new PluginLoadTriage(); $this->triagePlugins($path, $triage); @@ -404,6 +411,7 @@ class PluginManager{ } } + $this->loadPluginsGuard = false; return $loadedPlugins; } From 4f2bcb61d693d68243862f233f0c6c4272397640 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 20 Oct 2021 23:35:04 +0100 Subject: [PATCH 149/710] Fixed crashdump generation when crashing before PluginManager was created --- src/CrashDump.php | 9 ++++++--- src/Server.php | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/CrashDump.php b/src/CrashDump.php index 983ecd4a8..a42d757ae 100644 --- a/src/CrashDump.php +++ b/src/CrashDump.php @@ -101,9 +101,12 @@ class CrashDump{ /** @var string */ private $path; - public function __construct(Server $server){ + private ?PluginManager $pluginManager; + + public function __construct(Server $server, ?PluginManager $pluginManager){ $this->time = microtime(true); $this->server = $server; + $this->pluginManager = $pluginManager; $crashPath = Path::join($this->server->getDataPath(), "crashdumps"); if(!is_dir($crashPath)){ @@ -166,11 +169,11 @@ class CrashDump{ } private function pluginsData() : void{ - if($this->server->getPluginManager() instanceof PluginManager){ + if($this->pluginManager !== null){ + $plugins = $this->pluginManager->getPlugins(); $this->addLine(); $this->addLine("Loaded plugins:"); $this->data["plugins"] = []; - $plugins = $this->server->getPluginManager()->getPlugins(); ksort($plugins, SORT_STRING); foreach($plugins as $p){ $d = $p->getDescription(); diff --git a/src/Server.php b/src/Server.php index b1b357907..dcec8fb05 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1476,7 +1476,7 @@ class Server{ ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems try{ $this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_create())); - $dump = new CrashDump($this); + $dump = new CrashDump($this, $this->pluginManager ?? null); $this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($dump->getPath()))); From 2971bf30a50dc91e0a88c0e95d8465bdaa8c3bca Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 21 Oct 2021 00:30:19 +0100 Subject: [PATCH 150/710] actions: combine code verify into one step this way the diff takes one less click to get to. --- .github/workflows/main.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5a56fc25e..9ba874512 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -238,11 +238,10 @@ jobs: - name: Regenerate KnownTranslation APIs run: php build/generate-known-translation-apis.php - - name: Run git diff - run: git diff - - - name: Fail job if changes were made - run: git diff --quiet + - name: Verify code is unchanged + run: | + git diff + git diff --quiet codestyle: name: Code Style checks From 986b4e0651d665c72ec011542f95b4bd9529c6a8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 21 Oct 2021 20:32:37 +0100 Subject: [PATCH 151/710] Enforce single-line PhpDoc for properties where possible --- .github/workflows/main.yml | 4 ++-- .php-cs-fixer.php | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 79f39f899..67790cea1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -272,10 +272,10 @@ jobs: - uses: actions/checkout@v2 - name: Setup PHP and tools - uses: shivammathur/setup-php@2.12.0 + uses: shivammathur/setup-php@2.15.0 with: php-version: 8.0 - tools: php-cs-fixer + tools: php-cs-fixer:3.2 - name: Run PHP-CS-Fixer run: php-cs-fixer fix --dry-run --diff diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 373c8fc80..590f6ebd8 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -62,6 +62,11 @@ return (new PhpCsFixer\Config) ], 'sort_algorithm' => 'alpha' ], + 'phpdoc_line_span' => [ + 'property' => 'single', + 'method' => null, + 'const' => null + ], 'phpdoc_trim' => true, 'phpdoc_trim_consecutive_blank_line_separation' => true, 'single_import_per_statement' => true, From a4b65d6a3f40d74dac02ca5e842a8fb664a40047 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 21 Oct 2021 14:49:46 +0100 Subject: [PATCH 152/710] PlayerCreationEvent: verify that the class actually exists and is instantiable this ensures that crashdumps blame the plugin instead of the core on bad classes, such as in this case: https://crash.pmmp.io/view/5331225 --- src/event/player/PlayerCreationEvent.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/event/player/PlayerCreationEvent.php b/src/event/player/PlayerCreationEvent.php index d4056ee12..013fcdb2a 100644 --- a/src/event/player/PlayerCreationEvent.php +++ b/src/event/player/PlayerCreationEvent.php @@ -26,6 +26,7 @@ namespace pocketmine\event\player; use pocketmine\event\Event; use pocketmine\network\mcpe\NetworkSession; use pocketmine\player\Player; +use pocketmine\utils\Utils; use function is_a; /** @@ -96,10 +97,7 @@ class PlayerCreationEvent extends Event{ * @phpstan-param class-string $class */ public function setPlayerClass($class) : void{ - if(!is_a($class, $this->baseClass, true)){ - throw new \RuntimeException("Class $class must extend " . $this->baseClass); - } - + Utils::testValidInstance($class, $this->baseClass); $this->playerClass = $class; } } From c262c2e726fc0b474566ae6a41d577416b4d16c3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Oct 2021 01:14:54 +0100 Subject: [PATCH 153/710] Updated composer dependencies --- composer.lock | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index cb1287b83..dbeae084d 100644 --- a/composer.lock +++ b/composer.lock @@ -249,16 +249,16 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "3.0.1+bedrock1.17.40", + "version": "3.0.2+bedrock1.17.40", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "1add11e06366b983b97fa415fee55f31af3cb7a9" + "reference": "3edb21da787c1ab0f028d35243f87bd7c9038b9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/1add11e06366b983b97fa415fee55f31af3cb7a9", - "reference": "1add11e06366b983b97fa415fee55f31af3cb7a9", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/3edb21da787c1ab0f028d35243f87bd7c9038b9e", + "reference": "3edb21da787c1ab0f028d35243f87bd7c9038b9e", "shasum": "" }, "require": { @@ -290,22 +290,22 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/3.0.1+bedrock1.17.40" + "source": "https://github.com/pmmp/BedrockProtocol/tree/3.0.2+bedrock1.17.40" }, - "time": "2021-10-20T14:00:00+00:00" + "time": "2021-10-20T18:52:14+00:00" }, { "name": "pocketmine/binaryutils", - "version": "0.2.1", + "version": "0.2.2", "source": { "type": "git", "url": "https://github.com/pmmp/BinaryUtils.git", - "reference": "8cd078e2426f8100331f2d73bef10f481dad6cde" + "reference": "f883e1cf9099ed6a757a10a2f75b3333eeb2cdf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/8cd078e2426f8100331f2d73bef10f481dad6cde", - "reference": "8cd078e2426f8100331f2d73bef10f481dad6cde", + "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/f883e1cf9099ed6a757a10a2f75b3333eeb2cdf9", + "reference": "f883e1cf9099ed6a757a10a2f75b3333eeb2cdf9", "shasum": "" }, "require": { @@ -314,7 +314,7 @@ }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.85", + "phpstan/phpstan": "0.12.99", "phpstan/phpstan-strict-rules": "^0.12.4" }, "type": "library", @@ -330,9 +330,9 @@ "description": "Classes and methods for conveniently handling binary data", "support": { "issues": "https://github.com/pmmp/BinaryUtils/issues", - "source": "https://github.com/pmmp/BinaryUtils/tree/0.2.1" + "source": "https://github.com/pmmp/BinaryUtils/tree/0.2.2" }, - "time": "2021-05-30T19:42:57+00:00" + "time": "2021-10-22T19:54:16+00:00" }, { "name": "pocketmine/callback-validator", @@ -3325,7 +3325,6 @@ "type": "github" } ], - "abandoned": true, "time": "2020-09-28T06:45:17+00:00" }, { From c773e43eda0da159b181ef1c79f29a6c8986e697 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Oct 2021 01:16:45 +0100 Subject: [PATCH 154/710] Updated BedrockProtocol to pmmp/BedrockProtocol@97fa88e9eff2c9bd5408fa964515504a4d9230bf --- composer.json | 2 +- composer.lock | 16 +++-- src/block/inventory/ChestInventory.php | 3 +- src/block/inventory/EnderChestInventory.php | 3 +- src/block/inventory/ShulkerBoxInventory.php | 3 +- src/block/tile/Bell.php | 3 +- src/entity/Entity.php | 2 +- src/entity/Human.php | 4 +- src/entity/object/ItemEntity.php | 2 +- src/entity/object/Painting.php | 2 +- src/network/mcpe/InventoryManager.php | 21 +++--- src/network/mcpe/NetworkSession.php | 18 ++--- src/network/mcpe/cache/CraftingDataCache.php | 6 +- .../mcpe/handler/InGamePacketHandler.php | 53 ++++++++------- .../mcpe/handler/PreSpawnPacketHandler.php | 67 +++++++++++-------- .../handler/ResourcePacksPacketHandler.php | 8 ++- src/player/Player.php | 3 +- src/world/World.php | 11 ++- src/world/particle/FloatingTextParticle.php | 2 +- src/world/sound/ArrowHitSound.php | 2 +- src/world/sound/BarrelCloseSound.php | 2 +- src/world/sound/BarrelOpenSound.php | 2 +- src/world/sound/BellRingSound.php | 2 +- src/world/sound/BlockBreakSound.php | 2 +- src/world/sound/BlockPlaceSound.php | 2 +- src/world/sound/BlockPunchSound.php | 3 +- src/world/sound/BowShootSound.php | 2 +- src/world/sound/BucketEmptyLavaSound.php | 2 +- src/world/sound/BucketEmptyWaterSound.php | 2 +- src/world/sound/BucketFillLavaSound.php | 2 +- src/world/sound/BucketFillWaterSound.php | 2 +- src/world/sound/ChestCloseSound.php | 2 +- src/world/sound/ChestOpenSound.php | 2 +- src/world/sound/EnderChestCloseSound.php | 2 +- src/world/sound/EnderChestOpenSound.php | 2 +- src/world/sound/EntityAttackNoDamageSound.php | 4 +- src/world/sound/EntityAttackSound.php | 4 +- src/world/sound/EntityLandSound.php | 5 +- src/world/sound/EntityLongFallSound.php | 5 +- src/world/sound/EntityShortFallSound.php | 5 +- src/world/sound/ExplodeSound.php | 2 +- src/world/sound/FireExtinguishSound.php | 2 +- src/world/sound/FlintSteelSound.php | 2 +- src/world/sound/ItemBreakSound.php | 2 +- src/world/sound/NoteSound.php | 2 +- src/world/sound/PotionSplashSound.php | 2 +- src/world/sound/RecordSound.php | 2 +- src/world/sound/RecordStopSound.php | 2 +- src/world/sound/RedstonePowerOffSound.php | 2 +- src/world/sound/RedstonePowerOnSound.php | 2 +- src/world/sound/ShulkerBoxCloseSound.php | 2 +- src/world/sound/ShulkerBoxOpenSound.php | 2 +- src/world/sound/ThrowSound.php | 2 +- src/world/sound/XpLevelUpSound.php | 2 +- 54 files changed, 178 insertions(+), 135 deletions(-) diff --git a/composer.json b/composer.json index 4a01020a7..22b5cd7a0 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "adhocore/json-comment": "^1.1", "fgrosse/phpasn1": "^2.3", "netresearch/jsonmapper": "^4.0", - "pocketmine/bedrock-protocol": "^3.0.1+bedrock1.17.40", + "pocketmine/bedrock-protocol": "dev-master", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "dev-master", diff --git a/composer.lock b/composer.lock index dbeae084d..89bd8e43b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bc2b425a6f436a01de4e423ea651dc84", + "content-hash": "ddbcdbc7ea7247bea7fcb37e5c42340b", "packages": [ { "name": "adhocore/json-comment", @@ -249,16 +249,16 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "3.0.2+bedrock1.17.40", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "3edb21da787c1ab0f028d35243f87bd7c9038b9e" + "reference": "97fa88e9eff2c9bd5408fa964515504a4d9230bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/3edb21da787c1ab0f028d35243f87bd7c9038b9e", - "reference": "3edb21da787c1ab0f028d35243f87bd7c9038b9e", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/97fa88e9eff2c9bd5408fa964515504a4d9230bf", + "reference": "97fa88e9eff2c9bd5408fa964515504a4d9230bf", "shasum": "" }, "require": { @@ -277,6 +277,7 @@ "phpstan/phpstan-strict-rules": "^0.12.10", "phpunit/phpunit": "^9.5" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -290,9 +291,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/3.0.2+bedrock1.17.40" + "source": "https://github.com/pmmp/BedrockProtocol/tree/master" }, - "time": "2021-10-20T18:52:14+00:00" + "time": "2021-10-23T00:06:46+00:00" }, { "name": "pocketmine/binaryutils", @@ -3490,6 +3491,7 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { + "pocketmine/bedrock-protocol": 20, "pocketmine/classloader": 20, "pocketmine/spl": 20 }, diff --git a/src/block/inventory/ChestInventory.php b/src/block/inventory/ChestInventory.php index 1f8538e4b..b7594b232 100644 --- a/src/block/inventory/ChestInventory.php +++ b/src/block/inventory/ChestInventory.php @@ -25,6 +25,7 @@ namespace pocketmine\block\inventory; use pocketmine\inventory\SimpleInventory; use pocketmine\network\mcpe\protocol\BlockEventPacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\world\Position; use pocketmine\world\sound\ChestCloseSound; use pocketmine\world\sound\ChestOpenSound; @@ -50,6 +51,6 @@ class ChestInventory extends SimpleInventory implements BlockInventory{ $holder = $this->getHolder(); //event ID is always 1 for a chest - $holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(1, $isOpen ? 1 : 0, $holder->asVector3())); + $holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(BlockPosition::fromVector3($holder), 1, $isOpen ? 1 : 0)); } } diff --git a/src/block/inventory/EnderChestInventory.php b/src/block/inventory/EnderChestInventory.php index 6887219c6..b9ff1832e 100644 --- a/src/block/inventory/EnderChestInventory.php +++ b/src/block/inventory/EnderChestInventory.php @@ -28,6 +28,7 @@ use pocketmine\inventory\DelegateInventory; use pocketmine\inventory\Inventory; use pocketmine\inventory\PlayerEnderInventory; use pocketmine\network\mcpe\protocol\BlockEventPacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\player\Player; use pocketmine\world\Position; use pocketmine\world\sound\EnderChestCloseSound; @@ -74,7 +75,7 @@ class EnderChestInventory extends DelegateInventory implements BlockInventory{ $holder = $this->getHolder(); //event ID is always 1 for a chest - $holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(1, $isOpen ? 1 : 0, $holder->asVector3())); + $holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(BlockPosition::fromVector3($holder), 1, $isOpen ? 1 : 0)); } public function onClose(Player $who) : void{ diff --git a/src/block/inventory/ShulkerBoxInventory.php b/src/block/inventory/ShulkerBoxInventory.php index 3e4edcdd7..cace49652 100644 --- a/src/block/inventory/ShulkerBoxInventory.php +++ b/src/block/inventory/ShulkerBoxInventory.php @@ -27,6 +27,7 @@ use pocketmine\block\BlockLegacyIds; use pocketmine\inventory\SimpleInventory; use pocketmine\item\Item; use pocketmine\network\mcpe\protocol\BlockEventPacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\world\Position; use pocketmine\world\sound\ShulkerBoxCloseSound; use pocketmine\world\sound\ShulkerBoxOpenSound; @@ -59,6 +60,6 @@ class ShulkerBoxInventory extends SimpleInventory implements BlockInventory{ $holder = $this->getHolder(); //event ID is always 1 for a chest - $holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(1, $isOpen ? 1 : 0, $holder->asVector3())); + $holder->getWorld()->broadcastPacketToViewers($holder, BlockEventPacket::create(BlockPosition::fromVector3($holder), 1, $isOpen ? 1 : 0)); } } diff --git a/src/block/tile/Bell.php b/src/block/tile/Bell.php index b7e5eadde..bc2ab29fe 100644 --- a/src/block/tile/Bell.php +++ b/src/block/tile/Bell.php @@ -27,6 +27,7 @@ use pocketmine\block\utils\BlockDataSerializer; use pocketmine\math\Facing; use pocketmine\nbt\tag\CompoundTag; use pocketmine\network\mcpe\protocol\BlockActorDataPacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\types\CacheableNbt; final class Bell extends Spawnable{ @@ -81,6 +82,6 @@ final class Bell extends Spawnable{ $nbt->setByte(self::TAG_RINGING, 1); $nbt->setInt(self::TAG_DIRECTION, BlockDataSerializer::writeLegacyHorizontalFacing($bellHitFace)); $nbt->setInt(self::TAG_TICKS, 0); - return BlockActorDataPacket::create($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ(), new CacheableNbt($nbt)); + return BlockActorDataPacket::create(BlockPosition::fromVector3($this->position), new CacheableNbt($nbt)); } } diff --git a/src/entity/Entity.php b/src/entity/Entity.php index 8bab76480..ceb5a97b1 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -1419,7 +1419,7 @@ abstract class Entity{ */ protected function sendSpawnPacket(Player $player) : void{ $pk = new AddActorPacket(); - $pk->entityRuntimeId = $this->getId(); + $pk->actorRuntimeId = $this->getId(); $pk->type = static::getNetworkTypeId(); $pk->position = $this->location->asVector3(); $pk->motion = $this->getMotion(); diff --git a/src/entity/Human.php b/src/entity/Human.php index 4768422ae..c953ffb47 100644 --- a/src/entity/Human.php +++ b/src/entity/Human.php @@ -145,7 +145,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ */ public function sendSkin(?array $targets = null) : void{ $this->server->broadcastPackets($targets ?? $this->hasSpawned, [ - PlayerSkinPacket::create($this->getUniqueId(), SkinAdapterSingleton::get()->toSkinData($this->skin)) + PlayerSkinPacket::create($this->getUniqueId(), "", "", SkinAdapterSingleton::get()->toSkinData($this->skin)) ]); } @@ -447,7 +447,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ $pk = new AddPlayerPacket(); $pk->uuid = $this->getUniqueId(); $pk->username = $this->getName(); - $pk->entityRuntimeId = $this->getId(); + $pk->actorRuntimeId = $this->getId(); $pk->position = $this->location->asVector3(); $pk->motion = $this->getMotion(); $pk->yaw = $this->location->yaw; diff --git a/src/entity/object/ItemEntity.php b/src/entity/object/ItemEntity.php index 2b16b7a11..e9c71c6c2 100644 --- a/src/entity/object/ItemEntity.php +++ b/src/entity/object/ItemEntity.php @@ -207,7 +207,7 @@ class ItemEntity extends Entity{ protected function sendSpawnPacket(Player $player) : void{ $pk = new AddItemActorPacket(); - $pk->entityRuntimeId = $this->getId(); + $pk->actorRuntimeId = $this->getId(); $pk->position = $this->location->asVector3(); $pk->motion = $this->getMotion(); $pk->item = ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getItem())); diff --git a/src/entity/object/Painting.php b/src/entity/object/Painting.php index 4769df15d..fa031cb98 100644 --- a/src/entity/object/Painting.php +++ b/src/entity/object/Painting.php @@ -150,7 +150,7 @@ class Painting extends Entity{ protected function sendSpawnPacket(Player $player) : void{ $pk = new AddPaintingPacket(); - $pk->entityRuntimeId = $this->getId(); + $pk->actorRuntimeId = $this->getId(); $pk->position = new Vector3( ($this->boundingBox->minX + $this->boundingBox->maxX) / 2, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, diff --git a/src/network/mcpe/InventoryManager.php b/src/network/mcpe/InventoryManager.php index 67931b7d0..db5b3a2ae 100644 --- a/src/network/mcpe/InventoryManager.php +++ b/src/network/mcpe/InventoryManager.php @@ -45,6 +45,7 @@ use pocketmine\network\mcpe\protocol\CreativeContentPacket; use pocketmine\network\mcpe\protocol\InventoryContentPacket; use pocketmine\network\mcpe\protocol\InventorySlotPacket; use pocketmine\network\mcpe\protocol\MobEquipmentPacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds; use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry; use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; @@ -164,26 +165,27 @@ class InventoryManager{ //TODO: we should be using some kind of tagging system to identify the types. Instanceof is flaky especially //if the class isn't final, not to mention being inflexible. if($inv instanceof BlockInventory){ + $blockPosition = BlockPosition::fromVector3($inv->getHolder()); switch(true){ case $inv instanceof LoomInventory: - return [ContainerOpenPacket::blockInvVec3($id, WindowTypes::LOOM, $inv->getHolder())]; + return [ContainerOpenPacket::blockInv($id, WindowTypes::LOOM, $blockPosition)]; case $inv instanceof FurnaceInventory: return match($inv->getFurnaceType()->id()){ - FurnaceType::FURNACE()->id() => [ContainerOpenPacket::blockInvVec3($id, WindowTypes::FURNACE, $inv->getHolder())], - FurnaceType::BLAST_FURNACE()->id() => [ContainerOpenPacket::blockInvVec3($id, WindowTypes::BLAST_FURNACE, $inv->getHolder())], - FurnaceType::SMOKER()->id() => [ContainerOpenPacket::blockInvVec3($id, WindowTypes::SMOKER, $inv->getHolder())], + FurnaceType::FURNACE()->id() => [ContainerOpenPacket::blockInv($id, WindowTypes::FURNACE, $blockPosition)], + FurnaceType::BLAST_FURNACE()->id() => [ContainerOpenPacket::blockInv($id, WindowTypes::BLAST_FURNACE, $blockPosition)], + FurnaceType::SMOKER()->id() => [ContainerOpenPacket::blockInv($id, WindowTypes::SMOKER, $blockPosition)], default => throw new AssumptionFailedError("Unreachable") }; case $inv instanceof EnchantInventory: - return [ContainerOpenPacket::blockInvVec3($id, WindowTypes::ENCHANTMENT, $inv->getHolder())]; + return [ContainerOpenPacket::blockInv($id, WindowTypes::ENCHANTMENT, $blockPosition)]; case $inv instanceof BrewingStandInventory: - return [ContainerOpenPacket::blockInvVec3($id, WindowTypes::BREWING_STAND, $inv->getHolder())]; + return [ContainerOpenPacket::blockInv($id, WindowTypes::BREWING_STAND, $blockPosition)]; case $inv instanceof AnvilInventory: - return [ContainerOpenPacket::blockInvVec3($id, WindowTypes::ANVIL, $inv->getHolder())]; + return [ContainerOpenPacket::blockInv($id, WindowTypes::ANVIL, $blockPosition)]; case $inv instanceof HopperInventory: - return [ContainerOpenPacket::blockInvVec3($id, WindowTypes::HOPPER, $inv->getHolder())]; + return [ContainerOpenPacket::blockInv($id, WindowTypes::HOPPER, $blockPosition)]; default: - return [ContainerOpenPacket::blockInvVec3($id, WindowTypes::CONTAINER, $inv->getHolder())]; + return [ContainerOpenPacket::blockInv($id, WindowTypes::CONTAINER, $blockPosition)]; } } return null; @@ -279,6 +281,7 @@ class InventoryManager{ $this->player->getId(), ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->player->getInventory()->getItemInHand())), $selected, + $selected, ContainerIds::INVENTORY )); $this->clientSelectedHotbarSlot = $selected; diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index be4ea440a..720e99349 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -88,6 +88,7 @@ use pocketmine\network\mcpe\protocol\SetTitlePacket; use pocketmine\network\mcpe\protocol\TakeItemActorPacket; use pocketmine\network\mcpe\protocol\TextPacket; use pocketmine\network\mcpe\protocol\TransferPacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\types\command\CommandData; use pocketmine\network\mcpe\protocol\types\command\CommandEnum; use pocketmine\network\mcpe\protocol\types\command\CommandParameter; @@ -727,7 +728,7 @@ class NetworkSession{ $pitch = $pitch ?? $location->getPitch(); $pk = new MovePlayerPacket(); - $pk->entityRuntimeId = $this->player->getId(); + $pk->actorRuntimeId = $this->player->getId(); $pk->position = $this->player->getOffsetPosition($pos); $pk->pitch = $pitch; $pk->headYaw = $yaw; @@ -748,16 +749,17 @@ class NetworkSession{ } public function syncViewAreaCenterPoint(Vector3 $newPos, int $viewDistance) : void{ - $this->sendDataPacket(NetworkChunkPublisherUpdatePacket::create($newPos->getFloorX(), $newPos->getFloorY(), $newPos->getFloorZ(), $viewDistance * 16)); //blocks, not chunks >.> + $this->sendDataPacket(NetworkChunkPublisherUpdatePacket::create(BlockPosition::fromVector3($newPos), $viewDistance * 16)); //blocks, not chunks >.> } public function syncPlayerSpawnPoint(Position $newSpawn) : void{ - [$x, $y, $z] = [$newSpawn->getFloorX(), $newSpawn->getFloorY(), $newSpawn->getFloorZ()]; - $this->sendDataPacket(SetSpawnPositionPacket::playerSpawn($x, $y, $z, DimensionIds::OVERWORLD, $x, $y, $z)); + $newSpawnBlockPosition = BlockPosition::fromVector3($newSpawn); + //TODO: respawn causing block position (bed, respawn anchor) + $this->sendDataPacket(SetSpawnPositionPacket::playerSpawn($newSpawnBlockPosition, DimensionIds::OVERWORLD, $newSpawnBlockPosition)); } public function syncWorldSpawnPoint(Position $newSpawn) : void{ - $this->sendDataPacket(SetSpawnPositionPacket::worldSpawn($newSpawn->getFloorX(), $newSpawn->getFloorY(), $newSpawn->getFloorZ(), DimensionIds::OVERWORLD)); + $this->sendDataPacket(SetSpawnPositionPacket::worldSpawn(BlockPosition::fromVector3($newSpawn), DimensionIds::OVERWORLD)); } public function syncGameMode(GameMode $mode, bool $isRollback = false) : void{ @@ -788,7 +790,7 @@ class NetworkSession{ $isOp = $for->hasPermission(DefaultPermissions::ROOT_OPERATOR); $pk->commandPermission = ($isOp ? AdventureSettingsPacket::PERMISSION_OPERATOR : AdventureSettingsPacket::PERMISSION_NORMAL); $pk->playerPermission = ($isOp ? PlayerPermissions::OPERATOR : PlayerPermissions::MEMBER); - $pk->entityUniqueId = $for->getId(); + $pk->targetActorUniqueId = $for->getId(); $this->sendDataPacket($pk); } @@ -966,12 +968,12 @@ class NetworkSession{ public function onMobMainHandItemChange(Human $mob) : void{ //TODO: we could send zero for slot here because remote players don't need to know which slot was selected $inv = $mob->getInventory(); - $this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItemInHand())), $inv->getHeldItemIndex(), ContainerIds::INVENTORY)); + $this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItemInHand())), $inv->getHeldItemIndex(), $inv->getHeldItemIndex(), ContainerIds::INVENTORY)); } public function onMobOffHandItemChange(Human $mob) : void{ $inv = $mob->getOffHandInventory(); - $this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItem(0))), 0, ContainerIds::OFFHAND)); + $this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItem(0))), 0, 0, ContainerIds::OFFHAND)); } public function onMobArmorChange(Living $mob) : void{ diff --git a/src/network/mcpe/cache/CraftingDataCache.php b/src/network/mcpe/cache/CraftingDataCache.php index a87629a26..68414e835 100644 --- a/src/network/mcpe/cache/CraftingDataCache.php +++ b/src/network/mcpe/cache/CraftingDataCache.php @@ -79,7 +79,7 @@ final class CraftingDataCache{ $converter = TypeConverter::getInstance(); foreach($manager->getShapelessRecipes() as $list){ foreach($list as $recipe){ - $pk->entries[] = new ProtocolShapelessRecipe( + $pk->recipesWithTypeIds[] = new ProtocolShapelessRecipe( CraftingDataPacket::ENTRY_SHAPELESS, Binary::writeInt(++$counter), array_map(function(Item $item) use ($converter) : RecipeIngredient{ @@ -104,7 +104,7 @@ final class CraftingDataCache{ $inputs[$row][$column] = $converter->coreItemStackToRecipeIngredient($recipe->getIngredient($column, $row)); } } - $pk->entries[] = $r = new ProtocolShapedRecipe( + $pk->recipesWithTypeIds[] = $r = new ProtocolShapedRecipe( CraftingDataPacket::ENTRY_SHAPED, Binary::writeInt(++$counter), $inputs, @@ -128,7 +128,7 @@ final class CraftingDataCache{ }; foreach($manager->getFurnaceRecipeManager($furnaceType)->getAll() as $recipe){ $input = $converter->coreItemStackToNet($recipe->getInput()); - $pk->entries[] = new ProtocolFurnaceRecipe( + $pk->recipesWithTypeIds[] = new ProtocolFurnaceRecipe( CraftingDataPacket::ENTRY_FURNACE_DATA, $input->getId(), $input->getMeta(), diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 65d294ae8..a8e784ced 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -199,13 +199,13 @@ class InGamePacketHandler extends PacketHandler{ } public function handleActorEvent(ActorEventPacket $packet) : bool{ - if($packet->entityRuntimeId !== $this->player->getId()){ + if($packet->actorRuntimeId !== $this->player->getId()){ //TODO HACK: EATING_ITEM is sent back to the server when the server sends it for other players (1.14 bug, maybe earlier) - return $packet->event === ActorEventPacket::EATING_ITEM; + return $packet->actorRuntimeId === ActorEventPacket::EATING_ITEM; } $this->player->doCloseInventory(); - switch($packet->event){ + switch($packet->eventId){ case ActorEventPacket::EATING_ITEM: //TODO: ignore this and handle it server-side $item = $this->player->getInventory()->getItemInHand(); if($item->isNull()){ @@ -356,12 +356,12 @@ class InGamePacketHandler extends PacketHandler{ switch($data->getActionType()){ case UseItemTransactionData::ACTION_CLICK_BLOCK: //TODO: start hack for client spam bug - $clickPos = $data->getClickPos(); + $clickPos = $data->getClickPosition(); $spamBug = ($this->lastRightClickData !== null and microtime(true) - $this->lastRightClickTime < 0.1 and //100ms - $this->lastRightClickData->getPlayerPos()->distanceSquared($data->getPlayerPos()) < 0.00001 and - $this->lastRightClickData->getBlockPos()->equals($data->getBlockPos()) and - $this->lastRightClickData->getClickPos()->distanceSquared($clickPos) < 0.00001 //signature spam bug has 0 distance, but allow some error + $this->lastRightClickData->getPlayerPosition()->distanceSquared($data->getPlayerPosition()) < 0.00001 and + $this->lastRightClickData->getBlockPosition()->equals($data->getBlockPosition()) and + $this->lastRightClickData->getClickPosition()->distanceSquared($clickPos) < 0.00001 //signature spam bug has 0 distance, but allow some error ); //get rid of continued spam if the player clicks and holds right-click $this->lastRightClickData = $data; @@ -371,9 +371,10 @@ class InGamePacketHandler extends PacketHandler{ } //TODO: end hack for client spam bug - $blockPos = $data->getBlockPos(); - if(!$this->player->interactBlock($blockPos, $data->getFace(), $clickPos)){ - $this->onFailedBlockAction($blockPos, $data->getFace()); + $blockPos = $data->getBlockPosition(); + $vBlockPos = new Vector3($blockPos->getX(), $blockPos->getY(), $blockPos->getZ()); + if(!$this->player->interactBlock($vBlockPos, $data->getFace(), $clickPos)){ + $this->onFailedBlockAction($vBlockPos, $data->getFace()); }elseif( !array_key_exists($windowId = InventoryManager::HARDCODED_CRAFTING_GRID_WINDOW_ID, $this->openHardcodedWindows) && $this->player->getCraftingGrid()->getGridWidth() === CraftingGrid::SIZE_BIG @@ -381,7 +382,7 @@ class InGamePacketHandler extends PacketHandler{ //TODO: HACK! crafting grid doesn't fit very well into the current PM container system, so this hack //allows it to carry on working approximately the same way as it did in 1.14 $this->openHardcodedWindows[$windowId] = true; - $this->session->sendDataPacket(ContainerOpenPacket::blockInvVec3( + $this->session->sendDataPacket(ContainerOpenPacket::blockInv( InventoryManager::HARDCODED_CRAFTING_GRID_WINDOW_ID, WindowTypes::WORKBENCH, $blockPos @@ -389,9 +390,10 @@ class InGamePacketHandler extends PacketHandler{ } return true; case UseItemTransactionData::ACTION_BREAK_BLOCK: - $blockPos = $data->getBlockPos(); - if(!$this->player->breakBlock($blockPos)){ - $this->onFailedBlockAction($blockPos, null); + $blockPos = $data->getBlockPosition(); + $vBlockPos = new Vector3($blockPos->getX(), $blockPos->getY(), $blockPos->getZ()); + if(!$this->player->breakBlock($vBlockPos)){ + $this->onFailedBlockAction($vBlockPos, null); } return true; case UseItemTransactionData::ACTION_CLICK_AIR: @@ -432,7 +434,7 @@ class InGamePacketHandler extends PacketHandler{ } private function handleUseItemOnEntityTransaction(UseItemOnEntityTransactionData $data) : bool{ - $target = $this->player->getWorld()->getEntity($data->getEntityRuntimeId()); + $target = $this->player->getWorld()->getEntity($data->getActorRuntimeId()); if($target === null){ return false; } @@ -442,7 +444,7 @@ class InGamePacketHandler extends PacketHandler{ //TODO: use transactiondata for rollbacks here switch($data->getActionType()){ case UseItemOnEntityTransactionData::ACTION_INTERACT: - if(!$this->player->interactEntity($target, $data->getClickPos())){ + if(!$this->player->interactEntity($target, $data->getClickPosition())){ $this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex()); } return true; @@ -498,7 +500,7 @@ class InGamePacketHandler extends PacketHandler{ //TODO: implement handling for this where it matters return true; } - $target = $this->player->getWorld()->getEntity($packet->target); + $target = $this->player->getWorld()->getEntity($packet->targetActorRuntimeId); if($target === null){ return false; } @@ -521,7 +523,7 @@ class InGamePacketHandler extends PacketHandler{ } public function handleBlockPickRequest(BlockPickRequestPacket $packet) : bool{ - return $this->player->pickBlock(new Vector3($packet->blockX, $packet->blockY, $packet->blockZ), $packet->addUserData); + return $this->player->pickBlock(new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ()), $packet->addUserData); } public function handleActorPickRequest(ActorPickRequestPacket $packet) : bool{ @@ -529,7 +531,7 @@ class InGamePacketHandler extends PacketHandler{ } public function handlePlayerAction(PlayerActionPacket $packet) : bool{ - $pos = new Vector3($packet->x, $packet->y, $packet->z); + $pos = new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ()); switch($packet->action){ case PlayerActionPacket::ACTION_START_BREAK: @@ -628,7 +630,7 @@ class InGamePacketHandler extends PacketHandler{ } public function handleAdventureSettings(AdventureSettingsPacket $packet) : bool{ - if($packet->entityUniqueId !== $this->player->getId()){ + if($packet->targetActorUniqueId !== $this->player->getId()){ return false; //TODO: operators can change other people's permissions using this } @@ -648,13 +650,13 @@ class InGamePacketHandler extends PacketHandler{ } public function handleBlockActorData(BlockActorDataPacket $packet) : bool{ - $pos = new Vector3($packet->x, $packet->y, $packet->z); + $pos = new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ()); if($pos->distanceSquared($this->player->getLocation()) > 10000){ return false; } $block = $this->player->getLocation()->getWorld()->getBlock($pos); - $nbt = $packet->namedtag->getRoot(); + $nbt = $packet->nbt->getRoot(); if(!($nbt instanceof CompoundTag)) throw new AssumptionFailedError("PHPStan should ensure this is a CompoundTag"); //for phpstorm's benefit if($block instanceof BaseSign){ @@ -678,7 +680,7 @@ class InGamePacketHandler extends PacketHandler{ return true; } - $this->session->getLogger()->debug("Invalid sign update data: " . base64_encode($packet->namedtag->getEncodedNbt())); + $this->session->getLogger()->debug("Invalid sign update data: " . base64_encode($packet->nbt->getEncodedNbt())); } return false; @@ -712,9 +714,10 @@ class InGamePacketHandler extends PacketHandler{ } public function handleItemFrameDropItem(ItemFrameDropItemPacket $packet) : bool{ - $block = $this->player->getWorld()->getBlockAt($packet->x, $packet->y, $packet->z); + $blockPosition = $packet->blockPosition; + $block = $this->player->getWorld()->getBlockAt($blockPosition->getX(), $blockPosition->getY(), $blockPosition->getZ()); if($block instanceof ItemFrame and $block->getFramedItem() !== null){ - return $this->player->attackBlock(new Vector3($packet->x, $packet->y, $packet->z), $block->getFacing()); + return $this->player->attackBlock(new Vector3($blockPosition->getX(), $blockPosition->getY(), $blockPosition->getZ()), $block->getFacing()); } return false; } diff --git a/src/network/mcpe/handler/PreSpawnPacketHandler.php b/src/network/mcpe/handler/PreSpawnPacketHandler.php index 59d204d68..6d2091065 100644 --- a/src/network/mcpe/handler/PreSpawnPacketHandler.php +++ b/src/network/mcpe/handler/PreSpawnPacketHandler.php @@ -31,9 +31,11 @@ use pocketmine\network\mcpe\InventoryManager; use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket; use pocketmine\network\mcpe\protocol\StartGamePacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\types\BoolGameRule; use pocketmine\network\mcpe\protocol\types\DimensionIds; use pocketmine\network\mcpe\protocol\types\Experiments; +use pocketmine\network\mcpe\protocol\types\LevelSettings; use pocketmine\network\mcpe\protocol\types\PlayerMovementSettings; use pocketmine\network\mcpe\protocol\types\PlayerMovementType; use pocketmine\network\mcpe\protocol\types\SpawnSettings; @@ -64,39 +66,46 @@ class PreSpawnPacketHandler extends PacketHandler{ } public function setUp() : void{ - $spawnPosition = $this->player->getSpawn(); $location = $this->player->getLocation(); - $pk = new StartGamePacket(); - $pk->entityUniqueId = $this->player->getId(); - $pk->entityRuntimeId = $this->player->getId(); - $pk->playerGamemode = TypeConverter::getInstance()->coreGameModeToProtocol($this->player->getGamemode()); - $pk->playerPosition = $this->player->getOffsetPosition($location); - $pk->pitch = $location->pitch; - $pk->yaw = $location->yaw; - $pk->seed = -1; - $pk->spawnSettings = new SpawnSettings(SpawnSettings::BIOME_TYPE_DEFAULT, "", DimensionIds::OVERWORLD); //TODO: implement this properly - $pk->worldGamemode = TypeConverter::getInstance()->coreGameModeToProtocol($this->server->getGamemode()); - $pk->difficulty = $location->getWorld()->getDifficulty(); - $pk->spawnX = $spawnPosition->getFloorX(); - $pk->spawnY = $spawnPosition->getFloorY(); - $pk->spawnZ = $spawnPosition->getFloorZ(); - $pk->hasAchievementsDisabled = true; - $pk->time = $location->getWorld()->getTime(); - $pk->eduEditionOffer = 0; - $pk->rainLevel = 0; //TODO: implement these properly - $pk->lightningLevel = 0; - $pk->commandsEnabled = true; - $pk->gameRules = [ + $levelSettings = new LevelSettings(); + $levelSettings->seed = -1; + $levelSettings->spawnSettings = new SpawnSettings(SpawnSettings::BIOME_TYPE_DEFAULT, "", DimensionIds::OVERWORLD); //TODO: implement this properly + $levelSettings->worldGamemode = TypeConverter::getInstance()->coreGameModeToProtocol($this->server->getGamemode()); + $levelSettings->difficulty = $location->getWorld()->getDifficulty(); + $levelSettings->spawnPosition = BlockPosition::fromVector3($location->getWorld()->getSpawnLocation()); + $levelSettings->hasAchievementsDisabled = true; + $levelSettings->time = $location->getWorld()->getTime(); + $levelSettings->eduEditionOffer = 0; + $levelSettings->rainLevel = 0; //TODO: implement these properly + $levelSettings->lightningLevel = 0; + $levelSettings->commandsEnabled = true; + $levelSettings->gameRules = [ "naturalregeneration" => new BoolGameRule(false, false) //Hack for client side regeneration ]; - $pk->experiments = new Experiments([], false); - $pk->levelId = ""; - $pk->worldName = $this->server->getMotd(); - $pk->itemTable = GlobalItemTypeDictionary::getInstance()->getDictionary()->getEntries(); //TODO: check if this is actually needed - $pk->playerMovementSettings = new PlayerMovementSettings(PlayerMovementType::LEGACY, 0, false); - $pk->serverSoftwareVersion = sprintf("%s %s", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(true)); - $this->session->sendDataPacket($pk); + $levelSettings->experiments = new Experiments([], false); + + $this->session->sendDataPacket(StartGamePacket::create( + $this->player->getId(), + $this->player->getId(), + TypeConverter::getInstance()->coreGameModeToProtocol($this->player->getGamemode()), + $this->player->getOffsetPosition($location), + $location->pitch, + $location->yaw, + $levelSettings, + "", + $this->server->getMotd(), + "", + false, + new PlayerMovementSettings(PlayerMovementType::LEGACY, 0, false), + 0, + 0, + "", + false, + sprintf("%s %s", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(true)), + [], + GlobalItemTypeDictionary::getInstance()->getDictionary()->getEntries() + )); $this->session->sendDataPacket(StaticPacketCache::getInstance()->getAvailableActorIdentifiers()); $this->session->sendDataPacket(StaticPacketCache::getInstance()->getBiomeDefs()); diff --git a/src/network/mcpe/handler/ResourcePacksPacketHandler.php b/src/network/mcpe/handler/ResourcePacksPacketHandler.php index 5b6d1d7a5..8f93e2547 100644 --- a/src/network/mcpe/handler/ResourcePacksPacketHandler.php +++ b/src/network/mcpe/handler/ResourcePacksPacketHandler.php @@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe\handler; use pocketmine\lang\KnownTranslationKeys; use pocketmine\network\mcpe\NetworkSession; +use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\ResourcePackChunkDataPacket; use pocketmine\network\mcpe\protocol\ResourcePackChunkRequestPacket; use pocketmine\network\mcpe\protocol\ResourcePackClientResponsePacket; @@ -34,6 +35,7 @@ use pocketmine\network\mcpe\protocol\ResourcePackStackPacket; use pocketmine\network\mcpe\protocol\types\Experiments; use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackInfoEntry; use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackStackEntry; +use pocketmine\network\mcpe\protocol\types\resourcepacks\ResourcePackType; use pocketmine\resourcepacks\ResourcePack; use pocketmine\resourcepacks\ResourcePackManager; use function array_map; @@ -113,7 +115,9 @@ class ResourcePacksPacketHandler extends PacketHandler{ self::PACK_CHUNK_SIZE, (int) ceil($pack->getPackSize() / self::PACK_CHUNK_SIZE), $pack->getPackSize(), - $pack->getSha256() + $pack->getSha256(), + false, + ResourcePackType::ADDON //TODO: this might be an addon (not behaviour pack), needed to properly support client-side custom items )); } $this->session->getLogger()->debug("Player requested download of " . count($packet->packIds) . " resource packs"); @@ -130,7 +134,7 @@ class ResourcePacksPacketHandler extends PacketHandler{ //we don't force here, because it doesn't have user-facing effects //but it does have an annoying side-effect when true: it makes //the client remove its own non-server-supplied resource packs. - $this->session->sendDataPacket(ResourcePackStackPacket::create($stack, [], false, new Experiments([], false))); + $this->session->sendDataPacket(ResourcePackStackPacket::create($stack, [], false, ProtocolInfo::MINECRAFT_VERSION_NETWORK, new Experiments([], false))); $this->session->getLogger()->debug("Applying resource pack stack"); break; case ResourcePackClientResponsePacket::STATUS_COMPLETED: diff --git a/src/player/Player.php b/src/player/Player.php index bd7222af0..10265f466 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -97,6 +97,7 @@ use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\AnimatePacket; use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\SetActorMotionPacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; @@ -2183,7 +2184,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $properties->setGenericFlag(EntityMetadataFlags::ACTION, $this->startAction > -1); $properties->setPlayerFlag(PlayerMetadataFlags::SLEEP, $this->sleeping !== null); - $properties->setBlockPos(EntityMetadataProperties::PLAYER_BED_POSITION, $this->sleeping ?? new Vector3(0, 0, 0)); + $properties->setBlockPos(EntityMetadataProperties::PLAYER_BED_POSITION, $this->sleeping !== null ? BlockPosition::fromVector3($this->sleeping) : new BlockPosition(0, 0, 0)); } public function sendData(?array $targets, ?array $data = null) : void{ diff --git a/src/world/World.php b/src/world/World.php index f85320e34..282767e76 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -63,6 +63,7 @@ use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\BlockActorDataPacket; use pocketmine\network\mcpe\protocol\ClientboundPacket; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\UpdateBlockPacket; use pocketmine\player\Player; use pocketmine\scheduler\AsyncPool; @@ -952,11 +953,17 @@ class World implements ChunkManager{ } $fullBlock = $this->getBlockAt($b->x, $b->y, $b->z); - $packets[] = UpdateBlockPacket::create($b->x, $b->y, $b->z, RuntimeBlockMapping::getInstance()->toRuntimeId($fullBlock->getFullId())); + $blockPosition = BlockPosition::fromVector3($b); + $packets[] = UpdateBlockPacket::create( + $blockPosition, + RuntimeBlockMapping::getInstance()->toRuntimeId($fullBlock->getFullId()), + UpdateBlockPacket::FLAG_NETWORK, + UpdateBlockPacket::DATA_LAYER_NORMAL + ); $tile = $this->getTileAt($b->x, $b->y, $b->z); if($tile instanceof Spawnable){ - $packets[] = BlockActorDataPacket::create($b->x, $b->y, $b->z, $tile->getSerializedSpawnCompound()); + $packets[] = BlockActorDataPacket::create($blockPosition, $tile->getSerializedSpawnCompound()); } } diff --git a/src/world/particle/FloatingTextParticle.php b/src/world/particle/FloatingTextParticle.php index fd7e14f0c..bac075975 100644 --- a/src/world/particle/FloatingTextParticle.php +++ b/src/world/particle/FloatingTextParticle.php @@ -99,7 +99,7 @@ class FloatingTextParticle implements Particle{ $pk = new AddPlayerPacket(); $pk->uuid = $uuid; $pk->username = $name; - $pk->entityRuntimeId = $this->entityId; + $pk->actorRuntimeId = $this->entityId; $pk->position = $pos; //TODO: check offset $pk->item = ItemStackWrapper::legacy(ItemStack::null()); diff --git a/src/world/sound/ArrowHitSound.php b/src/world/sound/ArrowHitSound.php index 1927b0c2c..cb89dbc51 100644 --- a/src/world/sound/ArrowHitSound.php +++ b/src/world/sound/ArrowHitSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ArrowHitSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BOW_HIT, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BOW_HIT, $pos, false)]; } } diff --git a/src/world/sound/BarrelCloseSound.php b/src/world/sound/BarrelCloseSound.php index a49330511..6adb76093 100644 --- a/src/world/sound/BarrelCloseSound.php +++ b/src/world/sound/BarrelCloseSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BarrelCloseSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BLOCK_BARREL_CLOSE, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BLOCK_BARREL_CLOSE, $pos, false)]; } } diff --git a/src/world/sound/BarrelOpenSound.php b/src/world/sound/BarrelOpenSound.php index 7e77ef2c3..04edd7365 100644 --- a/src/world/sound/BarrelOpenSound.php +++ b/src/world/sound/BarrelOpenSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BarrelOpenSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BLOCK_BARREL_OPEN, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BLOCK_BARREL_OPEN, $pos, false)]; } } diff --git a/src/world/sound/BellRingSound.php b/src/world/sound/BellRingSound.php index c6ee1cffb..af96e7f09 100644 --- a/src/world/sound/BellRingSound.php +++ b/src/world/sound/BellRingSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; final class BellRingSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BLOCK_BELL_HIT, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BLOCK_BELL_HIT, $pos, false)]; } } diff --git a/src/world/sound/BlockBreakSound.php b/src/world/sound/BlockBreakSound.php index b5c9a11b9..041664cc8 100644 --- a/src/world/sound/BlockBreakSound.php +++ b/src/world/sound/BlockBreakSound.php @@ -38,6 +38,6 @@ class BlockBreakSound implements Sound{ } public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BREAK, $pos, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BREAK, $pos, false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; } } diff --git a/src/world/sound/BlockPlaceSound.php b/src/world/sound/BlockPlaceSound.php index 8635588b4..0c8967469 100644 --- a/src/world/sound/BlockPlaceSound.php +++ b/src/world/sound/BlockPlaceSound.php @@ -38,6 +38,6 @@ class BlockPlaceSound implements Sound{ } public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_PLACE, $pos, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_PLACE, $pos, false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; } } diff --git a/src/world/sound/BlockPunchSound.php b/src/world/sound/BlockPunchSound.php index 0637c4133..009e1a754 100644 --- a/src/world/sound/BlockPunchSound.php +++ b/src/world/sound/BlockPunchSound.php @@ -41,9 +41,10 @@ class BlockPunchSound implements Sound{ } public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create( + return [LevelSoundEventPacket::nonActorSound( LevelSoundEventPacket::SOUND_HIT, $pos, + false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()) )]; } diff --git a/src/world/sound/BowShootSound.php b/src/world/sound/BowShootSound.php index 09f644bfb..22b65cac6 100644 --- a/src/world/sound/BowShootSound.php +++ b/src/world/sound/BowShootSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BowShootSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BOW, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BOW, $pos, false)]; } } diff --git a/src/world/sound/BucketEmptyLavaSound.php b/src/world/sound/BucketEmptyLavaSound.php index 2764cc823..d0f66e7c1 100644 --- a/src/world/sound/BucketEmptyLavaSound.php +++ b/src/world/sound/BucketEmptyLavaSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BucketEmptyLavaSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BUCKET_EMPTY_LAVA, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_EMPTY_LAVA, $pos, false)]; } } diff --git a/src/world/sound/BucketEmptyWaterSound.php b/src/world/sound/BucketEmptyWaterSound.php index b3b847721..af4dec6e2 100644 --- a/src/world/sound/BucketEmptyWaterSound.php +++ b/src/world/sound/BucketEmptyWaterSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BucketEmptyWaterSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BUCKET_EMPTY_WATER, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_EMPTY_WATER, $pos, false)]; } } diff --git a/src/world/sound/BucketFillLavaSound.php b/src/world/sound/BucketFillLavaSound.php index c8dbba300..01d4edb09 100644 --- a/src/world/sound/BucketFillLavaSound.php +++ b/src/world/sound/BucketFillLavaSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BucketFillLavaSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BUCKET_FILL_LAVA, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_FILL_LAVA, $pos, false)]; } } diff --git a/src/world/sound/BucketFillWaterSound.php b/src/world/sound/BucketFillWaterSound.php index 0661a5da0..cdb126c7c 100644 --- a/src/world/sound/BucketFillWaterSound.php +++ b/src/world/sound/BucketFillWaterSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BucketFillWaterSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BUCKET_FILL_WATER, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_FILL_WATER, $pos, false)]; } } diff --git a/src/world/sound/ChestCloseSound.php b/src/world/sound/ChestCloseSound.php index 744305b1b..1738ed81f 100644 --- a/src/world/sound/ChestCloseSound.php +++ b/src/world/sound/ChestCloseSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ChestCloseSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_CHEST_CLOSED, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_CHEST_CLOSED, $pos, false)]; } } diff --git a/src/world/sound/ChestOpenSound.php b/src/world/sound/ChestOpenSound.php index 86a7ea8fc..dd7bb6a14 100644 --- a/src/world/sound/ChestOpenSound.php +++ b/src/world/sound/ChestOpenSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ChestOpenSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_CHEST_OPEN, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_CHEST_OPEN, $pos, false)]; } } diff --git a/src/world/sound/EnderChestCloseSound.php b/src/world/sound/EnderChestCloseSound.php index 07073b523..d016a3ae5 100644 --- a/src/world/sound/EnderChestCloseSound.php +++ b/src/world/sound/EnderChestCloseSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class EnderChestCloseSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_ENDERCHEST_CLOSED, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_ENDERCHEST_CLOSED, $pos, false)]; } } diff --git a/src/world/sound/EnderChestOpenSound.php b/src/world/sound/EnderChestOpenSound.php index 17e6fef9b..b2a664dd3 100644 --- a/src/world/sound/EnderChestOpenSound.php +++ b/src/world/sound/EnderChestOpenSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class EnderChestOpenSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_ENDERCHEST_OPEN, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_ENDERCHEST_OPEN, $pos, false)]; } } diff --git a/src/world/sound/EntityAttackNoDamageSound.php b/src/world/sound/EntityAttackNoDamageSound.php index edd39483c..0b2fb0cff 100644 --- a/src/world/sound/EntityAttackNoDamageSound.php +++ b/src/world/sound/EntityAttackNoDamageSound.php @@ -36,7 +36,9 @@ class EntityAttackNoDamageSound implements Sound{ LevelSoundEventPacket::SOUND_ATTACK_NODAMAGE, $pos, -1, - "minecraft:player" + "minecraft:player", + false, + false )]; } } diff --git a/src/world/sound/EntityAttackSound.php b/src/world/sound/EntityAttackSound.php index 04b461f49..d7fd63b7b 100644 --- a/src/world/sound/EntityAttackSound.php +++ b/src/world/sound/EntityAttackSound.php @@ -36,7 +36,9 @@ class EntityAttackSound implements Sound{ LevelSoundEventPacket::SOUND_ATTACK_STRONG, //TODO: seems like ATTACK is dysfunctional $pos, -1, - "minecraft:player" + "minecraft:player", + false, + false )]; } } diff --git a/src/world/sound/EntityLandSound.php b/src/world/sound/EntityLandSound.php index 983c0d2e6..7871082bb 100644 --- a/src/world/sound/EntityLandSound.php +++ b/src/world/sound/EntityLandSound.php @@ -49,8 +49,9 @@ class EntityLandSound implements Sound{ LevelSoundEventPacket::SOUND_LAND, $pos, RuntimeBlockMapping::getInstance()->toRuntimeId($this->blockLandedOn->getFullId()), - $this->entity::getNetworkTypeId() - //TODO: does isBaby have any relevance here? + $this->entity::getNetworkTypeId(), + false, //TODO: does isBaby have any relevance here? + false )]; } } diff --git a/src/world/sound/EntityLongFallSound.php b/src/world/sound/EntityLongFallSound.php index 2e95b9e8c..88246f846 100644 --- a/src/world/sound/EntityLongFallSound.php +++ b/src/world/sound/EntityLongFallSound.php @@ -45,8 +45,9 @@ class EntityLongFallSound implements Sound{ LevelSoundEventPacket::SOUND_FALL_BIG, $pos, -1, - $this->entity::getNetworkTypeId() - //TODO: is isBaby relevant here? + $this->entity::getNetworkTypeId(), + false, //TODO: is isBaby relevant here? + false )]; } } diff --git a/src/world/sound/EntityShortFallSound.php b/src/world/sound/EntityShortFallSound.php index de16c58b0..fcacd797e 100644 --- a/src/world/sound/EntityShortFallSound.php +++ b/src/world/sound/EntityShortFallSound.php @@ -44,8 +44,9 @@ class EntityShortFallSound implements Sound{ LevelSoundEventPacket::SOUND_FALL_SMALL, $pos, -1, - $this->entity::getNetworkTypeId() - //TODO: does isBaby have any relevance here? + $this->entity::getNetworkTypeId(), + false, //TODO: does isBaby have any relevance here? + false )]; } } diff --git a/src/world/sound/ExplodeSound.php b/src/world/sound/ExplodeSound.php index 86ed9b342..9dfcd19f8 100644 --- a/src/world/sound/ExplodeSound.php +++ b/src/world/sound/ExplodeSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ExplodeSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_EXPLODE, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_EXPLODE, $pos, false)]; } } diff --git a/src/world/sound/FireExtinguishSound.php b/src/world/sound/FireExtinguishSound.php index 0c0707911..e9f7e3097 100644 --- a/src/world/sound/FireExtinguishSound.php +++ b/src/world/sound/FireExtinguishSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; final class FireExtinguishSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_EXTINGUISH_FIRE, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_EXTINGUISH_FIRE, $pos, false)]; } } diff --git a/src/world/sound/FlintSteelSound.php b/src/world/sound/FlintSteelSound.php index 185216959..15ff96a28 100644 --- a/src/world/sound/FlintSteelSound.php +++ b/src/world/sound/FlintSteelSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class FlintSteelSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_IGNITE, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_IGNITE, $pos, false)]; } } diff --git a/src/world/sound/ItemBreakSound.php b/src/world/sound/ItemBreakSound.php index fbe9aef77..0b7f07435 100644 --- a/src/world/sound/ItemBreakSound.php +++ b/src/world/sound/ItemBreakSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ItemBreakSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_BREAK, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BREAK, $pos, false)]; } } diff --git a/src/world/sound/NoteSound.php b/src/world/sound/NoteSound.php index 70228021e..e84c736b0 100644 --- a/src/world/sound/NoteSound.php +++ b/src/world/sound/NoteSound.php @@ -42,6 +42,6 @@ class NoteSound implements Sound{ } public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_NOTE, $pos, ($this->instrument->getMagicNumber() << 8) | $this->note)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_NOTE, $pos, false, ($this->instrument->getMagicNumber() << 8) | $this->note)]; } } diff --git a/src/world/sound/PotionSplashSound.php b/src/world/sound/PotionSplashSound.php index 96a2f6ead..efde99b25 100644 --- a/src/world/sound/PotionSplashSound.php +++ b/src/world/sound/PotionSplashSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class PotionSplashSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_GLASS, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_GLASS, $pos, false)]; } } diff --git a/src/world/sound/RecordSound.php b/src/world/sound/RecordSound.php index 9f8bb15d1..99e781db9 100644 --- a/src/world/sound/RecordSound.php +++ b/src/world/sound/RecordSound.php @@ -37,6 +37,6 @@ class RecordSound implements Sound{ } public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create($this->recordType->getSoundId(), $pos)]; + return [LevelSoundEventPacket::nonActorSound($this->recordType->getSoundId(), $pos, false)]; } } diff --git a/src/world/sound/RecordStopSound.php b/src/world/sound/RecordStopSound.php index ccb139f82..2bdd0e611 100644 --- a/src/world/sound/RecordStopSound.php +++ b/src/world/sound/RecordStopSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class RecordStopSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_STOP_RECORD, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_STOP_RECORD, $pos, false)]; } } diff --git a/src/world/sound/RedstonePowerOffSound.php b/src/world/sound/RedstonePowerOffSound.php index d1363ed54..5f0ec7280 100644 --- a/src/world/sound/RedstonePowerOffSound.php +++ b/src/world/sound/RedstonePowerOffSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class RedstonePowerOffSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_POWER_OFF, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_POWER_OFF, $pos, false)]; } } diff --git a/src/world/sound/RedstonePowerOnSound.php b/src/world/sound/RedstonePowerOnSound.php index eaea5f617..e260d1166 100644 --- a/src/world/sound/RedstonePowerOnSound.php +++ b/src/world/sound/RedstonePowerOnSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class RedstonePowerOnSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_POWER_ON, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_POWER_ON, $pos, false)]; } } diff --git a/src/world/sound/ShulkerBoxCloseSound.php b/src/world/sound/ShulkerBoxCloseSound.php index cb170aab6..2e8e758a4 100644 --- a/src/world/sound/ShulkerBoxCloseSound.php +++ b/src/world/sound/ShulkerBoxCloseSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ShulkerBoxCloseSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_SHULKERBOX_CLOSED, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_SHULKERBOX_CLOSED, $pos, false)]; } } diff --git a/src/world/sound/ShulkerBoxOpenSound.php b/src/world/sound/ShulkerBoxOpenSound.php index fd75b2f82..a5dacea08 100644 --- a/src/world/sound/ShulkerBoxOpenSound.php +++ b/src/world/sound/ShulkerBoxOpenSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ShulkerBoxOpenSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_SHULKERBOX_OPEN, $pos)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_SHULKERBOX_OPEN, $pos, false)]; } } diff --git a/src/world/sound/ThrowSound.php b/src/world/sound/ThrowSound.php index 65c5079af..1e3297a65 100644 --- a/src/world/sound/ThrowSound.php +++ b/src/world/sound/ThrowSound.php @@ -29,6 +29,6 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ThrowSound implements Sound{ public function encode(?Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_THROW, $pos, -1, "minecraft:player")]; + return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_THROW, $pos, -1, "minecraft:player", false, false)]; } } diff --git a/src/world/sound/XpLevelUpSound.php b/src/world/sound/XpLevelUpSound.php index abc41fef7..aa44a5ff6 100644 --- a/src/world/sound/XpLevelUpSound.php +++ b/src/world/sound/XpLevelUpSound.php @@ -44,6 +44,6 @@ class XpLevelUpSound implements Sound{ public function encode(?Vector3 $pos) : array{ //No idea why such odd numbers, but this works... //TODO: check arbitrary volume - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_LEVELUP, $pos, 0x10000000 * intdiv(min(30, $this->xpLevel), 5))]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_LEVELUP, $pos, false, 0x10000000 * intdiv(min(30, $this->xpLevel), 5))]; } } From c77829f4adee4d5fe61829823f4dbad545c100e9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Oct 2021 01:46:01 +0100 Subject: [PATCH 155/710] Migrate packet creation to use ::create() methods in all but one case MovePlayerPacket doesn't yet have a ::create() due to a complication with fields that aren't always present. --- src/entity/Entity.php | 29 ++++++++-------- src/entity/Human.php | 31 +++++++++++------ src/entity/object/ItemEntity.php | 17 +++++----- src/entity/object/Painting.php | 22 ++++++------ src/network/mcpe/NetworkSession.php | 23 +++++++------ src/network/mcpe/cache/CraftingDataCache.php | 11 +++--- src/world/particle/FloatingTextParticle.php | 35 +++++++++++++------- 7 files changed, 96 insertions(+), 72 deletions(-) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index ceb5a97b1..6289a896b 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -1418,20 +1418,21 @@ abstract class Entity{ * Called by spawnTo() to send whatever packets needed to spawn the entity to the client. */ protected function sendSpawnPacket(Player $player) : void{ - $pk = new AddActorPacket(); - $pk->actorRuntimeId = $this->getId(); - $pk->type = static::getNetworkTypeId(); - $pk->position = $this->location->asVector3(); - $pk->motion = $this->getMotion(); - $pk->yaw = $this->location->yaw; - $pk->headYaw = $this->location->yaw; //TODO - $pk->pitch = $this->location->pitch; - $pk->attributes = array_map(function(Attribute $attr) : NetworkAttribute{ - return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue()); - }, $this->attributeMap->getAll()); - $pk->metadata = $this->getAllNetworkData(); - - $player->getNetworkSession()->sendDataPacket($pk); + $player->getNetworkSession()->sendDataPacket(AddActorPacket::create( + $this->getId(), //TODO: actor unique ID + $this->getId(), + static::getNetworkTypeId(), + $this->location->asVector3(), + $this->getMotion(), + $this->location->pitch, + $this->location->yaw, + $this->location->yaw, //TODO: head yaw + array_map(function(Attribute $attr) : NetworkAttribute{ + return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue()); + }, $this->attributeMap->getAll()), + $this->getAllNetworkData(), + [] //TODO: entity links + )); } public function spawnTo(Player $player) : void{ diff --git a/src/entity/Human.php b/src/entity/Human.php index c953ffb47..c77de5005 100644 --- a/src/entity/Human.php +++ b/src/entity/Human.php @@ -47,8 +47,10 @@ use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\convert\SkinAdapterSingleton; use pocketmine\network\mcpe\convert\TypeConverter; use pocketmine\network\mcpe\protocol\AddPlayerPacket; +use pocketmine\network\mcpe\protocol\AdventureSettingsPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\PlayerSkinPacket; +use pocketmine\network\mcpe\protocol\types\DeviceOS; use pocketmine\network\mcpe\protocol\types\entity\EntityIds; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty; @@ -444,17 +446,24 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ $player->getNetworkSession()->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))])); } - $pk = new AddPlayerPacket(); - $pk->uuid = $this->getUniqueId(); - $pk->username = $this->getName(); - $pk->actorRuntimeId = $this->getId(); - $pk->position = $this->location->asVector3(); - $pk->motion = $this->getMotion(); - $pk->yaw = $this->location->yaw; - $pk->pitch = $this->location->pitch; - $pk->item = ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())); - $pk->metadata = $this->getAllNetworkData(); - $player->getNetworkSession()->sendDataPacket($pk); + $player->getNetworkSession()->sendDataPacket(AddPlayerPacket::create( + $this->getUniqueId(), + $this->getName(), + $this->getId(), //TODO: actor unique ID + $this->getId(), + "", + $this->location->asVector3(), + $this->getMotion(), + $this->location->pitch, + $this->location->yaw, + $this->location->yaw, //TODO: head yaw + ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())), + $this->getAllNetworkData(), + AdventureSettingsPacket::create(0, 0, 0, 0, 0, $this->getId()), //TODO + [], //TODO: entity links + "", //device ID (we intentionally don't send this - secvuln) + DeviceOS::UNKNOWN //we intentionally don't send this (secvuln) + )); //TODO: Hack for MCPE 1.2.13: DATA_NAMETAG is useless in AddPlayerPacket, so it has to be sent separately $this->sendData([$player], [EntityMetadataProperties::NAMETAG => new StringMetadataProperty($this->getNameTag())]); diff --git a/src/entity/object/ItemEntity.php b/src/entity/object/ItemEntity.php index e9c71c6c2..899cbc279 100644 --- a/src/entity/object/ItemEntity.php +++ b/src/entity/object/ItemEntity.php @@ -206,14 +206,15 @@ class ItemEntity extends Entity{ } protected function sendSpawnPacket(Player $player) : void{ - $pk = new AddItemActorPacket(); - $pk->actorRuntimeId = $this->getId(); - $pk->position = $this->location->asVector3(); - $pk->motion = $this->getMotion(); - $pk->item = ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getItem())); - $pk->metadata = $this->getAllNetworkData(); - - $player->getNetworkSession()->sendDataPacket($pk); + $player->getNetworkSession()->sendDataPacket(AddItemActorPacket::create( + $this->getId(), //TODO: entity unique ID + $this->getId(), + ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getItem())), + $this->location->asVector3(), + $this->getMotion(), + $this->getAllNetworkData(), + false //TODO: I have no idea what this is needed for, but right now we don't support fishing anyway + )); } public function getOffsetPosition(Vector3 $vector3) : Vector3{ diff --git a/src/entity/object/Painting.php b/src/entity/object/Painting.php index fa031cb98..a95560e24 100644 --- a/src/entity/object/Painting.php +++ b/src/entity/object/Painting.php @@ -149,17 +149,17 @@ class Painting extends Entity{ } protected function sendSpawnPacket(Player $player) : void{ - $pk = new AddPaintingPacket(); - $pk->actorRuntimeId = $this->getId(); - $pk->position = new Vector3( - ($this->boundingBox->minX + $this->boundingBox->maxX) / 2, - ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, - ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2 - ); - $pk->direction = self::FACING_TO_DATA[$this->facing]; - $pk->title = $this->motive->getName(); - - $player->getNetworkSession()->sendDataPacket($pk); + $player->getNetworkSession()->sendDataPacket(AddPaintingPacket::create( + $this->getId(), //TODO: entity unique ID + $this->getId(), + new Vector3( + ($this->boundingBox->minX + $this->boundingBox->maxX) / 2, + ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, + ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2 + ), + self::FACING_TO_DATA[$this->facing], + $this->motive->getName() + )); } /** diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 720e99349..2ca46db0e 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -776,7 +776,15 @@ class NetworkSession{ * TODO: make this less specialized */ public function syncAdventureSettings(Player $for) : void{ - $pk = new AdventureSettingsPacket(); + $isOp = $for->hasPermission(DefaultPermissions::ROOT_OPERATOR); + $pk = AdventureSettingsPacket::create( + 0, + $isOp ? AdventureSettingsPacket::PERMISSION_OPERATOR : AdventureSettingsPacket::PERMISSION_NORMAL, + 0, + $isOp ? PlayerPermissions::OPERATOR : PlayerPermissions::MEMBER, + 0, + $for->getId() + ); $pk->setFlag(AdventureSettingsPacket::WORLD_IMMUTABLE, $for->isSpectator()); $pk->setFlag(AdventureSettingsPacket::NO_PVP, $for->isSpectator()); @@ -787,11 +795,6 @@ class NetworkSession{ //TODO: permission flags - $isOp = $for->hasPermission(DefaultPermissions::ROOT_OPERATOR); - $pk->commandPermission = ($isOp ? AdventureSettingsPacket::PERMISSION_OPERATOR : AdventureSettingsPacket::PERMISSION_NORMAL); - $pk->playerPermission = ($isOp ? PlayerPermissions::OPERATOR : PlayerPermissions::MEMBER); - $pk->targetActorUniqueId = $for->getId(); - $this->sendDataPacket($pk); } @@ -828,9 +831,9 @@ class NetworkSession{ } public function syncAvailableCommands() : void{ - $pk = new AvailableCommandsPacket(); + $commandData = []; foreach($this->server->getCommandMap()->getCommands() as $name => $command){ - if(isset($pk->commandData[$command->getName()]) or $command->getName() === "help" or !$command->testPermissionSilent($this->player)){ + if(isset($commandData[$command->getName()]) or $command->getName() === "help" or !$command->testPermissionSilent($this->player)){ continue; } @@ -857,10 +860,10 @@ class NetworkSession{ ] ); - $pk->commandData[$command->getName()] = $data; + $commandData[$command->getName()] = $data; } - $this->sendDataPacket($pk); + $this->sendDataPacket(AvailableCommandsPacket::create($commandData, [], [], [])); } public function onRawChatMessage(string $message) : void{ diff --git a/src/network/mcpe/cache/CraftingDataCache.php b/src/network/mcpe/cache/CraftingDataCache.php index 68414e835..369a45039 100644 --- a/src/network/mcpe/cache/CraftingDataCache.php +++ b/src/network/mcpe/cache/CraftingDataCache.php @@ -71,15 +71,14 @@ final class CraftingDataCache{ */ private function buildCraftingDataCache(CraftingManager $manager) : CraftingDataPacket{ Timings::$craftingDataCacheRebuild->startTiming(); - $pk = new CraftingDataPacket(); - $pk->cleanRecipes = true; $counter = 0; $nullUUID = Uuid::fromString(Uuid::NIL); $converter = TypeConverter::getInstance(); + $recipesWithTypeIds = []; foreach($manager->getShapelessRecipes() as $list){ foreach($list as $recipe){ - $pk->recipesWithTypeIds[] = new ProtocolShapelessRecipe( + $recipesWithTypeIds[] = new ProtocolShapelessRecipe( CraftingDataPacket::ENTRY_SHAPELESS, Binary::writeInt(++$counter), array_map(function(Item $item) use ($converter) : RecipeIngredient{ @@ -104,7 +103,7 @@ final class CraftingDataCache{ $inputs[$row][$column] = $converter->coreItemStackToRecipeIngredient($recipe->getIngredient($column, $row)); } } - $pk->recipesWithTypeIds[] = $r = new ProtocolShapedRecipe( + $recipesWithTypeIds[] = $r = new ProtocolShapedRecipe( CraftingDataPacket::ENTRY_SHAPED, Binary::writeInt(++$counter), $inputs, @@ -128,7 +127,7 @@ final class CraftingDataCache{ }; foreach($manager->getFurnaceRecipeManager($furnaceType)->getAll() as $recipe){ $input = $converter->coreItemStackToNet($recipe->getInput()); - $pk->recipesWithTypeIds[] = new ProtocolFurnaceRecipe( + $recipesWithTypeIds[] = new ProtocolFurnaceRecipe( CraftingDataPacket::ENTRY_FURNACE_DATA, $input->getId(), $input->getMeta(), @@ -139,6 +138,6 @@ final class CraftingDataCache{ } Timings::$craftingDataCacheRebuild->stopTiming(); - return $pk; + return CraftingDataPacket::create($recipesWithTypeIds, [], [], [], true); } } diff --git a/src/world/particle/FloatingTextParticle.php b/src/world/particle/FloatingTextParticle.php index bac075975..1fe3ee008 100644 --- a/src/world/particle/FloatingTextParticle.php +++ b/src/world/particle/FloatingTextParticle.php @@ -28,8 +28,10 @@ use pocketmine\entity\Skin; use pocketmine\math\Vector3; use pocketmine\network\mcpe\convert\SkinAdapterSingleton; use pocketmine\network\mcpe\protocol\AddPlayerPacket; +use pocketmine\network\mcpe\protocol\AdventureSettingsPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\RemoveActorPacket; +use pocketmine\network\mcpe\protocol\types\DeviceOS; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags; use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty; @@ -96,22 +98,31 @@ class FloatingTextParticle implements Particle{ $p[] = PlayerListPacket::add([PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, SkinAdapterSingleton::get()->toSkinData(new Skin("Standard_Custom", str_repeat("\x00", 8192))))]); - $pk = new AddPlayerPacket(); - $pk->uuid = $uuid; - $pk->username = $name; - $pk->actorRuntimeId = $this->entityId; - $pk->position = $pos; //TODO: check offset - $pk->item = ItemStackWrapper::legacy(ItemStack::null()); - - $flags = ( + $actorFlags = ( 1 << EntityMetadataFlags::IMMOBILE ); - $pk->metadata = [ - EntityMetadataProperties::FLAGS => new LongMetadataProperty($flags), + $actorMetadata = [ + EntityMetadataProperties::FLAGS => new LongMetadataProperty($actorFlags), EntityMetadataProperties::SCALE => new FloatMetadataProperty(0.01) //zero causes problems on debug builds ]; - - $p[] = $pk; + $p[] = AddPlayerPacket::create( + $uuid, + $name, + $this->entityId, //TODO: actor unique ID + $this->entityId, + "", + $pos, //TODO: check offset + null, + 0, + 0, + 0, + ItemStackWrapper::legacy(ItemStack::null()), + $actorMetadata, + AdventureSettingsPacket::create(0, 0, 0, 0, 0, $this->entityId), + [], + "", + DeviceOS::UNKNOWN + ); $p[] = PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($uuid)]); } From e50072dc2756b479ca478aa2c6b12ebe07fbf418 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Oct 2021 01:55:10 +0100 Subject: [PATCH 156/710] Clean PHPStan baselines --- tests/phpstan/configs/actual-problems.neon | 5 ---- tests/phpstan/configs/l7-baseline.neon | 30 ---------------------- 2 files changed, 35 deletions(-) diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 312971fa6..ed9a6f986 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -1,10 +1,5 @@ parameters: ignoreErrors: - - - message: "#^Instanceof between pocketmine\\\\plugin\\\\PluginManager and pocketmine\\\\plugin\\\\PluginManager will always evaluate to true\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - message: "#^Property pocketmine\\\\event\\\\entity\\\\EntityShootBowEvent\\:\\:\\$projectile \\(pocketmine\\\\entity\\\\projectile\\\\Projectile\\) does not accept pocketmine\\\\entity\\\\Entity\\.$#" count: 1 diff --git a/tests/phpstan/configs/l7-baseline.neon b/tests/phpstan/configs/l7-baseline.neon index 4cd255836..950cef3e6 100644 --- a/tests/phpstan/configs/l7-baseline.neon +++ b/tests/phpstan/configs/l7-baseline.neon @@ -650,16 +650,6 @@ parameters: count: 3 path: ../../../src/world/World.php - - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BlockActorDataPacket\\:\\:create\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/World.php - - - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UpdateBlockPacket\\:\\:create\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/World.php - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" count: 3 @@ -690,16 +680,6 @@ parameters: count: 3 path: ../../../src/world/World.php - - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BlockActorDataPacket\\:\\:create\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/World.php - - - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UpdateBlockPacket\\:\\:create\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/World.php - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" count: 3 @@ -730,16 +710,6 @@ parameters: count: 3 path: ../../../src/world/World.php - - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BlockActorDataPacket\\:\\:create\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/World.php - - - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UpdateBlockPacket\\:\\:create\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/world/World.php - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\world\\\\World\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" count: 3 From 701a71a4ee7d54de8ad9fbed9796059d87b7256f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Oct 2021 02:01:26 +0100 Subject: [PATCH 157/710] Sound::encode() position is no longer nullable making this nullable was based on the invalid assumption that global sounds have no position, but it turns out they _do_ still use the position to make the sound come from the correct direction. --- src/world/sound/AnvilBreakSound.php | 2 +- src/world/sound/AnvilFallSound.php | 2 +- src/world/sound/AnvilUseSound.php | 2 +- src/world/sound/ArrowHitSound.php | 2 +- src/world/sound/BarrelCloseSound.php | 2 +- src/world/sound/BarrelOpenSound.php | 2 +- src/world/sound/BellRingSound.php | 2 +- src/world/sound/BlazeShootSound.php | 2 +- src/world/sound/BlockBreakSound.php | 2 +- src/world/sound/BlockPlaceSound.php | 2 +- src/world/sound/BlockPunchSound.php | 2 +- src/world/sound/BowShootSound.php | 2 +- src/world/sound/BucketEmptyLavaSound.php | 2 +- src/world/sound/BucketEmptyWaterSound.php | 2 +- src/world/sound/BucketFillLavaSound.php | 2 +- src/world/sound/BucketFillWaterSound.php | 2 +- src/world/sound/ChestCloseSound.php | 2 +- src/world/sound/ChestOpenSound.php | 2 +- src/world/sound/ClickSound.php | 2 +- src/world/sound/DoorBumpSound.php | 2 +- src/world/sound/DoorCrashSound.php | 2 +- src/world/sound/DoorSound.php | 2 +- src/world/sound/EnderChestCloseSound.php | 2 +- src/world/sound/EnderChestOpenSound.php | 2 +- src/world/sound/EndermanTeleportSound.php | 2 +- src/world/sound/EntityAttackNoDamageSound.php | 2 +- src/world/sound/EntityAttackSound.php | 2 +- src/world/sound/EntityLandSound.php | 2 +- src/world/sound/EntityLongFallSound.php | 2 +- src/world/sound/EntityShortFallSound.php | 2 +- src/world/sound/ExplodeSound.php | 2 +- src/world/sound/FireExtinguishSound.php | 2 +- src/world/sound/FizzSound.php | 2 +- src/world/sound/FlintSteelSound.php | 2 +- src/world/sound/GhastShootSound.php | 2 +- src/world/sound/GhastSound.php | 2 +- src/world/sound/IgniteSound.php | 2 +- src/world/sound/ItemBreakSound.php | 2 +- src/world/sound/LaunchSound.php | 2 +- src/world/sound/NoteSound.php | 2 +- src/world/sound/PaintingPlaceSound.php | 2 +- src/world/sound/PopSound.php | 2 +- src/world/sound/PotionSplashSound.php | 2 +- src/world/sound/RecordSound.php | 2 +- src/world/sound/RecordStopSound.php | 2 +- src/world/sound/RedstonePowerOffSound.php | 2 +- src/world/sound/RedstonePowerOnSound.php | 2 +- src/world/sound/ShulkerBoxCloseSound.php | 2 +- src/world/sound/ShulkerBoxOpenSound.php | 2 +- src/world/sound/Sound.php | 2 +- src/world/sound/ThrowSound.php | 2 +- src/world/sound/TotemUseSound.php | 2 +- src/world/sound/XpCollectSound.php | 2 +- src/world/sound/XpLevelUpSound.php | 2 +- 54 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/world/sound/AnvilBreakSound.php b/src/world/sound/AnvilBreakSound.php index 9da378b35..cde91af4c 100644 --- a/src/world/sound/AnvilBreakSound.php +++ b/src/world/sound/AnvilBreakSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class AnvilBreakSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ANVIL_BREAK, 0, $pos)]; } } diff --git a/src/world/sound/AnvilFallSound.php b/src/world/sound/AnvilFallSound.php index 7abf3f6ce..3ef6cc61e 100644 --- a/src/world/sound/AnvilFallSound.php +++ b/src/world/sound/AnvilFallSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class AnvilFallSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ANVIL_FALL, 0, $pos)]; } } diff --git a/src/world/sound/AnvilUseSound.php b/src/world/sound/AnvilUseSound.php index 93c0b64ee..99beb8b0e 100644 --- a/src/world/sound/AnvilUseSound.php +++ b/src/world/sound/AnvilUseSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class AnvilUseSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ANVIL_USE, 0, $pos)]; } } diff --git a/src/world/sound/ArrowHitSound.php b/src/world/sound/ArrowHitSound.php index cb89dbc51..4b1d9da58 100644 --- a/src/world/sound/ArrowHitSound.php +++ b/src/world/sound/ArrowHitSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ArrowHitSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BOW_HIT, $pos, false)]; } } diff --git a/src/world/sound/BarrelCloseSound.php b/src/world/sound/BarrelCloseSound.php index 6adb76093..fa673a938 100644 --- a/src/world/sound/BarrelCloseSound.php +++ b/src/world/sound/BarrelCloseSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BarrelCloseSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BLOCK_BARREL_CLOSE, $pos, false)]; } } diff --git a/src/world/sound/BarrelOpenSound.php b/src/world/sound/BarrelOpenSound.php index 04edd7365..ed8a1a4df 100644 --- a/src/world/sound/BarrelOpenSound.php +++ b/src/world/sound/BarrelOpenSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BarrelOpenSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BLOCK_BARREL_OPEN, $pos, false)]; } } diff --git a/src/world/sound/BellRingSound.php b/src/world/sound/BellRingSound.php index af96e7f09..c14b63d68 100644 --- a/src/world/sound/BellRingSound.php +++ b/src/world/sound/BellRingSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; final class BellRingSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BLOCK_BELL_HIT, $pos, false)]; } } diff --git a/src/world/sound/BlazeShootSound.php b/src/world/sound/BlazeShootSound.php index 3924784d0..00f772bbe 100644 --- a/src/world/sound/BlazeShootSound.php +++ b/src/world/sound/BlazeShootSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class BlazeShootSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_BLAZE_SHOOT, 0, $pos)]; } } diff --git a/src/world/sound/BlockBreakSound.php b/src/world/sound/BlockBreakSound.php index 041664cc8..99cac4c7b 100644 --- a/src/world/sound/BlockBreakSound.php +++ b/src/world/sound/BlockBreakSound.php @@ -37,7 +37,7 @@ class BlockBreakSound implements Sound{ $this->block = $block; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BREAK, $pos, false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; } } diff --git a/src/world/sound/BlockPlaceSound.php b/src/world/sound/BlockPlaceSound.php index 0c8967469..7a95b2222 100644 --- a/src/world/sound/BlockPlaceSound.php +++ b/src/world/sound/BlockPlaceSound.php @@ -37,7 +37,7 @@ class BlockPlaceSound implements Sound{ $this->block = $block; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_PLACE, $pos, false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; } } diff --git a/src/world/sound/BlockPunchSound.php b/src/world/sound/BlockPunchSound.php index 009e1a754..51093522e 100644 --- a/src/world/sound/BlockPunchSound.php +++ b/src/world/sound/BlockPunchSound.php @@ -40,7 +40,7 @@ class BlockPunchSound implements Sound{ $this->block = $block; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound( LevelSoundEventPacket::SOUND_HIT, $pos, diff --git a/src/world/sound/BowShootSound.php b/src/world/sound/BowShootSound.php index 22b65cac6..abdb8169c 100644 --- a/src/world/sound/BowShootSound.php +++ b/src/world/sound/BowShootSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BowShootSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BOW, $pos, false)]; } } diff --git a/src/world/sound/BucketEmptyLavaSound.php b/src/world/sound/BucketEmptyLavaSound.php index d0f66e7c1..99241daf1 100644 --- a/src/world/sound/BucketEmptyLavaSound.php +++ b/src/world/sound/BucketEmptyLavaSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BucketEmptyLavaSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_EMPTY_LAVA, $pos, false)]; } } diff --git a/src/world/sound/BucketEmptyWaterSound.php b/src/world/sound/BucketEmptyWaterSound.php index af4dec6e2..087675aa9 100644 --- a/src/world/sound/BucketEmptyWaterSound.php +++ b/src/world/sound/BucketEmptyWaterSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BucketEmptyWaterSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_EMPTY_WATER, $pos, false)]; } } diff --git a/src/world/sound/BucketFillLavaSound.php b/src/world/sound/BucketFillLavaSound.php index 01d4edb09..d4df3ef67 100644 --- a/src/world/sound/BucketFillLavaSound.php +++ b/src/world/sound/BucketFillLavaSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BucketFillLavaSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_FILL_LAVA, $pos, false)]; } } diff --git a/src/world/sound/BucketFillWaterSound.php b/src/world/sound/BucketFillWaterSound.php index cdb126c7c..638922413 100644 --- a/src/world/sound/BucketFillWaterSound.php +++ b/src/world/sound/BucketFillWaterSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class BucketFillWaterSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_FILL_WATER, $pos, false)]; } } diff --git a/src/world/sound/ChestCloseSound.php b/src/world/sound/ChestCloseSound.php index 1738ed81f..2ccaaa035 100644 --- a/src/world/sound/ChestCloseSound.php +++ b/src/world/sound/ChestCloseSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ChestCloseSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_CHEST_CLOSED, $pos, false)]; } } diff --git a/src/world/sound/ChestOpenSound.php b/src/world/sound/ChestOpenSound.php index dd7bb6a14..ee8c9313b 100644 --- a/src/world/sound/ChestOpenSound.php +++ b/src/world/sound/ChestOpenSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ChestOpenSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_CHEST_OPEN, $pos, false)]; } } diff --git a/src/world/sound/ClickSound.php b/src/world/sound/ClickSound.php index dad9e325a..db472b292 100644 --- a/src/world/sound/ClickSound.php +++ b/src/world/sound/ClickSound.php @@ -39,7 +39,7 @@ class ClickSound implements Sound{ return $this->pitch; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_CLICK, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/DoorBumpSound.php b/src/world/sound/DoorBumpSound.php index 2d13b0ad8..239401637 100644 --- a/src/world/sound/DoorBumpSound.php +++ b/src/world/sound/DoorBumpSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class DoorBumpSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_DOOR_BUMP, 0, $pos)]; } } diff --git a/src/world/sound/DoorCrashSound.php b/src/world/sound/DoorCrashSound.php index fa9524a74..6f3a6cbe0 100644 --- a/src/world/sound/DoorCrashSound.php +++ b/src/world/sound/DoorCrashSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class DoorCrashSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_DOOR_CRASH, 0, $pos)]; } } diff --git a/src/world/sound/DoorSound.php b/src/world/sound/DoorSound.php index 9eca4181d..b3e4addf9 100644 --- a/src/world/sound/DoorSound.php +++ b/src/world/sound/DoorSound.php @@ -39,7 +39,7 @@ class DoorSound implements Sound{ return $this->pitch; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_DOOR, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/EnderChestCloseSound.php b/src/world/sound/EnderChestCloseSound.php index d016a3ae5..4292dec35 100644 --- a/src/world/sound/EnderChestCloseSound.php +++ b/src/world/sound/EnderChestCloseSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class EnderChestCloseSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_ENDERCHEST_CLOSED, $pos, false)]; } } diff --git a/src/world/sound/EnderChestOpenSound.php b/src/world/sound/EnderChestOpenSound.php index b2a664dd3..ab1894450 100644 --- a/src/world/sound/EnderChestOpenSound.php +++ b/src/world/sound/EnderChestOpenSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class EnderChestOpenSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_ENDERCHEST_OPEN, $pos, false)]; } } diff --git a/src/world/sound/EndermanTeleportSound.php b/src/world/sound/EndermanTeleportSound.php index 544ffcd21..e2f3f03e8 100644 --- a/src/world/sound/EndermanTeleportSound.php +++ b/src/world/sound/EndermanTeleportSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class EndermanTeleportSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ENDERMAN_TELEPORT, 0, $pos)]; } } diff --git a/src/world/sound/EntityAttackNoDamageSound.php b/src/world/sound/EntityAttackNoDamageSound.php index 0b2fb0cff..2ab77a241 100644 --- a/src/world/sound/EntityAttackNoDamageSound.php +++ b/src/world/sound/EntityAttackNoDamageSound.php @@ -31,7 +31,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; */ class EntityAttackNoDamageSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( LevelSoundEventPacket::SOUND_ATTACK_NODAMAGE, $pos, diff --git a/src/world/sound/EntityAttackSound.php b/src/world/sound/EntityAttackSound.php index d7fd63b7b..ecf39a888 100644 --- a/src/world/sound/EntityAttackSound.php +++ b/src/world/sound/EntityAttackSound.php @@ -31,7 +31,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; */ class EntityAttackSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( LevelSoundEventPacket::SOUND_ATTACK_STRONG, //TODO: seems like ATTACK is dysfunctional $pos, diff --git a/src/world/sound/EntityLandSound.php b/src/world/sound/EntityLandSound.php index 7871082bb..38ba283fc 100644 --- a/src/world/sound/EntityLandSound.php +++ b/src/world/sound/EntityLandSound.php @@ -44,7 +44,7 @@ class EntityLandSound implements Sound{ $this->blockLandedOn = $blockLandedOn; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( LevelSoundEventPacket::SOUND_LAND, $pos, diff --git a/src/world/sound/EntityLongFallSound.php b/src/world/sound/EntityLongFallSound.php index 88246f846..1d0a07f40 100644 --- a/src/world/sound/EntityLongFallSound.php +++ b/src/world/sound/EntityLongFallSound.php @@ -40,7 +40,7 @@ class EntityLongFallSound implements Sound{ $this->entity = $entity; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( LevelSoundEventPacket::SOUND_FALL_BIG, $pos, diff --git a/src/world/sound/EntityShortFallSound.php b/src/world/sound/EntityShortFallSound.php index fcacd797e..2f64cc269 100644 --- a/src/world/sound/EntityShortFallSound.php +++ b/src/world/sound/EntityShortFallSound.php @@ -39,7 +39,7 @@ class EntityShortFallSound implements Sound{ $this->entity = $entity; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( LevelSoundEventPacket::SOUND_FALL_SMALL, $pos, diff --git a/src/world/sound/ExplodeSound.php b/src/world/sound/ExplodeSound.php index 9dfcd19f8..1f2db9c89 100644 --- a/src/world/sound/ExplodeSound.php +++ b/src/world/sound/ExplodeSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ExplodeSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_EXPLODE, $pos, false)]; } } diff --git a/src/world/sound/FireExtinguishSound.php b/src/world/sound/FireExtinguishSound.php index e9f7e3097..255e821f9 100644 --- a/src/world/sound/FireExtinguishSound.php +++ b/src/world/sound/FireExtinguishSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; final class FireExtinguishSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_EXTINGUISH_FIRE, $pos, false)]; } } diff --git a/src/world/sound/FizzSound.php b/src/world/sound/FizzSound.php index 0e7b42ffb..67be8db44 100644 --- a/src/world/sound/FizzSound.php +++ b/src/world/sound/FizzSound.php @@ -39,7 +39,7 @@ class FizzSound implements Sound{ return $this->pitch; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_FIZZ, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/FlintSteelSound.php b/src/world/sound/FlintSteelSound.php index 15ff96a28..4569ed510 100644 --- a/src/world/sound/FlintSteelSound.php +++ b/src/world/sound/FlintSteelSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class FlintSteelSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_IGNITE, $pos, false)]; } } diff --git a/src/world/sound/GhastShootSound.php b/src/world/sound/GhastShootSound.php index 40f6a47cc..e7cb550ff 100644 --- a/src/world/sound/GhastShootSound.php +++ b/src/world/sound/GhastShootSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class GhastShootSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_GHAST_SHOOT, 0, $pos)]; } } diff --git a/src/world/sound/GhastSound.php b/src/world/sound/GhastSound.php index b49a9c374..2e707d3db 100644 --- a/src/world/sound/GhastSound.php +++ b/src/world/sound/GhastSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class GhastSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_GHAST, 0, $pos)]; } } diff --git a/src/world/sound/IgniteSound.php b/src/world/sound/IgniteSound.php index dd72342da..1f1e88703 100644 --- a/src/world/sound/IgniteSound.php +++ b/src/world/sound/IgniteSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class IgniteSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_IGNITE, 0, $pos)]; } } diff --git a/src/world/sound/ItemBreakSound.php b/src/world/sound/ItemBreakSound.php index 0b7f07435..c2329ce12 100644 --- a/src/world/sound/ItemBreakSound.php +++ b/src/world/sound/ItemBreakSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ItemBreakSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BREAK, $pos, false)]; } } diff --git a/src/world/sound/LaunchSound.php b/src/world/sound/LaunchSound.php index e6772f1c9..af8b02041 100644 --- a/src/world/sound/LaunchSound.php +++ b/src/world/sound/LaunchSound.php @@ -39,7 +39,7 @@ class LaunchSound implements Sound{ return $this->pitch; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_SHOOT, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/NoteSound.php b/src/world/sound/NoteSound.php index e84c736b0..7d2bdef42 100644 --- a/src/world/sound/NoteSound.php +++ b/src/world/sound/NoteSound.php @@ -41,7 +41,7 @@ class NoteSound implements Sound{ $this->note = $note; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_NOTE, $pos, false, ($this->instrument->getMagicNumber() << 8) | $this->note)]; } } diff --git a/src/world/sound/PaintingPlaceSound.php b/src/world/sound/PaintingPlaceSound.php index c836e0842..6d9a7ebe3 100644 --- a/src/world/sound/PaintingPlaceSound.php +++ b/src/world/sound/PaintingPlaceSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class PaintingPlaceSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ //item frame and painting have the same sound return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ITEMFRAME_PLACE, 0, $pos)]; } diff --git a/src/world/sound/PopSound.php b/src/world/sound/PopSound.php index 5bce1145f..421018333 100644 --- a/src/world/sound/PopSound.php +++ b/src/world/sound/PopSound.php @@ -39,7 +39,7 @@ class PopSound implements Sound{ return $this->pitch; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_POP, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/PotionSplashSound.php b/src/world/sound/PotionSplashSound.php index efde99b25..2547f2aee 100644 --- a/src/world/sound/PotionSplashSound.php +++ b/src/world/sound/PotionSplashSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class PotionSplashSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_GLASS, $pos, false)]; } } diff --git a/src/world/sound/RecordSound.php b/src/world/sound/RecordSound.php index 99e781db9..57051d5b6 100644 --- a/src/world/sound/RecordSound.php +++ b/src/world/sound/RecordSound.php @@ -36,7 +36,7 @@ class RecordSound implements Sound{ $this->recordType = $recordType; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound($this->recordType->getSoundId(), $pos, false)]; } } diff --git a/src/world/sound/RecordStopSound.php b/src/world/sound/RecordStopSound.php index 2bdd0e611..9e331a9ff 100644 --- a/src/world/sound/RecordStopSound.php +++ b/src/world/sound/RecordStopSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class RecordStopSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_STOP_RECORD, $pos, false)]; } } diff --git a/src/world/sound/RedstonePowerOffSound.php b/src/world/sound/RedstonePowerOffSound.php index 5f0ec7280..b07c723b4 100644 --- a/src/world/sound/RedstonePowerOffSound.php +++ b/src/world/sound/RedstonePowerOffSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class RedstonePowerOffSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_POWER_OFF, $pos, false)]; } } diff --git a/src/world/sound/RedstonePowerOnSound.php b/src/world/sound/RedstonePowerOnSound.php index e260d1166..d71f6b998 100644 --- a/src/world/sound/RedstonePowerOnSound.php +++ b/src/world/sound/RedstonePowerOnSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class RedstonePowerOnSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_POWER_ON, $pos, false)]; } } diff --git a/src/world/sound/ShulkerBoxCloseSound.php b/src/world/sound/ShulkerBoxCloseSound.php index 2e8e758a4..ea7a630c3 100644 --- a/src/world/sound/ShulkerBoxCloseSound.php +++ b/src/world/sound/ShulkerBoxCloseSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ShulkerBoxCloseSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_SHULKERBOX_CLOSED, $pos, false)]; } } diff --git a/src/world/sound/ShulkerBoxOpenSound.php b/src/world/sound/ShulkerBoxOpenSound.php index a5dacea08..491b5dace 100644 --- a/src/world/sound/ShulkerBoxOpenSound.php +++ b/src/world/sound/ShulkerBoxOpenSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ShulkerBoxOpenSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_SHULKERBOX_OPEN, $pos, false)]; } } diff --git a/src/world/sound/Sound.php b/src/world/sound/Sound.php index 84121db6a..19074e256 100644 --- a/src/world/sound/Sound.php +++ b/src/world/sound/Sound.php @@ -31,5 +31,5 @@ interface Sound{ /** * @return ClientboundPacket[] */ - public function encode(?Vector3 $pos) : array; + public function encode(Vector3 $pos) : array; } diff --git a/src/world/sound/ThrowSound.php b/src/world/sound/ThrowSound.php index 1e3297a65..b24474e5f 100644 --- a/src/world/sound/ThrowSound.php +++ b/src/world/sound/ThrowSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; class ThrowSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_THROW, $pos, -1, "minecraft:player", false, false)]; } } diff --git a/src/world/sound/TotemUseSound.php b/src/world/sound/TotemUseSound.php index baa04275c..561d9c41a 100644 --- a/src/world/sound/TotemUseSound.php +++ b/src/world/sound/TotemUseSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class TotemUseSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_TOTEM, 0, $pos)]; } } diff --git a/src/world/sound/XpCollectSound.php b/src/world/sound/XpCollectSound.php index 71a304f30..655835069 100644 --- a/src/world/sound/XpCollectSound.php +++ b/src/world/sound/XpCollectSound.php @@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket; class XpCollectSound implements Sound{ - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ORB, 0, $pos)]; } } diff --git a/src/world/sound/XpLevelUpSound.php b/src/world/sound/XpLevelUpSound.php index aa44a5ff6..8334b7bea 100644 --- a/src/world/sound/XpLevelUpSound.php +++ b/src/world/sound/XpLevelUpSound.php @@ -41,7 +41,7 @@ class XpLevelUpSound implements Sound{ return $this->xpLevel; } - public function encode(?Vector3 $pos) : array{ + public function encode(Vector3 $pos) : array{ //No idea why such odd numbers, but this works... //TODO: check arbitrary volume return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_LEVELUP, $pos, false, 0x10000000 * intdiv(min(30, $this->xpLevel), 5))]; From 04aedc64946923d91caa9870b39556c4e1fa9069 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Oct 2021 23:54:49 +0100 Subject: [PATCH 158/710] Updated BedrockProtocol --- composer.lock | 8 ++-- src/block/utils/RecordType.php | 25 ++++++------ src/entity/animation/ArmSwingAnimation.php | 3 +- src/entity/animation/ArrowShakeAnimation.php | 3 +- .../animation/ConsumingItemAnimation.php | 3 +- src/entity/animation/DeathAnimation.php | 3 +- src/entity/animation/HurtAnimation.php | 3 +- src/entity/animation/RespawnAnimation.php | 3 +- .../animation/SquidInkCloudAnimation.php | 3 +- src/entity/animation/TotemUseAnimation.php | 3 +- .../mcpe/handler/DeathPacketHandler.php | 3 +- .../mcpe/handler/InGamePacketHandler.php | 40 ++++++++++--------- src/player/SurvivalBlockBreakHandler.php | 5 ++- src/world/particle/BlockBreakParticle.php | 3 +- src/world/particle/BlockPunchParticle.php | 3 +- .../particle/DragonEggTeleportParticle.php | 3 +- .../particle/EndermanTeleportParticle.php | 3 +- src/world/particle/MobSpawnParticle.php | 3 +- src/world/particle/PotionSplashParticle.php | 3 +- src/world/sound/AnvilBreakSound.php | 3 +- src/world/sound/AnvilFallSound.php | 3 +- src/world/sound/AnvilUseSound.php | 3 +- src/world/sound/ArrowHitSound.php | 3 +- src/world/sound/BarrelCloseSound.php | 3 +- src/world/sound/BarrelOpenSound.php | 3 +- src/world/sound/BellRingSound.php | 3 +- src/world/sound/BlazeShootSound.php | 3 +- src/world/sound/BlockBreakSound.php | 3 +- src/world/sound/BlockPlaceSound.php | 3 +- src/world/sound/BlockPunchSound.php | 3 +- src/world/sound/BowShootSound.php | 3 +- src/world/sound/BucketEmptyLavaSound.php | 3 +- src/world/sound/BucketEmptyWaterSound.php | 3 +- src/world/sound/BucketFillLavaSound.php | 3 +- src/world/sound/BucketFillWaterSound.php | 3 +- src/world/sound/ChestCloseSound.php | 3 +- src/world/sound/ChestOpenSound.php | 3 +- src/world/sound/ClickSound.php | 3 +- src/world/sound/DoorBumpSound.php | 3 +- src/world/sound/DoorCrashSound.php | 3 +- src/world/sound/DoorSound.php | 3 +- src/world/sound/EnderChestCloseSound.php | 3 +- src/world/sound/EnderChestOpenSound.php | 3 +- src/world/sound/EndermanTeleportSound.php | 3 +- src/world/sound/EntityAttackNoDamageSound.php | 3 +- src/world/sound/EntityAttackSound.php | 3 +- src/world/sound/EntityLandSound.php | 3 +- src/world/sound/EntityLongFallSound.php | 3 +- src/world/sound/EntityShortFallSound.php | 3 +- src/world/sound/ExplodeSound.php | 3 +- src/world/sound/FireExtinguishSound.php | 3 +- src/world/sound/FizzSound.php | 3 +- src/world/sound/FlintSteelSound.php | 3 +- src/world/sound/GhastShootSound.php | 3 +- src/world/sound/GhastSound.php | 3 +- src/world/sound/IgniteSound.php | 3 +- src/world/sound/ItemBreakSound.php | 3 +- src/world/sound/LaunchSound.php | 3 +- src/world/sound/NoteSound.php | 3 +- src/world/sound/PaintingPlaceSound.php | 3 +- src/world/sound/PopSound.php | 3 +- src/world/sound/PotionSplashSound.php | 3 +- src/world/sound/RecordStopSound.php | 3 +- src/world/sound/RedstonePowerOffSound.php | 3 +- src/world/sound/RedstonePowerOnSound.php | 3 +- src/world/sound/ShulkerBoxCloseSound.php | 3 +- src/world/sound/ShulkerBoxOpenSound.php | 3 +- src/world/sound/ThrowSound.php | 3 +- src/world/sound/TotemUseSound.php | 3 +- src/world/sound/XpCollectSound.php | 3 +- src/world/sound/XpLevelUpSound.php | 3 +- 71 files changed, 175 insertions(+), 104 deletions(-) diff --git a/composer.lock b/composer.lock index 89bd8e43b..883984a57 100644 --- a/composer.lock +++ b/composer.lock @@ -253,12 +253,12 @@ "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "97fa88e9eff2c9bd5408fa964515504a4d9230bf" + "reference": "5285dde125b529e070db7eeb0d3774208e1652ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/97fa88e9eff2c9bd5408fa964515504a4d9230bf", - "reference": "97fa88e9eff2c9bd5408fa964515504a4d9230bf", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/5285dde125b529e070db7eeb0d3774208e1652ef", + "reference": "5285dde125b529e070db7eeb0d3774208e1652ef", "shasum": "" }, "require": { @@ -293,7 +293,7 @@ "issues": "https://github.com/pmmp/BedrockProtocol/issues", "source": "https://github.com/pmmp/BedrockProtocol/tree/master" }, - "time": "2021-10-23T00:06:46+00:00" + "time": "2021-10-23T15:18:49+00:00" }, { "name": "pocketmine/binaryutils", diff --git a/src/block/utils/RecordType.php b/src/block/utils/RecordType.php index 093663d0b..967cdc034 100644 --- a/src/block/utils/RecordType.php +++ b/src/block/utils/RecordType.php @@ -26,6 +26,7 @@ namespace pocketmine\block\utils; use pocketmine\lang\KnownTranslationFactory; use pocketmine\lang\Translatable; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; use pocketmine\utils\EnumTrait; /** @@ -54,18 +55,18 @@ final class RecordType{ protected static function setup() : void{ self::registerAll( - new RecordType("disk_13", "C418 - 13", LevelSoundEventPacket::SOUND_RECORD_13, KnownTranslationFactory::item_record_13_desc()), - new RecordType("disk_cat", "C418 - cat", LevelSoundEventPacket::SOUND_RECORD_CAT, KnownTranslationFactory::item_record_cat_desc()), - new RecordType("disk_blocks", "C418 - blocks", LevelSoundEventPacket::SOUND_RECORD_BLOCKS, KnownTranslationFactory::item_record_blocks_desc()), - new RecordType("disk_chirp", "C418 - chirp", LevelSoundEventPacket::SOUND_RECORD_CHIRP, KnownTranslationFactory::item_record_chirp_desc()), - new RecordType("disk_far", "C418 - far", LevelSoundEventPacket::SOUND_RECORD_FAR, KnownTranslationFactory::item_record_far_desc()), - new RecordType("disk_mall", "C418 - mall", LevelSoundEventPacket::SOUND_RECORD_MALL, KnownTranslationFactory::item_record_mall_desc()), - new RecordType("disk_mellohi", "C418 - mellohi", LevelSoundEventPacket::SOUND_RECORD_MELLOHI, KnownTranslationFactory::item_record_mellohi_desc()), - new RecordType("disk_stal", "C418 - stal", LevelSoundEventPacket::SOUND_RECORD_STAL, KnownTranslationFactory::item_record_stal_desc()), - new RecordType("disk_strad", "C418 - strad", LevelSoundEventPacket::SOUND_RECORD_STRAD, KnownTranslationFactory::item_record_strad_desc()), - new RecordType("disk_ward", "C418 - ward", LevelSoundEventPacket::SOUND_RECORD_WARD, KnownTranslationFactory::item_record_ward_desc()), - new RecordType("disk_11", "C418 - 11", LevelSoundEventPacket::SOUND_RECORD_11, KnownTranslationFactory::item_record_11_desc()), - new RecordType("disk_wait", "C418 - wait", LevelSoundEventPacket::SOUND_RECORD_WAIT, KnownTranslationFactory::item_record_wait_desc()) + new RecordType("disk_13", "C418 - 13", LevelSoundEvent::RECORD_13, KnownTranslationFactory::item_record_13_desc()), + new RecordType("disk_cat", "C418 - cat", LevelSoundEvent::RECORD_CAT, KnownTranslationFactory::item_record_cat_desc()), + new RecordType("disk_blocks", "C418 - blocks", LevelSoundEvent::RECORD_BLOCKS, KnownTranslationFactory::item_record_blocks_desc()), + new RecordType("disk_chirp", "C418 - chirp", LevelSoundEvent::RECORD_CHIRP, KnownTranslationFactory::item_record_chirp_desc()), + new RecordType("disk_far", "C418 - far", LevelSoundEvent::RECORD_FAR, KnownTranslationFactory::item_record_far_desc()), + new RecordType("disk_mall", "C418 - mall", LevelSoundEvent::RECORD_MALL, KnownTranslationFactory::item_record_mall_desc()), + new RecordType("disk_mellohi", "C418 - mellohi", LevelSoundEvent::RECORD_MELLOHI, KnownTranslationFactory::item_record_mellohi_desc()), + new RecordType("disk_stal", "C418 - stal", LevelSoundEvent::RECORD_STAL, KnownTranslationFactory::item_record_stal_desc()), + new RecordType("disk_strad", "C418 - strad", LevelSoundEvent::RECORD_STRAD, KnownTranslationFactory::item_record_strad_desc()), + new RecordType("disk_ward", "C418 - ward", LevelSoundEvent::RECORD_WARD, KnownTranslationFactory::item_record_ward_desc()), + new RecordType("disk_11", "C418 - 11", LevelSoundEvent::RECORD_11, KnownTranslationFactory::item_record_11_desc()), + new RecordType("disk_wait", "C418 - wait", LevelSoundEvent::RECORD_WAIT, KnownTranslationFactory::item_record_wait_desc()) //TODO: Lena Raine - Pigstep ); } diff --git a/src/entity/animation/ArmSwingAnimation.php b/src/entity/animation/ArmSwingAnimation.php index c309472bf..8871415a2 100644 --- a/src/entity/animation/ArmSwingAnimation.php +++ b/src/entity/animation/ArmSwingAnimation.php @@ -25,6 +25,7 @@ namespace pocketmine\entity\animation; use pocketmine\entity\Living; use pocketmine\network\mcpe\protocol\ActorEventPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; final class ArmSwingAnimation implements Animation{ @@ -37,7 +38,7 @@ final class ArmSwingAnimation implements Animation{ public function encode() : array{ return [ - ActorEventPacket::create($this->entity->getId(), ActorEventPacket::ARM_SWING, 0) + ActorEventPacket::create($this->entity->getId(), ActorEvent::ARM_SWING, 0) ]; } } diff --git a/src/entity/animation/ArrowShakeAnimation.php b/src/entity/animation/ArrowShakeAnimation.php index 925b93d3a..256c6142b 100644 --- a/src/entity/animation/ArrowShakeAnimation.php +++ b/src/entity/animation/ArrowShakeAnimation.php @@ -25,6 +25,7 @@ namespace pocketmine\entity\animation; use pocketmine\entity\projectile\Arrow; use pocketmine\network\mcpe\protocol\ActorEventPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; class ArrowShakeAnimation implements Animation{ @@ -40,7 +41,7 @@ class ArrowShakeAnimation implements Animation{ public function encode() : array{ return [ - ActorEventPacket::create($this->arrow->getId(), ActorEventPacket::ARROW_SHAKE, $this->durationInTicks) + ActorEventPacket::create($this->arrow->getId(), ActorEvent::ARROW_SHAKE, $this->durationInTicks) ]; } } diff --git a/src/entity/animation/ConsumingItemAnimation.php b/src/entity/animation/ConsumingItemAnimation.php index 4f3e34ba4..b32f118bb 100644 --- a/src/entity/animation/ConsumingItemAnimation.php +++ b/src/entity/animation/ConsumingItemAnimation.php @@ -27,6 +27,7 @@ use pocketmine\entity\Human; use pocketmine\item\Item; use pocketmine\network\mcpe\convert\ItemTranslator; use pocketmine\network\mcpe\protocol\ActorEventPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; final class ConsumingItemAnimation implements Animation{ @@ -45,7 +46,7 @@ final class ConsumingItemAnimation implements Animation{ [$netId, $netData] = ItemTranslator::getInstance()->toNetworkId($this->item->getId(), $this->item->getMeta()); return [ //TODO: need to check the data values - ActorEventPacket::create($this->human->getId(), ActorEventPacket::EATING_ITEM, ($netId << 16) | $netData) + ActorEventPacket::create($this->human->getId(), ActorEvent::EATING_ITEM, ($netId << 16) | $netData) ]; } } diff --git a/src/entity/animation/DeathAnimation.php b/src/entity/animation/DeathAnimation.php index 35dab4597..a3a924413 100644 --- a/src/entity/animation/DeathAnimation.php +++ b/src/entity/animation/DeathAnimation.php @@ -25,6 +25,7 @@ namespace pocketmine\entity\animation; use pocketmine\entity\Living; use pocketmine\network\mcpe\protocol\ActorEventPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; final class DeathAnimation implements Animation{ @@ -37,7 +38,7 @@ final class DeathAnimation implements Animation{ public function encode() : array{ return [ - ActorEventPacket::create($this->entity->getId(), ActorEventPacket::DEATH_ANIMATION, 0) + ActorEventPacket::create($this->entity->getId(), ActorEvent::DEATH_ANIMATION, 0) ]; } } diff --git a/src/entity/animation/HurtAnimation.php b/src/entity/animation/HurtAnimation.php index 3ba5ebb8c..355b49d47 100644 --- a/src/entity/animation/HurtAnimation.php +++ b/src/entity/animation/HurtAnimation.php @@ -25,6 +25,7 @@ namespace pocketmine\entity\animation; use pocketmine\entity\Living; use pocketmine\network\mcpe\protocol\ActorEventPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; final class HurtAnimation implements Animation{ @@ -37,7 +38,7 @@ final class HurtAnimation implements Animation{ public function encode() : array{ return [ - ActorEventPacket::create($this->entity->getId(), ActorEventPacket::HURT_ANIMATION, 0) + ActorEventPacket::create($this->entity->getId(), ActorEvent::HURT_ANIMATION, 0) ]; } } diff --git a/src/entity/animation/RespawnAnimation.php b/src/entity/animation/RespawnAnimation.php index defb26cf7..e8466e26e 100644 --- a/src/entity/animation/RespawnAnimation.php +++ b/src/entity/animation/RespawnAnimation.php @@ -25,6 +25,7 @@ namespace pocketmine\entity\animation; use pocketmine\entity\Living; use pocketmine\network\mcpe\protocol\ActorEventPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; final class RespawnAnimation implements Animation{ @@ -37,7 +38,7 @@ final class RespawnAnimation implements Animation{ public function encode() : array{ return [ - ActorEventPacket::create($this->entity->getId(), ActorEventPacket::RESPAWN, 0) + ActorEventPacket::create($this->entity->getId(), ActorEvent::RESPAWN, 0) ]; } } diff --git a/src/entity/animation/SquidInkCloudAnimation.php b/src/entity/animation/SquidInkCloudAnimation.php index fa3a9fd6b..6ae728a79 100644 --- a/src/entity/animation/SquidInkCloudAnimation.php +++ b/src/entity/animation/SquidInkCloudAnimation.php @@ -25,6 +25,7 @@ namespace pocketmine\entity\animation; use pocketmine\entity\Squid; use pocketmine\network\mcpe\protocol\ActorEventPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; final class SquidInkCloudAnimation implements Animation{ @@ -37,7 +38,7 @@ final class SquidInkCloudAnimation implements Animation{ public function encode() : array{ return [ - ActorEventPacket::create($this->squid->getId(), ActorEventPacket::SQUID_INK_CLOUD, 0) + ActorEventPacket::create($this->squid->getId(), ActorEvent::SQUID_INK_CLOUD, 0) ]; } } diff --git a/src/entity/animation/TotemUseAnimation.php b/src/entity/animation/TotemUseAnimation.php index 11eb68e46..ec0d3b12c 100644 --- a/src/entity/animation/TotemUseAnimation.php +++ b/src/entity/animation/TotemUseAnimation.php @@ -25,6 +25,7 @@ namespace pocketmine\entity\animation; use pocketmine\entity\Human; use pocketmine\network\mcpe\protocol\ActorEventPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; final class TotemUseAnimation implements Animation{ @@ -38,7 +39,7 @@ final class TotemUseAnimation implements Animation{ public function encode() : array{ return [ - ActorEventPacket::create($this->human->getId(), ActorEventPacket::CONSUME_TOTEM, 0) + ActorEventPacket::create($this->human->getId(), ActorEvent::CONSUME_TOTEM, 0) ]; } } diff --git a/src/network/mcpe/handler/DeathPacketHandler.php b/src/network/mcpe/handler/DeathPacketHandler.php index db4cbaa7d..c3421f1a5 100644 --- a/src/network/mcpe/handler/DeathPacketHandler.php +++ b/src/network/mcpe/handler/DeathPacketHandler.php @@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\handler; use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\PlayerActionPacket; use pocketmine\network\mcpe\protocol\RespawnPacket; +use pocketmine\network\mcpe\protocol\types\PlayerAction; use pocketmine\player\Player; class DeathPacketHandler extends PacketHandler{ @@ -49,7 +50,7 @@ class DeathPacketHandler extends PacketHandler{ } public function handlePlayerAction(PlayerActionPacket $packet) : bool{ - if($packet->action === PlayerActionPacket::ACTION_RESPAWN){ + if($packet->action === PlayerAction::RESPAWN){ $this->player->respawn(); return true; } diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index a8e784ced..ef49cb355 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -83,6 +83,7 @@ use pocketmine\network\mcpe\protocol\ShowCreditsPacket; use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket; use pocketmine\network\mcpe\protocol\SubClientLoginPacket; use pocketmine\network\mcpe\protocol\TextPacket; +use pocketmine\network\mcpe\protocol\types\ActorEvent; use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds; use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\NetworkInventoryAction; @@ -92,6 +93,7 @@ use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset; use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\WindowTypes; +use pocketmine\network\mcpe\protocol\types\PlayerAction; use pocketmine\network\PacketHandlingException; use pocketmine\player\Player; use pocketmine\utils\AssumptionFailedError; @@ -201,12 +203,12 @@ class InGamePacketHandler extends PacketHandler{ public function handleActorEvent(ActorEventPacket $packet) : bool{ if($packet->actorRuntimeId !== $this->player->getId()){ //TODO HACK: EATING_ITEM is sent back to the server when the server sends it for other players (1.14 bug, maybe earlier) - return $packet->actorRuntimeId === ActorEventPacket::EATING_ITEM; + return $packet->actorRuntimeId === ActorEvent::EATING_ITEM; } $this->player->doCloseInventory(); switch($packet->eventId){ - case ActorEventPacket::EATING_ITEM: //TODO: ignore this and handle it server-side + case ActorEvent::EATING_ITEM: //TODO: ignore this and handle it server-side $item = $this->player->getInventory()->getItemInHand(); if($item->isNull()){ return false; @@ -534,60 +536,60 @@ class InGamePacketHandler extends PacketHandler{ $pos = new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ()); switch($packet->action){ - case PlayerActionPacket::ACTION_START_BREAK: + case PlayerAction::START_BREAK: if(!$this->player->attackBlock($pos, $packet->face)){ $this->onFailedBlockAction($pos, $packet->face); } break; - case PlayerActionPacket::ACTION_ABORT_BREAK: - case PlayerActionPacket::ACTION_STOP_BREAK: + case PlayerAction::ABORT_BREAK: + case PlayerAction::STOP_BREAK: $this->player->stopBreakBlock($pos); break; - case PlayerActionPacket::ACTION_START_SLEEPING: + case PlayerAction::START_SLEEPING: //unused break; - case PlayerActionPacket::ACTION_STOP_SLEEPING: + case PlayerAction::STOP_SLEEPING: $this->player->stopSleep(); break; - case PlayerActionPacket::ACTION_JUMP: + case PlayerAction::JUMP: $this->player->jump(); return true; - case PlayerActionPacket::ACTION_START_SPRINT: + case PlayerAction::START_SPRINT: if(!$this->player->toggleSprint(true)){ $this->player->sendData([$this->player]); } return true; - case PlayerActionPacket::ACTION_STOP_SPRINT: + case PlayerAction::STOP_SPRINT: if(!$this->player->toggleSprint(false)){ $this->player->sendData([$this->player]); } return true; - case PlayerActionPacket::ACTION_START_SNEAK: + case PlayerAction::START_SNEAK: if(!$this->player->toggleSneak(true)){ $this->player->sendData([$this->player]); } return true; - case PlayerActionPacket::ACTION_STOP_SNEAK: + case PlayerAction::STOP_SNEAK: if(!$this->player->toggleSneak(false)){ $this->player->sendData([$this->player]); } return true; - case PlayerActionPacket::ACTION_START_GLIDE: - case PlayerActionPacket::ACTION_STOP_GLIDE: + case PlayerAction::START_GLIDE: + case PlayerAction::STOP_GLIDE: break; //TODO - case PlayerActionPacket::ACTION_CRACK_BREAK: + case PlayerAction::CRACK_BREAK: $this->player->continueBreakBlock($pos, $packet->face); break; - case PlayerActionPacket::ACTION_START_SWIMMING: + case PlayerAction::START_SWIMMING: break; //TODO - case PlayerActionPacket::ACTION_STOP_SWIMMING: + case PlayerAction::STOP_SWIMMING: //TODO: handle this when it doesn't spam every damn tick (yet another spam bug!!) break; - case PlayerActionPacket::ACTION_INTERACT_BLOCK: //TODO: ignored (for now) + case PlayerAction::INTERACT_BLOCK: //TODO: ignored (for now) break; - case PlayerActionPacket::ACTION_CREATIVE_PLAYER_DESTROY_BLOCK: + case PlayerAction::CREATIVE_PLAYER_DESTROY_BLOCK: //TODO: do we need to handle this? break; default: diff --git a/src/player/SurvivalBlockBreakHandler.php b/src/player/SurvivalBlockBreakHandler.php index 3992e8fa5..ee9ff4df9 100644 --- a/src/player/SurvivalBlockBreakHandler.php +++ b/src/player/SurvivalBlockBreakHandler.php @@ -28,6 +28,7 @@ use pocketmine\entity\animation\ArmSwingAnimation; use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; use pocketmine\world\particle\BlockPunchParticle; use pocketmine\world\sound\BlockPunchSound; use function abs; @@ -70,7 +71,7 @@ final class SurvivalBlockBreakHandler{ if($this->breakSpeed > 0){ $this->player->getWorld()->broadcastPacketToViewers( $this->blockPos, - LevelEventPacket::create(LevelEventPacket::EVENT_BLOCK_START_BREAK, (int) (65535 * $this->breakSpeed), $this->blockPos) + LevelEventPacket::create(LevelEvent::BLOCK_START_BREAK, (int) (65535 * $this->breakSpeed), $this->blockPos) ); } } @@ -147,7 +148,7 @@ final class SurvivalBlockBreakHandler{ if($this->player->getWorld()->isInLoadedTerrain($this->blockPos)){ $this->player->getWorld()->broadcastPacketToViewers( $this->blockPos, - LevelEventPacket::create(LevelEventPacket::EVENT_BLOCK_STOP_BREAK, 0, $this->blockPos) + LevelEventPacket::create(LevelEvent::BLOCK_STOP_BREAK, 0, $this->blockPos) ); } } diff --git a/src/world/particle/BlockBreakParticle.php b/src/world/particle/BlockBreakParticle.php index bf3c23511..40e8d8bea 100644 --- a/src/world/particle/BlockBreakParticle.php +++ b/src/world/particle/BlockBreakParticle.php @@ -27,6 +27,7 @@ use pocketmine\block\Block; use pocketmine\math\Vector3; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class BlockBreakParticle implements Particle{ @@ -38,6 +39,6 @@ class BlockBreakParticle implements Particle{ } public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_PARTICLE_DESTROY, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()), $pos)]; + return [LevelEventPacket::create(LevelEvent::PARTICLE_DESTROY, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()), $pos)]; } } diff --git a/src/world/particle/BlockPunchParticle.php b/src/world/particle/BlockPunchParticle.php index e0a7eaaf8..5ee0c3352 100644 --- a/src/world/particle/BlockPunchParticle.php +++ b/src/world/particle/BlockPunchParticle.php @@ -27,6 +27,7 @@ use pocketmine\block\Block; use pocketmine\math\Vector3; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; /** * This particle appears when a player is attacking a block face in survival mode attempting to break it. @@ -44,6 +45,6 @@ class BlockPunchParticle implements Particle{ } public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_PARTICLE_PUNCH_BLOCK, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()) | ($this->face << 24), $pos)]; + return [LevelEventPacket::create(LevelEvent::PARTICLE_PUNCH_BLOCK, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()) | ($this->face << 24), $pos)]; } } diff --git a/src/world/particle/DragonEggTeleportParticle.php b/src/world/particle/DragonEggTeleportParticle.php index 5c17650da..a2f2ae3ac 100644 --- a/src/world/particle/DragonEggTeleportParticle.php +++ b/src/world/particle/DragonEggTeleportParticle.php @@ -25,6 +25,7 @@ namespace pocketmine\world\particle; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; use function abs; class DragonEggTeleportParticle implements Particle{ @@ -57,6 +58,6 @@ class DragonEggTeleportParticle implements Particle{ (abs($this->yDiff) << 8) | abs($this->zDiff); - return [LevelEventPacket::create(LevelEventPacket::EVENT_PARTICLE_DRAGON_EGG_TELEPORT, $data, $pos)]; + return [LevelEventPacket::create(LevelEvent::PARTICLE_DRAGON_EGG_TELEPORT, $data, $pos)]; } } diff --git a/src/world/particle/EndermanTeleportParticle.php b/src/world/particle/EndermanTeleportParticle.php index 274d1540e..f370e4487 100644 --- a/src/world/particle/EndermanTeleportParticle.php +++ b/src/world/particle/EndermanTeleportParticle.php @@ -25,10 +25,11 @@ namespace pocketmine\world\particle; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class EndermanTeleportParticle implements Particle{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_PARTICLE_ENDERMAN_TELEPORT, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::PARTICLE_ENDERMAN_TELEPORT, 0, $pos)]; } } diff --git a/src/world/particle/MobSpawnParticle.php b/src/world/particle/MobSpawnParticle.php index bdc2f0144..07706888e 100644 --- a/src/world/particle/MobSpawnParticle.php +++ b/src/world/particle/MobSpawnParticle.php @@ -25,6 +25,7 @@ namespace pocketmine\world\particle; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class MobSpawnParticle implements Particle{ /** @var int */ @@ -39,6 +40,6 @@ class MobSpawnParticle implements Particle{ } public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_PARTICLE_SPAWN, ($this->width & 0xff) | (($this->height & 0xff) << 8), $pos)]; + return [LevelEventPacket::create(LevelEvent::PARTICLE_SPAWN, ($this->width & 0xff) | (($this->height & 0xff) << 8), $pos)]; } } diff --git a/src/world/particle/PotionSplashParticle.php b/src/world/particle/PotionSplashParticle.php index 83ad8c699..1175e9518 100644 --- a/src/world/particle/PotionSplashParticle.php +++ b/src/world/particle/PotionSplashParticle.php @@ -26,6 +26,7 @@ namespace pocketmine\world\particle; use pocketmine\color\Color; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class PotionSplashParticle implements Particle{ @@ -50,6 +51,6 @@ class PotionSplashParticle implements Particle{ } public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_PARTICLE_SPLASH, $this->color->toARGB(), $pos)]; + return [LevelEventPacket::create(LevelEvent::PARTICLE_SPLASH, $this->color->toARGB(), $pos)]; } } diff --git a/src/world/sound/AnvilBreakSound.php b/src/world/sound/AnvilBreakSound.php index cde91af4c..e57c0e02b 100644 --- a/src/world/sound/AnvilBreakSound.php +++ b/src/world/sound/AnvilBreakSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class AnvilBreakSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ANVIL_BREAK, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_ANVIL_BREAK, 0, $pos)]; } } diff --git a/src/world/sound/AnvilFallSound.php b/src/world/sound/AnvilFallSound.php index 3ef6cc61e..fd6efc7fe 100644 --- a/src/world/sound/AnvilFallSound.php +++ b/src/world/sound/AnvilFallSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class AnvilFallSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ANVIL_FALL, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_ANVIL_FALL, 0, $pos)]; } } diff --git a/src/world/sound/AnvilUseSound.php b/src/world/sound/AnvilUseSound.php index 99beb8b0e..b384c8624 100644 --- a/src/world/sound/AnvilUseSound.php +++ b/src/world/sound/AnvilUseSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class AnvilUseSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ANVIL_USE, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_ANVIL_USE, 0, $pos)]; } } diff --git a/src/world/sound/ArrowHitSound.php b/src/world/sound/ArrowHitSound.php index 4b1d9da58..abfdfc4a4 100644 --- a/src/world/sound/ArrowHitSound.php +++ b/src/world/sound/ArrowHitSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class ArrowHitSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BOW_HIT, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BOW_HIT, $pos, false)]; } } diff --git a/src/world/sound/BarrelCloseSound.php b/src/world/sound/BarrelCloseSound.php index fa673a938..be2bdaf79 100644 --- a/src/world/sound/BarrelCloseSound.php +++ b/src/world/sound/BarrelCloseSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class BarrelCloseSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BLOCK_BARREL_CLOSE, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BLOCK_BARREL_CLOSE, $pos, false)]; } } diff --git a/src/world/sound/BarrelOpenSound.php b/src/world/sound/BarrelOpenSound.php index ed8a1a4df..ee695060c 100644 --- a/src/world/sound/BarrelOpenSound.php +++ b/src/world/sound/BarrelOpenSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class BarrelOpenSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BLOCK_BARREL_OPEN, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BLOCK_BARREL_OPEN, $pos, false)]; } } diff --git a/src/world/sound/BellRingSound.php b/src/world/sound/BellRingSound.php index c14b63d68..c2a45a561 100644 --- a/src/world/sound/BellRingSound.php +++ b/src/world/sound/BellRingSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; final class BellRingSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BLOCK_BELL_HIT, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BLOCK_BELL_HIT, $pos, false)]; } } diff --git a/src/world/sound/BlazeShootSound.php b/src/world/sound/BlazeShootSound.php index 00f772bbe..a86c09344 100644 --- a/src/world/sound/BlazeShootSound.php +++ b/src/world/sound/BlazeShootSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class BlazeShootSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_BLAZE_SHOOT, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_BLAZE_SHOOT, 0, $pos)]; } } diff --git a/src/world/sound/BlockBreakSound.php b/src/world/sound/BlockBreakSound.php index 99cac4c7b..39323259d 100644 --- a/src/world/sound/BlockBreakSound.php +++ b/src/world/sound/BlockBreakSound.php @@ -27,6 +27,7 @@ use pocketmine\block\Block; use pocketmine\math\Vector3; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class BlockBreakSound implements Sound{ @@ -38,6 +39,6 @@ class BlockBreakSound implements Sound{ } public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BREAK, $pos, false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BREAK, $pos, false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; } } diff --git a/src/world/sound/BlockPlaceSound.php b/src/world/sound/BlockPlaceSound.php index 7a95b2222..831c879a1 100644 --- a/src/world/sound/BlockPlaceSound.php +++ b/src/world/sound/BlockPlaceSound.php @@ -27,6 +27,7 @@ use pocketmine\block\Block; use pocketmine\math\Vector3; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class BlockPlaceSound implements Sound{ @@ -38,6 +39,6 @@ class BlockPlaceSound implements Sound{ } public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_PLACE, $pos, false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::PLACE, $pos, false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()))]; } } diff --git a/src/world/sound/BlockPunchSound.php b/src/world/sound/BlockPunchSound.php index 51093522e..03d3ded64 100644 --- a/src/world/sound/BlockPunchSound.php +++ b/src/world/sound/BlockPunchSound.php @@ -27,6 +27,7 @@ use pocketmine\block\Block; use pocketmine\math\Vector3; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; /** * Played when a player attacks a block in survival, attempting to break it. @@ -42,7 +43,7 @@ class BlockPunchSound implements Sound{ public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::nonActorSound( - LevelSoundEventPacket::SOUND_HIT, + LevelSoundEvent::HIT, $pos, false, RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()) diff --git a/src/world/sound/BowShootSound.php b/src/world/sound/BowShootSound.php index abdb8169c..2b595972f 100644 --- a/src/world/sound/BowShootSound.php +++ b/src/world/sound/BowShootSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class BowShootSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BOW, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BOW, $pos, false)]; } } diff --git a/src/world/sound/BucketEmptyLavaSound.php b/src/world/sound/BucketEmptyLavaSound.php index 99241daf1..e3e991597 100644 --- a/src/world/sound/BucketEmptyLavaSound.php +++ b/src/world/sound/BucketEmptyLavaSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class BucketEmptyLavaSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_EMPTY_LAVA, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BUCKET_EMPTY_LAVA, $pos, false)]; } } diff --git a/src/world/sound/BucketEmptyWaterSound.php b/src/world/sound/BucketEmptyWaterSound.php index 087675aa9..b80b90311 100644 --- a/src/world/sound/BucketEmptyWaterSound.php +++ b/src/world/sound/BucketEmptyWaterSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class BucketEmptyWaterSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_EMPTY_WATER, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BUCKET_EMPTY_WATER, $pos, false)]; } } diff --git a/src/world/sound/BucketFillLavaSound.php b/src/world/sound/BucketFillLavaSound.php index d4df3ef67..0315c8a8e 100644 --- a/src/world/sound/BucketFillLavaSound.php +++ b/src/world/sound/BucketFillLavaSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class BucketFillLavaSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_FILL_LAVA, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BUCKET_FILL_LAVA, $pos, false)]; } } diff --git a/src/world/sound/BucketFillWaterSound.php b/src/world/sound/BucketFillWaterSound.php index 638922413..431435788 100644 --- a/src/world/sound/BucketFillWaterSound.php +++ b/src/world/sound/BucketFillWaterSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class BucketFillWaterSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BUCKET_FILL_WATER, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BUCKET_FILL_WATER, $pos, false)]; } } diff --git a/src/world/sound/ChestCloseSound.php b/src/world/sound/ChestCloseSound.php index 2ccaaa035..e1c15e523 100644 --- a/src/world/sound/ChestCloseSound.php +++ b/src/world/sound/ChestCloseSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class ChestCloseSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_CHEST_CLOSED, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::CHEST_CLOSED, $pos, false)]; } } diff --git a/src/world/sound/ChestOpenSound.php b/src/world/sound/ChestOpenSound.php index ee8c9313b..0e835d5fa 100644 --- a/src/world/sound/ChestOpenSound.php +++ b/src/world/sound/ChestOpenSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class ChestOpenSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_CHEST_OPEN, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::CHEST_OPEN, $pos, false)]; } } diff --git a/src/world/sound/ClickSound.php b/src/world/sound/ClickSound.php index db472b292..c02471f87 100644 --- a/src/world/sound/ClickSound.php +++ b/src/world/sound/ClickSound.php @@ -25,6 +25,7 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class ClickSound implements Sound{ @@ -40,6 +41,6 @@ class ClickSound implements Sound{ } public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_CLICK, (int) ($this->pitch * 1000), $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_CLICK, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/DoorBumpSound.php b/src/world/sound/DoorBumpSound.php index 239401637..86ed0f339 100644 --- a/src/world/sound/DoorBumpSound.php +++ b/src/world/sound/DoorBumpSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class DoorBumpSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_DOOR_BUMP, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_DOOR_BUMP, 0, $pos)]; } } diff --git a/src/world/sound/DoorCrashSound.php b/src/world/sound/DoorCrashSound.php index 6f3a6cbe0..3259c4889 100644 --- a/src/world/sound/DoorCrashSound.php +++ b/src/world/sound/DoorCrashSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class DoorCrashSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_DOOR_CRASH, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_DOOR_CRASH, 0, $pos)]; } } diff --git a/src/world/sound/DoorSound.php b/src/world/sound/DoorSound.php index b3e4addf9..368136c91 100644 --- a/src/world/sound/DoorSound.php +++ b/src/world/sound/DoorSound.php @@ -25,6 +25,7 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class DoorSound implements Sound{ @@ -40,6 +41,6 @@ class DoorSound implements Sound{ } public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_DOOR, (int) ($this->pitch * 1000), $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_DOOR, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/EnderChestCloseSound.php b/src/world/sound/EnderChestCloseSound.php index 4292dec35..3b7269821 100644 --- a/src/world/sound/EnderChestCloseSound.php +++ b/src/world/sound/EnderChestCloseSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class EnderChestCloseSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_ENDERCHEST_CLOSED, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::ENDERCHEST_CLOSED, $pos, false)]; } } diff --git a/src/world/sound/EnderChestOpenSound.php b/src/world/sound/EnderChestOpenSound.php index ab1894450..6d88ac1f5 100644 --- a/src/world/sound/EnderChestOpenSound.php +++ b/src/world/sound/EnderChestOpenSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class EnderChestOpenSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_ENDERCHEST_OPEN, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::ENDERCHEST_OPEN, $pos, false)]; } } diff --git a/src/world/sound/EndermanTeleportSound.php b/src/world/sound/EndermanTeleportSound.php index e2f3f03e8..a5857aab2 100644 --- a/src/world/sound/EndermanTeleportSound.php +++ b/src/world/sound/EndermanTeleportSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class EndermanTeleportSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ENDERMAN_TELEPORT, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_ENDERMAN_TELEPORT, 0, $pos)]; } } diff --git a/src/world/sound/EntityAttackNoDamageSound.php b/src/world/sound/EntityAttackNoDamageSound.php index 2ab77a241..d329147f6 100644 --- a/src/world/sound/EntityAttackNoDamageSound.php +++ b/src/world/sound/EntityAttackNoDamageSound.php @@ -25,6 +25,7 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; /** * Played when a player attacks a mob, but fails to deal damage (e.g. cancelled or attack cooldown). @@ -33,7 +34,7 @@ class EntityAttackNoDamageSound implements Sound{ public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( - LevelSoundEventPacket::SOUND_ATTACK_NODAMAGE, + LevelSoundEvent::ATTACK_NODAMAGE, $pos, -1, "minecraft:player", diff --git a/src/world/sound/EntityAttackSound.php b/src/world/sound/EntityAttackSound.php index ecf39a888..289f2d597 100644 --- a/src/world/sound/EntityAttackSound.php +++ b/src/world/sound/EntityAttackSound.php @@ -25,6 +25,7 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; /** * Played when a player attacks a mob, dealing damage. @@ -33,7 +34,7 @@ class EntityAttackSound implements Sound{ public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( - LevelSoundEventPacket::SOUND_ATTACK_STRONG, //TODO: seems like ATTACK is dysfunctional + LevelSoundEvent::ATTACK_STRONG, //TODO: seems like ATTACK is dysfunctional $pos, -1, "minecraft:player", diff --git a/src/world/sound/EntityLandSound.php b/src/world/sound/EntityLandSound.php index 38ba283fc..a973e3ba5 100644 --- a/src/world/sound/EntityLandSound.php +++ b/src/world/sound/EntityLandSound.php @@ -28,6 +28,7 @@ use pocketmine\entity\Entity; use pocketmine\math\Vector3; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; /** * Played when an entity hits the ground after falling a distance that doesn't cause damage, e.g. due to jumping. @@ -46,7 +47,7 @@ class EntityLandSound implements Sound{ public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( - LevelSoundEventPacket::SOUND_LAND, + LevelSoundEvent::LAND, $pos, RuntimeBlockMapping::getInstance()->toRuntimeId($this->blockLandedOn->getFullId()), $this->entity::getNetworkTypeId(), diff --git a/src/world/sound/EntityLongFallSound.php b/src/world/sound/EntityLongFallSound.php index 1d0a07f40..c6cd2a33a 100644 --- a/src/world/sound/EntityLongFallSound.php +++ b/src/world/sound/EntityLongFallSound.php @@ -26,6 +26,7 @@ namespace pocketmine\world\sound; use pocketmine\entity\Entity; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; /** * Played when an entity hits ground after falling a long distance (damage). @@ -42,7 +43,7 @@ class EntityLongFallSound implements Sound{ public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( - LevelSoundEventPacket::SOUND_FALL_BIG, + LevelSoundEvent::FALL_BIG, $pos, -1, $this->entity::getNetworkTypeId(), diff --git a/src/world/sound/EntityShortFallSound.php b/src/world/sound/EntityShortFallSound.php index 2f64cc269..722a3c1a3 100644 --- a/src/world/sound/EntityShortFallSound.php +++ b/src/world/sound/EntityShortFallSound.php @@ -26,6 +26,7 @@ namespace pocketmine\world\sound; use pocketmine\entity\Entity; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; /** * Played when an entity hits the ground after falling a short distance. @@ -41,7 +42,7 @@ class EntityShortFallSound implements Sound{ public function encode(Vector3 $pos) : array{ return [LevelSoundEventPacket::create( - LevelSoundEventPacket::SOUND_FALL_SMALL, + LevelSoundEvent::FALL_SMALL, $pos, -1, $this->entity::getNetworkTypeId(), diff --git a/src/world/sound/ExplodeSound.php b/src/world/sound/ExplodeSound.php index 1f2db9c89..b20f5a359 100644 --- a/src/world/sound/ExplodeSound.php +++ b/src/world/sound/ExplodeSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class ExplodeSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_EXPLODE, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::EXPLODE, $pos, false)]; } } diff --git a/src/world/sound/FireExtinguishSound.php b/src/world/sound/FireExtinguishSound.php index 255e821f9..a4f02fb03 100644 --- a/src/world/sound/FireExtinguishSound.php +++ b/src/world/sound/FireExtinguishSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; final class FireExtinguishSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_EXTINGUISH_FIRE, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::EXTINGUISH_FIRE, $pos, false)]; } } diff --git a/src/world/sound/FizzSound.php b/src/world/sound/FizzSound.php index 67be8db44..62b54ee16 100644 --- a/src/world/sound/FizzSound.php +++ b/src/world/sound/FizzSound.php @@ -25,6 +25,7 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class FizzSound implements Sound{ @@ -40,6 +41,6 @@ class FizzSound implements Sound{ } public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_FIZZ, (int) ($this->pitch * 1000), $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_FIZZ, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/FlintSteelSound.php b/src/world/sound/FlintSteelSound.php index 4569ed510..7edd564cf 100644 --- a/src/world/sound/FlintSteelSound.php +++ b/src/world/sound/FlintSteelSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class FlintSteelSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_IGNITE, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::IGNITE, $pos, false)]; } } diff --git a/src/world/sound/GhastShootSound.php b/src/world/sound/GhastShootSound.php index e7cb550ff..3dae9758f 100644 --- a/src/world/sound/GhastShootSound.php +++ b/src/world/sound/GhastShootSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class GhastShootSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_GHAST_SHOOT, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_GHAST_SHOOT, 0, $pos)]; } } diff --git a/src/world/sound/GhastSound.php b/src/world/sound/GhastSound.php index 2e707d3db..d62413dac 100644 --- a/src/world/sound/GhastSound.php +++ b/src/world/sound/GhastSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class GhastSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_GHAST, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_GHAST, 0, $pos)]; } } diff --git a/src/world/sound/IgniteSound.php b/src/world/sound/IgniteSound.php index 1f1e88703..05f443123 100644 --- a/src/world/sound/IgniteSound.php +++ b/src/world/sound/IgniteSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class IgniteSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_IGNITE, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_IGNITE, 0, $pos)]; } } diff --git a/src/world/sound/ItemBreakSound.php b/src/world/sound/ItemBreakSound.php index c2329ce12..98ee24c8b 100644 --- a/src/world/sound/ItemBreakSound.php +++ b/src/world/sound/ItemBreakSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class ItemBreakSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_BREAK, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BREAK, $pos, false)]; } } diff --git a/src/world/sound/LaunchSound.php b/src/world/sound/LaunchSound.php index af8b02041..11ef5ad1d 100644 --- a/src/world/sound/LaunchSound.php +++ b/src/world/sound/LaunchSound.php @@ -25,6 +25,7 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class LaunchSound implements Sound{ @@ -40,6 +41,6 @@ class LaunchSound implements Sound{ } public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_SHOOT, (int) ($this->pitch * 1000), $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_SHOOT, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/NoteSound.php b/src/world/sound/NoteSound.php index 7d2bdef42..00101b8d7 100644 --- a/src/world/sound/NoteSound.php +++ b/src/world/sound/NoteSound.php @@ -25,6 +25,7 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class NoteSound implements Sound{ @@ -42,6 +43,6 @@ class NoteSound implements Sound{ } public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_NOTE, $pos, false, ($this->instrument->getMagicNumber() << 8) | $this->note)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::NOTE, $pos, false, ($this->instrument->getMagicNumber() << 8) | $this->note)]; } } diff --git a/src/world/sound/PaintingPlaceSound.php b/src/world/sound/PaintingPlaceSound.php index 6d9a7ebe3..2363299f3 100644 --- a/src/world/sound/PaintingPlaceSound.php +++ b/src/world/sound/PaintingPlaceSound.php @@ -25,11 +25,12 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class PaintingPlaceSound implements Sound{ public function encode(Vector3 $pos) : array{ //item frame and painting have the same sound - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ITEMFRAME_PLACE, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_ITEMFRAME_PLACE, 0, $pos)]; } } diff --git a/src/world/sound/PopSound.php b/src/world/sound/PopSound.php index 421018333..a706e6d03 100644 --- a/src/world/sound/PopSound.php +++ b/src/world/sound/PopSound.php @@ -25,6 +25,7 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class PopSound implements Sound{ @@ -40,6 +41,6 @@ class PopSound implements Sound{ } public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_POP, (int) ($this->pitch * 1000), $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_POP, (int) ($this->pitch * 1000), $pos)]; } } diff --git a/src/world/sound/PotionSplashSound.php b/src/world/sound/PotionSplashSound.php index 2547f2aee..083e8e021 100644 --- a/src/world/sound/PotionSplashSound.php +++ b/src/world/sound/PotionSplashSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class PotionSplashSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_GLASS, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::GLASS, $pos, false)]; } } diff --git a/src/world/sound/RecordStopSound.php b/src/world/sound/RecordStopSound.php index 9e331a9ff..0f2b7dcc9 100644 --- a/src/world/sound/RecordStopSound.php +++ b/src/world/sound/RecordStopSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class RecordStopSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_STOP_RECORD, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::STOP_RECORD, $pos, false)]; } } diff --git a/src/world/sound/RedstonePowerOffSound.php b/src/world/sound/RedstonePowerOffSound.php index b07c723b4..d32ef391e 100644 --- a/src/world/sound/RedstonePowerOffSound.php +++ b/src/world/sound/RedstonePowerOffSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class RedstonePowerOffSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_POWER_OFF, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::POWER_OFF, $pos, false)]; } } diff --git a/src/world/sound/RedstonePowerOnSound.php b/src/world/sound/RedstonePowerOnSound.php index d71f6b998..3c98832ee 100644 --- a/src/world/sound/RedstonePowerOnSound.php +++ b/src/world/sound/RedstonePowerOnSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class RedstonePowerOnSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_POWER_ON, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::POWER_ON, $pos, false)]; } } diff --git a/src/world/sound/ShulkerBoxCloseSound.php b/src/world/sound/ShulkerBoxCloseSound.php index ea7a630c3..6c8ace783 100644 --- a/src/world/sound/ShulkerBoxCloseSound.php +++ b/src/world/sound/ShulkerBoxCloseSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class ShulkerBoxCloseSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_SHULKERBOX_CLOSED, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::SHULKERBOX_CLOSED, $pos, false)]; } } diff --git a/src/world/sound/ShulkerBoxOpenSound.php b/src/world/sound/ShulkerBoxOpenSound.php index 491b5dace..9aafb95ce 100644 --- a/src/world/sound/ShulkerBoxOpenSound.php +++ b/src/world/sound/ShulkerBoxOpenSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class ShulkerBoxOpenSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_SHULKERBOX_OPEN, $pos, false)]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::SHULKERBOX_OPEN, $pos, false)]; } } diff --git a/src/world/sound/ThrowSound.php b/src/world/sound/ThrowSound.php index b24474e5f..5ac34cbe6 100644 --- a/src/world/sound/ThrowSound.php +++ b/src/world/sound/ThrowSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; class ThrowSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelSoundEventPacket::create(LevelSoundEventPacket::SOUND_THROW, $pos, -1, "minecraft:player", false, false)]; + return [LevelSoundEventPacket::create(LevelSoundEvent::THROW, $pos, -1, "minecraft:player", false, false)]; } } diff --git a/src/world/sound/TotemUseSound.php b/src/world/sound/TotemUseSound.php index 561d9c41a..7d82c3110 100644 --- a/src/world/sound/TotemUseSound.php +++ b/src/world/sound/TotemUseSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class TotemUseSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_TOTEM, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_TOTEM, 0, $pos)]; } } diff --git a/src/world/sound/XpCollectSound.php b/src/world/sound/XpCollectSound.php index 655835069..bbf60041b 100644 --- a/src/world/sound/XpCollectSound.php +++ b/src/world/sound/XpCollectSound.php @@ -25,10 +25,11 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelEvent; class XpCollectSound implements Sound{ public function encode(Vector3 $pos) : array{ - return [LevelEventPacket::create(LevelEventPacket::EVENT_SOUND_ORB, 0, $pos)]; + return [LevelEventPacket::create(LevelEvent::SOUND_ORB, 0, $pos)]; } } diff --git a/src/world/sound/XpLevelUpSound.php b/src/world/sound/XpLevelUpSound.php index 8334b7bea..b9e2737b2 100644 --- a/src/world/sound/XpLevelUpSound.php +++ b/src/world/sound/XpLevelUpSound.php @@ -25,6 +25,7 @@ namespace pocketmine\world\sound; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; use function intdiv; use function min; @@ -44,6 +45,6 @@ class XpLevelUpSound implements Sound{ public function encode(Vector3 $pos) : array{ //No idea why such odd numbers, but this works... //TODO: check arbitrary volume - return [LevelSoundEventPacket::nonActorSound(LevelSoundEventPacket::SOUND_LEVELUP, $pos, false, 0x10000000 * intdiv(min(30, $this->xpLevel), 5))]; + return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::LEVELUP, $pos, false, 0x10000000 * intdiv(min(30, $this->xpLevel), 5))]; } } From 42ede30e77bb0f66f8f40023aa4329b9b89dc312 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Oct 2021 23:57:28 +0100 Subject: [PATCH 159/710] ... --- src/block/utils/RecordType.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/block/utils/RecordType.php b/src/block/utils/RecordType.php index 967cdc034..e497d419c 100644 --- a/src/block/utils/RecordType.php +++ b/src/block/utils/RecordType.php @@ -25,7 +25,6 @@ namespace pocketmine\block\utils; use pocketmine\lang\KnownTranslationFactory; use pocketmine\lang\Translatable; -use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\network\mcpe\protocol\types\LevelSoundEvent; use pocketmine\utils\EnumTrait; From f6e53f826b5dcb78f9722603e356c2420cc760e5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 19:52:44 +0100 Subject: [PATCH 160/710] Fixed Anvil/McRegion chunks getting autosaved on first time, even when unchanged setGenerated/setPopulated and friends set hasChanged = true, which causes the world to autosave them the first time around, even though they weren't modified. --- src/pocketmine/level/format/io/region/Anvil.php | 1 + src/pocketmine/level/format/io/region/McRegion.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/pocketmine/level/format/io/region/Anvil.php b/src/pocketmine/level/format/io/region/Anvil.php index 6464269cf..bf1e69f0d 100644 --- a/src/pocketmine/level/format/io/region/Anvil.php +++ b/src/pocketmine/level/format/io/region/Anvil.php @@ -135,6 +135,7 @@ class Anvil extends McRegion{ $result->setLightPopulated($chunk->getByte("LightPopulated", 0) !== 0); $result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0); $result->setGenerated(); + $result->setChanged(false); return $result; } diff --git a/src/pocketmine/level/format/io/region/McRegion.php b/src/pocketmine/level/format/io/region/McRegion.php index cde0b06d9..fb39a8e4c 100644 --- a/src/pocketmine/level/format/io/region/McRegion.php +++ b/src/pocketmine/level/format/io/region/McRegion.php @@ -201,6 +201,7 @@ class McRegion extends BaseLevelProvider{ $result->setLightPopulated($chunk->getByte("LightPopulated", 0) !== 0); $result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0); $result->setGenerated(true); + $result->setChanged(false); return $result; } From b8519d1af4a9ff2182c15da29e715a2d506150e8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 19:49:35 +0100 Subject: [PATCH 161/710] World: fixed every chunk having terrain saved at least once, even if unmodified setPopulated() sets dirty flags on the chunk, causing the autosave sweep to think they've been changed when they haven't. We now pass terrainPopulated to the constructor to avoid this ambiguity recurring in the future. --- src/world/format/Chunk.php | 4 +++- src/world/format/io/FastChunkSerializer.php | 6 +----- src/world/format/io/leveldb/LevelDB.php | 21 +++++++++++-------- .../io/region/LegacyAnvilChunkTrait.php | 12 +++++------ src/world/format/io/region/McRegion.php | 9 +++++--- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index c90c18482..fe37161b8 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -69,7 +69,7 @@ class Chunk{ /** * @param SubChunk[] $subChunks */ - public function __construct(array $subChunks = [], ?BiomeArray $biomeIds = null, ?HeightArray $heightMap = null){ + public function __construct(array $subChunks = [], ?BiomeArray $biomeIds = null, ?HeightArray $heightMap = null, bool $terrainPopulated = false){ $this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS); foreach($this->subChunks as $y => $null){ @@ -79,6 +79,8 @@ class Chunk{ $val = ($this->subChunks->getSize() * SubChunk::EDGE_LENGTH); $this->heightMap = $heightMap ?? new HeightArray(array_fill(0, 256, $val)); $this->biomeIds = $biomeIds ?? BiomeArray::fill(BiomeIds::OCEAN); + + $this->terrainPopulated = $terrainPopulated; } /** diff --git a/src/world/format/io/FastChunkSerializer.php b/src/world/format/io/FastChunkSerializer.php index cc8544411..62a22352e 100644 --- a/src/world/format/io/FastChunkSerializer.php +++ b/src/world/format/io/FastChunkSerializer.php @@ -115,10 +115,6 @@ final class FastChunkSerializer{ $biomeIds = new BiomeArray($stream->get(256)); - $chunk = new Chunk($subChunks, $biomeIds); - $chunk->setPopulated($terrainPopulated); - $chunk->clearTerrainDirtyFlags(); - - return $chunk; + return new Chunk($subChunks, $biomeIds, null, $terrainPopulated); } } diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index 6713818ac..2ab5ef0cb 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -404,20 +404,23 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ } } - $chunk = new Chunk( - $subChunks, - $biomeArray - ); - - //TODO: tile ticks, biome states (?) - $finalisationChr = $this->db->get($index . self::TAG_STATE_FINALISATION); if($finalisationChr !== false){ $finalisation = ord($finalisationChr); - $chunk->setPopulated($finalisation === self::FINALISATION_DONE); + $terrainPopulated = $finalisation === self::FINALISATION_DONE; }else{ //older versions didn't have this tag - $chunk->setPopulated(); + $terrainPopulated = true; } + + //TODO: tile ticks, biome states (?) + + $chunk = new Chunk( + $subChunks, + $biomeArray, + null, + $terrainPopulated + ); + if($hasBeenUpgraded){ $chunk->setTerrainDirty(); //trigger rewriting chunk to disk if it was converted from an older format } diff --git a/src/world/format/io/region/LegacyAnvilChunkTrait.php b/src/world/format/io/region/LegacyAnvilChunkTrait.php index 831f02b18..4f6ce4123 100644 --- a/src/world/format/io/region/LegacyAnvilChunkTrait.php +++ b/src/world/format/io/region/LegacyAnvilChunkTrait.php @@ -88,13 +88,13 @@ trait LegacyAnvilChunkTrait{ $biomeArray = $makeBiomeArray($biomesTag->getValue()); } - $result = new Chunk( - $subChunks, - $biomeArray - ); - $result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0); return new ChunkData( - $result, + new Chunk( + $subChunks, + $biomeArray, + null, + $chunk->getByte("TerrainPopulated", 0) !== 0 + ), ($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [], ($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [], ); diff --git a/src/world/format/io/region/McRegion.php b/src/world/format/io/region/McRegion.php index aab62a3db..0aac96159 100644 --- a/src/world/format/io/region/McRegion.php +++ b/src/world/format/io/region/McRegion.php @@ -82,10 +82,13 @@ class McRegion extends RegionWorldProvider{ $biomeIds = $makeBiomeArray($biomesTag->getValue()); } - $result = new Chunk($subChunks, $biomeIds); - $result->setPopulated($chunk->getByte("TerrainPopulated", 0) !== 0); return new ChunkData( - $result, + new Chunk( + $subChunks, + $biomeIds, + null, + $chunk->getByte("TerrainPopulated", 0) !== 0 + ), ($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [], ($tilesTag = $chunk->getTag("TileEntities")) instanceof ListTag ? self::getCompoundList("TileEntities", $tilesTag) : [], ); From 9835d75f65570b4bb5baf68c6127147ae7b324c7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 20:13:50 +0100 Subject: [PATCH 162/710] Chunk: removed heighArray parameter from constructor we don't pass this anywhere, and really it should be dynamically initialized anyway, just like light. --- src/world/format/Chunk.php | 4 ++-- src/world/format/io/FastChunkSerializer.php | 2 +- src/world/format/io/leveldb/LevelDB.php | 1 - src/world/format/io/region/LegacyAnvilChunkTrait.php | 1 - src/world/format/io/region/McRegion.php | 1 - 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index fe37161b8..42daa1bcb 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -69,7 +69,7 @@ class Chunk{ /** * @param SubChunk[] $subChunks */ - public function __construct(array $subChunks = [], ?BiomeArray $biomeIds = null, ?HeightArray $heightMap = null, bool $terrainPopulated = false){ + public function __construct(array $subChunks = [], ?BiomeArray $biomeIds = null, bool $terrainPopulated = false){ $this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS); foreach($this->subChunks as $y => $null){ @@ -77,7 +77,7 @@ class Chunk{ } $val = ($this->subChunks->getSize() * SubChunk::EDGE_LENGTH); - $this->heightMap = $heightMap ?? new HeightArray(array_fill(0, 256, $val)); + $this->heightMap = new HeightArray(array_fill(0, 256, $val)); //TODO: what about lazily initializing this? $this->biomeIds = $biomeIds ?? BiomeArray::fill(BiomeIds::OCEAN); $this->terrainPopulated = $terrainPopulated; diff --git a/src/world/format/io/FastChunkSerializer.php b/src/world/format/io/FastChunkSerializer.php index 62a22352e..bb8bec687 100644 --- a/src/world/format/io/FastChunkSerializer.php +++ b/src/world/format/io/FastChunkSerializer.php @@ -115,6 +115,6 @@ final class FastChunkSerializer{ $biomeIds = new BiomeArray($stream->get(256)); - return new Chunk($subChunks, $biomeIds, null, $terrainPopulated); + return new Chunk($subChunks, $biomeIds, $terrainPopulated); } } diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index 2ab5ef0cb..17f42f7bd 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -417,7 +417,6 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $chunk = new Chunk( $subChunks, $biomeArray, - null, $terrainPopulated ); diff --git a/src/world/format/io/region/LegacyAnvilChunkTrait.php b/src/world/format/io/region/LegacyAnvilChunkTrait.php index 4f6ce4123..a7181718f 100644 --- a/src/world/format/io/region/LegacyAnvilChunkTrait.php +++ b/src/world/format/io/region/LegacyAnvilChunkTrait.php @@ -92,7 +92,6 @@ trait LegacyAnvilChunkTrait{ new Chunk( $subChunks, $biomeArray, - null, $chunk->getByte("TerrainPopulated", 0) !== 0 ), ($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [], diff --git a/src/world/format/io/region/McRegion.php b/src/world/format/io/region/McRegion.php index 0aac96159..d4864f934 100644 --- a/src/world/format/io/region/McRegion.php +++ b/src/world/format/io/region/McRegion.php @@ -86,7 +86,6 @@ class McRegion extends RegionWorldProvider{ new Chunk( $subChunks, $biomeIds, - null, $chunk->getByte("TerrainPopulated", 0) !== 0 ), ($entitiesTag = $chunk->getTag("Entities")) instanceof ListTag ? self::getCompoundList("Entities", $entitiesTag) : [], From 401e8d117b4f6c26a4ea71c64994b90af15bc29c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 20:15:33 +0100 Subject: [PATCH 163/710] Flat: use a less dumb way to build biome array --- src/world/generator/Flat.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/world/generator/Flat.php b/src/world/generator/Flat.php index fff96db94..39d782de3 100644 --- a/src/world/generator/Flat.php +++ b/src/world/generator/Flat.php @@ -25,6 +25,7 @@ namespace pocketmine\world\generator; use pocketmine\block\VanillaBlocks; use pocketmine\world\ChunkManager; +use pocketmine\world\format\BiomeArray; use pocketmine\world\format\Chunk; use pocketmine\world\format\SubChunk; use pocketmine\world\generator\object\OreType; @@ -68,14 +69,7 @@ class Flat extends Generator{ } protected function generateBaseChunk() : void{ - $this->chunk = new Chunk(); - - $biomeId = $this->options->getBiomeId(); - for($Z = 0; $Z < Chunk::EDGE_LENGTH; ++$Z){ - for($X = 0; $X < Chunk::EDGE_LENGTH; ++$X){ - $this->chunk->setBiomeId($X, $Z, $biomeId); - } - } + $this->chunk = new Chunk([], BiomeArray::fill($this->options->getBiomeId())); $structure = $this->options->getStructure(); $count = count($structure); From d53347454bf9b6fb21f8fc7e74a5b68c0c2abbc3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 20:17:17 +0100 Subject: [PATCH 164/710] Chunk: use HeightArray::fill() --- src/world/format/Chunk.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index 42daa1bcb..c287823d4 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -30,7 +30,6 @@ use pocketmine\block\Block; use pocketmine\block\BlockLegacyIds; use pocketmine\block\tile\Tile; use pocketmine\data\bedrock\BiomeIds; -use function array_fill; use function array_map; class Chunk{ @@ -77,7 +76,7 @@ class Chunk{ } $val = ($this->subChunks->getSize() * SubChunk::EDGE_LENGTH); - $this->heightMap = new HeightArray(array_fill(0, 256, $val)); //TODO: what about lazily initializing this? + $this->heightMap = HeightArray::fill($val); //TODO: what about lazily initializing this? $this->biomeIds = $biomeIds ?? BiomeArray::fill(BiomeIds::OCEAN); $this->terrainPopulated = $terrainPopulated; From baba25953fe8a1cbce745a94e645cce62d4e0e59 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 20:22:50 +0100 Subject: [PATCH 165/710] Chunk: make all parameters of __construct() mandatory and non-nullable having the constructor fill in defaults for these invariably causes bugs. --- src/world/format/Chunk.php | 4 ++-- src/world/format/io/leveldb/LevelDB.php | 3 ++- src/world/format/io/region/LegacyAnvilChunkTrait.php | 3 +++ src/world/format/io/region/McRegion.php | 3 +++ src/world/generator/Flat.php | 2 +- src/world/generator/PopulationTask.php | 4 +++- tests/phpunit/world/format/ChunkTest.php | 3 ++- 7 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index c287823d4..9f001fd37 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -68,7 +68,7 @@ class Chunk{ /** * @param SubChunk[] $subChunks */ - public function __construct(array $subChunks = [], ?BiomeArray $biomeIds = null, bool $terrainPopulated = false){ + public function __construct(array $subChunks, BiomeArray $biomeIds, bool $terrainPopulated){ $this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS); foreach($this->subChunks as $y => $null){ @@ -77,7 +77,7 @@ class Chunk{ $val = ($this->subChunks->getSize() * SubChunk::EDGE_LENGTH); $this->heightMap = HeightArray::fill($val); //TODO: what about lazily initializing this? - $this->biomeIds = $biomeIds ?? BiomeArray::fill(BiomeIds::OCEAN); + $this->biomeIds = $biomeIds; $this->terrainPopulated = $terrainPopulated; } diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index 17f42f7bd..54433214e 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -25,6 +25,7 @@ namespace pocketmine\world\format\io\leveldb; use pocketmine\block\Block; use pocketmine\block\BlockLegacyIds; +use pocketmine\data\bedrock\BiomeIds; use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap; use pocketmine\nbt\LittleEndianNbtSerializer; use pocketmine\nbt\NbtDataException; @@ -416,7 +417,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $chunk = new Chunk( $subChunks, - $biomeArray, + $biomeArray ?? BiomeArray::fill(BiomeIds::OCEAN), //TODO: maybe missing biomes should be an error? $terrainPopulated ); diff --git a/src/world/format/io/region/LegacyAnvilChunkTrait.php b/src/world/format/io/region/LegacyAnvilChunkTrait.php index a7181718f..8970a2fb3 100644 --- a/src/world/format/io/region/LegacyAnvilChunkTrait.php +++ b/src/world/format/io/region/LegacyAnvilChunkTrait.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\world\format\io\region; +use pocketmine\data\bedrock\BiomeIds; use pocketmine\nbt\BigEndianNbtSerializer; use pocketmine\nbt\NbtDataException; use pocketmine\nbt\tag\ByteArrayTag; @@ -86,6 +87,8 @@ trait LegacyAnvilChunkTrait{ $biomeArray = $makeBiomeArray(ChunkUtils::convertBiomeColors($biomeColorsTag->getValue())); //Convert back to original format }elseif(($biomesTag = $chunk->getTag("Biomes")) instanceof ByteArrayTag){ $biomeArray = $makeBiomeArray($biomesTag->getValue()); + }else{ + $biomeArray = BiomeArray::fill(BiomeIds::OCEAN); } return new ChunkData( diff --git a/src/world/format/io/region/McRegion.php b/src/world/format/io/region/McRegion.php index d4864f934..3367a2f81 100644 --- a/src/world/format/io/region/McRegion.php +++ b/src/world/format/io/region/McRegion.php @@ -25,6 +25,7 @@ namespace pocketmine\world\format\io\region; use pocketmine\block\Block; use pocketmine\block\BlockLegacyIds; +use pocketmine\data\bedrock\BiomeIds; use pocketmine\nbt\BigEndianNbtSerializer; use pocketmine\nbt\NbtDataException; use pocketmine\nbt\tag\ByteArrayTag; @@ -80,6 +81,8 @@ class McRegion extends RegionWorldProvider{ $biomeIds = $makeBiomeArray(ChunkUtils::convertBiomeColors($biomeColorsTag->getValue())); //Convert back to original format }elseif(($biomesTag = $chunk->getTag("Biomes")) instanceof ByteArrayTag){ $biomeIds = $makeBiomeArray($biomesTag->getValue()); + }else{ + $biomeIds = BiomeArray::fill(BiomeIds::OCEAN); } return new ChunkData( diff --git a/src/world/generator/Flat.php b/src/world/generator/Flat.php index 39d782de3..26a658b6d 100644 --- a/src/world/generator/Flat.php +++ b/src/world/generator/Flat.php @@ -69,7 +69,7 @@ class Flat extends Generator{ } protected function generateBaseChunk() : void{ - $this->chunk = new Chunk([], BiomeArray::fill($this->options->getBiomeId())); + $this->chunk = new Chunk([], BiomeArray::fill($this->options->getBiomeId()), false); $structure = $this->options->getStructure(); $count = count($structure); diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 5af9ed650..74594c879 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -23,8 +23,10 @@ declare(strict_types=1); namespace pocketmine\world\generator; +use pocketmine\data\bedrock\BiomeIds; use pocketmine\scheduler\AsyncTask; use pocketmine\utils\AssumptionFailedError; +use pocketmine\world\format\BiomeArray; use pocketmine\world\format\Chunk; use pocketmine\world\format\io\FastChunkSerializer; use pocketmine\world\SimpleChunkManager; @@ -127,7 +129,7 @@ class PopulationTask extends AsyncTask{ } private static function setOrGenerateChunk(SimpleChunkManager $manager, Generator $generator, int $chunkX, int $chunkZ, ?Chunk $chunk) : Chunk{ - $manager->setChunk($chunkX, $chunkZ, $chunk ?? new Chunk()); + $manager->setChunk($chunkX, $chunkZ, $chunk ?? new Chunk([], BiomeArray::fill(BiomeIds::OCEAN), false)); if($chunk === null){ $generator->generateChunk($manager, $chunkX, $chunkZ); $chunk = $manager->getChunk($chunkX, $chunkZ); diff --git a/tests/phpunit/world/format/ChunkTest.php b/tests/phpunit/world/format/ChunkTest.php index c557c65c3..5d12f7dd2 100644 --- a/tests/phpunit/world/format/ChunkTest.php +++ b/tests/phpunit/world/format/ChunkTest.php @@ -24,11 +24,12 @@ declare(strict_types=1); namespace pocketmine\world\format; use PHPUnit\Framework\TestCase; +use pocketmine\data\bedrock\BiomeIds; class ChunkTest extends TestCase{ public function testClone() : void{ - $chunk = new Chunk(); + $chunk = new Chunk([], BiomeArray::fill(BiomeIds::OCEAN), false); $chunk->setFullBlock(0, 0, 0, 1); $chunk->setBiomeId(0, 0, 1); $chunk->setHeightMap(0, 0, 1); From a5418a019dc2a83210084632130db8ce06f529ea Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 20:53:11 +0100 Subject: [PATCH 166/710] Chunk: added modification counter this is independent from the terrain dirty flags (which are specifically used to track state of chunks needing to be saved). --- src/world/format/Chunk.php | 16 +++++++++++++++- src/world/format/io/FastChunkSerializer.php | 5 ++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index 9f001fd37..2bef86b26 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -42,6 +42,8 @@ class Chunk{ public const COORD_BIT_SIZE = SubChunk::COORD_BIT_SIZE; public const COORD_MASK = SubChunk::COORD_MASK; + private int $modificationCount; + /** @var int */ private $terrainDirtyFlags = 0; @@ -68,7 +70,7 @@ class Chunk{ /** * @param SubChunk[] $subChunks */ - public function __construct(array $subChunks, BiomeArray $biomeIds, bool $terrainPopulated){ + public function __construct(array $subChunks, BiomeArray $biomeIds, bool $terrainPopulated, int $modificationCount = 0){ $this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS); foreach($this->subChunks as $y => $null){ @@ -80,6 +82,7 @@ class Chunk{ $this->biomeIds = $biomeIds; $this->terrainPopulated = $terrainPopulated; + $this->modificationCount = $modificationCount; } /** @@ -108,6 +111,7 @@ class Chunk{ public function setFullBlock(int $x, int $y, int $z, int $block) : void{ $this->getSubChunk($y >> SubChunk::COORD_BIT_SIZE)->setFullBlock($x, $y & SubChunk::COORD_MASK, $z, $block); $this->terrainDirtyFlags |= self::DIRTY_FLAG_TERRAIN; + $this->modificationCount++; } /** @@ -171,6 +175,7 @@ class Chunk{ public function setBiomeId(int $x, int $z, int $biomeId) : void{ $this->biomeIds->set($x, $z, $biomeId); $this->terrainDirtyFlags |= self::DIRTY_FLAG_BIOMES; + $this->modificationCount++; } public function isLightPopulated() : ?bool{ @@ -188,6 +193,7 @@ class Chunk{ public function setPopulated(bool $value = true) : void{ $this->terrainPopulated = $value; $this->terrainDirtyFlags |= self::DIRTY_FLAG_TERRAIN; + $this->modificationCount++; } public function addTile(Tile $tile) : void{ @@ -270,16 +276,24 @@ class Chunk{ }else{ $this->terrainDirtyFlags &= ~$flag; } + $this->modificationCount++; } public function setTerrainDirty() : void{ $this->terrainDirtyFlags = ~0; + $this->modificationCount++; } public function clearTerrainDirtyFlags() : void{ $this->terrainDirtyFlags = 0; } + /** + * Returns the modcount for this chunk. Any saveable change to the chunk will cause this number to be incremented, + * so you can use this to detect when the chunk has been modified. + */ + public function getModificationCount() : int{ return $this->modificationCount; } + public function getSubChunk(int $y) : SubChunk{ if($y < 0 || $y >= $this->subChunks->getSize()){ throw new \InvalidArgumentException("Invalid subchunk Y coordinate $y"); diff --git a/src/world/format/io/FastChunkSerializer.php b/src/world/format/io/FastChunkSerializer.php index bb8bec687..0f3db73d1 100644 --- a/src/world/format/io/FastChunkSerializer.php +++ b/src/world/format/io/FastChunkSerializer.php @@ -51,6 +51,8 @@ final class FastChunkSerializer{ */ public static function serializeTerrain(Chunk $chunk) : string{ $stream = new BinaryStream(); + $stream->putLong($chunk->getModificationCount()); + $stream->putByte( ($chunk->isPopulated() ? self::FLAG_POPULATED : 0) ); @@ -88,6 +90,7 @@ final class FastChunkSerializer{ */ public static function deserializeTerrain(string $data) : Chunk{ $stream = new BinaryStream($data); + $modificationCounter = $stream->getLong(); $flags = $stream->getByte(); $terrainPopulated = (bool) ($flags & self::FLAG_POPULATED); @@ -115,6 +118,6 @@ final class FastChunkSerializer{ $biomeIds = new BiomeArray($stream->get(256)); - return new Chunk($subChunks, $biomeIds, $terrainPopulated); + return new Chunk($subChunks, $biomeIds, $terrainPopulated, $modificationCounter); } } From d4cbde6f100e82da6e40f98c9ff0d5fabe8413c5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 20:53:50 +0100 Subject: [PATCH 167/710] PopulationTask: use modification counters to detect changed chunks instead of using terrain dirty flags, which aren't suitable for this purpose --- src/world/generator/PopulationTask.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 74594c879..ad0602efc 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -89,6 +89,7 @@ class PopulationTask extends AsyncTask{ /** @var Chunk[] $chunks */ $chunks = []; + $oldModCounts = []; $chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : null; @@ -101,6 +102,7 @@ class PopulationTask extends AsyncTask{ $chunks[$i] = null; }else{ $chunks[$i] = FastChunkSerializer::deserializeTerrain($ck); + $oldModCounts[$i] = $chunks[$i]->getModificationCount(); } } @@ -124,7 +126,8 @@ class PopulationTask extends AsyncTask{ $this->chunk = FastChunkSerializer::serializeTerrain($chunk); foreach($chunks as $i => $c){ - $this->{"chunk$i"} = $c->isTerrainDirty() ? FastChunkSerializer::serializeTerrain($c) : null; + $oldModCount = $oldModCounts[$i] ?? 0; + $this->{"chunk$i"} = $oldModCount !== $c->getModificationCounter() ? FastChunkSerializer::serializeTerrain($c) : null; } } From 359d0835f3e3ce5e19b608916c471ae4b6c843bd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 20:54:39 +0100 Subject: [PATCH 168/710] CS --- src/world/format/Chunk.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index 2bef86b26..13a84742b 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -29,7 +29,6 @@ namespace pocketmine\world\format; use pocketmine\block\Block; use pocketmine\block\BlockLegacyIds; use pocketmine\block\tile\Tile; -use pocketmine\data\bedrock\BiomeIds; use function array_map; class Chunk{ From 2e2515354c707d96b73accd454596f91cd602922 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 20:57:43 +0100 Subject: [PATCH 169/710] PopulationTask: fixed undefined method call fuck you PhpStorm! fuck you PhpStorm! fuck you PhpStorm! --- src/world/generator/PopulationTask.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index ad0602efc..2f601a80d 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -127,7 +127,7 @@ class PopulationTask extends AsyncTask{ foreach($chunks as $i => $c){ $oldModCount = $oldModCounts[$i] ?? 0; - $this->{"chunk$i"} = $oldModCount !== $c->getModificationCounter() ? FastChunkSerializer::serializeTerrain($c) : null; + $this->{"chunk$i"} = $oldModCount !== $c->getModificationCount() ? FastChunkSerializer::serializeTerrain($c) : null; } } From 94f4ef5862de594daa21bf3cf51bdd7e48c25e01 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 25 Oct 2021 21:07:03 +0100 Subject: [PATCH 170/710] PopulationTask: Throw AssumptionFailedError if center chunk is null for some reason --- src/world/generator/PopulationTask.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 2f601a80d..2cd68ebde 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -149,7 +149,9 @@ class PopulationTask extends AsyncTask{ /** @var World $world */ $world = $this->fetchLocal(self::TLS_KEY_WORLD); if($world->isLoaded()){ - $chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : null; + $chunk = $this->chunk !== null ? + FastChunkSerializer::deserializeTerrain($this->chunk) : + throw new AssumptionFailedError("Center chunk should never be null"); for($i = 0; $i < 9; ++$i){ if($i === 4){ From 4178c812094fac387f0b2ca063a968d93362aaad Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 26 Oct 2021 00:31:30 +0100 Subject: [PATCH 171/710] Utils: fixed testValidInstance() not accepting the same valid class for both className and baseName this caused problems in PlayerCreationEvent because plugins set the base class and then set the player class to the same thing. --- src/utils/Utils.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/utils/Utils.php b/src/utils/Utils.php index e8add3c9c..de1ade0bd 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -519,12 +519,10 @@ final class Utils{ if(!class_exists($className)){ throw new \InvalidArgumentException("Class $className does not exist"); } - $base = new \ReflectionClass($baseName); - $class = new \ReflectionClass($className); - - if(!$class->isSubclassOf($baseName)){ - throw new \InvalidArgumentException("Class $className does not " . ($base->isInterface() ? "implement" : "extend") . " " . $baseName); + if(!is_a($className, $baseName, true)){ + throw new \InvalidArgumentException("Class $className does not extend or implement $baseName"); } + $class = new \ReflectionClass($className); if(!$class->isInstantiable()){ throw new \InvalidArgumentException("Class $className cannot be constructed"); } From 24d4daec90af7bbfabe11b932217baf1bbb97eda Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 26 Oct 2021 00:32:32 +0100 Subject: [PATCH 172/710] Utils::testValidInstance() now accepts interfaces for the baseName --- src/utils/Utils.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/utils/Utils.php b/src/utils/Utils.php index de1ade0bd..bd4d8ea69 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -53,6 +53,7 @@ use function get_loaded_extensions; use function getenv; use function gettype; use function implode; +use function interface_exists; use function is_array; use function is_bool; use function is_int; @@ -513,14 +514,18 @@ final class Utils{ * @phpstan-param class-string $baseName */ public static function testValidInstance(string $className, string $baseName) : void{ + $baseInterface = false; if(!class_exists($baseName)){ - throw new \InvalidArgumentException("Base class $baseName does not exist"); + if(!interface_exists($baseName)){ + throw new \InvalidArgumentException("Base class $baseName does not exist"); + } + $baseInterface = true; } if(!class_exists($className)){ - throw new \InvalidArgumentException("Class $className does not exist"); + throw new \InvalidArgumentException("Class $className does not exist or is not a class"); } if(!is_a($className, $baseName, true)){ - throw new \InvalidArgumentException("Class $className does not extend or implement $baseName"); + throw new \InvalidArgumentException("Class $className does not " . ($baseInterface ? "implement" : "extend") . " $baseName"); } $class = new \ReflectionClass($className); if(!$class->isInstantiable()){ From bd8cba1a7fb36185301cbe95458b0bb340fcd6ff Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 26 Oct 2021 00:49:41 +0100 Subject: [PATCH 173/710] Added unit tests for Utils::testValidInstance() --- tests/phpunit/utils/UtilsTest.php | 58 +++++++++++++++++++ .../utils/fixtures/TestAbstractClass.php | 7 +++ .../utils/fixtures/TestInstantiableClass.php | 7 +++ .../phpunit/utils/fixtures/TestInterface.php | 7 +++ .../TestSubclassOfInstantiableClass.php | 7 +++ tests/phpunit/utils/fixtures/TestTrait.php | 7 +++ 6 files changed, 93 insertions(+) create mode 100644 tests/phpunit/utils/fixtures/TestAbstractClass.php create mode 100644 tests/phpunit/utils/fixtures/TestInstantiableClass.php create mode 100644 tests/phpunit/utils/fixtures/TestInterface.php create mode 100644 tests/phpunit/utils/fixtures/TestSubclassOfInstantiableClass.php create mode 100644 tests/phpunit/utils/fixtures/TestTrait.php diff --git a/tests/phpunit/utils/UtilsTest.php b/tests/phpunit/utils/UtilsTest.php index 20bb88cdf..80fe84a45 100644 --- a/tests/phpunit/utils/UtilsTest.php +++ b/tests/phpunit/utils/UtilsTest.php @@ -24,6 +24,11 @@ declare(strict_types=1); namespace pocketmine\utils; use PHPUnit\Framework\TestCase; +use pocketmine\utils\fixtures\TestAbstractClass; +use pocketmine\utils\fixtures\TestInstantiableClass; +use pocketmine\utils\fixtures\TestInterface; +use pocketmine\utils\fixtures\TestSubclassOfInstantiableClass; +use pocketmine\utils\fixtures\TestTrait; use function define; use function defined; @@ -89,4 +94,57 @@ class UtilsTest extends TestCase{ //be careful with this test. The closure has to be declared on the same line as the assertion. self::assertSame('closure@' . Filesystem::cleanPath(__FILE__) . '#L' . __LINE__, Utils::getNiceClosureName(function() : void{})); } + + /** + * @return string[][] + * @return list + */ + public function validInstanceProvider() : array{ + return [ + //direct instance / implement / extend + [TestInstantiableClass::class, TestInstantiableClass::class], + [TestInstantiableClass::class, TestAbstractClass::class], + [TestInstantiableClass::class, TestInterface::class], + + //inherited + [TestSubclassOfInstantiableClass::class, TestInstantiableClass::class], + [TestSubclassOfInstantiableClass::class, TestAbstractClass::class], + [TestSubclassOfInstantiableClass::class, TestInterface::class] + ]; + } + + /** + * @dataProvider validInstanceProvider + * @doesNotPerformAssertions + * @phpstan-param class-string $className + * @phpstan-param class-string $baseName + */ + public function testValidInstanceWithValidCombinations(string $className, string $baseName) : void{ + Utils::testValidInstance($className, $baseName); + } + + /** + * @return string[][] + * @return list + */ + public function validInstanceInvalidCombinationsProvider() : array{ + return [ + ["iDontExist abc", TestInstantiableClass::class], + [TestInstantiableClass::class, "iDon'tExist abc"], + ["iDontExist", "iAlsoDontExist"], + [TestInstantiableClass::class, TestTrait::class], + [TestTrait::class, TestTrait::class], + [TestAbstractClass::class, TestAbstractClass::class], + [TestInterface::class, TestInterface::class], + [TestInstantiableClass::class, TestSubclassOfInstantiableClass::class] + ]; + } + + /** + * @dataProvider validInstanceInvalidCombinationsProvider + */ + public function testValidInstanceInvalidParameters(string $className, string $baseName) : void{ + $this->expectException(\InvalidArgumentException::class); + Utils::testValidInstance($className, $baseName); //@phpstan-ignore-line + } } diff --git a/tests/phpunit/utils/fixtures/TestAbstractClass.php b/tests/phpunit/utils/fixtures/TestAbstractClass.php new file mode 100644 index 000000000..2384d3eb1 --- /dev/null +++ b/tests/phpunit/utils/fixtures/TestAbstractClass.php @@ -0,0 +1,7 @@ + Date: Tue, 26 Oct 2021 00:50:43 +0100 Subject: [PATCH 174/710] CS again --- src/utils/Utils.php | 1 + tests/phpunit/utils/fixtures/TestAbstractClass.php | 2 ++ tests/phpunit/utils/fixtures/TestInstantiableClass.php | 2 ++ tests/phpunit/utils/fixtures/TestInterface.php | 2 ++ .../phpunit/utils/fixtures/TestSubclassOfInstantiableClass.php | 2 ++ tests/phpunit/utils/fixtures/TestTrait.php | 2 ++ 6 files changed, 11 insertions(+) diff --git a/src/utils/Utils.php b/src/utils/Utils.php index bd4d8ea69..8e8445baa 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -54,6 +54,7 @@ use function getenv; use function gettype; use function implode; use function interface_exists; +use function is_a; use function is_array; use function is_bool; use function is_int; diff --git a/tests/phpunit/utils/fixtures/TestAbstractClass.php b/tests/phpunit/utils/fixtures/TestAbstractClass.php index 2384d3eb1..212806c4f 100644 --- a/tests/phpunit/utils/fixtures/TestAbstractClass.php +++ b/tests/phpunit/utils/fixtures/TestAbstractClass.php @@ -1,5 +1,7 @@ Date: Tue, 26 Oct 2021 01:07:14 +0100 Subject: [PATCH 175/710] ConsoleReaderThread: trim the string before returning it it will have a newline at the end that was added by the subprocess when posting it to the main process. --- src/console/ConsoleReaderThread.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/console/ConsoleReaderThread.php b/src/console/ConsoleReaderThread.php index f1cca9bb3..fde505f3c 100644 --- a/src/console/ConsoleReaderThread.php +++ b/src/console/ConsoleReaderThread.php @@ -39,6 +39,7 @@ use function stream_socket_accept; use function stream_socket_get_name; use function stream_socket_server; use function stream_socket_shutdown; +use function trim; use const PHP_BINARY; use const STREAM_SHUT_RDWR; @@ -113,7 +114,7 @@ final class ConsoleReaderThread extends Thread{ break; } - $buffer[] = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", $command); + $buffer[] = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", trim($command)); if($notifier !== null){ $notifier->wakeupSleeper(); } From 8f883931841e7b73ea7a11dc04c4e28fa5c0f4f3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 26 Oct 2021 15:28:00 +0100 Subject: [PATCH 176/710] World: Specialize generateChunkCallback() for PopulationTask this allows us to also set the adjacent chunks before calling ChunkPopulateEvent, to give a more accurate picture of what changed. --- src/world/World.php | 23 +++++++++++------------ src/world/generator/PopulationTask.php | 6 +++--- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 282767e76..d5bca0195 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2145,12 +2145,13 @@ class World implements ChunkManager{ } } - public function generateChunkCallback(int $x, int $z, ?Chunk $chunk) : void{ + /** + * @param Chunk[] $adjacentChunks + * @phpstan-param array $adjacentChunks + */ + public function generateChunkCallback(int $x, int $z, Chunk $chunk, array $adjacentChunks) : void{ Timings::$generationCallback->startTiming(); if(isset($this->chunkPopulationRequestMap[$index = World::chunkHash($x, $z)]) && isset($this->activeChunkPopulationTasks[$index])){ - if($chunk === null){ - throw new AssumptionFailedError("Primary chunk should never be NULL"); - } for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ $this->unlockChunk($x + $xx, $z + $zz); @@ -2159,6 +2160,12 @@ class World implements ChunkManager{ $oldChunk = $this->loadChunk($x, $z); $this->setChunk($x, $z, $chunk, false); + + foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){ + World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk); + $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk); + } + if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ (new ChunkPopulateEvent($this, $x, $z, $chunk))->call(); @@ -2172,14 +2179,6 @@ class World implements ChunkManager{ $promise->resolve($chunk); $this->drainPopulationRequestQueue(); - }elseif($this->isChunkLocked($x, $z)){ - $this->unlockChunk($x, $z); - if($chunk !== null){ - $this->setChunk($x, $z, $chunk, false); - } - $this->drainPopulationRequestQueue(); - }elseif($chunk !== null){ - $this->setChunk($x, $z, $chunk, false); } Timings::$generationCallback->stopTiming(); } diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 2cd68ebde..0237a8cc0 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -153,6 +153,7 @@ class PopulationTask extends AsyncTask{ FastChunkSerializer::deserializeTerrain($this->chunk) : throw new AssumptionFailedError("Center chunk should never be null"); + $adjacentChunks = []; for($i = 0; $i < 9; ++$i){ if($i === 4){ continue; @@ -162,12 +163,11 @@ class PopulationTask extends AsyncTask{ $xx = -1 + $i % 3; $zz = -1 + intdiv($i, 3); - $c = FastChunkSerializer::deserializeTerrain($c); - $world->generateChunkCallback($this->chunkX + $xx, $this->chunkZ + $zz, $c); + $adjacentChunks[World::chunkHash($this->chunkX + $xx, $this->chunkZ + $zz)] = FastChunkSerializer::deserializeTerrain($c); } } - $world->generateChunkCallback($this->chunkX, $this->chunkZ, $chunk); + $world->generateChunkCallback($this->chunkX, $this->chunkZ, $chunk, $adjacentChunks); } } } From fca70efbb1f247b5fe7680bfb3cafcbf795d5c6a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 26 Oct 2021 16:44:08 +0100 Subject: [PATCH 177/710] World: move chunk population related methods to be in the same overall place --- src/world/World.php | 118 ++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index d5bca0195..5474aba61 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2124,65 +2124,6 @@ class World implements ChunkManager{ return isset($this->chunkLock[World::chunkHash($chunkX, $chunkZ)]); } - private function drainPopulationRequestQueue() : void{ - $failed = []; - while(count($this->activeChunkPopulationTasks) < $this->maxConcurrentChunkPopulationTasks && !$this->chunkPopulationRequestQueue->isEmpty()){ - $nextChunkHash = $this->chunkPopulationRequestQueue->dequeue(); - World::getXZ($nextChunkHash, $nextChunkX, $nextChunkZ); - if(isset($this->chunkPopulationRequestMap[$nextChunkHash])){ - assert(!isset($this->activeChunkPopulationTasks[$nextChunkHash]), "Population for chunk $nextChunkX $nextChunkZ already running"); - $this->orderChunkPopulation($nextChunkX, $nextChunkZ, null); - if(!isset($this->activeChunkPopulationTasks[$nextChunkHash])){ - $failed[] = $nextChunkHash; - } - } - } - - //these requests failed even though they weren't rate limited; we can't directly re-add them to the back of the - //queue because it would result in an infinite loop - foreach($failed as $hash){ - $this->chunkPopulationRequestQueue->enqueue($hash); - } - } - - /** - * @param Chunk[] $adjacentChunks - * @phpstan-param array $adjacentChunks - */ - public function generateChunkCallback(int $x, int $z, Chunk $chunk, array $adjacentChunks) : void{ - Timings::$generationCallback->startTiming(); - if(isset($this->chunkPopulationRequestMap[$index = World::chunkHash($x, $z)]) && isset($this->activeChunkPopulationTasks[$index])){ - for($xx = -1; $xx <= 1; ++$xx){ - for($zz = -1; $zz <= 1; ++$zz){ - $this->unlockChunk($x + $xx, $z + $zz); - } - } - - $oldChunk = $this->loadChunk($x, $z); - $this->setChunk($x, $z, $chunk, false); - - foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){ - World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk); - $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk); - } - - if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ - (new ChunkPopulateEvent($this, $x, $z, $chunk))->call(); - - foreach($this->getChunkListeners($x, $z) as $listener){ - $listener->onChunkPopulated($x, $z, $chunk); - } - } - unset($this->activeChunkPopulationTasks[$index]); - $promise = $this->chunkPopulationRequestMap[$index]; - unset($this->chunkPopulationRequestMap[$index]); - $promise->resolve($chunk); - - $this->drainPopulationRequestQueue(); - } - Timings::$generationCallback->stopTiming(); - } - /** * @param bool $deleteEntitiesAndTiles Whether to delete entities and tiles on the old chunk, or transfer them to the new one */ @@ -2775,6 +2716,27 @@ class World implements ChunkManager{ return $promise; } + private function drainPopulationRequestQueue() : void{ + $failed = []; + while(count($this->activeChunkPopulationTasks) < $this->maxConcurrentChunkPopulationTasks && !$this->chunkPopulationRequestQueue->isEmpty()){ + $nextChunkHash = $this->chunkPopulationRequestQueue->dequeue(); + World::getXZ($nextChunkHash, $nextChunkX, $nextChunkZ); + if(isset($this->chunkPopulationRequestMap[$nextChunkHash])){ + assert(!isset($this->activeChunkPopulationTasks[$nextChunkHash]), "Population for chunk $nextChunkX $nextChunkZ already running"); + $this->orderChunkPopulation($nextChunkX, $nextChunkZ, null); + if(!isset($this->activeChunkPopulationTasks[$nextChunkHash])){ + $failed[] = $nextChunkHash; + } + } + } + + //these requests failed even though they weren't rate limited; we can't directly re-add them to the back of the + //queue because it would result in an infinite loop + foreach($failed as $hash){ + $this->chunkPopulationRequestQueue->enqueue($hash); + } + } + /** * Attempts to initiate asynchronous generation/population of the target chunk, if it's currently reasonable to do * so (and if it isn't already generated/populated). @@ -2859,6 +2821,44 @@ class World implements ChunkManager{ return $result; } + /** + * @param Chunk[] $adjacentChunks + * @phpstan-param array $adjacentChunks + */ + public function generateChunkCallback(int $x, int $z, Chunk $chunk, array $adjacentChunks) : void{ + Timings::$generationCallback->startTiming(); + if(isset($this->chunkPopulationRequestMap[$index = World::chunkHash($x, $z)]) && isset($this->activeChunkPopulationTasks[$index])){ + for($xx = -1; $xx <= 1; ++$xx){ + for($zz = -1; $zz <= 1; ++$zz){ + $this->unlockChunk($x + $xx, $z + $zz); + } + } + + $oldChunk = $this->loadChunk($x, $z); + $this->setChunk($x, $z, $chunk, false); + + foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){ + World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk); + $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk); + } + + if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ + (new ChunkPopulateEvent($this, $x, $z, $chunk))->call(); + + foreach($this->getChunkListeners($x, $z) as $listener){ + $listener->onChunkPopulated($x, $z, $chunk); + } + } + unset($this->activeChunkPopulationTasks[$index]); + $promise = $this->chunkPopulationRequestMap[$index]; + unset($this->chunkPopulationRequestMap[$index]); + $promise->resolve($chunk); + + $this->drainPopulationRequestQueue(); + } + Timings::$generationCallback->stopTiming(); + } + public function doChunkGarbageCollection() : void{ $this->timings->doChunkGC->startTiming(); From 18734578407486798529b1ef5253b61d36ad8ffd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 26 Oct 2021 20:21:58 +0100 Subject: [PATCH 178/710] PopulationTask: stop using dynamic properties --- src/world/generator/PopulationTask.php | 72 ++++++++-------------- tests/phpstan/configs/actual-problems.neon | 5 -- 2 files changed, 27 insertions(+), 50 deletions(-) diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 0237a8cc0..7ed3abcc7 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -31,7 +31,12 @@ use pocketmine\world\format\Chunk; use pocketmine\world\format\io\FastChunkSerializer; use pocketmine\world\SimpleChunkManager; use pocketmine\world\World; +use function array_map; +use function igbinary_serialize; +use function igbinary_unserialize; use function intdiv; +use function is_array; +use function is_string; class PopulationTask extends AsyncTask{ private const TLS_KEY_WORLD = "world"; @@ -46,25 +51,7 @@ class PopulationTask extends AsyncTask{ /** @var string|null */ public $chunk; - /** @var string|null */ - public $chunk0; - /** @var string|null */ - public $chunk1; - /** @var string|null */ - public $chunk2; - /** @var string|null */ - public $chunk3; - - //center chunk - - /** @var string|null */ - public $chunk5; - /** @var string|null */ - public $chunk6; - /** @var string|null */ - public $chunk7; - /** @var string|null */ - public $chunk8; + private string $adjacentChunks; public function __construct(World $world, int $chunkX, int $chunkZ, ?Chunk $chunk){ $this->worldId = $world->getId(); @@ -72,9 +59,10 @@ class PopulationTask extends AsyncTask{ $this->chunkZ = $chunkZ; $this->chunk = $chunk !== null ? FastChunkSerializer::serializeTerrain($chunk) : null; - foreach($world->getAdjacentChunks($chunkX, $chunkZ) as $i => $c){ - $this->{"chunk$i"} = $c !== null ? FastChunkSerializer::serializeTerrain($c) : null; - } + $this->adjacentChunks = igbinary_serialize(array_map( + fn(?Chunk $c) => $c !== null ? FastChunkSerializer::serializeTerrain($c) : null, + $world->getAdjacentChunks($chunkX, $chunkZ) + )) ?? throw new AssumptionFailedError("igbinary_serialize() returned null"); $this->storeLocal(self::TLS_KEY_WORLD, $world); } @@ -87,27 +75,19 @@ class PopulationTask extends AsyncTask{ $generator = $context->getGenerator(); $manager = new SimpleChunkManager($context->getWorldMinY(), $context->getWorldMaxY()); - /** @var Chunk[] $chunks */ - $chunks = []; - $oldModCounts = []; - $chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : null; - for($i = 0; $i < 9; ++$i){ - if($i === 4){ - continue; - } - $ck = $this->{"chunk$i"}; - if($ck === null){ - $chunks[$i] = null; - }else{ - $chunks[$i] = FastChunkSerializer::deserializeTerrain($ck); - $oldModCounts[$i] = $chunks[$i]->getModificationCount(); - } - } + /** @var string[] $serialChunks */ + $serialChunks = igbinary_unserialize($this->adjacentChunks); + $chunks = array_map( + fn(?string $serialized) => $serialized !== null ? FastChunkSerializer::deserializeTerrain($serialized) : null, + $serialChunks + ); + $oldModCounts = array_map(fn(?Chunk $chunk) => $chunk !== null ? $chunk->getModificationCount() : null, $chunks); self::setOrGenerateChunk($manager, $generator, $this->chunkX, $this->chunkZ, $chunk); + /** @var Chunk[] $resultChunks */ $resultChunks = []; //this is just to keep phpstan's type inference happy foreach($chunks as $i => $c){ $cX = (-1 + $i % 3) + $this->chunkX; @@ -125,10 +105,11 @@ class PopulationTask extends AsyncTask{ $this->chunk = FastChunkSerializer::serializeTerrain($chunk); + $serialChunks = []; foreach($chunks as $i => $c){ - $oldModCount = $oldModCounts[$i] ?? 0; - $this->{"chunk$i"} = $oldModCount !== $c->getModificationCount() ? FastChunkSerializer::serializeTerrain($c) : null; + $serialChunks[$i] = $oldModCounts[$i] !== $c->getModificationCount() ? FastChunkSerializer::serializeTerrain($c) : null; } + $this->adjacentChunks = igbinary_serialize($serialChunks) ?? throw new AssumptionFailedError("igbinary_serialize() returned null"); } private static function setOrGenerateChunk(SimpleChunkManager $manager, Generator $generator, int $chunkX, int $chunkZ, ?Chunk $chunk) : Chunk{ @@ -153,12 +134,13 @@ class PopulationTask extends AsyncTask{ FastChunkSerializer::deserializeTerrain($this->chunk) : throw new AssumptionFailedError("Center chunk should never be null"); + /** + * @var string[]|null[] $serialAdjacentChunks + * @phpstan-var array $serialAdjacentChunks + */ + $serialAdjacentChunks = igbinary_unserialize($this->adjacentChunks); $adjacentChunks = []; - for($i = 0; $i < 9; ++$i){ - if($i === 4){ - continue; - } - $c = $this->{"chunk$i"}; + foreach($serialAdjacentChunks as $i => $c){ if($c !== null){ $xx = -1 + $i % 3; $zz = -1 + intdiv($i, 3); diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index ed9a6f986..1ad3c569f 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -5,8 +5,3 @@ parameters: count: 1 path: ../../../src/event/entity/EntityShootBowEvent.php - - - message: "#^Variable property access on \\$this\\(pocketmine\\\\world\\\\generator\\\\PopulationTask\\)\\.$#" - count: 4 - path: ../../../src/world/generator/PopulationTask.php - From 51fbff204bd7d01acb30636ec9900446b7d0d637 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 26 Oct 2021 20:29:50 +0100 Subject: [PATCH 179/710] World: make PhpStorm understand return type of getAdjacentChunks() --- src/world/World.php | 2 +- src/world/generator/PopulationTask.php | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 5474aba61..0af46a4f9 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2091,7 +2091,7 @@ class World implements ChunkManager{ /** * Returns the chunks adjacent to the specified chunk. * - * @return (Chunk|null)[] + * @return Chunk[]|null[] */ public function getAdjacentChunks(int $x, int $z) : array{ $result = []; diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 7ed3abcc7..fe5f6fc8a 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -35,8 +35,6 @@ use function array_map; use function igbinary_serialize; use function igbinary_unserialize; use function intdiv; -use function is_array; -use function is_string; class PopulationTask extends AsyncTask{ private const TLS_KEY_WORLD = "world"; From a7d8a598e15fd31e0b9203d986ae1c0ee13ee883 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 26 Oct 2021 22:58:17 +0100 Subject: [PATCH 180/710] World: reduce code duplication for chunk coordinate calculation --- src/world/World.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 0af46a4f9..522aa57b2 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -1610,7 +1610,7 @@ class World implements ChunkManager{ $block->writeStateToWorld(); $pos = $block->getPosition(); - $chunkHash = World::chunkHash($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE); + $chunkHash = World::chunkHash($chunkX, $chunkZ); $relativeBlockHash = World::chunkBlockHash($x, $y, $z); unset($this->blockCache[$chunkHash][$relativeBlockHash]); @@ -1620,7 +1620,7 @@ class World implements ChunkManager{ } $this->changedBlocks[$chunkHash][$relativeBlockHash] = $pos; - foreach($this->getChunkListeners($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE) as $listener){ + foreach($this->getChunkListeners($chunkX, $chunkZ) as $listener){ $listener->onBlockChanged($pos); } From 6d89265510212a082f79e333a707b5aef5e5a832 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 26 Oct 2021 23:02:50 +0100 Subject: [PATCH 181/710] Player: reduce code duplication back when this was just hardcoded >> 4 everywhere, nobody thought anything of it, but now it uses constants, it's easy to cross-reference and see where the duplicates are. --- src/player/Player.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/player/Player.php b/src/player/Player.php index 10265f466..8a8ba1ce2 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -271,9 +271,11 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $world = $spawnLocation->getWorld(); //load the spawn chunk so we can see the terrain - $world->registerChunkLoader($this->chunkLoader, $spawnLocation->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawnLocation->getFloorZ() >> Chunk::COORD_BIT_SIZE, true); - $world->registerChunkListener($this, $spawnLocation->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawnLocation->getFloorZ() >> Chunk::COORD_BIT_SIZE); - $this->usedChunks[World::chunkHash($spawnLocation->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawnLocation->getFloorZ() >> Chunk::COORD_BIT_SIZE)] = UsedChunkStatus::NEEDED(); + $xSpawnChunk = $spawnLocation->getFloorX() >> Chunk::COORD_BIT_SIZE; + $zSpawnChunk = $spawnLocation->getFloorZ() >> Chunk::COORD_BIT_SIZE; + $world->registerChunkLoader($this->chunkLoader, $xSpawnChunk, $zSpawnChunk, true); + $world->registerChunkListener($this, $xSpawnChunk, $zSpawnChunk); + $this->usedChunks[World::chunkHash($xSpawnChunk, $zSpawnChunk)] = UsedChunkStatus::NEEDED(); parent::__construct($spawnLocation, $this->playerInfo->getSkin(), $namedtag); } From 0ef5c67b9b6b2b42b42e9e93001299b784dd96b9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 27 Oct 2021 21:10:16 +0100 Subject: [PATCH 182/710] Use static constructor for MovePlayerPacket this marks the last of the packets created using the old way. --- composer.lock | 8 ++++---- src/network/mcpe/NetworkSession.php | 21 +++++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index 883984a57..4348bbce6 100644 --- a/composer.lock +++ b/composer.lock @@ -253,12 +253,12 @@ "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "5285dde125b529e070db7eeb0d3774208e1652ef" + "reference": "58c53a259e819a076bf8fe875d2a012da7d19d65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/5285dde125b529e070db7eeb0d3774208e1652ef", - "reference": "5285dde125b529e070db7eeb0d3774208e1652ef", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/58c53a259e819a076bf8fe875d2a012da7d19d65", + "reference": "58c53a259e819a076bf8fe875d2a012da7d19d65", "shasum": "" }, "require": { @@ -293,7 +293,7 @@ "issues": "https://github.com/pmmp/BedrockProtocol/issues", "source": "https://github.com/pmmp/BedrockProtocol/tree/master" }, - "time": "2021-10-23T15:18:49+00:00" + "time": "2021-10-27T19:49:20+00:00" }, { "name": "pocketmine/binaryutils", diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 2ca46db0e..5ff3998a2 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -727,16 +727,17 @@ class NetworkSession{ $yaw = $yaw ?? $location->getYaw(); $pitch = $pitch ?? $location->getPitch(); - $pk = new MovePlayerPacket(); - $pk->actorRuntimeId = $this->player->getId(); - $pk->position = $this->player->getOffsetPosition($pos); - $pk->pitch = $pitch; - $pk->headYaw = $yaw; - $pk->yaw = $yaw; - $pk->mode = $mode; - $pk->onGround = $this->player->onGround; - - $this->sendDataPacket($pk); + $this->sendDataPacket(MovePlayerPacket::simple( + $this->player->getId(), + $this->player->getOffsetPosition($pos), + $pitch, + $yaw, + $yaw, //TODO: head yaw + $mode, + $this->player->onGround, + 0, //TODO: riding entity ID + 0 //TODO: tick + )); if($this->handler instanceof InGamePacketHandler){ $this->handler->forceMoveSync = true; From bb05af103d22148dbe3aa053a2119c2603282343 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 15:55:05 +0100 Subject: [PATCH 183/710] PluginManager: fixed crash when using a plugin-loader plugin (read: devtools) closes #4518 --- src/plugin/PluginManager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index c46ad4a65..1b02e082a 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -41,7 +41,7 @@ use pocketmine\timings\TimingsHandler; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; -use function array_diff_assoc; +use function array_diff_key; use function array_key_exists; use function array_keys; use function array_merge; @@ -355,7 +355,7 @@ class PluginManager{ $this->server->getLogger()->debug("Plugin $name registered a new plugin loader during load, scanning for new plugins"); $plugins = $triage->plugins; $this->triagePlugins($path, $triage, $diffLoaders); - $diffPlugins = array_diff_assoc($triage->plugins, $plugins); + $diffPlugins = array_diff_key($triage->plugins, $plugins); $this->server->getLogger()->debug("Re-triage found plugins: " . implode(", ", array_keys($diffPlugins))); } } From 48f77abe7e4b078c2f8b185f738b5d269dceb203 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 16:03:43 +0100 Subject: [PATCH 184/710] Leave channel ID in VersionInfo so that I don't have to type it out every time I make a new release. Most of the time it's going to be posted to the same channel as before anyway. --- src/VersionInfo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 701598a17..cc0170c8b 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ final class VersionInfo{ public const BASE_VERSION = "4.0.0-BETA7"; public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; - public const BUILD_CHANNEL = ""; + public const BUILD_CHANNEL = "beta"; private function __construct(){ //NOOP From dba148cfaa3b9cc53a3bdd7bb622bb35c39a5194 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 16:25:18 +0100 Subject: [PATCH 185/710] build/make-release: make arg parsing use getopt --- build/make-release.php | 57 ++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/build/make-release.php b/build/make-release.php index d90623332..65f46f385 100644 --- a/build/make-release.php +++ b/build/make-release.php @@ -25,18 +25,26 @@ namespace pocketmine\build\make_release; use pocketmine\utils\VersionString; use pocketmine\VersionInfo; -use function count; +use function array_keys; +use function array_map; use function dirname; use function fgets; use function file_get_contents; use function file_put_contents; use function fwrite; +use function getopt; +use function is_string; +use function max; use function preg_replace; use function sleep; use function sprintf; +use function str_pad; +use function strlen; use function system; use const STDERR; use const STDIN; +use const STDOUT; +use const STR_PAD_LEFT; require_once dirname(__DIR__) . '/vendor/autoload.php'; @@ -60,22 +68,38 @@ function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev file_put_contents($versionInfoPath, $versionInfo); } -/** - * @param string[] $argv - * @phpstan-param list $argv - */ -function main(array $argv) : void{ - if(count($argv) < 2){ - fwrite(STDERR, "Arguments: [release version] [next version]\n"); - exit(1); +const ACCEPTED_OPTS = [ + "current" => "Version to insert and tag", + "next" => "Version to put in the file after tagging", + "channel" => "Release channel to post this build into" +]; + +function main() : void{ + $filteredOpts = []; + foreach(getopt("", ["current:", "next:", "channel:", "help"]) as $optName => $optValue){ + if($optName === "help"){ + fwrite(STDOUT, "Options:\n"); + + $maxLength = max(array_map(fn(string $str) => strlen($str), array_keys(ACCEPTED_OPTS))); + foreach(ACCEPTED_OPTS as $acceptedName => $description){ + fwrite(STDOUT, str_pad("--$acceptedName", $maxLength + 4, " ", STR_PAD_LEFT) . ": $description\n"); + } + exit(0); + } + if(!is_string($optValue)){ + fwrite(STDERR, "--$optName expects exactly 1 value\n"); + exit(1); + } + $filteredOpts[$optName] = $optValue; } - if(isset($argv[2])){ - $currentVer = new VersionString($argv[2]); + + if(isset($filteredOpts["current"])){ + $currentVer = new VersionString($filteredOpts["current"]); }else{ $currentVer = VersionInfo::VERSION(); } - if(isset($argv[3])){ - $nextVer = new VersionString($argv[3]); + if(isset($filteredOpts["next"])){ + $nextVer = new VersionString($filteredOpts["next"]); }else{ $nextVer = new VersionString(sprintf( "%u.%u.%u", @@ -84,6 +108,7 @@ function main(array $argv) : void{ $currentVer->getPatch() + 1 )); } + $channel = $filteredOpts["channel"] ?? VersionInfo::BUILD_CHANNEL; echo "About to tag version $currentVer. Next version will be $nextVer.\n"; echo "please add appropriate notes to the changelog and press enter..."; @@ -95,10 +120,10 @@ function main(array $argv) : void{ exit(1); } $versionInfoPath = dirname(__DIR__) . '/src/VersionInfo.php'; - replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $argv[1]); + replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel); system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"'); system('git tag ' . $currentVer->getBaseVersion()); - replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, ""); + replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel); system('git add "' . $versionInfoPath . '"'); system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"'); echo "pushing changes in 5 seconds\n"; @@ -106,4 +131,4 @@ function main(array $argv) : void{ system('git push origin HEAD ' . $currentVer->getBaseVersion()); } -main($argv); +main(); From 2b0768f7208cfa4fa4cb0c0c23f492c9f0189498 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 16:26:56 +0100 Subject: [PATCH 186/710] make-release: fixed retention of +dev on release versions --- build/make-release.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/make-release.php b/build/make-release.php index 65f46f385..ea334e04d 100644 --- a/build/make-release.php +++ b/build/make-release.php @@ -96,7 +96,7 @@ function main() : void{ if(isset($filteredOpts["current"])){ $currentVer = new VersionString($filteredOpts["current"]); }else{ - $currentVer = VersionInfo::VERSION(); + $currentVer = new VersionString(VersionInfo::BASE_VERSION); } if(isset($filteredOpts["next"])){ $nextVer = new VersionString($filteredOpts["next"]); From d0474ccd9257c1992a6014f5e4a3c82caa2f4c45 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 16:29:20 +0100 Subject: [PATCH 187/710] make-release: note which channel the build will be released into --- build/make-release.php | 1 + 1 file changed, 1 insertion(+) diff --git a/build/make-release.php b/build/make-release.php index ea334e04d..90961c392 100644 --- a/build/make-release.php +++ b/build/make-release.php @@ -111,6 +111,7 @@ function main() : void{ $channel = $filteredOpts["channel"] ?? VersionInfo::BUILD_CHANNEL; echo "About to tag version $currentVer. Next version will be $nextVer.\n"; + echo "$currentVer will be published on release channel \"$channel\".\n"; echo "please add appropriate notes to the changelog and press enter..."; fgets(STDIN); system('git add "' . dirname(__DIR__) . '/changelogs"'); From 7effa03ba45083ad8364b38a1c6399a8d9d3c74e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 17:28:48 +0100 Subject: [PATCH 188/710] Release 4.0.0-BETA7 --- changelogs/4.0.md | 36 ++++++++++++++++++++++++++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 708822771..d9a268bef 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1460,3 +1460,39 @@ Released 19th October 2021. ## Gameplay - Picking up some items from a dropped stack of items is now supported. This fixes various bugs with being unable to pick up items with an almost-full inventory. + +# 4.0.0-BETA7 +Released 28 October 2021. + +## General +- Phar plugins are now able to depend on folder plugins loaded by DevTools. +- Now uses [`pocketmine/bedrock-protocol@58c53a259e819a076bf8fe875d2a012da7d19d65`](https://github.com/pmmp/BedrockProtocol/tree/58c53a259e819a076bf8fe875d2a012da7d19d65). This version features significant changes, including: + - Standardisation of various field names (e.g. `eid` -> `actorRuntimeId`, `evid` -> `eventId`) + - Rename of `entity` related fields to `actor` where appropriate (e.g. `entityRuntimeId` -> `actorRuntimeId`) + - Block position `x`/`y`/`z` fields replaced by `BlockPosition` + - Static `::create()` functions for all packets, which ensure that fields can't be forgotten + +## Fixes +- Fixed server crash when clients send itemstacks with unmappable dynamic item IDs. +- Fixed server crash on invalid ItemStackRequest action types. +- Fixed autosave bug that caused unmodified chunks to be saved at least once (during the first autosave after they were loaded). +- Fixed `ConsoleReaderThread` returning strings with newlines still on the end. +- Fixed changes made to adjacent chunks in `ChunkPopulateEvent` (e.g. setting blocks) sometimes getting overwritten. + +## API +### Event +- `PlayerCreationEvent` now verifies that the player class set is instantiable - this ensures that plugins get properly blamed for breaking things. + +### World +- `World->generateChunkCallback()` has been specialized for use by `PopulationTask`. This allows fixing various inconsistencies involving `ChunkPopulateEvent` (e.g. modifications to adjacent chunks in `ChunkPopulationEvent` might be wiped out, if the population of the target chunk modified the adjacent chunk). + - It now accepts `Chunk $centerChunk, array $adjacentChunks` (instead of `?Chunk $chunk`). + - It's no longer expected to be used by plugins - plugins should be using `World->setChunk()` anyway. +- `Chunk->getModificationCounter()` has been added. This is a number starting from `0` when the `Chunk` object is first created (unless overridden by the constructor). It's incremented every time blocks or biomes are changed in the chunk. It resets after the chunk is unloaded and reloaded. +- The following API methods have changed signatures: + - `Sound->encode()` no longer accepts `null` for the position. + - `Chunk->__construct()`: removed `HeightArray $heightMap` parameter, added `bool $terrainPopulated` and `int $modificationCounter` parameters. + +### Plugin +- `PluginManager->loadPlugins()` now accepts paths to files as well as directories, in which case it will load only the plugin found in the target file. +- The following API methods have been removed: + - `PluginManager->loadPlugin()`: use `PluginManager->loadPlugins()` instead diff --git a/src/VersionInfo.php b/src/VersionInfo.php index cc0170c8b..f9b39cab4 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,7 +30,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA7"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From b3720b3f17024ac6d1dad50e6dc1bee7649461d4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 17:28:53 +0100 Subject: [PATCH 189/710] 4.0.0-BETA8 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index f9b39cab4..c56b36a60 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,8 +29,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA7"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA8"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From eb40b741aee28502bab400f25a8649adef69a609 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 20:15:37 +0100 Subject: [PATCH 190/710] StandardPacketBroadcaster now splits broadcasts by session-specific PacketSerializerContext in the normal case, all sessions will share the same PacketSerializerContext and Compressor, so this code will be the same as before However, for the multi-protocol hackers out there, this should reduce the maintenance burden (@Driesboy) since now only the PacketSerializerContext needs to be maintained. I recommend a separate PacketSerializerContext for each protocol (perhaps put the protocol version in the serializer context too, if you need it for some reason). --- src/network/mcpe/NetworkSession.php | 2 + .../mcpe/StandardPacketBroadcaster.php | 50 ++++++++++--------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 5ff3998a2..fc46f8ae5 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -447,6 +447,8 @@ class NetworkSession{ } } + public function getPacketSerializerContext() : PacketSerializerContext{ return $this->packetSerializerContext; } + public function getBroadcaster() : PacketBroadcaster{ return $this->broadcaster; } public function getCompressor() : Compressor{ diff --git a/src/network/mcpe/StandardPacketBroadcaster.php b/src/network/mcpe/StandardPacketBroadcaster.php index 1442a5bbf..4da9b0951 100644 --- a/src/network/mcpe/StandardPacketBroadcaster.php +++ b/src/network/mcpe/StandardPacketBroadcaster.php @@ -23,10 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe; -use pocketmine\network\mcpe\compression\Compressor; -use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary; use pocketmine\network\mcpe\protocol\serializer\PacketBatch; -use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext; use pocketmine\Server; use function spl_object_id; @@ -40,35 +37,40 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{ } public function broadcastPackets(array $recipients, array $packets) : void{ - //TODO: we should be using session-specific serializer contexts for this - $stream = PacketBatch::fromPackets(new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()), ...$packets); - - /** @var Compressor[] $compressors */ + $buffers = []; $compressors = []; - /** @var NetworkSession[][] $compressorTargets */ - $compressorTargets = []; + $targetMap = []; foreach($recipients as $recipient){ - $compressor = $recipient->getCompressor(); - $compressorId = spl_object_id($compressor); + $serializerContext = $recipient->getPacketSerializerContext(); + $bufferId = spl_object_id($serializerContext); + if(!isset($buffers[$bufferId])){ + $buffers[$bufferId] = PacketBatch::fromPackets($serializerContext, ...$packets); + } + //TODO: different compressors might be compatible, it might not be necessary to split them up by object - $compressors[$compressorId] = $compressor; - $compressorTargets[$compressorId][] = $recipient; + $compressor = $recipient->getCompressor(); + $compressors[spl_object_id($compressor)] = $compressor; + + $targetMap[$bufferId][spl_object_id($compressor)][] = $recipient; } - foreach($compressors as $compressorId => $compressor){ - if(!$compressor->willCompress($stream->getBuffer())){ - foreach($compressorTargets[$compressorId] as $target){ - foreach($packets as $pk){ - $target->addToSendBuffer($pk); + foreach($targetMap as $bufferId => $compressorMap){ + $buffer = $buffers[$bufferId]; + foreach($compressorMap as $compressorId => $compressorTargets){ + $compressor = $compressors[$compressorId]; + if(!$compressor->willCompress($buffer->getBuffer())){ + foreach($compressorTargets as $target){ + foreach($packets as $pk){ + $target->addToSendBuffer($pk); + } + } + }else{ + $promise = $this->server->prepareBatch($buffer, $compressor); + foreach($compressorTargets as $target){ + $target->queueCompressed($promise); } - } - }else{ - $promise = $this->server->prepareBatch($stream, $compressor); - foreach($compressorTargets[$compressorId] as $target){ - $target->queueCompressed($promise); } } } - } } From 5db3915aad8b6218be25fc6b49646cefac36c696 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 20:28:00 +0100 Subject: [PATCH 191/710] Make MemoryManager aware of ChunkCache --- src/MemoryManager.php | 2 ++ src/network/mcpe/cache/ChunkCache.php | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/MemoryManager.php b/src/MemoryManager.php index dbcd80092..f45647969 100644 --- a/src/MemoryManager.php +++ b/src/MemoryManager.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine; use pocketmine\event\server\LowMemoryEvent; +use pocketmine\network\mcpe\cache\ChunkCache; use pocketmine\scheduler\DumpWorkerMemoryTask; use pocketmine\scheduler\GarbageCollectionTask; use pocketmine\timings\Timings; @@ -187,6 +188,7 @@ class MemoryManager{ foreach($this->server->getWorldManager()->getWorlds() as $world){ $world->clearCache(true); } + ChunkCache::pruneCaches(); } if($this->lowMemChunkGC){ diff --git a/src/network/mcpe/cache/ChunkCache.php b/src/network/mcpe/cache/ChunkCache.php index 269451f49..bf0ee4419 100644 --- a/src/network/mcpe/cache/ChunkCache.php +++ b/src/network/mcpe/cache/ChunkCache.php @@ -36,9 +36,6 @@ use function strlen; /** * This class is used by the current MCPE protocol system to store cached chunk packets for fast resending. - * - * TODO: make MemoryManager aware of this so the cache can be destroyed when memory is low - * TODO: this needs a hook for world unloading */ class ChunkCache implements ChunkListener{ /** @var self[][] */ @@ -69,6 +66,19 @@ class ChunkCache implements ChunkListener{ return self::$instances[$worldId][$compressorId]; } + public static function pruneCaches() : void{ + foreach(self::$instances as $compressorMap){ + foreach($compressorMap as $chunkCache){ + foreach($chunkCache->caches as $chunkHash => $promise){ + if($promise->hasResult()){ + //Do not clear promises that are not yet fulfilled; they will have requesters waiting on them + unset($chunkCache->caches[$chunkHash]); + } + } + } + } + } + /** @var World */ private $world; /** @var Compressor */ From a62ce64fdd337003e065073d33778d9486bc8e22 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 20:59:51 +0100 Subject: [PATCH 192/710] Revert "Chunk: added modification counter" This reverts commit a5418a019dc2a83210084632130db8ce06f529ea. The more I assessed this, the more I realized that this implementation doesn't actually offer any value. Since modcounters don't persist after chunk unload + reload, they can't be reliably used to detect changes in chunks without additional event subscriptions. For the purpose I actually intended to use them for (population task cancellation) there's a) another solution, and b) modcounts are unreliable for that too, because of the aforementioned potential for chunks to get unloaded and reloaded. For the case of detecting dirty chunks within PopulationTask itself, they are also unnecessary, since the dirty flags are sufficient within there, since FastChunkSerializer doesn't copy dirty flags. In conclusion, this was a misbegotten addition with little real value, but does impact performance in hot paths. --- src/world/format/Chunk.php | 16 +--------------- src/world/format/io/FastChunkSerializer.php | 5 +---- src/world/generator/PopulationTask.php | 3 +-- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index 13a84742b..23367ef7e 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -41,8 +41,6 @@ class Chunk{ public const COORD_BIT_SIZE = SubChunk::COORD_BIT_SIZE; public const COORD_MASK = SubChunk::COORD_MASK; - private int $modificationCount; - /** @var int */ private $terrainDirtyFlags = 0; @@ -69,7 +67,7 @@ class Chunk{ /** * @param SubChunk[] $subChunks */ - public function __construct(array $subChunks, BiomeArray $biomeIds, bool $terrainPopulated, int $modificationCount = 0){ + public function __construct(array $subChunks, BiomeArray $biomeIds, bool $terrainPopulated){ $this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS); foreach($this->subChunks as $y => $null){ @@ -81,7 +79,6 @@ class Chunk{ $this->biomeIds = $biomeIds; $this->terrainPopulated = $terrainPopulated; - $this->modificationCount = $modificationCount; } /** @@ -110,7 +107,6 @@ class Chunk{ public function setFullBlock(int $x, int $y, int $z, int $block) : void{ $this->getSubChunk($y >> SubChunk::COORD_BIT_SIZE)->setFullBlock($x, $y & SubChunk::COORD_MASK, $z, $block); $this->terrainDirtyFlags |= self::DIRTY_FLAG_TERRAIN; - $this->modificationCount++; } /** @@ -174,7 +170,6 @@ class Chunk{ public function setBiomeId(int $x, int $z, int $biomeId) : void{ $this->biomeIds->set($x, $z, $biomeId); $this->terrainDirtyFlags |= self::DIRTY_FLAG_BIOMES; - $this->modificationCount++; } public function isLightPopulated() : ?bool{ @@ -192,7 +187,6 @@ class Chunk{ public function setPopulated(bool $value = true) : void{ $this->terrainPopulated = $value; $this->terrainDirtyFlags |= self::DIRTY_FLAG_TERRAIN; - $this->modificationCount++; } public function addTile(Tile $tile) : void{ @@ -275,24 +269,16 @@ class Chunk{ }else{ $this->terrainDirtyFlags &= ~$flag; } - $this->modificationCount++; } public function setTerrainDirty() : void{ $this->terrainDirtyFlags = ~0; - $this->modificationCount++; } public function clearTerrainDirtyFlags() : void{ $this->terrainDirtyFlags = 0; } - /** - * Returns the modcount for this chunk. Any saveable change to the chunk will cause this number to be incremented, - * so you can use this to detect when the chunk has been modified. - */ - public function getModificationCount() : int{ return $this->modificationCount; } - public function getSubChunk(int $y) : SubChunk{ if($y < 0 || $y >= $this->subChunks->getSize()){ throw new \InvalidArgumentException("Invalid subchunk Y coordinate $y"); diff --git a/src/world/format/io/FastChunkSerializer.php b/src/world/format/io/FastChunkSerializer.php index 0f3db73d1..bb8bec687 100644 --- a/src/world/format/io/FastChunkSerializer.php +++ b/src/world/format/io/FastChunkSerializer.php @@ -51,8 +51,6 @@ final class FastChunkSerializer{ */ public static function serializeTerrain(Chunk $chunk) : string{ $stream = new BinaryStream(); - $stream->putLong($chunk->getModificationCount()); - $stream->putByte( ($chunk->isPopulated() ? self::FLAG_POPULATED : 0) ); @@ -90,7 +88,6 @@ final class FastChunkSerializer{ */ public static function deserializeTerrain(string $data) : Chunk{ $stream = new BinaryStream($data); - $modificationCounter = $stream->getLong(); $flags = $stream->getByte(); $terrainPopulated = (bool) ($flags & self::FLAG_POPULATED); @@ -118,6 +115,6 @@ final class FastChunkSerializer{ $biomeIds = new BiomeArray($stream->get(256)); - return new Chunk($subChunks, $biomeIds, $terrainPopulated, $modificationCounter); + return new Chunk($subChunks, $biomeIds, $terrainPopulated); } } diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index fe5f6fc8a..0e35961be 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -81,7 +81,6 @@ class PopulationTask extends AsyncTask{ fn(?string $serialized) => $serialized !== null ? FastChunkSerializer::deserializeTerrain($serialized) : null, $serialChunks ); - $oldModCounts = array_map(fn(?Chunk $chunk) => $chunk !== null ? $chunk->getModificationCount() : null, $chunks); self::setOrGenerateChunk($manager, $generator, $this->chunkX, $this->chunkZ, $chunk); @@ -105,7 +104,7 @@ class PopulationTask extends AsyncTask{ $serialChunks = []; foreach($chunks as $i => $c){ - $serialChunks[$i] = $oldModCounts[$i] !== $c->getModificationCount() ? FastChunkSerializer::serializeTerrain($c) : null; + $serialChunks[$i] = $c->isTerrainDirty() ? FastChunkSerializer::serializeTerrain($c) : null; } $this->adjacentChunks = igbinary_serialize($serialChunks) ?? throw new AssumptionFailedError("igbinary_serialize() returned null"); } From d410db4302855b9df05d17b84a4300db4aa5ca84 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 22:11:07 +0100 Subject: [PATCH 193/710] Chunk: rename DIRTY_FLAG_TERRAIN to DIRTY_FLAG_BLOCKS we use the word 'terrain' elsewhere to refer to the combination of blocks and biomes, so using TERRAIN here is misleading. --- src/world/format/Chunk.php | 8 ++++---- src/world/format/io/leveldb/LevelDB.php | 2 +- src/world/generator/PopulationTask.php | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index 23367ef7e..f1b1320ae 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -32,7 +32,7 @@ use pocketmine\block\tile\Tile; use function array_map; class Chunk{ - public const DIRTY_FLAG_TERRAIN = 1 << 0; + public const DIRTY_FLAG_BLOCKS = 1 << 0; public const DIRTY_FLAG_BIOMES = 1 << 3; public const MAX_SUBCHUNKS = 16; @@ -106,7 +106,7 @@ class Chunk{ */ public function setFullBlock(int $x, int $y, int $z, int $block) : void{ $this->getSubChunk($y >> SubChunk::COORD_BIT_SIZE)->setFullBlock($x, $y & SubChunk::COORD_MASK, $z, $block); - $this->terrainDirtyFlags |= self::DIRTY_FLAG_TERRAIN; + $this->terrainDirtyFlags |= self::DIRTY_FLAG_BLOCKS; } /** @@ -186,7 +186,7 @@ class Chunk{ public function setPopulated(bool $value = true) : void{ $this->terrainPopulated = $value; - $this->terrainDirtyFlags |= self::DIRTY_FLAG_TERRAIN; + $this->terrainDirtyFlags |= self::DIRTY_FLAG_BLOCKS; } public function addTile(Tile $tile) : void{ @@ -295,7 +295,7 @@ class Chunk{ } $this->subChunks[$y] = $subChunk ?? new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, []); - $this->setTerrainDirtyFlag(self::DIRTY_FLAG_TERRAIN, true); + $this->setTerrainDirtyFlag(self::DIRTY_FLAG_BLOCKS, true); } /** diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index 54433214e..a96e329b3 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -436,7 +436,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $write->put($index . self::TAG_VERSION, chr(self::CURRENT_LEVEL_CHUNK_VERSION)); $chunk = $chunkData->getChunk(); - if($chunk->getTerrainDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN)){ + if($chunk->getTerrainDirtyFlag(Chunk::DIRTY_FLAG_BLOCKS)){ $subChunks = $chunk->getSubChunks(); foreach($subChunks as $y => $subChunk){ $key = $index . self::TAG_SUBCHUNK_PREFIX . chr($y); diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 0e35961be..e3bccbbfb 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -117,7 +117,7 @@ class PopulationTask extends AsyncTask{ if($chunk === null){ throw new AssumptionFailedError("We just set this chunk, so it must exist"); } - $chunk->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_TERRAIN, true); + $chunk->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_BLOCKS, true); $chunk->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_BIOMES, true); } return $chunk; From d78801b9d5c2f53c3340448c657dc52ff3e8c7f9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 22:24:47 +0100 Subject: [PATCH 194/710] World: fixed tiles and entities getting deleted when adjacent chunks are modified during population --- src/world/World.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/World.php b/src/world/World.php index 522aa57b2..148363254 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2839,7 +2839,7 @@ class World implements ChunkManager{ foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){ World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk); - $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk); + $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk, false); } if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ From c66790b6a69da5ed2aa3bcb653f7864d2e52c93f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 23:42:28 +0100 Subject: [PATCH 195/710] World: never delete entities in setChunk() entities exist completely independently from chunks now, so there is no need to interact with them whatsoever. As I wrote in #4520, there's no sense in deleting entities here, since a chunk replacement is essentially just a mass block update. On that theme, it might be a good idea to call Entity->onNearbyBlockChange() for all entities in the target and adjacent chunks when replacing a chunk, to ensure that they get the proper movement updates. --- src/world/World.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 148363254..ae3837b06 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2125,18 +2125,13 @@ class World implements ChunkManager{ } /** - * @param bool $deleteEntitiesAndTiles Whether to delete entities and tiles on the old chunk, or transfer them to the new one + * @param bool $deleteTiles Whether to delete tiles on the old chunk, or transfer them to the new one */ - public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk, bool $deleteEntitiesAndTiles = true) : void{ + public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk, bool $deleteTiles = true) : void{ $chunkHash = World::chunkHash($chunkX, $chunkZ); $oldChunk = $this->loadChunk($chunkX, $chunkZ); if($oldChunk !== null and $oldChunk !== $chunk){ - if($deleteEntitiesAndTiles){ - foreach($this->getChunkEntities($chunkX, $chunkZ) as $entity){ - if(!($entity instanceof Player)){ - $entity->close(); - } - } + if($deleteTiles){ foreach($oldChunk->getTiles() as $tile){ $tile->close(); } From eb75df6f8e338b22927ad7ee6ae58c103ea0a9fb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 23:46:35 +0100 Subject: [PATCH 196/710] World: Intelligently perform automatic transfer or deletion of tiles in setChunk(), depending on the context tiles may be deleted in the following circumstances: 1) the target block in the new chunk doesn't expect a tile 2) the target block in the new chunk expects a different type of tile (responsibility of the plugin developer to create the new tile) 3) there's already a tile in the target chunk which conflicts with the old one In all other cases, the tile will be transferred. This resolves a large number of unintentional bugs caused by world editors replacing chunks without setting the deleteTilesAndEntities parameter to false (even the core itself does it). closes #4520 --- src/world/World.php | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index ae3837b06..df780e5a1 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2124,23 +2124,36 @@ class World implements ChunkManager{ return isset($this->chunkLock[World::chunkHash($chunkX, $chunkZ)]); } - /** - * @param bool $deleteTiles Whether to delete tiles on the old chunk, or transfer them to the new one - */ - public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk, bool $deleteTiles = true) : void{ + public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{ $chunkHash = World::chunkHash($chunkX, $chunkZ); $oldChunk = $this->loadChunk($chunkX, $chunkZ); if($oldChunk !== null and $oldChunk !== $chunk){ - if($deleteTiles){ - foreach($oldChunk->getTiles() as $tile){ - $tile->close(); - } - }else{ - foreach($oldChunk->getTiles() as $tile){ - $chunk->addTile($tile); - $oldChunk->removeTile($tile); + $deletedTiles = 0; + $transferredTiles = 0; + foreach($oldChunk->getTiles() as $oldTile){ + $tilePosition = $oldTile->getPosition(); + $localX = $tilePosition->getFloorX() & Chunk::COORD_MASK; + $localY = $tilePosition->getFloorY(); + $localZ = $tilePosition->getFloorZ() & Chunk::COORD_MASK; + + $newBlock = BlockFactory::getInstance()->fromFullBlock($chunk->getFullBlock($localX, $localY, $localZ)); + $expectedTileClass = $newBlock->getIdInfo()->getTileClass(); + if( + $expectedTileClass === null || //new block doesn't expect a tile + !($oldTile instanceof $expectedTileClass) || //new block expects a different tile + (($newTile = $chunk->getTile($localX, $localY, $localZ)) !== null && $newTile !== $oldTile) //new chunk already has a different tile + ){ + $oldTile->close(); + $deletedTiles++; + }else{ + $transferredTiles++; + $chunk->addTile($oldTile); + $oldChunk->removeTile($oldTile); } } + if($deletedTiles > 0 || $transferredTiles > 0){ + $this->logger->debug("Replacement of chunk $chunkX $chunkZ caused deletion of $deletedTiles obsolete/conflicted tiles, and transfer of $transferredTiles"); + } } $this->chunks[$chunkHash] = $chunk; @@ -2830,11 +2843,11 @@ class World implements ChunkManager{ } $oldChunk = $this->loadChunk($x, $z); - $this->setChunk($x, $z, $chunk, false); + $this->setChunk($x, $z, $chunk); foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){ World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk); - $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk, false); + $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk); } if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ From a4eda9a8f5a0d30e364470c2a5c9fc214b4f6e24 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 28 Oct 2021 23:59:32 +0100 Subject: [PATCH 197/710] World: call nearby entities' onNearbyBlockChange() in setChunk() fixes #2779 in all known cases. --- src/world/World.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/world/World.php b/src/world/World.php index df780e5a1..4aaba2d51 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2177,6 +2177,14 @@ class World implements ChunkManager{ $listener->onChunkChanged($chunkX, $chunkZ, $chunk); } } + + for($cX = -1; $cX <= 1; ++$cX){ + for($cZ = -1; $cZ <= 1; ++$cZ){ + foreach($this->getChunkEntities($chunkX + $cX, $chunkZ + $cZ) as $entity){ + $entity->onNearbyBlockChange(); + } + } + } } /** From fb5543a2adf8f25e79e894f346969a4efc290020 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 00:16:11 +0100 Subject: [PATCH 198/710] Updated BedrockProtocol dependency --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 4348bbce6..706fbcc04 100644 --- a/composer.lock +++ b/composer.lock @@ -253,12 +253,12 @@ "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "58c53a259e819a076bf8fe875d2a012da7d19d65" + "reference": "49e929d3a7c9aba21d6f0d9ac5ce73e23e6ca8b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/58c53a259e819a076bf8fe875d2a012da7d19d65", - "reference": "58c53a259e819a076bf8fe875d2a012da7d19d65", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/49e929d3a7c9aba21d6f0d9ac5ce73e23e6ca8b2", + "reference": "49e929d3a7c9aba21d6f0d9ac5ce73e23e6ca8b2", "shasum": "" }, "require": { @@ -293,7 +293,7 @@ "issues": "https://github.com/pmmp/BedrockProtocol/issues", "source": "https://github.com/pmmp/BedrockProtocol/tree/master" }, - "time": "2021-10-27T19:49:20+00:00" + "time": "2021-10-28T23:13:59+00:00" }, { "name": "pocketmine/binaryutils", From f1cc168d2606b2a1bc52e9d6a7d5f39885566c79 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 00:23:13 +0100 Subject: [PATCH 199/710] phpstan: exclude a couple of files from analysis temporarily close #4472 --- phpstan.neon.dist | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 0dee95aa2..df2c4a10b 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -34,6 +34,9 @@ parameters: analyseAndScan: - build/php - build/preprocessor + analyse: + - src/pocketmine/block/StoneSlab.php #overrides STONE constant + - src/pocketmine/item/Potion.php #overrides WATER constant dynamicConstantNames: - pocketmine\DEBUG - pocketmine\IS_DEVELOPMENT_BUILD From 88b7389080cad7a3a0a2020f42b55ec44fbd99a0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 15:37:52 +0100 Subject: [PATCH 200/710] InventoryManager: reduce code duplication --- src/network/mcpe/InventoryManager.php | 34 +++++++++++---------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/network/mcpe/InventoryManager.php b/src/network/mcpe/InventoryManager.php index db5b3a2ae..b5271f5f9 100644 --- a/src/network/mcpe/InventoryManager.php +++ b/src/network/mcpe/InventoryManager.php @@ -166,27 +166,21 @@ class InventoryManager{ //if the class isn't final, not to mention being inflexible. if($inv instanceof BlockInventory){ $blockPosition = BlockPosition::fromVector3($inv->getHolder()); - switch(true){ - case $inv instanceof LoomInventory: - return [ContainerOpenPacket::blockInv($id, WindowTypes::LOOM, $blockPosition)]; - case $inv instanceof FurnaceInventory: - return match($inv->getFurnaceType()->id()){ - FurnaceType::FURNACE()->id() => [ContainerOpenPacket::blockInv($id, WindowTypes::FURNACE, $blockPosition)], - FurnaceType::BLAST_FURNACE()->id() => [ContainerOpenPacket::blockInv($id, WindowTypes::BLAST_FURNACE, $blockPosition)], - FurnaceType::SMOKER()->id() => [ContainerOpenPacket::blockInv($id, WindowTypes::SMOKER, $blockPosition)], + $windowType = match(true){ + $inv instanceof LoomInventory => WindowTypes::LOOM, + $inv instanceof FurnaceInventory => match($inv->getFurnaceType()->id()){ + FurnaceType::FURNACE()->id() => WindowTypes::FURNACE, + FurnaceType::BLAST_FURNACE()->id() => WindowTypes::BLAST_FURNACE, + FurnaceType::SMOKER()->id() => WindowTypes::SMOKER, default => throw new AssumptionFailedError("Unreachable") - }; - case $inv instanceof EnchantInventory: - return [ContainerOpenPacket::blockInv($id, WindowTypes::ENCHANTMENT, $blockPosition)]; - case $inv instanceof BrewingStandInventory: - return [ContainerOpenPacket::blockInv($id, WindowTypes::BREWING_STAND, $blockPosition)]; - case $inv instanceof AnvilInventory: - return [ContainerOpenPacket::blockInv($id, WindowTypes::ANVIL, $blockPosition)]; - case $inv instanceof HopperInventory: - return [ContainerOpenPacket::blockInv($id, WindowTypes::HOPPER, $blockPosition)]; - default: - return [ContainerOpenPacket::blockInv($id, WindowTypes::CONTAINER, $blockPosition)]; - } + }, + $inv instanceof EnchantInventory => WindowTypes::ENCHANTMENT, + $inv instanceof BrewingStandInventory => WindowTypes::BREWING_STAND, + $inv instanceof AnvilInventory => WindowTypes::ANVIL, + $inv instanceof HopperInventory => WindowTypes::HOPPER, + default => WindowTypes::CONTAINER + }; + return [ContainerOpenPacket::blockInv($id, $windowType, $blockPosition)]; } return null; } From ee9f5e0044c7b355470b3c9d8b411805b3e3ea94 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 15:40:58 +0100 Subject: [PATCH 201/710] Location: make __construct() parameters mandatory I did consider allowing yaw/pitch to remain optional, but considering the implicit immutability of Location, it really doesn't make any sense to create a Location with default yaw/pitch - just create a Position in that case instead. --- src/entity/Location.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entity/Location.php b/src/entity/Location.php index 156062a41..fe02f6eec 100644 --- a/src/entity/Location.php +++ b/src/entity/Location.php @@ -34,7 +34,7 @@ class Location extends Position{ /** @var float */ public $pitch; - public function __construct(float $x, float $y, float $z, float $yaw = 0.0, float $pitch = 0.0, ?World $world = null){ + public function __construct(float $x, float $y, float $z, float $yaw, float $pitch, ?World $world){ $this->yaw = $yaw; $this->pitch = $pitch; parent::__construct($x, $y, $z, $world); From 32a34d249473d172e85eb7a8a1f8a66055f1727f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 15:43:09 +0100 Subject: [PATCH 202/710] Location: change order of constructor parameters to be consistent with Position::__construct() and Location::fromObject() (although Location::fromObject() has no choice, thanks to the anti-feature known as late static binding ...) --- src/command/defaults/TeleportCommand.php | 2 +- src/entity/Entity.php | 4 ++-- src/entity/Location.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/command/defaults/TeleportCommand.php b/src/command/defaults/TeleportCommand.php index 1ece20f30..e3bbff7d0 100644 --- a/src/command/defaults/TeleportCommand.php +++ b/src/command/defaults/TeleportCommand.php @@ -113,7 +113,7 @@ class TeleportCommand extends VanillaCommand{ $x = $this->getRelativeDouble($base->x, $sender, $targetArgs[0]); $y = $this->getRelativeDouble($base->y, $sender, $targetArgs[1], 0, 256); $z = $this->getRelativeDouble($base->z, $sender, $targetArgs[2]); - $targetLocation = new Location($x, $y, $z, $yaw, $pitch, $base->getWorld()); + $targetLocation = new Location($x, $y, $z, $base->getWorld(), $yaw, $pitch); $subject->teleport($targetLocation); Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_tp_success_coordinates( diff --git a/src/entity/Entity.php b/src/entity/Entity.php index 6289a896b..c917f6001 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -1185,9 +1185,9 @@ abstract class Entity{ ($this->boundingBox->minX + $this->boundingBox->maxX) / 2, $this->boundingBox->minY - $this->ySize, ($this->boundingBox->minZ + $this->boundingBox->maxZ) / 2, + $this->location->world, $this->location->yaw, - $this->location->pitch, - $this->location->world + $this->location->pitch ); $this->getWorld()->onEntityMoved($this); diff --git a/src/entity/Location.php b/src/entity/Location.php index fe02f6eec..c04ac9acb 100644 --- a/src/entity/Location.php +++ b/src/entity/Location.php @@ -34,7 +34,7 @@ class Location extends Position{ /** @var float */ public $pitch; - public function __construct(float $x, float $y, float $z, float $yaw, float $pitch, ?World $world){ + public function __construct(float $x, float $y, float $z, ?World $world, float $yaw, float $pitch){ $this->yaw = $yaw; $this->pitch = $pitch; parent::__construct($x, $y, $z, $world); @@ -44,14 +44,14 @@ class Location extends Position{ * @return Location */ public static function fromObject(Vector3 $pos, ?World $world, float $yaw = 0.0, float $pitch = 0.0){ - return new Location($pos->x, $pos->y, $pos->z, $yaw, $pitch, $world ?? (($pos instanceof Position) ? $pos->world : null)); + return new Location($pos->x, $pos->y, $pos->z, $world ?? (($pos instanceof Position) ? $pos->world : null), $yaw, $pitch); } /** * Return a Location instance */ public function asLocation() : Location{ - return new Location($this->x, $this->y, $this->z, $this->yaw, $this->pitch, $this->world); + return new Location($this->x, $this->y, $this->z, $this->world, $this->yaw, $this->pitch); } public function getYaw() : float{ From 089e62b44e51dc780306694c4638eeb2e4179b44 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 18:54:00 +0100 Subject: [PATCH 203/710] Entity::spawnTo(): verify that the target player belongs to the same world as the entity this should never be hit in the PM case, but it's an InvalidArgument rather than AssumptionFailedError because plugins can and do call this with bad things. --- src/pocketmine/Player.php | 2 +- src/pocketmine/entity/Entity.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index f08f704ae..9883b52d6 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -563,7 +563,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } public function spawnTo(Player $player) : void{ - if($this->spawned and $player->spawned and $this->isAlive() and $player->isAlive() and $player->getLevelNonNull() === $this->level and $player->canSee($this) and !$this->isSpectator()){ + if($this->spawned and $player->spawned and $this->isAlive() and $player->isAlive() and $player->canSee($this) and !$this->isSpectator()){ parent::spawnTo($player); } } diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 419a4ee14..c4c017874 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -1950,6 +1950,9 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ } public function spawnTo(Player $player) : void{ + if($player->getLevelNonNull() !== $this->level){ + throw new \InvalidArgumentException("Player is not in the same world"); + } if( !isset($this->hasSpawned[$player->getLoaderId()]) and $this->chunk !== null and From 1c18c731efd780a2136c4cd11368c7e36fb07c16 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 19:15:12 +0100 Subject: [PATCH 204/710] bootstrap: check for zlib raw support in leveldb --- src/PocketMine.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PocketMine.php b/src/PocketMine.php index 44b7ebdd6..f944d445d 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -126,6 +126,9 @@ namespace pocketmine { if(version_compare($leveldb_version, "0.2.1") < 0){ $messages[] = "php-leveldb >= 0.2.1 is required, while you have $leveldb_version."; } + if(!defined('LEVELDB_ZLIB_RAW_COMPRESSION')){ + $messages[] = "Given version of php-leveldb doesn't support ZLIB_RAW compression (use https://github.com/pmmp/php-leveldb)"; + } } $chunkutils2_version = phpversion("chunkutils2"); From 19f448d074f6f0eccb1a76570d629962a21dbf51 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 21:56:56 +0100 Subject: [PATCH 205/710] pocketmine/math 0.4.0 --- composer.json | 2 +- composer.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index 22b5cd7a0..ee148e213 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "pocketmine/errorhandler": "^0.3.0", "pocketmine/log": "^0.3.0", "pocketmine/log-pthreads": "^0.2.0", - "pocketmine/math": "^0.3.0", + "pocketmine/math": "^0.4.0", "pocketmine/nbt": "^0.3.0", "pocketmine/raklib": "^0.14.2", "pocketmine/raklib-ipc": "^0.1.0", diff --git a/composer.lock b/composer.lock index 706fbcc04..747ede114 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ddbcdbc7ea7247bea7fcb37e5c42340b", + "content-hash": "3f467dca67940d465ceafbe5774d6977", "packages": [ { "name": "adhocore/json-comment", @@ -253,12 +253,12 @@ "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "49e929d3a7c9aba21d6f0d9ac5ce73e23e6ca8b2" + "reference": "c8d891b4dff9817d5fcd373dfec0608b20be3b0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/49e929d3a7c9aba21d6f0d9ac5ce73e23e6ca8b2", - "reference": "49e929d3a7c9aba21d6f0d9ac5ce73e23e6ca8b2", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/c8d891b4dff9817d5fcd373dfec0608b20be3b0a", + "reference": "c8d891b4dff9817d5fcd373dfec0608b20be3b0a", "shasum": "" }, "require": { @@ -267,7 +267,7 @@ "php": "^8.0", "pocketmine/binaryutils": "^0.2.0", "pocketmine/color": "^0.2.0", - "pocketmine/math": "^0.3.0", + "pocketmine/math": "^0.3.0 || ^0.4.0", "pocketmine/nbt": "^0.3.0", "ramsey/uuid": "^4.1" }, @@ -293,7 +293,7 @@ "issues": "https://github.com/pmmp/BedrockProtocol/issues", "source": "https://github.com/pmmp/BedrockProtocol/tree/master" }, - "time": "2021-10-28T23:13:59+00:00" + "time": "2021-10-29T20:54:42+00:00" }, { "name": "pocketmine/binaryutils", @@ -593,26 +593,26 @@ }, { "name": "pocketmine/math", - "version": "0.3.0", + "version": "0.4.0", "source": { "type": "git", "url": "https://github.com/pmmp/Math.git", - "reference": "83ec067b12c066fc61d9fb129daf7e61ef3b1d63" + "reference": "6d64e2555bd2e95ed024574f75d1cefc135c89fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Math/zipball/83ec067b12c066fc61d9fb129daf7e61ef3b1d63", - "reference": "83ec067b12c066fc61d9fb129daf7e61ef3b1d63", + "url": "https://api.github.com/repos/pmmp/Math/zipball/6d64e2555bd2e95ed024574f75d1cefc135c89fc", + "reference": "6d64e2555bd2e95ed024574f75d1cefc135c89fc", "shasum": "" }, "require": { - "php": "^7.4 || ^8.0", + "php": "^8.0", "php-64bit": "*" }, "require-dev": { "irstea/phpunit-shim": "^8.5 || ^9.5", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.90", + "phpstan/phpstan": "0.12.99", "phpstan/phpstan-strict-rules": "^0.12.4" }, "type": "library", @@ -628,9 +628,9 @@ "description": "PHP library containing math related code used in PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Math/issues", - "source": "https://github.com/pmmp/Math/tree/0.3.0" + "source": "https://github.com/pmmp/Math/tree/0.4.0" }, - "time": "2021-07-14T18:39:31+00:00" + "time": "2021-10-29T20:33:10+00:00" }, { "name": "pocketmine/nbt", From a8d5e8c5f6dc33dc697213de60694590b263ff44 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 22:23:22 +0100 Subject: [PATCH 206/710] Release 3.25.1 --- changelogs/3.25.md | 5 +++++ src/pocketmine/VersionInfo.php | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/changelogs/3.25.md b/changelogs/3.25.md index 8c66ff9f3..360729e3c 100644 --- a/changelogs/3.25.md +++ b/changelogs/3.25.md @@ -9,3 +9,8 @@ Plugin developers should **only** update their required API to this version if y # 3.25.0 - Added support for Minecraft: Bedrock Edition 1.17.40. - Removed compatibility with earlier versions. + +# 3.25.1 +- Fixed autosave bug that caused unmodified chunks to be saved at least once (during the first autosave after they were loaded). +- `Entity->spawnTo()` now has an additional sanity check for matching worlds (might expose a few new errors in plugins). +- Fixed a missing field in `CraftRecipeAuto` item stack request type. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 82af4e6ce..534fb4d72 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,6 +34,6 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.25.1"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = ""; +const BUILD_CHANNEL = "stable"; From d17cd658030e66009c0bb32941387c7444d3ffe0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 22:23:28 +0100 Subject: [PATCH 207/710] 3.25.2 is next --- src/pocketmine/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 534fb4d72..46aca0d7a 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.25.1"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.25.2"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = "stable"; +const BUILD_CHANNEL = ""; From 428bd5ae91b23d8d542a0217dda6b2bd1c3157d5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 22:35:15 +0100 Subject: [PATCH 208/710] Release 4.0.0-BETA8 --- changelogs/4.0.md | 31 ++++++++++++++++++++++++++++++- src/VersionInfo.php | 2 +- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index d9a268bef..dd27e019d 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1462,7 +1462,7 @@ Released 19th October 2021. - Picking up some items from a dropped stack of items is now supported. This fixes various bugs with being unable to pick up items with an almost-full inventory. # 4.0.0-BETA7 -Released 28 October 2021. +Released 28th October 2021. ## General - Phar plugins are now able to depend on folder plugins loaded by DevTools. @@ -1496,3 +1496,32 @@ Released 28 October 2021. - `PluginManager->loadPlugins()` now accepts paths to files as well as directories, in which case it will load only the plugin found in the target file. - The following API methods have been removed: - `PluginManager->loadPlugin()`: use `PluginManager->loadPlugins()` instead + +# 4.0.0-BETA8 +Released 29th October 2021. + +## General +- Chunk packet caches are now cleared by the memory manager on low memory. +- `Entity->spawnTo()` now has an additional sanity check for matching worlds (might expose a few new errors in plugins). +- [`pocketmine/math` 0.4.0](https://github.com/pmmp/Math/releases/tag/0.4.0) is now used. Please see its release notes for changes. + +## Fixes +- Zlib raw check for LevelDB is now done directly on startup, avoiding crashes when later trying to load worlds. +- Fixed tiles and entities getting deleted from adjacent chunks during chunk population. +- Fixed players being unable to open their inventories more than once. +- Fixed entities not getting updated when a nearby chunk is replaced (e.g. dropped items would float in midair if the ground was lower than before) + +## API +### World +- `World::setChunk()` has the following changes: + - `$deleteEntitiesAndTiles` parameter has been removed. + - Entities are no longer deleted on chunk replacement. + - Tiles are no longer deleted on chunk replacement, unless one of the following conditions is met: + - the target block in the new chunk doesn't expect a tile + - the target block in the new chunk expects a different type of tile (responsibility of the plugin developer to create the new tile) + - there's already a tile in the target chunk which conflicts with the old one +- `Location::__construct()` has the following changes: + - `world` parameter is now 4th instead of last. + - All parameters are now mandatory. +- Reverted addition of chunk modification counters in previous beta. +- `Chunk::DIRTY_FLAG_TERRAIN` has been renamed to `Chunk::DIRTY_FLAG_BLOCKS`. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index c56b36a60..282461242 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,7 +30,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA8"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From 63dfcc60c31dd60a7c358fd50ecca931f53010de Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 29 Oct 2021 22:35:23 +0100 Subject: [PATCH 209/710] 4.0.0-BETA9 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 282461242..10d2f6e4b 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,8 +29,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA8"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA9"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From 71f2a34616961d6328f06fd911b6d4450a61643e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 15:38:27 +0100 Subject: [PATCH 210/710] Entity: spawnTo() must silently swallow errors Player->showPlayer() assumes that spawnTo() will take care of all the checks necessary to ensure we don't actually spawn a player to someone it shouldn't be able to see. In PM3, there's nothing we can do about that. This could be a problem if anything decides to override spawnTo() to do additional stuff and assumes that the function will always succeed; however, there's not much reason to do that (plugins sending packets should override sendSpawnPacket() instead). --- src/pocketmine/entity/Entity.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index c4c017874..39e1a28fc 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -1950,12 +1950,10 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ } public function spawnTo(Player $player) : void{ - if($player->getLevelNonNull() !== $this->level){ - throw new \InvalidArgumentException("Player is not in the same world"); - } if( !isset($this->hasSpawned[$player->getLoaderId()]) and $this->chunk !== null and + $player->getLevelNonNull() === $this->level and isset($player->usedChunks[$chunkHash = Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())]) and $player->usedChunks[$chunkHash] === true ){ From 69952ae2aff244715b986d35c3ed041863fb39ef Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 16:05:10 +0100 Subject: [PATCH 211/710] Human: limit lifetime total XP range to INT32_MAX closes #4484 --- src/pocketmine/entity/Human.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 462c0e81d..9d590db0c 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -475,8 +475,8 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ * score when they die. (TODO: add this when MCPE supports it) */ public function setLifetimeTotalXp(int $amount) : void{ - if($amount < 0){ - throw new \InvalidArgumentException("XP must be greater than 0"); + if($amount < 0 || $amount > INT32_MAX){ + throw new \InvalidArgumentException("XP must be greater than 0 and less than " . INT32_MAX); } $this->totalXp = $amount; From 465a5098589af4e08456495c21c920d069ea5310 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 16:13:01 +0100 Subject: [PATCH 212/710] World: remove spammy debug message --- src/world/World.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/world/World.php b/src/world/World.php index 4aaba2d51..3b5d12ffa 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -1412,7 +1412,6 @@ class World implements ChunkManager{ public function updateAllLight(int $x, int $y, int $z) : void{ if(($chunk = $this->getChunk($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE)) === null || $chunk->isLightPopulated() !== true){ - $this->logger->debug("Skipped runtime light update of x=$x,y=$y,z=$z because the target area has not received base light calculation"); return; } From 141fbde6604da5001b73db0dae86fc6f397939e0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 16:58:03 +0100 Subject: [PATCH 213/710] Player: fixed getting re-banned on rejoin after unban from hardcore death closes #2175 --- src/pocketmine/Player.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 9883b52d6..23a382b4c 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -1117,7 +1117,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } if($this->getHealth() <= 0){ - $this->respawn(); + $this->actuallyRespawn(); } } @@ -3891,6 +3891,10 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ return; } + $this->actuallyRespawn(); + } + + protected function actuallyRespawn() : void{ $ev = new PlayerRespawnEvent($this, $this->getSpawn()); $ev->call(); From 08f3c18de930d00240867f719c0fd1d2b59cdb45 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 17:16:46 +0100 Subject: [PATCH 214/710] Arrow: do not add pickups to creative players' inventories closes #2932 --- src/entity/projectile/Arrow.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/entity/projectile/Arrow.php b/src/entity/projectile/Arrow.php index 5fbef6486..ca194d2c5 100644 --- a/src/entity/projectile/Arrow.php +++ b/src/entity/projectile/Arrow.php @@ -175,6 +175,7 @@ class Arrow extends Projectile{ $item = VanillaItems::ARROW(); $playerInventory = match(true){ + !$player->hasFiniteResources() => null, //arrows are not picked up in creative $player->getOffHandInventory()->getItem(0)->canStackWith($item) and $player->getOffHandInventory()->canAddItem($item) => $player->getOffHandInventory(), $player->getInventory()->canAddItem($item) => $player->getInventory(), default => null From 5b8ce7e3e218e869092904206fcc80e3ad2b643a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 21:02:24 +0100 Subject: [PATCH 215/710] Cake: fixed desync on cancellation of eating closes #3591 we don't support eating in creative right now, but the cake shouldn't appear to be eaten when it's not. --- src/block/Cake.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/block/Cake.php b/src/block/Cake.php index 75030c659..e9f82943f 100644 --- a/src/block/Cake.php +++ b/src/block/Cake.php @@ -94,8 +94,7 @@ class Cake extends Transparent implements FoodSource{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($player !== null){ - $player->consumeObject($this); - return true; + return $player->consumeObject($this); } return false; From 1d22761d272815730e94afd974cef39170cd42ed Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 21:25:47 +0100 Subject: [PATCH 216/710] Remove useless newline --- src/player/SurvivalBlockBreakHandler.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/player/SurvivalBlockBreakHandler.php b/src/player/SurvivalBlockBreakHandler.php index ee9ff4df9..d407f02cd 100644 --- a/src/player/SurvivalBlockBreakHandler.php +++ b/src/player/SurvivalBlockBreakHandler.php @@ -101,8 +101,7 @@ final class SurvivalBlockBreakHandler{ } public function update() : bool{ - if( - $this->player->getPosition()->distanceSquared($this->blockPos->add(0.5, 0.5, 0.5)) > $this->maxPlayerDistance ** 2){ + if($this->player->getPosition()->distanceSquared($this->blockPos->add(0.5, 0.5, 0.5)) > $this->maxPlayerDistance ** 2){ return false; } From 4f816d03a767d55f5312ef4668cb34545503ce62 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 21:35:58 +0100 Subject: [PATCH 217/710] SurvivalBlockBreakHandler: remove useless code --- src/player/Player.php | 4 ++-- src/player/SurvivalBlockBreakHandler.php | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/player/Player.php b/src/player/Player.php index 33c61b302..2f743fea3 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1518,8 +1518,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ return true; } - if(!$this->isCreative()){ - $this->blockBreakHandler = SurvivalBlockBreakHandler::createIfNecessary($this, $pos, $target, $face, 16); + if(!$this->isCreative() && !$block->getBreakInfo()->breaksInstantly()){ + $this->blockBreakHandler = new SurvivalBlockBreakHandler($this, $pos, $target, $face, 16); } return true; diff --git a/src/player/SurvivalBlockBreakHandler.php b/src/player/SurvivalBlockBreakHandler.php index d407f02cd..5e27392cf 100644 --- a/src/player/SurvivalBlockBreakHandler.php +++ b/src/player/SurvivalBlockBreakHandler.php @@ -59,7 +59,7 @@ final class SurvivalBlockBreakHandler{ /** @var float */ private $breakProgress = 0; - private function __construct(Player $player, Vector3 $blockPos, Block $block, int $targetedFace, int $maxPlayerDistance, int $fxTickInterval = self::DEFAULT_FX_INTERVAL_TICKS){ + public function __construct(Player $player, Vector3 $blockPos, Block $block, int $targetedFace, int $maxPlayerDistance, int $fxTickInterval = self::DEFAULT_FX_INTERVAL_TICKS){ $this->player = $player; $this->blockPos = $blockPos; $this->block = $block; @@ -76,14 +76,6 @@ final class SurvivalBlockBreakHandler{ } } - public static function createIfNecessary(Player $player, Vector3 $blockPos, Block $block, int $targetedFace, int $maxPlayerDistance, int $fxTickInterval = self::DEFAULT_FX_INTERVAL_TICKS) : ?self{ - $breakInfo = $block->getBreakInfo(); - if(!$breakInfo->breaksInstantly()){ - return new self($player, $blockPos, $block, $targetedFace, $maxPlayerDistance, $fxTickInterval); - } - return null; - } - /** * Returns the calculated break speed as percentage progress per game tick. */ From faad2365e2529d4bb6e86fcb26d6f46dc7ee93c9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 22:17:06 +0100 Subject: [PATCH 218/710] World: Register a temporary chunk loader on chunks used by PopulationTask fixes #3839 --- src/world/World.php | 13 +++++++++++-- src/world/generator/PopulationTask.php | 9 +++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 3b5d12ffa..a4bd8e81a 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2813,13 +2813,15 @@ class World implements ChunkManager{ $this->chunkPopulationRequestMap[$index] = $promise; } + $temporaryChunkLoader = new class implements ChunkLoader{}; for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ $this->lockChunk($x + $xx, $z + $zz); + $this->registerChunkLoader($temporaryChunkLoader, $x + $xx, $z + $zz); } } - $task = new PopulationTask($this, $x, $z, $chunk); + $task = new PopulationTask($this, $x, $z, $chunk, $temporaryChunkLoader); $workerId = $this->workerPool->selectWorker(); if(!isset($this->generatorRegisteredWorkers[$workerId])){ $this->registerGeneratorToWorker($workerId); @@ -2840,8 +2842,15 @@ class World implements ChunkManager{ * @param Chunk[] $adjacentChunks * @phpstan-param array $adjacentChunks */ - public function generateChunkCallback(int $x, int $z, Chunk $chunk, array $adjacentChunks) : void{ + public function generateChunkCallback(int $x, int $z, Chunk $chunk, array $adjacentChunks, ChunkLoader $temporaryChunkLoader) : void{ Timings::$generationCallback->startTiming(); + + for($xx = -1; $xx <= 1; ++$xx){ + for($zz = -1; $zz <= 1; ++$zz){ + $this->unregisterChunkLoader($temporaryChunkLoader, $x + $xx, $z + $zz); + } + } + if(isset($this->chunkPopulationRequestMap[$index = World::chunkHash($x, $z)]) && isset($this->activeChunkPopulationTasks[$index])){ for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index e3bccbbfb..19c0038fa 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -26,6 +26,7 @@ namespace pocketmine\world\generator; use pocketmine\data\bedrock\BiomeIds; use pocketmine\scheduler\AsyncTask; use pocketmine\utils\AssumptionFailedError; +use pocketmine\world\ChunkLoader; use pocketmine\world\format\BiomeArray; use pocketmine\world\format\Chunk; use pocketmine\world\format\io\FastChunkSerializer; @@ -38,6 +39,7 @@ use function intdiv; class PopulationTask extends AsyncTask{ private const TLS_KEY_WORLD = "world"; + private const TLS_KEY_CHUNK_LOADER = "chunkLoader"; /** @var int */ public $worldId; @@ -51,7 +53,7 @@ class PopulationTask extends AsyncTask{ private string $adjacentChunks; - public function __construct(World $world, int $chunkX, int $chunkZ, ?Chunk $chunk){ + public function __construct(World $world, int $chunkX, int $chunkZ, ?Chunk $chunk, ChunkLoader $temporaryChunkLoader){ $this->worldId = $world->getId(); $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; @@ -63,6 +65,7 @@ class PopulationTask extends AsyncTask{ )) ?? throw new AssumptionFailedError("igbinary_serialize() returned null"); $this->storeLocal(self::TLS_KEY_WORLD, $world); + $this->storeLocal(self::TLS_KEY_CHUNK_LOADER, $temporaryChunkLoader); } public function onRun() : void{ @@ -126,6 +129,8 @@ class PopulationTask extends AsyncTask{ public function onCompletion() : void{ /** @var World $world */ $world = $this->fetchLocal(self::TLS_KEY_WORLD); + /** @var ChunkLoader $temporaryChunkLoader */ + $temporaryChunkLoader = $this->fetchLocal(self::TLS_KEY_CHUNK_LOADER); if($world->isLoaded()){ $chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : @@ -146,7 +151,7 @@ class PopulationTask extends AsyncTask{ } } - $world->generateChunkCallback($this->chunkX, $this->chunkZ, $chunk, $adjacentChunks); + $world->generateChunkCallback($this->chunkX, $this->chunkZ, $chunk, $adjacentChunks, $temporaryChunkLoader); } } } From 73dc0598e4512166db65ddfd51bc0b51c455eaba Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Oct 2021 23:22:37 +0100 Subject: [PATCH 219/710] CrashDump: remove derp space --- src/pocketmine/CrashDump.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/CrashDump.php b/src/pocketmine/CrashDump.php index dc81e4331..511f67388 100644 --- a/src/pocketmine/CrashDump.php +++ b/src/pocketmine/CrashDump.php @@ -383,7 +383,7 @@ class CrashDump{ $this->addLine("uname -a: " . php_uname("a")); $this->addLine("PHP Version: " . phpversion()); $this->addLine("Zend version: " . zend_version()); - $this->addLine("OS : " . PHP_OS . ", " . Utils::getOS()); + $this->addLine("OS: " . PHP_OS . ", " . Utils::getOS()); $this->addLine("Composer libraries: "); foreach($composerLibraries as $library => $libraryVersion){ $this->addLine("- $library $libraryVersion"); From 1cabe4baf33c4901af4f446330caf2edd838614f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 13:58:32 +0000 Subject: [PATCH 220/710] World: do not crash on duplicate tiles loaded from disk closes #4049 --- src/world/World.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/world/World.php b/src/world/World.php index a4bd8e81a..c9fb8f816 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2485,6 +2485,8 @@ class World implements ChunkManager{ $this->getLogger()->warning("Chunk $chunkX $chunkZ: Deleted unknown tile entity type " . $nbt->getString("id", "")); }elseif(!$this->isChunkLoaded($tile->getPosition()->getFloorX() >> Chunk::COORD_BIT_SIZE, $tile->getPosition()->getFloorZ() >> Chunk::COORD_BIT_SIZE)){ $this->logger->error("Chunk $chunkX $chunkZ: Found tile saved on wrong chunk - unable to fix due to correct chunk not loaded"); + }elseif($this->getTile($tilePosition = $tile->getPosition()) !== null){ + $this->logger->error("Chunk $chunkX $chunkZ: Cannot add tile at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z: Another tile is already at that position"); }else{ $this->addTile($tile); } From 3dc75644d9546e7e57439d8e07677b1c7ce66ec0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 14:02:25 +0000 Subject: [PATCH 221/710] World: avoid duplicated logger code in initChunk() --- src/world/World.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index c9fb8f816..ab7e18ce9 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2442,6 +2442,7 @@ class World implements ChunkManager{ } private function initChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void{ + $logger = new \PrefixedLogger($this->logger, "Loading chunk $chunkX $chunkZ"); if(count($chunkData->getEntityNBT()) !== 0){ $this->timings->syncChunkLoadEntities->startTiming(); $entityFactory = EntityFactory::getInstance(); @@ -2449,8 +2450,8 @@ class World implements ChunkManager{ try{ $entity = $entityFactory->createFromData($this, $nbt); }catch(NbtDataException $e){ - $this->getLogger()->error("Chunk $chunkX $chunkZ: Bad entity data at list position $k: " . $e->getMessage()); - $this->getLogger()->logException($e); + $logger->error("Bad entity data at list position $k: " . $e->getMessage()); + $logger->logException($e); continue; } if($entity === null){ @@ -2461,7 +2462,7 @@ class World implements ChunkManager{ }elseif($saveIdTag instanceof IntTag){ //legacy MCPE format $saveId = "legacy(" . $saveIdTag->getValue() . ")"; } - $this->getLogger()->warning("Chunk $chunkX $chunkZ: Deleted unknown entity type $saveId"); + $logger->warning("Deleted unknown entity type $saveId"); } //TODO: we can't prevent entities getting added to unloaded chunks if they were saved in the wrong place //here, because entities currently add themselves to the world @@ -2477,16 +2478,16 @@ class World implements ChunkManager{ try{ $tile = $tileFactory->createFromData($this, $nbt); }catch(NbtDataException $e){ - $this->getLogger()->error("Chunk $chunkX $chunkZ: Bad tile entity data at list position $k: " . $e->getMessage()); - $this->getLogger()->logException($e); + $logger->error("Bad tile entity data at list position $k: " . $e->getMessage()); + $logger->logException($e); continue; } if($tile === null){ - $this->getLogger()->warning("Chunk $chunkX $chunkZ: Deleted unknown tile entity type " . $nbt->getString("id", "")); + $logger->warning("Deleted unknown tile entity type " . $nbt->getString("id", "")); }elseif(!$this->isChunkLoaded($tile->getPosition()->getFloorX() >> Chunk::COORD_BIT_SIZE, $tile->getPosition()->getFloorZ() >> Chunk::COORD_BIT_SIZE)){ - $this->logger->error("Chunk $chunkX $chunkZ: Found tile saved on wrong chunk - unable to fix due to correct chunk not loaded"); + $logger->error("Found tile saved on wrong chunk - unable to fix due to correct chunk not loaded"); }elseif($this->getTile($tilePosition = $tile->getPosition()) !== null){ - $this->logger->error("Chunk $chunkX $chunkZ: Cannot add tile at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z: Another tile is already at that position"); + $logger->error("Cannot add tile at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z: Another tile is already at that position"); }else{ $this->addTile($tile); } From fbb91d123d882315715fc2261a44cecce94f68a6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 14:03:40 +0000 Subject: [PATCH 222/710] World::unregisterChunkListenerFromAll(): go through unregisterChunkListener() this ensures that everything gets cleaned up properly (e.g. player chunk listeners). --- src/world/World.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index ab7e18ce9..484b06182 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -731,14 +731,9 @@ class World implements ChunkManager{ * Unregisters a chunk listener from all chunks it is listening on in this World. */ public function unregisterChunkListenerFromAll(ChunkListener $listener) : void{ - $id = spl_object_id($listener); foreach($this->chunkListeners as $hash => $listeners){ - if(isset($listeners[$id])){ - unset($this->chunkListeners[$hash][$id]); - if(count($this->chunkListeners[$hash]) === 0){ - unset($this->chunkListeners[$hash]); - } - } + World::getXZ($hash, $chunkX, $chunkZ); + $this->unregisterChunkListener($listener, $chunkX, $chunkZ); } } From 018006541ec2d0b130846ef17b181de8dc9b6934 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 14:12:12 +0000 Subject: [PATCH 223/710] changelog: mention block-picking changes [ci skip] --- changelogs/4.0.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index dd27e019d..12f7fff64 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1274,6 +1274,8 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` ### Inventory - Implemented offhand inventory. +- Block-picking is now supported in survival mode. +- Block picking behaviour now matches vanilla (no longer overwrites held item, jumps to existing item where possible). # 4.0.0-BETA2 Released 10th September 2021. From 4fe3f697025831dcd9f7f316147bcc53e7b300c2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 14:33:27 +0000 Subject: [PATCH 224/710] World: eliminate final remaining 'no loaders attached' debug message on player creation --- src/world/World.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 484b06182..a285af58e 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2801,6 +2801,8 @@ class World implements ChunkManager{ } } + $temporaryChunkLoader = new class implements ChunkLoader{}; + $this->registerChunkLoader($temporaryChunkLoader, $x, $z); $chunk = $this->loadChunk($x, $z); if($chunk === null || !$chunk->isPopulated()){ Timings::$population->startTiming(); @@ -2811,11 +2813,12 @@ class World implements ChunkManager{ $this->chunkPopulationRequestMap[$index] = $promise; } - $temporaryChunkLoader = new class implements ChunkLoader{}; for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ $this->lockChunk($x + $xx, $z + $zz); - $this->registerChunkLoader($temporaryChunkLoader, $x + $xx, $z + $zz); + if($xx !== 0 || $zz !== 0){ //avoid registering it twice for the center chunk; we already did that above + $this->registerChunkLoader($temporaryChunkLoader, $x + $xx, $z + $zz); + } } } @@ -2830,6 +2833,8 @@ class World implements ChunkManager{ return $promise; } + $this->unregisterChunkLoader($temporaryChunkLoader, $x, $z); + //chunk is already populated; return a pre-resolved promise that will directly fire callbacks assigned $result = new Promise(); $result->resolve($chunk); From c580bb24341e645c9dc4586239b7206ddcce880a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 14:41:31 +0000 Subject: [PATCH 225/710] InGamePacketHandler: mark player as not using item in more cases fixes #4355 --- src/network/mcpe/handler/InGamePacketHandler.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index ef49cb355..a884bf7c2 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -297,6 +297,7 @@ class InGamePacketHandler extends PacketHandler{ //all of the parts before we can execute it return true; } + $this->player->setUsingItem(false); try{ $this->inventoryManager->onTransactionStart($this->craftingTransaction); $this->craftingTransaction->execute(); @@ -332,6 +333,7 @@ class InGamePacketHandler extends PacketHandler{ return true; } + $this->player->setUsingItem(false); $transaction = new InventoryTransaction($this->player, $actions); $this->inventoryManager->onTransactionStart($transaction); try{ From 866020dfdb06434b4f361a4a0f0faf7a89c30ed2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 16:43:32 +0000 Subject: [PATCH 226/710] Player: do not re-request the same ungenerated chunks multiple times this doesn't affect chunk resends, since they'll be kicked back to NEEDED, which is detected by orderChunks(). --- src/network/mcpe/NetworkSession.php | 2 +- src/player/Player.php | 14 +++++--------- src/player/UsedChunkStatus.php | 6 ++++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index fc46f8ae5..82f1516b6 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -924,7 +924,7 @@ class NetworkSession{ $this->logger->debug("Tried to send no-longer-active chunk $chunkX $chunkZ in world " . $world->getFolderName()); return; } - if(!$status->equals(UsedChunkStatus::REQUESTED())){ + if(!$status->equals(UsedChunkStatus::REQUESTED_SENDING())){ //TODO: make this an error //this could be triggered due to the shitty way that chunk resends are handled //right now - not because of the spammy re-requesting, but because the chunk status reverts diff --git a/src/player/Player.php b/src/player/Player.php index 2f743fea3..469c025f7 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -676,7 +676,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ ++$count; - $this->usedChunks[$index] = UsedChunkStatus::NEEDED(); + $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_GENERATION(); + unset($this->loadQueue[$index]); $this->getWorld()->registerChunkLoader($this->chunkLoader, $X, $Z, true); $this->getWorld()->registerChunkListener($this, $X, $Z); @@ -685,15 +686,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if(!$this->isConnected() || !isset($this->usedChunks[$index]) || $world !== $this->getWorld()){ return; } - if(!$this->usedChunks[$index]->equals(UsedChunkStatus::NEEDED())){ - //TODO: make this an error - //we may have added multiple completion handlers, since the Player keeps re-requesting chunks - //it doesn't have yet (a relic from the old system, but also currently relied on for chunk resends). - //in this event, make sure we don't try to send the chunk multiple times. - return; + if(!$this->usedChunks[$index]->equals(UsedChunkStatus::REQUESTED_GENERATION())){ + throw new AssumptionFailedError("Used chunk status should not have changed while in REQUESTED_GENERATION mode"); } - unset($this->loadQueue[$index]); - $this->usedChunks[$index] = UsedChunkStatus::REQUESTED(); + $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_SENDING(); $this->getNetworkSession()->startUsingChunk($X, $Z, function() use ($X, $Z, $index) : void{ $this->usedChunks[$index] = UsedChunkStatus::SENT(); diff --git a/src/player/UsedChunkStatus.php b/src/player/UsedChunkStatus.php index bbdb9a061..fa8227628 100644 --- a/src/player/UsedChunkStatus.php +++ b/src/player/UsedChunkStatus.php @@ -32,7 +32,8 @@ use pocketmine\utils\EnumTrait; * @generate-registry-docblock * * @method static UsedChunkStatus NEEDED() - * @method static UsedChunkStatus REQUESTED() + * @method static UsedChunkStatus REQUESTED_GENERATION() + * @method static UsedChunkStatus REQUESTED_SENDING() * @method static UsedChunkStatus SENT() */ final class UsedChunkStatus{ @@ -41,7 +42,8 @@ final class UsedChunkStatus{ protected static function setup() : void{ self::registerAll( new self("NEEDED"), - new self("REQUESTED"), + new self("REQUESTED_GENERATION"), + new self("REQUESTED_SENDING"), new self("SENT") ); } From f1a791ef75fdbaf0d9923b84ebbfa619d963a1c2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 19:49:57 +0000 Subject: [PATCH 227/710] Improved Promise API - separate resolver and consumer APIs this makes creating a promise slightly more cumbersome, but I'm more concerned about people who might try to call 'new Promise' directly. --- src/Server.php | 15 ++++--- src/utils/Promise.php | 60 ++++---------------------- src/utils/PromiseResolver.php | 75 +++++++++++++++++++++++++++++++++ src/utils/PromiseSharedData.php | 51 ++++++++++++++++++++++ src/world/World.php | 39 ++++++++--------- 5 files changed, 163 insertions(+), 77 deletions(-) create mode 100644 src/utils/PromiseResolver.php create mode 100644 src/utils/PromiseSharedData.php diff --git a/src/Server.php b/src/Server.php index dcec8fb05..475a4385b 100644 --- a/src/Server.php +++ b/src/Server.php @@ -98,6 +98,7 @@ use pocketmine\utils\NotCloneable; use pocketmine\utils\NotSerializable; use pocketmine\utils\Process; use pocketmine\utils\Promise; +use pocketmine\utils\PromiseResolver; use pocketmine\utils\SignalHandler; use pocketmine\utils\Terminal; use pocketmine\utils\TextFormat; @@ -548,11 +549,11 @@ class Server{ $playerPos = null; $spawn = $world->getSpawnLocation(); } - $playerPromise = new Promise(); + $playerPromiseResolver = new PromiseResolver(); $world->requestChunkPopulation($spawn->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawn->getFloorZ() >> Chunk::COORD_BIT_SIZE, null)->onCompletion( - function() use ($playerPromise, $class, $session, $playerInfo, $authenticated, $world, $playerPos, $spawn, $offlinePlayerData) : void{ + function() use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $world, $playerPos, $spawn, $offlinePlayerData) : void{ if(!$session->isConnected()){ - $playerPromise->reject(); + $playerPromiseResolver->reject(); return; } @@ -572,16 +573,16 @@ class Server{ if(!$player->hasPlayedBefore()){ $player->onGround = true; //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move } - $playerPromise->resolve($player); + $playerPromiseResolver->resolve($player); }, - static function() use ($playerPromise, $session) : void{ + static function() use ($playerPromiseResolver, $session) : void{ if($session->isConnected()){ $session->disconnect("Spawn terrain generation failed"); } - $playerPromise->reject(); + $playerPromiseResolver->reject(); } ); - return $playerPromise; + return $playerPromiseResolver->getPromise(); } /** diff --git a/src/utils/Promise.php b/src/utils/Promise.php index 4ccfc4bc5..c4cf7eb2f 100644 --- a/src/utils/Promise.php +++ b/src/utils/Promise.php @@ -30,64 +30,22 @@ use function spl_object_id; */ final class Promise{ /** - * @var \Closure[] - * @phpstan-var array + * @internal Do NOT call this directly; create a new Resolver and call Resolver->promise() + * @see PromiseResolver + * @phpstan-param PromiseSharedData $shared */ - private array $onSuccess = []; - - /** - * @var \Closure[] - * @phpstan-var array - */ - private array $onFailure = []; - - private bool $resolved = false; - - /** - * @var mixed - * @phpstan-var TValue|null - */ - private $result = null; + public function __construct(private PromiseSharedData $shared){} /** * @phpstan-param \Closure(TValue) : void $onSuccess * @phpstan-param \Closure() : void $onFailure */ public function onCompletion(\Closure $onSuccess, \Closure $onFailure) : void{ - if($this->resolved){ - $this->result === null ? $onFailure() : $onSuccess($this->result); + if($this->shared->resolved){ + $this->shared->result === null ? $onFailure() : $onSuccess($this->shared->result); }else{ - $this->onSuccess[spl_object_id($onSuccess)] = $onSuccess; - $this->onFailure[spl_object_id($onFailure)] = $onFailure; + $this->shared->onSuccess[spl_object_id($onSuccess)] = $onSuccess; + $this->shared->onFailure[spl_object_id($onFailure)] = $onFailure; } } - - /** - * @param mixed $value - * @phpstan-param TValue $value - */ - public function resolve($value) : void{ - if($this->resolved){ - throw new \InvalidStateException("Promise has already been resolved/rejected"); - } - $this->resolved = true; - $this->result = $value; - foreach($this->onSuccess as $c){ - $c($value); - } - $this->onSuccess = []; - $this->onFailure = []; - } - - public function reject() : void{ - if($this->resolved){ - throw new \InvalidStateException("Promise has already been resolved/rejected"); - } - $this->resolved = true; - foreach($this->onFailure as $c){ - $c(); - } - $this->onSuccess = []; - $this->onFailure = []; - } -} +} \ No newline at end of file diff --git a/src/utils/PromiseResolver.php b/src/utils/PromiseResolver.php new file mode 100644 index 000000000..860d683b0 --- /dev/null +++ b/src/utils/PromiseResolver.php @@ -0,0 +1,75 @@ + */ + private PromiseSharedData $shared; + /** @phpstan-var Promise */ + private Promise $promise; + + public function __construct(){ + $this->shared = new PromiseSharedData(); + $this->promise = new Promise($this->shared); + } + + /** + * @param mixed $value + * @phpstan-param TValue $value + */ + public function resolve($value) : void{ + if($this->shared->resolved){ + throw new \InvalidStateException("Promise has already been resolved/rejected"); + } + $this->shared->resolved = true; + $this->shared->result = $value; + foreach($this->shared->onSuccess as $c){ + $c($value); + } + $this->shared->onSuccess = []; + $this->shared->onFailure = []; + } + + public function reject() : void{ + if($this->shared->resolved){ + throw new \InvalidStateException("Promise has already been resolved/rejected"); + } + $this->shared->resolved = true; + foreach($this->shared->onFailure as $c){ + $c(); + } + $this->shared->onSuccess = []; + $this->shared->onFailure = []; + } + + /** + * @phpstan-return Promise + */ + public function getPromise() : Promise{ + return $this->promise; + } +} \ No newline at end of file diff --git a/src/utils/PromiseSharedData.php b/src/utils/PromiseSharedData.php new file mode 100644 index 000000000..05c5ab007 --- /dev/null +++ b/src/utils/PromiseSharedData.php @@ -0,0 +1,51 @@ + + */ + public array $onSuccess = []; + + /** + * @var \Closure[] + * @phpstan-var array + */ + public array $onFailure = []; + + public bool $resolved = false; + + /** + * @var mixed + * @phpstan-var TValue|null + */ + public $result = null; +} diff --git a/src/world/World.php b/src/world/World.php index a285af58e..2d391a92a 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -72,6 +72,7 @@ use pocketmine\timings\Timings; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Limits; use pocketmine\utils\Promise; +use pocketmine\utils\PromiseResolver; use pocketmine\utils\ReversePriorityQueue; use pocketmine\world\biome\Biome; use pocketmine\world\biome\BiomeRegistry; @@ -253,8 +254,8 @@ class World implements ChunkManager{ /** @var int */ private $maxConcurrentChunkPopulationTasks = 2; /** - * @var Promise[] chunkHash => promise - * @phpstan-var array> + * @var PromiseResolver[] chunkHash => promise + * @phpstan-var array> */ private array $chunkPopulationRequestMap = []; /** @@ -2717,16 +2718,16 @@ class World implements ChunkManager{ private function enqueuePopulationRequest(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader) : Promise{ $chunkHash = World::chunkHash($chunkX, $chunkZ); $this->chunkPopulationRequestQueue->enqueue($chunkHash); - $promise = $this->chunkPopulationRequestMap[$chunkHash] = new Promise(); + $resolver = $this->chunkPopulationRequestMap[$chunkHash] = new PromiseResolver(); if($associatedChunkLoader === null){ $temporaryLoader = new class implements ChunkLoader{}; $this->registerChunkLoader($temporaryLoader, $chunkX, $chunkZ); - $promise->onCompletion( + $resolver->getPromise()->onCompletion( fn() => $this->unregisterChunkLoader($temporaryLoader, $chunkX, $chunkZ), static function() : void{} ); } - return $promise; + return $resolver->getPromise(); } private function drainPopulationRequestQueue() : void{ @@ -2763,14 +2764,14 @@ class World implements ChunkManager{ */ public function requestChunkPopulation(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader) : Promise{ $chunkHash = World::chunkHash($chunkX, $chunkZ); - $promise = $this->chunkPopulationRequestMap[$chunkHash] ?? null; - if($promise !== null && isset($this->activeChunkPopulationTasks[$chunkHash])){ + $resolver = $this->chunkPopulationRequestMap[$chunkHash] ?? null; + if($resolver !== null && isset($this->activeChunkPopulationTasks[$chunkHash])){ //generation is already running - return $promise; + return $resolver->getPromise(); } if(count($this->activeChunkPopulationTasks) >= $this->maxConcurrentChunkPopulationTasks){ //too many chunks are already generating; delay resolution of the request until later - return $promise ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); + return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); } return $this->orderChunkPopulation($chunkX, $chunkZ, $associatedChunkLoader); } @@ -2787,16 +2788,16 @@ class World implements ChunkManager{ */ public function orderChunkPopulation(int $x, int $z, ?ChunkLoader $associatedChunkLoader) : Promise{ $index = World::chunkHash($x, $z); - $promise = $this->chunkPopulationRequestMap[$index] ?? null; - if($promise !== null && isset($this->activeChunkPopulationTasks[$index])){ + $resolver = $this->chunkPopulationRequestMap[$index] ?? null; + if($resolver !== null && isset($this->activeChunkPopulationTasks[$index])){ //generation is already running - return $promise; + return $resolver->getPromise(); } for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ if($this->isChunkLocked($x + $xx, $z + $zz)){ //chunk is already in use by another generation request; queue the request for later - return $promise ?? $this->enqueuePopulationRequest($x, $z, $associatedChunkLoader); + return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($x, $z, $associatedChunkLoader); } } } @@ -2808,9 +2809,9 @@ class World implements ChunkManager{ Timings::$population->startTiming(); $this->activeChunkPopulationTasks[$index] = true; - if($promise === null){ - $promise = new Promise(); - $this->chunkPopulationRequestMap[$index] = $promise; + if($resolver === null){ + $resolver = new PromiseResolver(); + $this->chunkPopulationRequestMap[$index] = $resolver; } for($xx = -1; $xx <= 1; ++$xx){ @@ -2830,15 +2831,15 @@ class World implements ChunkManager{ $this->workerPool->submitTaskToWorker($task, $workerId); Timings::$population->stopTiming(); - return $promise; + return $resolver->getPromise(); } $this->unregisterChunkLoader($temporaryChunkLoader, $x, $z); //chunk is already populated; return a pre-resolved promise that will directly fire callbacks assigned - $result = new Promise(); + $result = new PromiseResolver(); $result->resolve($chunk); - return $result; + return $result->getPromise(); } /** From 0f78a2b5efac27fb7e16832c11c8d80f15b252a2 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Sun, 31 Oct 2021 21:11:20 +0000 Subject: [PATCH 228/710] Advisory chunk locking for chunk population (#4513) this allows chunks locked for population to be modified. If the PopulationTask detects that the chunk was modified during the onCompletion(), the result of the population will be discarded and rescheduled, so that it includes user modifications. --- src/world/ChunkLockId.php | 38 ++++++++ src/world/World.php | 117 ++++++++++++++++++------- src/world/generator/PopulationTask.php | 9 +- 3 files changed, 129 insertions(+), 35 deletions(-) create mode 100644 src/world/ChunkLockId.php diff --git a/src/world/ChunkLockId.php b/src/world/ChunkLockId.php new file mode 100644 index 000000000..312b8c910 --- /dev/null +++ b/src/world/ChunkLockId.php @@ -0,0 +1,38 @@ +> Chunk::COORD_BIT_SIZE; $chunkZ = $z >> Chunk::COORD_BIT_SIZE; - if($this->isChunkLocked($chunkX, $chunkZ)){ - throw new WorldException("Terrain is locked for generation/population"); - } if($this->loadChunk($chunkX, $chunkZ) === null){ //current expected behaviour is to try to load the terrain synchronously throw new WorldException("Cannot set a block in un-generated terrain"); } $this->timings->setBlock->startTiming(); + $this->unlockChunk($chunkX, $chunkZ, null); + $oldBlock = $this->getBlockAt($x, $y, $z, true, false); $block = clone $block; @@ -2046,10 +2045,7 @@ class World implements ChunkManager{ public function setBiomeId(int $x, int $z, int $biomeId) : void{ $chunkX = $x >> Chunk::COORD_BIT_SIZE; $chunkZ = $z >> Chunk::COORD_BIT_SIZE; - if($this->isChunkLocked($chunkX, $chunkZ)){ - //the changes would be overwritten when the generation finishes - throw new WorldException("Chunk is currently locked for async generation/population"); - } + $this->unlockChunk($chunkX, $chunkZ, null); if(($chunk = $this->loadChunk($chunkX, $chunkZ)) !== null){ $chunk->setBiomeId($x & Chunk::COORD_MASK, $z & Chunk::COORD_MASK, $biomeId); }else{ @@ -2103,18 +2099,50 @@ class World implements ChunkManager{ return $result; } - public function lockChunk(int $chunkX, int $chunkZ) : void{ + /** + * Flags a chunk as locked, usually for async modification. + * + * This is an **advisory lock**. This means that the lock does **not** prevent the chunk from being modified on the + * main thread, such as by setBlock() or setBiomeId(). However, you can use it to detect when such modifications + * have taken place - unlockChunk() with the same lockID will fail and return false if this happens. + * + * This is used internally by the generation system to ensure that two PopulationTasks don't try to modify the same + * chunk at the same time. Generation will respect these locks and won't try to do generation of chunks over which + * a lock is held. + * + * WARNING: Be sure to release all locks once you're done with them, or you WILL have problems with terrain not + * being generated. + */ + public function lockChunk(int $chunkX, int $chunkZ, ChunkLockId $lockId) : void{ $chunkHash = World::chunkHash($chunkX, $chunkZ); if(isset($this->chunkLock[$chunkHash])){ throw new \InvalidArgumentException("Chunk $chunkX $chunkZ is already locked"); } - $this->chunkLock[$chunkHash] = true; + $this->chunkLock[$chunkHash] = $lockId; } - public function unlockChunk(int $chunkX, int $chunkZ) : void{ - unset($this->chunkLock[World::chunkHash($chunkX, $chunkZ)]); + /** + * Unlocks a chunk previously locked by lockChunk(). + * + * You must provide the same lockID as provided to lockChunk(). + * If a null lockID is given, any existing lock will be removed from the chunk, regardless of who owns it. + * + * Returns true if unlocking was successful, false otherwise. + */ + public function unlockChunk(int $chunkX, int $chunkZ, ?ChunkLockId $lockId) : bool{ + $chunkHash = World::chunkHash($chunkX, $chunkZ); + if(isset($this->chunkLock[$chunkHash]) && ($lockId === null || $this->chunkLock[$chunkHash] === $lockId)){ + unset($this->chunkLock[$chunkHash]); + return true; + } + return false; } + /** + * Returns whether anyone currently has a lock on the chunk at the given coordinates. + * You should check this to make sure that population tasks aren't currently modifying chunks that you want to use + * in async tasks. + */ public function isChunkLocked(int $chunkX, int $chunkZ) : bool{ return isset($this->chunkLock[World::chunkHash($chunkX, $chunkZ)]); } @@ -2814,16 +2842,18 @@ class World implements ChunkManager{ $this->chunkPopulationRequestMap[$index] = $resolver; } + $chunkPopulationLockId = new ChunkLockId(); + for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ - $this->lockChunk($x + $xx, $z + $zz); + $this->lockChunk($x + $xx, $z + $zz, $chunkPopulationLockId); if($xx !== 0 || $zz !== 0){ //avoid registering it twice for the center chunk; we already did that above $this->registerChunkLoader($temporaryChunkLoader, $x + $xx, $z + $zz); } } } - $task = new PopulationTask($this, $x, $z, $chunk, $temporaryChunkLoader); + $task = new PopulationTask($this, $x, $z, $chunk, $temporaryChunkLoader, $chunkPopulationLockId); $workerId = $this->workerPool->selectWorker(); if(!isset($this->generatorRegisteredWorkers[$workerId])){ $this->registerGeneratorToWorker($workerId); @@ -2843,10 +2873,10 @@ class World implements ChunkManager{ } /** - * @param Chunk[] $adjacentChunks + * @param Chunk[] $adjacentChunks chunkHash => chunk * @phpstan-param array $adjacentChunks */ - public function generateChunkCallback(int $x, int $z, Chunk $chunk, array $adjacentChunks, ChunkLoader $temporaryChunkLoader) : void{ + public function generateChunkCallback(ChunkLockId $chunkLockId, int $x, int $z, Chunk $chunk, array $adjacentChunks, ChunkLoader $temporaryChunkLoader) : void{ Timings::$generationCallback->startTiming(); for($xx = -1; $xx <= 1; ++$xx){ @@ -2856,31 +2886,52 @@ class World implements ChunkManager{ } if(isset($this->chunkPopulationRequestMap[$index = World::chunkHash($x, $z)]) && isset($this->activeChunkPopulationTasks[$index])){ + $dirtyChunks = 0; for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ - $this->unlockChunk($x + $xx, $z + $zz); + if(!$this->unlockChunk($x + $xx, $z + $zz, $chunkLockId)){ + $dirtyChunks++; + } } } + if($dirtyChunks === 0){ + $oldChunk = $this->loadChunk($x, $z); + $this->setChunk($x, $z, $chunk); - $oldChunk = $this->loadChunk($x, $z); - $this->setChunk($x, $z, $chunk); - - foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){ - World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk); - $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk); - } - - if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ - (new ChunkPopulateEvent($this, $x, $z, $chunk))->call(); - - foreach($this->getChunkListeners($x, $z) as $listener){ - $listener->onChunkPopulated($x, $z, $chunk); + foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){ + World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk); + $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk); } + + if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ + (new ChunkPopulateEvent($this, $x, $z, $chunk))->call(); + + foreach($this->getChunkListeners($x, $z) as $listener){ + $listener->onChunkPopulated($x, $z, $chunk); + } + } + }else{ + $this->logger->debug("Discarding population result for chunk x=$x,z=$z - terrain was modified on the main thread before async population completed"); } + + //This needs to be in this specific spot because user code might call back to orderChunkPopulation(). + //If it does, and finds the promise, and doesn't find an active task associated with it, it will schedule + //another PopulationTask. We don't want that because we're here processing the results. + //We can't remove the promise from the array before setting the chunks in the world because that would lead + //to the same problem. Therefore, it's necessary that this code be split into two if/else, with this in the + //middle. unset($this->activeChunkPopulationTasks[$index]); - $promise = $this->chunkPopulationRequestMap[$index]; - unset($this->chunkPopulationRequestMap[$index]); - $promise->resolve($chunk); + + if($dirtyChunks === 0){ + $promise = $this->chunkPopulationRequestMap[$index]; + unset($this->chunkPopulationRequestMap[$index]); + $promise->resolve($chunk); + }else{ + //request failed, stick it back on the queue + //we didn't resolve the promise or touch it in any way, so any fake chunk loaders are still valid and + //don't need to be added a second time. + $this->chunkPopulationRequestQueue->enqueue($index); + } $this->drainPopulationRequestQueue(); } diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 19c0038fa..5a628248d 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -27,6 +27,7 @@ use pocketmine\data\bedrock\BiomeIds; use pocketmine\scheduler\AsyncTask; use pocketmine\utils\AssumptionFailedError; use pocketmine\world\ChunkLoader; +use pocketmine\world\ChunkLockId; use pocketmine\world\format\BiomeArray; use pocketmine\world\format\Chunk; use pocketmine\world\format\io\FastChunkSerializer; @@ -40,6 +41,7 @@ use function intdiv; class PopulationTask extends AsyncTask{ private const TLS_KEY_WORLD = "world"; private const TLS_KEY_CHUNK_LOADER = "chunkLoader"; + private const TLS_KEY_LOCK_ID = "chunkLockId"; /** @var int */ public $worldId; @@ -53,7 +55,7 @@ class PopulationTask extends AsyncTask{ private string $adjacentChunks; - public function __construct(World $world, int $chunkX, int $chunkZ, ?Chunk $chunk, ChunkLoader $temporaryChunkLoader){ + public function __construct(World $world, int $chunkX, int $chunkZ, ?Chunk $chunk, ChunkLoader $temporaryChunkLoader, ChunkLockId $chunkLockId){ $this->worldId = $world->getId(); $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; @@ -66,6 +68,7 @@ class PopulationTask extends AsyncTask{ $this->storeLocal(self::TLS_KEY_WORLD, $world); $this->storeLocal(self::TLS_KEY_CHUNK_LOADER, $temporaryChunkLoader); + $this->storeLocal(self::TLS_KEY_LOCK_ID, $chunkLockId); } public function onRun() : void{ @@ -131,6 +134,8 @@ class PopulationTask extends AsyncTask{ $world = $this->fetchLocal(self::TLS_KEY_WORLD); /** @var ChunkLoader $temporaryChunkLoader */ $temporaryChunkLoader = $this->fetchLocal(self::TLS_KEY_CHUNK_LOADER); + /** @var ChunkLockId $lockId */ + $lockId = $this->fetchLocal(self::TLS_KEY_LOCK_ID); if($world->isLoaded()){ $chunk = $this->chunk !== null ? FastChunkSerializer::deserializeTerrain($this->chunk) : @@ -151,7 +156,7 @@ class PopulationTask extends AsyncTask{ } } - $world->generateChunkCallback($this->chunkX, $this->chunkZ, $chunk, $adjacentChunks, $temporaryChunkLoader); + $world->generateChunkCallback($lockId, $this->chunkX, $this->chunkZ, $chunk, $adjacentChunks, $temporaryChunkLoader); } } } From 3265d3f6b4d6705276b56fab5f765e2f97b5d992 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 21:23:36 +0000 Subject: [PATCH 229/710] Revert "Player: do not re-request the same ungenerated chunks multiple times" This reverts commit 866020dfdb06434b4f361a4a0f0faf7a89c30ed2. For some fucking reason this broke resending chunks in some cases (and sending chunks at all in others). I don't have time to debug this right now, so it's going to have to remain broken, infuriatingly enough. --- src/network/mcpe/NetworkSession.php | 2 +- src/player/Player.php | 14 +++++++++----- src/player/UsedChunkStatus.php | 6 ++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 82f1516b6..fc46f8ae5 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -924,7 +924,7 @@ class NetworkSession{ $this->logger->debug("Tried to send no-longer-active chunk $chunkX $chunkZ in world " . $world->getFolderName()); return; } - if(!$status->equals(UsedChunkStatus::REQUESTED_SENDING())){ + if(!$status->equals(UsedChunkStatus::REQUESTED())){ //TODO: make this an error //this could be triggered due to the shitty way that chunk resends are handled //right now - not because of the spammy re-requesting, but because the chunk status reverts diff --git a/src/player/Player.php b/src/player/Player.php index 469c025f7..2f743fea3 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -676,8 +676,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ ++$count; - $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_GENERATION(); - unset($this->loadQueue[$index]); + $this->usedChunks[$index] = UsedChunkStatus::NEEDED(); $this->getWorld()->registerChunkLoader($this->chunkLoader, $X, $Z, true); $this->getWorld()->registerChunkListener($this, $X, $Z); @@ -686,10 +685,15 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if(!$this->isConnected() || !isset($this->usedChunks[$index]) || $world !== $this->getWorld()){ return; } - if(!$this->usedChunks[$index]->equals(UsedChunkStatus::REQUESTED_GENERATION())){ - throw new AssumptionFailedError("Used chunk status should not have changed while in REQUESTED_GENERATION mode"); + if(!$this->usedChunks[$index]->equals(UsedChunkStatus::NEEDED())){ + //TODO: make this an error + //we may have added multiple completion handlers, since the Player keeps re-requesting chunks + //it doesn't have yet (a relic from the old system, but also currently relied on for chunk resends). + //in this event, make sure we don't try to send the chunk multiple times. + return; } - $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_SENDING(); + unset($this->loadQueue[$index]); + $this->usedChunks[$index] = UsedChunkStatus::REQUESTED(); $this->getNetworkSession()->startUsingChunk($X, $Z, function() use ($X, $Z, $index) : void{ $this->usedChunks[$index] = UsedChunkStatus::SENT(); diff --git a/src/player/UsedChunkStatus.php b/src/player/UsedChunkStatus.php index fa8227628..bbdb9a061 100644 --- a/src/player/UsedChunkStatus.php +++ b/src/player/UsedChunkStatus.php @@ -32,8 +32,7 @@ use pocketmine\utils\EnumTrait; * @generate-registry-docblock * * @method static UsedChunkStatus NEEDED() - * @method static UsedChunkStatus REQUESTED_GENERATION() - * @method static UsedChunkStatus REQUESTED_SENDING() + * @method static UsedChunkStatus REQUESTED() * @method static UsedChunkStatus SENT() */ final class UsedChunkStatus{ @@ -42,8 +41,7 @@ final class UsedChunkStatus{ protected static function setup() : void{ self::registerAll( new self("NEEDED"), - new self("REQUESTED_GENERATION"), - new self("REQUESTED_SENDING"), + new self("REQUESTED"), new self("SENT") ); } From 08636d079dd4c390a36b89f433fa7e823d945975 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 22:48:52 +0000 Subject: [PATCH 230/710] Promise: expose isResolved() --- src/utils/Promise.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/Promise.php b/src/utils/Promise.php index c4cf7eb2f..d9ae9c563 100644 --- a/src/utils/Promise.php +++ b/src/utils/Promise.php @@ -48,4 +48,8 @@ final class Promise{ $this->shared->onFailure[spl_object_id($onFailure)] = $onFailure; } } + + public function isResolved() : bool{ + return $this->shared->resolved; + } } \ No newline at end of file From 2fa0a914ff6dce7a051e176374c3441098b5e255 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 22:51:37 +0000 Subject: [PATCH 231/710] World::orderChunkPopulation() may return a pre-resolved promise this does not indicate a failure; it indicates that the chunk has already been successfully populated. In this case, we shouldn't be putting the task back on the queue. This is skirting around the real bug, which is that requestChunkPopulation() doesn't check if the target chunk is already populated before it creates a new promise that it will be. --- src/world/World.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 2267d4c08..7c17cc88b 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2765,8 +2765,10 @@ class World implements ChunkManager{ World::getXZ($nextChunkHash, $nextChunkX, $nextChunkZ); if(isset($this->chunkPopulationRequestMap[$nextChunkHash])){ assert(!isset($this->activeChunkPopulationTasks[$nextChunkHash]), "Population for chunk $nextChunkX $nextChunkZ already running"); - $this->orderChunkPopulation($nextChunkX, $nextChunkZ, null); - if(!isset($this->activeChunkPopulationTasks[$nextChunkHash])){ + if( + !$this->orderChunkPopulation($nextChunkX, $nextChunkZ, null)->isResolved() && + !isset($this->activeChunkPopulationTasks[$nextChunkHash]) + ){ $failed[] = $nextChunkHash; } } From 96cfdc79b85bbcf63d87811966c625d200d5014d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 22:54:37 +0000 Subject: [PATCH 232/710] World: fixed original promise not getting fulfilled if the chunk became populated=true after a promise was already made (but not fulfilled) to populate it this could happen if a plugin calls setPopulated(true) on a chunk after a request for its population landed in the queue, but before it actually got processed. In that case, the promise would never get fulfilled. --- src/world/World.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 7c17cc88b..47b4fd712 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2869,9 +2869,9 @@ class World implements ChunkManager{ $this->unregisterChunkLoader($temporaryChunkLoader, $x, $z); //chunk is already populated; return a pre-resolved promise that will directly fire callbacks assigned - $result = new PromiseResolver(); - $result->resolve($chunk); - return $result->getPromise(); + $resolver ??= new PromiseResolver(); + $resolver->resolve($chunk); + return $resolver->getPromise(); } /** From bd60e41268c52aba16513cfc86e5dd41cfc4bea9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 22:57:56 +0000 Subject: [PATCH 233/710] Revert "Revert "Player: do not re-request the same ungenerated chunks multiple times"" This reverts commit 3265d3f6b4d6705276b56fab5f765e2f97b5d992. --- src/network/mcpe/NetworkSession.php | 2 +- src/player/Player.php | 14 +++++--------- src/player/UsedChunkStatus.php | 6 ++++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index fc46f8ae5..82f1516b6 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -924,7 +924,7 @@ class NetworkSession{ $this->logger->debug("Tried to send no-longer-active chunk $chunkX $chunkZ in world " . $world->getFolderName()); return; } - if(!$status->equals(UsedChunkStatus::REQUESTED())){ + if(!$status->equals(UsedChunkStatus::REQUESTED_SENDING())){ //TODO: make this an error //this could be triggered due to the shitty way that chunk resends are handled //right now - not because of the spammy re-requesting, but because the chunk status reverts diff --git a/src/player/Player.php b/src/player/Player.php index 2f743fea3..469c025f7 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -676,7 +676,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ ++$count; - $this->usedChunks[$index] = UsedChunkStatus::NEEDED(); + $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_GENERATION(); + unset($this->loadQueue[$index]); $this->getWorld()->registerChunkLoader($this->chunkLoader, $X, $Z, true); $this->getWorld()->registerChunkListener($this, $X, $Z); @@ -685,15 +686,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if(!$this->isConnected() || !isset($this->usedChunks[$index]) || $world !== $this->getWorld()){ return; } - if(!$this->usedChunks[$index]->equals(UsedChunkStatus::NEEDED())){ - //TODO: make this an error - //we may have added multiple completion handlers, since the Player keeps re-requesting chunks - //it doesn't have yet (a relic from the old system, but also currently relied on for chunk resends). - //in this event, make sure we don't try to send the chunk multiple times. - return; + if(!$this->usedChunks[$index]->equals(UsedChunkStatus::REQUESTED_GENERATION())){ + throw new AssumptionFailedError("Used chunk status should not have changed while in REQUESTED_GENERATION mode"); } - unset($this->loadQueue[$index]); - $this->usedChunks[$index] = UsedChunkStatus::REQUESTED(); + $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_SENDING(); $this->getNetworkSession()->startUsingChunk($X, $Z, function() use ($X, $Z, $index) : void{ $this->usedChunks[$index] = UsedChunkStatus::SENT(); diff --git a/src/player/UsedChunkStatus.php b/src/player/UsedChunkStatus.php index bbdb9a061..fa8227628 100644 --- a/src/player/UsedChunkStatus.php +++ b/src/player/UsedChunkStatus.php @@ -32,7 +32,8 @@ use pocketmine\utils\EnumTrait; * @generate-registry-docblock * * @method static UsedChunkStatus NEEDED() - * @method static UsedChunkStatus REQUESTED() + * @method static UsedChunkStatus REQUESTED_GENERATION() + * @method static UsedChunkStatus REQUESTED_SENDING() * @method static UsedChunkStatus SENT() */ final class UsedChunkStatus{ @@ -41,7 +42,8 @@ final class UsedChunkStatus{ protected static function setup() : void{ self::registerAll( new self("NEEDED"), - new self("REQUESTED"), + new self("REQUESTED_GENERATION"), + new self("REQUESTED_SENDING"), new self("SENT") ); } From 74031d2fbea2256262aa81a45ce5f6f5f45ff54d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 23:05:12 +0000 Subject: [PATCH 234/710] World: remove the fulfilled promise from the population request map fixes crash when unregistering chunk loaders --- src/world/World.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/world/World.php b/src/world/World.php index 47b4fd712..2cd4fab2c 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2870,6 +2870,7 @@ class World implements ChunkManager{ //chunk is already populated; return a pre-resolved promise that will directly fire callbacks assigned $resolver ??= new PromiseResolver(); + unset($this->chunkPopulationRequestMap[$index]); $resolver->resolve($chunk); return $resolver->getPromise(); } From 9dec82cdbc168a900fd860d9b5739bb9cf1df88c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 23:40:34 +0000 Subject: [PATCH 235/710] World: fixed requestChunkPopulation() queuing requests for chunks which are already populated this led to chunk sending getting bogged down if there were more than population-queue-size chunks waiting to be generated. --- src/world/World.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/world/World.php b/src/world/World.php index 2cd4fab2c..f58b3ca29 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2799,6 +2799,19 @@ class World implements ChunkManager{ //generation is already running return $resolver->getPromise(); } + + $temporaryChunkLoader = new class implements ChunkLoader{}; + $this->registerChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); + $chunk = $this->loadChunk($chunkX, $chunkZ); + $this->unregisterChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); + if($chunk !== null && $chunk->isPopulated()){ + //chunk is already populated; return a pre-resolved promise that will directly fire callbacks assigned + $resolver ??= new PromiseResolver(); + unset($this->chunkPopulationRequestMap[$chunkHash]); + $resolver->resolve($chunk); + return $resolver->getPromise(); + } + if(count($this->activeChunkPopulationTasks) >= $this->maxConcurrentChunkPopulationTasks){ //too many chunks are already generating; delay resolution of the request until later return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); From f4a3c40b5c3ab39a1432e5c358e27c6aa8884e58 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 23:48:00 +0000 Subject: [PATCH 236/710] World: use better variable names in orderChunkPopulation() --- src/world/World.php | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index f58b3ca29..3fa24f12e 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2829,46 +2829,46 @@ class World implements ChunkManager{ * * @phpstan-return Promise */ - public function orderChunkPopulation(int $x, int $z, ?ChunkLoader $associatedChunkLoader) : Promise{ - $index = World::chunkHash($x, $z); - $resolver = $this->chunkPopulationRequestMap[$index] ?? null; - if($resolver !== null && isset($this->activeChunkPopulationTasks[$index])){ + public function orderChunkPopulation(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader) : Promise{ + $chunkHash = World::chunkHash($chunkX, $chunkZ); + $resolver = $this->chunkPopulationRequestMap[$chunkHash] ?? null; + if($resolver !== null && isset($this->activeChunkPopulationTasks[$chunkHash])){ //generation is already running return $resolver->getPromise(); } for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ - if($this->isChunkLocked($x + $xx, $z + $zz)){ + if($this->isChunkLocked($chunkX + $xx, $chunkZ + $zz)){ //chunk is already in use by another generation request; queue the request for later - return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($x, $z, $associatedChunkLoader); + return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); } } } $temporaryChunkLoader = new class implements ChunkLoader{}; - $this->registerChunkLoader($temporaryChunkLoader, $x, $z); - $chunk = $this->loadChunk($x, $z); + $this->registerChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); + $chunk = $this->loadChunk($chunkX, $chunkZ); if($chunk === null || !$chunk->isPopulated()){ Timings::$population->startTiming(); - $this->activeChunkPopulationTasks[$index] = true; + $this->activeChunkPopulationTasks[$chunkHash] = true; if($resolver === null){ $resolver = new PromiseResolver(); - $this->chunkPopulationRequestMap[$index] = $resolver; + $this->chunkPopulationRequestMap[$chunkHash] = $resolver; } $chunkPopulationLockId = new ChunkLockId(); for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ - $this->lockChunk($x + $xx, $z + $zz, $chunkPopulationLockId); + $this->lockChunk($chunkX + $xx, $chunkZ + $zz, $chunkPopulationLockId); if($xx !== 0 || $zz !== 0){ //avoid registering it twice for the center chunk; we already did that above - $this->registerChunkLoader($temporaryChunkLoader, $x + $xx, $z + $zz); + $this->registerChunkLoader($temporaryChunkLoader, $chunkX + $xx, $chunkZ + $zz); } } } - $task = new PopulationTask($this, $x, $z, $chunk, $temporaryChunkLoader, $chunkPopulationLockId); + $task = new PopulationTask($this, $chunkX, $chunkZ, $chunk, $temporaryChunkLoader, $chunkPopulationLockId); $workerId = $this->workerPool->selectWorker(); if(!isset($this->generatorRegisteredWorkers[$workerId])){ $this->registerGeneratorToWorker($workerId); @@ -2879,11 +2879,11 @@ class World implements ChunkManager{ return $resolver->getPromise(); } - $this->unregisterChunkLoader($temporaryChunkLoader, $x, $z); + $this->unregisterChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); //chunk is already populated; return a pre-resolved promise that will directly fire callbacks assigned $resolver ??= new PromiseResolver(); - unset($this->chunkPopulationRequestMap[$index]); + unset($this->chunkPopulationRequestMap[$chunkHash]); $resolver->resolve($chunk); return $resolver->getPromise(); } From 8f803df5114182bac73621694a32ae38bb95c48e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 31 Oct 2021 23:54:27 +0000 Subject: [PATCH 237/710] World: check population locks _after_ checking if the chunk is already populated, not before this led to another case where a population request would be queued up for an already-populated chunk for no reason. --- src/world/World.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 3fa24f12e..375869da1 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2836,14 +2836,6 @@ class World implements ChunkManager{ //generation is already running return $resolver->getPromise(); } - for($xx = -1; $xx <= 1; ++$xx){ - for($zz = -1; $zz <= 1; ++$zz){ - if($this->isChunkLocked($chunkX + $xx, $chunkZ + $zz)){ - //chunk is already in use by another generation request; queue the request for later - return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); - } - } - } $temporaryChunkLoader = new class implements ChunkLoader{}; $this->registerChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); @@ -2851,6 +2843,15 @@ class World implements ChunkManager{ if($chunk === null || !$chunk->isPopulated()){ Timings::$population->startTiming(); + for($xx = -1; $xx <= 1; ++$xx){ + for($zz = -1; $zz <= 1; ++$zz){ + if($this->isChunkLocked($chunkX + $xx, $chunkZ + $zz)){ + //chunk is already in use by another generation request; queue the request for later + return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); + } + } + } + $this->activeChunkPopulationTasks[$chunkHash] = true; if($resolver === null){ $resolver = new PromiseResolver(); From afb54f1ae4380c2a65ad423de599dd9ea73939c7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 00:25:30 +0000 Subject: [PATCH 238/710] World: flip orderChunkPopulation() condition around this makes it more obvious that the code is similar to requestChunkPopulation() barring one distinct difference. --- src/world/World.php | 82 ++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 375869da1..b1726e144 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2840,52 +2840,52 @@ class World implements ChunkManager{ $temporaryChunkLoader = new class implements ChunkLoader{}; $this->registerChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); $chunk = $this->loadChunk($chunkX, $chunkZ); - if($chunk === null || !$chunk->isPopulated()){ - Timings::$population->startTiming(); + if($chunk !== null && $chunk->isPopulated()){ + $this->unregisterChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); - for($xx = -1; $xx <= 1; ++$xx){ - for($zz = -1; $zz <= 1; ++$zz){ - if($this->isChunkLocked($chunkX + $xx, $chunkZ + $zz)){ - //chunk is already in use by another generation request; queue the request for later - return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); - } - } - } - - $this->activeChunkPopulationTasks[$chunkHash] = true; - if($resolver === null){ - $resolver = new PromiseResolver(); - $this->chunkPopulationRequestMap[$chunkHash] = $resolver; - } - - $chunkPopulationLockId = new ChunkLockId(); - - for($xx = -1; $xx <= 1; ++$xx){ - for($zz = -1; $zz <= 1; ++$zz){ - $this->lockChunk($chunkX + $xx, $chunkZ + $zz, $chunkPopulationLockId); - if($xx !== 0 || $zz !== 0){ //avoid registering it twice for the center chunk; we already did that above - $this->registerChunkLoader($temporaryChunkLoader, $chunkX + $xx, $chunkZ + $zz); - } - } - } - - $task = new PopulationTask($this, $chunkX, $chunkZ, $chunk, $temporaryChunkLoader, $chunkPopulationLockId); - $workerId = $this->workerPool->selectWorker(); - if(!isset($this->generatorRegisteredWorkers[$workerId])){ - $this->registerGeneratorToWorker($workerId); - } - $this->workerPool->submitTaskToWorker($task, $workerId); - - Timings::$population->stopTiming(); + //chunk is already populated; return a pre-resolved promise that will directly fire callbacks assigned + $resolver ??= new PromiseResolver(); + unset($this->chunkPopulationRequestMap[$chunkHash]); + $resolver->resolve($chunk); return $resolver->getPromise(); } - $this->unregisterChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); + Timings::$population->startTiming(); - //chunk is already populated; return a pre-resolved promise that will directly fire callbacks assigned - $resolver ??= new PromiseResolver(); - unset($this->chunkPopulationRequestMap[$chunkHash]); - $resolver->resolve($chunk); + for($xx = -1; $xx <= 1; ++$xx){ + for($zz = -1; $zz <= 1; ++$zz){ + if($this->isChunkLocked($chunkX + $xx, $chunkZ + $zz)){ + //chunk is already in use by another generation request; queue the request for later + return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); + } + } + } + + $this->activeChunkPopulationTasks[$chunkHash] = true; + if($resolver === null){ + $resolver = new PromiseResolver(); + $this->chunkPopulationRequestMap[$chunkHash] = $resolver; + } + + $chunkPopulationLockId = new ChunkLockId(); + + for($xx = -1; $xx <= 1; ++$xx){ + for($zz = -1; $zz <= 1; ++$zz){ + $this->lockChunk($chunkX + $xx, $chunkZ + $zz, $chunkPopulationLockId); + if($xx !== 0 || $zz !== 0){ //avoid registering it twice for the center chunk; we already did that above + $this->registerChunkLoader($temporaryChunkLoader, $chunkX + $xx, $chunkZ + $zz); + } + } + } + + $task = new PopulationTask($this, $chunkX, $chunkZ, $chunk, $temporaryChunkLoader, $chunkPopulationLockId); + $workerId = $this->workerPool->selectWorker(); + if(!isset($this->generatorRegisteredWorkers[$workerId])){ + $this->registerGeneratorToWorker($workerId); + } + $this->workerPool->submitTaskToWorker($task, $workerId); + + Timings::$population->stopTiming(); return $resolver->getPromise(); } From e4a54f5b6ab96866c478bb7aedbe23124b7abc99 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 00:33:18 +0000 Subject: [PATCH 239/710] World: deduplicate code in request/orderChunkPopulation --- src/world/World.php | 67 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index b1726e144..74cf52821 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2782,22 +2782,16 @@ class World implements ChunkManager{ } /** - * Attempts to initiate asynchronous generation/population of the target chunk, if it's currently reasonable to do - * so (and if it isn't already generated/populated). - * If the generator is busy, the request will be put into a queue and delayed until a better time. - * - * A ChunkLoader can be associated with the generation request to ensure that the generation request is cancelled if - * no loaders are attached to the target chunk. If no loader is provided, one will be assigned (and automatically - * removed when the generation request completes). - * - * @phpstan-return Promise + * Checks if a chunk needs to be populated, and whether it's ready to do so. + * @return bool[]|PromiseResolver[]|null[] + * @phpstan-return array{?PromiseResolver, bool} */ - public function requestChunkPopulation(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader) : Promise{ + private function checkChunkPopulationPreconditions(int $chunkX, int $chunkZ) : array{ $chunkHash = World::chunkHash($chunkX, $chunkZ); $resolver = $this->chunkPopulationRequestMap[$chunkHash] ?? null; if($resolver !== null && isset($this->activeChunkPopulationTasks[$chunkHash])){ //generation is already running - return $resolver->getPromise(); + return [$resolver, false]; } $temporaryChunkLoader = new class implements ChunkLoader{}; @@ -2809,7 +2803,26 @@ class World implements ChunkManager{ $resolver ??= new PromiseResolver(); unset($this->chunkPopulationRequestMap[$chunkHash]); $resolver->resolve($chunk); - return $resolver->getPromise(); + return [$resolver, false]; + } + return [$resolver, true]; + } + + /** + * Attempts to initiate asynchronous generation/population of the target chunk, if it's currently reasonable to do + * so (and if it isn't already generated/populated). + * If the generator is busy, the request will be put into a queue and delayed until a better time. + * + * A ChunkLoader can be associated with the generation request to ensure that the generation request is cancelled if + * no loaders are attached to the target chunk. If no loader is provided, one will be assigned (and automatically + * removed when the generation request completes). + * + * @phpstan-return Promise + */ + public function requestChunkPopulation(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader) : Promise{ + [$resolver, $proceedWithPopulation] = $this->checkChunkPopulationPreconditions($chunkX, $chunkZ); + if(!$proceedWithPopulation){ + return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); } if(count($this->activeChunkPopulationTasks) >= $this->maxConcurrentChunkPopulationTasks){ @@ -2830,25 +2843,12 @@ class World implements ChunkManager{ * @phpstan-return Promise */ public function orderChunkPopulation(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader) : Promise{ + [$resolver, $proceedWithPopulation] = $this->checkChunkPopulationPreconditions($chunkX, $chunkZ); + if(!$proceedWithPopulation){ + return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); + } + $chunkHash = World::chunkHash($chunkX, $chunkZ); - $resolver = $this->chunkPopulationRequestMap[$chunkHash] ?? null; - if($resolver !== null && isset($this->activeChunkPopulationTasks[$chunkHash])){ - //generation is already running - return $resolver->getPromise(); - } - - $temporaryChunkLoader = new class implements ChunkLoader{}; - $this->registerChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); - $chunk = $this->loadChunk($chunkX, $chunkZ); - if($chunk !== null && $chunk->isPopulated()){ - $this->unregisterChunkLoader($temporaryChunkLoader, $chunkX, $chunkZ); - - //chunk is already populated; return a pre-resolved promise that will directly fire callbacks assigned - $resolver ??= new PromiseResolver(); - unset($this->chunkPopulationRequestMap[$chunkHash]); - $resolver->resolve($chunk); - return $resolver->getPromise(); - } Timings::$population->startTiming(); @@ -2869,16 +2869,15 @@ class World implements ChunkManager{ $chunkPopulationLockId = new ChunkLockId(); + $temporaryChunkLoader = new class implements ChunkLoader{}; for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ $this->lockChunk($chunkX + $xx, $chunkZ + $zz, $chunkPopulationLockId); - if($xx !== 0 || $zz !== 0){ //avoid registering it twice for the center chunk; we already did that above - $this->registerChunkLoader($temporaryChunkLoader, $chunkX + $xx, $chunkZ + $zz); - } + $this->registerChunkLoader($temporaryChunkLoader, $chunkX + $xx, $chunkZ + $zz); } } - $task = new PopulationTask($this, $chunkX, $chunkZ, $chunk, $temporaryChunkLoader, $chunkPopulationLockId); + $task = new PopulationTask($this, $chunkX, $chunkZ, $this->loadChunk($chunkX, $chunkZ), $temporaryChunkLoader, $chunkPopulationLockId); $workerId = $this->workerPool->selectWorker(); if(!isset($this->generatorRegisteredWorkers[$workerId])){ $this->registerGeneratorToWorker($workerId); From c781efcf90c3bff76899462058255304978654a3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 00:36:57 +0000 Subject: [PATCH 240/710] World: avoid calling the same logic twice in requestChunkPopulation() orderChunkPopulation() checks the preconditions too. Have them both call an internal function that doesn't. --- src/world/World.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/world/World.php b/src/world/World.php index 74cf52821..17de8eefe 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2829,7 +2829,7 @@ class World implements ChunkManager{ //too many chunks are already generating; delay resolution of the request until later return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); } - return $this->orderChunkPopulation($chunkX, $chunkZ, $associatedChunkLoader); + return $this->internalOrderChunkPopulation($chunkX, $chunkZ, $associatedChunkLoader, $resolver); } /** @@ -2848,6 +2848,14 @@ class World implements ChunkManager{ return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader); } + return $this->internalOrderChunkPopulation($chunkX, $chunkZ, $associatedChunkLoader, $resolver); + } + + /** + * @phpstan-param PromiseResolver|null $resolver + * @phpstan-return Promise + */ + private function internalOrderChunkPopulation(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader, ?PromiseResolver $resolver) : Promise{ $chunkHash = World::chunkHash($chunkX, $chunkZ); Timings::$population->startTiming(); From 46b7d35cd38114d86536941c6216d34c95cb96b8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 01:45:49 +0000 Subject: [PATCH 241/710] Player: return from callback if used chunk status is not REQUESTED_GENERATION() this can happen especially on large render distances when flying fast and changing direction - we decide we don't want the chunk, then, after changing direction and re-ordering chunks, we decide we do want it again, and end up registering a second callback. In this case, we need to ensure that only one of the callbacks gets executed (it doesn't matter which one). --- src/player/Player.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/player/Player.php b/src/player/Player.php index 469c025f7..5c34c6680 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -687,7 +687,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ return; } if(!$this->usedChunks[$index]->equals(UsedChunkStatus::REQUESTED_GENERATION())){ - throw new AssumptionFailedError("Used chunk status should not have changed while in REQUESTED_GENERATION mode"); + //We may have previously requested this, decided we didn't want it, and then decided we did want + //it again, all before the generation request got executed. In that case, the promise would have + //multiple callbacks for this player. In that case, only the first one matters. + return; } $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_SENDING(); From 9d30bc8b95705b41177f677293b6ede46acc63e8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 02:17:11 +0000 Subject: [PATCH 242/710] World: fixed assertion failure when requesting, cancelling, and then re-requesting chunks via requestChunkPopulation() if the request/cancel/re-request happens all in the time before the queue gets drained, chunk hashes may appear multiple times in the queue. We don't want to process them twice if this happens (although it's mostly harmless anyway). --- src/world/World.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/world/World.php b/src/world/World.php index 17de8eefe..ded2d9524 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2760,8 +2760,17 @@ class World implements ChunkManager{ private function drainPopulationRequestQueue() : void{ $failed = []; + $seen = []; while(count($this->activeChunkPopulationTasks) < $this->maxConcurrentChunkPopulationTasks && !$this->chunkPopulationRequestQueue->isEmpty()){ $nextChunkHash = $this->chunkPopulationRequestQueue->dequeue(); + if(isset($seen[$nextChunkHash])){ + //We may have previously requested this, decided we didn't want it, and then decided we did want it + //again, all before the generation request got executed. In that case, the chunk hash may appear in the + //queue multiple times (it can't be quickly removed from the queue when the request is cancelled, so we + //leave it in the queue). + continue; + } + $seen[$nextChunkHash] = true; World::getXZ($nextChunkHash, $nextChunkX, $nextChunkZ); if(isset($this->chunkPopulationRequestMap[$nextChunkHash])){ assert(!isset($this->activeChunkPopulationTasks[$nextChunkHash]), "Population for chunk $nextChunkX $nextChunkZ already running"); From 616eb0050dc9e760b95db60fd944b77fe94c46f5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 02:34:44 +0000 Subject: [PATCH 243/710] World: remove premature optimisation of setBlockAt() introduced by ece28e5d7b0d4c8d12a9477cdd1d3337277e892d closes #4531 it turns out that letting the light updates themselves handle this is faster than trying to get in the way. --- src/world/World.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index ded2d9524..a6c71cd6f 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -1596,8 +1596,6 @@ class World implements ChunkManager{ $this->unlockChunk($chunkX, $chunkZ, null); - $oldBlock = $this->getBlockAt($x, $y, $z, true, false); - $block = clone $block; $block->position($this, $x, $y, $z); @@ -1619,9 +1617,7 @@ class World implements ChunkManager{ } if($update){ - if($oldBlock->getLightFilter() !== $block->getLightFilter() or $oldBlock->getLightLevel() !== $block->getLightLevel()){ - $this->updateAllLight($x, $y, $z); - } + $this->updateAllLight($x, $y, $z); $this->tryAddToNeighbourUpdateQueue($pos); foreach($pos->sides() as $side){ $this->tryAddToNeighbourUpdateQueue($side); From debb469de15493218e46df42d0444bd332e0f16f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 13:54:04 +0000 Subject: [PATCH 244/710] Updated PHPUnit dependency junk --- composer.lock | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index 838f72322..e8c116de0 100644 --- a/composer.lock +++ b/composer.lock @@ -837,16 +837,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", "shasum": "" }, "require": { @@ -857,7 +857,8 @@ "webmozart/assert": "^1.9.1" }, "require-dev": { - "mockery/mockery": "~1.3.2" + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" }, "type": "library", "extra": { @@ -887,9 +888,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" }, - "time": "2020-09-03T19:13:55+00:00" + "time": "2021-10-19T17:43:47+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -1178,23 +1179,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.7", + "version": "9.2.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" + "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", + "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.12.0", + "nikic/php-parser": "^4.13.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -1243,7 +1244,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.8" }, "funding": [ { @@ -1251,7 +1252,7 @@ "type": "github" } ], - "time": "2021-09-17T05:39:03+00:00" + "time": "2021-10-30T08:01:38+00:00" }, { "name": "phpunit/php-file-iterator", From 94737934de12954b16c8692697f94b584f8ccb2b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 14:17:54 +0000 Subject: [PATCH 245/710] PlayerDeathEvent: fixed LSP violation reported by PHPStan 1.0 --- src/pocketmine/event/player/PlayerDeathEvent.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/event/player/PlayerDeathEvent.php b/src/pocketmine/event/player/PlayerDeathEvent.php index 84d539a11..ba48894aa 100644 --- a/src/pocketmine/event/player/PlayerDeathEvent.php +++ b/src/pocketmine/event/player/PlayerDeathEvent.php @@ -36,7 +36,7 @@ use pocketmine\Player; class PlayerDeathEvent extends EntityDeathEvent{ /** @var Player */ - protected $entity; + protected $player; /** @var TextContainer|string */ private $deathMessage; @@ -49,6 +49,7 @@ class PlayerDeathEvent extends EntityDeathEvent{ */ public function __construct(Player $entity, array $drops, $deathMessage = null, int $xp = 0){ parent::__construct($entity, $drops, $xp); + $this->player = $entity; $this->deathMessage = $deathMessage ?? self::deriveMessage($entity->getDisplayName(), $entity->getLastDamageCause()); } @@ -56,11 +57,11 @@ class PlayerDeathEvent extends EntityDeathEvent{ * @return Player */ public function getEntity(){ - return $this->entity; + return $this->player; } public function getPlayer() : Player{ - return $this->entity; + return $this->player; } /** From f8f39687e221b478d3bc6bc0affcd2180b3338dd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 15:22:33 +0000 Subject: [PATCH 246/710] Achievement: declare proper type for $list static property --- src/pocketmine/Achievement.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/Achievement.php b/src/pocketmine/Achievement.php index 0e732879a..ae9a62b69 100644 --- a/src/pocketmine/Achievement.php +++ b/src/pocketmine/Achievement.php @@ -30,7 +30,10 @@ use pocketmine\utils\TextFormat; * Handles the achievement list and a bit more */ abstract class Achievement{ - /** @var array[] */ + /** + * @var mixed[][] + * @phpstan-var array}> + */ public static $list = [ /*"openInventory" => array( "name" => "Taking Inventory", From 27ae959e89ee2feb74812e2e1ae0689cc6fd9efd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 15:23:36 +0000 Subject: [PATCH 247/710] Terminal: backport shell_exec() code from PM4 to make PHPStan 1.0 happy --- src/pocketmine/utils/Terminal.php | 65 +++++++++++++++++-------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/src/pocketmine/utils/Terminal.php b/src/pocketmine/utils/Terminal.php index 9485acc9b..d667f0f4c 100644 --- a/src/pocketmine/utils/Terminal.php +++ b/src/pocketmine/utils/Terminal.php @@ -28,7 +28,9 @@ use function fopen; use function function_exists; use function getenv; use function is_array; +use function is_string; use function sapi_windows_vt100_support; +use function shell_exec; use function stream_isatty; abstract class Terminal{ @@ -137,41 +139,44 @@ abstract class Terminal{ * @return void */ protected static function getEscapeCodes(){ - self::$FORMAT_BOLD = `tput bold`; - self::$FORMAT_OBFUSCATED = `tput smacs`; - self::$FORMAT_ITALIC = `tput sitm`; - self::$FORMAT_UNDERLINE = `tput smul`; + $tput = fn(string $args) => is_string($result = shell_exec("tput $args")) ? $result : ""; + $setaf = fn(int $code) => $tput("setaf $code"); + + self::$FORMAT_BOLD = $tput("bold"); + self::$FORMAT_OBFUSCATED = $tput("smacs"); + self::$FORMAT_ITALIC = $tput("sitm"); + self::$FORMAT_UNDERLINE = $tput("smul"); self::$FORMAT_STRIKETHROUGH = "\x1b[9m"; //`tput `; - self::$FORMAT_RESET = `tput sgr0`; + self::$FORMAT_RESET = $tput("sgr0"); - $colors = (int) `tput colors`; + $colors = (int) $tput("colors"); if($colors > 8){ - self::$COLOR_BLACK = $colors >= 256 ? `tput setaf 16` : `tput setaf 0`; - self::$COLOR_DARK_BLUE = $colors >= 256 ? `tput setaf 19` : `tput setaf 4`; - self::$COLOR_DARK_GREEN = $colors >= 256 ? `tput setaf 34` : `tput setaf 2`; - self::$COLOR_DARK_AQUA = $colors >= 256 ? `tput setaf 37` : `tput setaf 6`; - self::$COLOR_DARK_RED = $colors >= 256 ? `tput setaf 124` : `tput setaf 1`; - self::$COLOR_PURPLE = $colors >= 256 ? `tput setaf 127` : `tput setaf 5`; - self::$COLOR_GOLD = $colors >= 256 ? `tput setaf 214` : `tput setaf 3`; - self::$COLOR_GRAY = $colors >= 256 ? `tput setaf 145` : `tput setaf 7`; - self::$COLOR_DARK_GRAY = $colors >= 256 ? `tput setaf 59` : `tput setaf 8`; - self::$COLOR_BLUE = $colors >= 256 ? `tput setaf 63` : `tput setaf 12`; - self::$COLOR_GREEN = $colors >= 256 ? `tput setaf 83` : `tput setaf 10`; - self::$COLOR_AQUA = $colors >= 256 ? `tput setaf 87` : `tput setaf 14`; - self::$COLOR_RED = $colors >= 256 ? `tput setaf 203` : `tput setaf 9`; - self::$COLOR_LIGHT_PURPLE = $colors >= 256 ? `tput setaf 207` : `tput setaf 13`; - self::$COLOR_YELLOW = $colors >= 256 ? `tput setaf 227` : `tput setaf 11`; - self::$COLOR_WHITE = $colors >= 256 ? `tput setaf 231` : `tput setaf 15`; + self::$COLOR_BLACK = $colors >= 256 ? $setaf(16) : $setaf(0); + self::$COLOR_DARK_BLUE = $colors >= 256 ? $setaf(19) : $setaf(4); + self::$COLOR_DARK_GREEN = $colors >= 256 ? $setaf(34) : $setaf(2); + self::$COLOR_DARK_AQUA = $colors >= 256 ? $setaf(37) : $setaf(6); + self::$COLOR_DARK_RED = $colors >= 256 ? $setaf(124) : $setaf(1); + self::$COLOR_PURPLE = $colors >= 256 ? $setaf(127) : $setaf(5); + self::$COLOR_GOLD = $colors >= 256 ? $setaf(214) : $setaf(3); + self::$COLOR_GRAY = $colors >= 256 ? $setaf(145) : $setaf(7); + self::$COLOR_DARK_GRAY = $colors >= 256 ? $setaf(59) : $setaf(8); + self::$COLOR_BLUE = $colors >= 256 ? $setaf(63) : $setaf(12); + self::$COLOR_GREEN = $colors >= 256 ? $setaf(83) : $setaf(10); + self::$COLOR_AQUA = $colors >= 256 ? $setaf(87) : $setaf(14); + self::$COLOR_RED = $colors >= 256 ? $setaf(203) : $setaf(9); + self::$COLOR_LIGHT_PURPLE = $colors >= 256 ? $setaf(207) : $setaf(13); + self::$COLOR_YELLOW = $colors >= 256 ? $setaf(227) : $setaf(11); + self::$COLOR_WHITE = $colors >= 256 ? $setaf(231) : $setaf(15); }else{ - self::$COLOR_BLACK = self::$COLOR_DARK_GRAY = `tput setaf 0`; - self::$COLOR_RED = self::$COLOR_DARK_RED = `tput setaf 1`; - self::$COLOR_GREEN = self::$COLOR_DARK_GREEN = `tput setaf 2`; - self::$COLOR_YELLOW = self::$COLOR_GOLD = `tput setaf 3`; - self::$COLOR_BLUE = self::$COLOR_DARK_BLUE = `tput setaf 4`; - self::$COLOR_LIGHT_PURPLE = self::$COLOR_PURPLE = `tput setaf 5`; - self::$COLOR_AQUA = self::$COLOR_DARK_AQUA = `tput setaf 6`; - self::$COLOR_GRAY = self::$COLOR_WHITE = `tput setaf 7`; + self::$COLOR_BLACK = self::$COLOR_DARK_GRAY = $setaf(0); + self::$COLOR_RED = self::$COLOR_DARK_RED = $setaf(1); + self::$COLOR_GREEN = self::$COLOR_DARK_GREEN = $setaf(2); + self::$COLOR_YELLOW = self::$COLOR_GOLD = $setaf(3); + self::$COLOR_BLUE = self::$COLOR_DARK_BLUE = $setaf(4); + self::$COLOR_LIGHT_PURPLE = self::$COLOR_PURPLE = $setaf(5); + self::$COLOR_AQUA = self::$COLOR_DARK_AQUA = $setaf(6); + self::$COLOR_GRAY = self::$COLOR_WHITE = $setaf(7); } } From d5f13d8be2bbdf6367c471ce9ad0adf4e3a58aab Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 15:24:16 +0000 Subject: [PATCH 248/710] Timezone: make PHPStan 1.0 happy --- src/pocketmine/utils/Timezone.php | 78 +++++++++++++++---------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/pocketmine/utils/Timezone.php b/src/pocketmine/utils/Timezone.php index 08a7c78bf..54fe0049c 100644 --- a/src/pocketmine/utils/Timezone.php +++ b/src/pocketmine/utils/Timezone.php @@ -31,6 +31,7 @@ use function file_get_contents; use function implode; use function ini_get; use function ini_set; +use function is_array; use function is_string; use function json_decode; use function parse_ini_file; @@ -58,50 +59,49 @@ abstract class Timezone{ */ public static function init() : array{ $messages = []; - do{ - $timezone = self::get(); - if($timezone !== ""){ - /* - * This is here so that people don't come to us complaining and fill up the issue tracker when they put - * an incorrect timezone abbreviation in php.ini apparently. - */ - if(strpos($timezone, "/") === false){ - $default_timezone = timezone_name_from_abbr($timezone); - if($default_timezone !== false){ - ini_set("date.timezone", $default_timezone); - date_default_timezone_set($default_timezone); - break; - }else{ - //Bad php.ini value, try another method to detect timezone - $messages[] = "Timezone \"$timezone\" could not be parsed as a valid timezone from php.ini, falling back to auto-detection"; - } - }else{ - date_default_timezone_set($timezone); - break; + $timezone = self::get(); + if($timezone !== ""){ + /* + * This is here so that people don't come to us complaining and fill up the issue tracker when they put + * an incorrect timezone abbreviation in php.ini apparently. + */ + if(strpos($timezone, "/") === false){ + $default_timezone = timezone_name_from_abbr($timezone); + if($default_timezone !== false){ + ini_set("date.timezone", $default_timezone); + date_default_timezone_set($default_timezone); + return $messages; } + //Bad php.ini value, try another method to detect timezone + $messages[] = "Timezone \"$timezone\" could not be parsed as a valid timezone from php.ini, falling back to auto-detection"; + }else{ + date_default_timezone_set($timezone); + return $messages; } + } - if(($timezone = self::detectSystemTimezone()) and date_default_timezone_set($timezone)){ - //Success! Timezone has already been set and validated in the if statement. - //This here is just for redundancy just in case some program wants to read timezone data from the ini. - ini_set("date.timezone", $timezone); - break; - } + if(($timezone = self::detectSystemTimezone()) !== false and date_default_timezone_set($timezone)){ + //Success! Timezone has already been set and validated in the if statement. + //This here is just for redundancy just in case some program wants to read timezone data from the ini. + ini_set("date.timezone", $timezone); + return $messages; + } - if(($response = Internet::getURL("http://ip-api.com/json")) !== false //If system timezone detection fails or timezone is an invalid value. - and $ip_geolocation_data = json_decode($response, true) - and $ip_geolocation_data['status'] !== 'fail' - and date_default_timezone_set($ip_geolocation_data['timezone']) - ){ - //Again, for redundancy. - ini_set("date.timezone", $ip_geolocation_data['timezone']); - break; - } + if(($response = Internet::getURL("http://ip-api.com/json")) !== false //If system timezone detection fails or timezone is an invalid value. + and is_array($ip_geolocation_data = json_decode($response, true)) + and isset($ip_geolocation_data['status']) + and $ip_geolocation_data['status'] !== 'fail' + and is_string($ip_geolocation_data['timezone']) + and date_default_timezone_set($ip_geolocation_data['timezone']) + ){ + //Again, for redundancy. + ini_set("date.timezone", $ip_geolocation_data['timezone']); + return $messages; + } - ini_set("date.timezone", "UTC"); - date_default_timezone_set("UTC"); - $messages[] = "Timezone could not be automatically determined or was set to an invalid value. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file."; - }while(false); + ini_set("date.timezone", "UTC"); + date_default_timezone_set("UTC"); + $messages[] = "Timezone could not be automatically determined or was set to an invalid value. An incorrect timezone will result in incorrect timestamps on console logs. It has been set to \"UTC\" by default. You can change it on the php.ini file."; return $messages; } From 0f0b6f0efae60d7b45d17d64d053a621ca8a3ec2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 15:25:56 +0000 Subject: [PATCH 249/710] Utils: eliminate usages of backtick operator --- src/pocketmine/utils/Utils.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index c92fc373a..90a58aca7 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -71,6 +71,7 @@ use function rmdir; use function rtrim; use function scandir; use function sha1; +use function shell_exec; use function spl_object_hash; use function str_pad; use function str_replace; @@ -235,7 +236,7 @@ class Utils{ }elseif($os === Utils::OS_ANDROID){ $machine .= @file_get_contents("/system/build.prop"); }elseif($os === Utils::OS_MACOS){ - $machine .= `system_profiler SPHardwareDataType | grep UUID`; + $machine .= shell_exec("system_profiler SPHardwareDataType | grep UUID"); } $data = $machine . PHP_MAXPATHLEN; $data .= PHP_INT_MAX; @@ -358,7 +359,7 @@ class Utils{ break; case Utils::OS_BSD: case Utils::OS_MACOS: - $processors = (int) `sysctl -n hw.ncpu`; + $processors = (int) shell_exec("sysctl -n hw.ncpu"); break; case Utils::OS_WINDOWS: $processors = (int) getenv("NUMBER_OF_PROCESSORS"); From 2dee1dbc283fc8af4ccb3004be0ce47a1c82ef24 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 15:41:21 +0000 Subject: [PATCH 250/710] Remove ridiculous code in ResourcePackManager --- src/pocketmine/resourcepacks/ResourcePackManager.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/resourcepacks/ResourcePackManager.php b/src/pocketmine/resourcepacks/ResourcePackManager.php index aa21079d5..d1cd2803c 100644 --- a/src/pocketmine/resourcepacks/ResourcePackManager.php +++ b/src/pocketmine/resourcepacks/ResourcePackManager.php @@ -31,6 +31,9 @@ use function file_exists; use function gettype; use function is_array; use function is_dir; +use function is_float; +use function is_int; +use function is_string; use function mkdir; use function strtolower; use const DIRECTORY_SEPARATOR; @@ -78,14 +81,12 @@ class ResourcePackManager{ } foreach($resourceStack as $pos => $pack){ - try{ - $pack = (string) $pack; - }catch(\ErrorException $e){ + if(!is_string($pack) && !is_int($pack) && !is_float($pack)){ $logger->critical("Found invalid entry in resource pack list at offset $pos of type " . gettype($pack)); continue; } + $pack = (string) $pack; try{ - /** @var string $pack */ $packPath = $this->path . DIRECTORY_SEPARATOR . $pack; if(!file_exists($packPath)){ throw new ResourcePackException("File or directory not found"); From 8865bb73ba27c5e2c9021e4d1bcc587d0246a04d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 15:52:55 +0000 Subject: [PATCH 251/710] BanEntry: remove useless do/while --- src/pocketmine/permission/BanEntry.php | 42 ++++++++++++-------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/pocketmine/permission/BanEntry.php b/src/pocketmine/permission/BanEntry.php index 44d8c03e1..397de1cc2 100644 --- a/src/pocketmine/permission/BanEntry.php +++ b/src/pocketmine/permission/BanEntry.php @@ -163,32 +163,28 @@ class BanEntry{ }else{ $str = explode("|", trim($str)); $entry = new BanEntry(trim(array_shift($str))); - do{ - if(count($str) === 0){ - break; - } + if(count($str) === 0){ + return $entry; + } - $entry->setCreated(self::parseDate(array_shift($str))); - if(count($str) === 0){ - break; - } + $entry->setCreated(self::parseDate(array_shift($str))); + if(count($str) === 0){ + return $entry; + } - $entry->setSource(trim(array_shift($str))); - if(count($str) === 0){ - break; - } - - $expire = trim(array_shift($str)); - if($expire !== "" and strtolower($expire) !== "forever"){ - $entry->setExpires(self::parseDate($expire)); - } - if(count($str) === 0){ - break; - } - - $entry->setReason(trim(array_shift($str))); - }while(false); + $entry->setSource(trim(array_shift($str))); + if(count($str) === 0){ + return $entry; + } + $expire = trim(array_shift($str)); + if($expire !== "" and strtolower($expire) !== "forever"){ + $entry->setExpires(self::parseDate($expire)); + } + if(count($str) === 0){ + return $entry; + } + $entry->setReason(trim(array_shift($str))); return $entry; } } From 9f5c16bc46c11540434abe37b6de3d7efb58e433 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 15:56:28 +0000 Subject: [PATCH 252/710] Projectile: use closure instead of do/while for reading id/data of block not ideal, but whatever I guess... this at least provides scope isolation --- src/pocketmine/entity/projectile/Projectile.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/pocketmine/entity/projectile/Projectile.php b/src/pocketmine/entity/projectile/Projectile.php index 5e0ddf1f9..f05b75c3c 100644 --- a/src/pocketmine/entity/projectile/Projectile.php +++ b/src/pocketmine/entity/projectile/Projectile.php @@ -80,33 +80,29 @@ abstract class Projectile extends Entity{ $this->setHealth(1); $this->damage = $this->namedtag->getDouble("damage", $this->damage); - do{ - $blockHit = null; - $blockId = null; - $blockData = null; - + (function() : void{ if($this->namedtag->hasTag("tileX", IntTag::class) and $this->namedtag->hasTag("tileY", IntTag::class) and $this->namedtag->hasTag("tileZ", IntTag::class)){ $blockHit = new Vector3($this->namedtag->getInt("tileX"), $this->namedtag->getInt("tileY"), $this->namedtag->getInt("tileZ")); }else{ - break; + return; } if($this->namedtag->hasTag("blockId", IntTag::class)){ $blockId = $this->namedtag->getInt("blockId"); }else{ - break; + return; } if($this->namedtag->hasTag("blockData", ByteTag::class)){ $blockData = $this->namedtag->getByte("blockData"); }else{ - break; + return; } $this->blockHit = $blockHit; $this->blockHitId = $blockId; $this->blockHitData = $blockData; - }while(false); + })(); } public function canCollideWith(Entity $entity) : bool{ From f6480017ce31039f90635e7cffcbfb6e7180145b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 16:12:37 +0000 Subject: [PATCH 253/710] Update PHPUnit dependency junk --- composer.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.lock b/composer.lock index 747ede114..34c1f14b0 100644 --- a/composer.lock +++ b/composer.lock @@ -2054,23 +2054,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.7", + "version": "9.2.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" + "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", + "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.12.0", + "nikic/php-parser": "^4.13.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -2119,7 +2119,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.8" }, "funding": [ { @@ -2127,7 +2127,7 @@ "type": "github" } ], - "time": "2021-09-17T05:39:03+00:00" + "time": "2021-10-30T08:01:38+00:00" }, { "name": "phpunit/php-file-iterator", From c3768b997a835cc3bcc39627e0ef4d4d0ddab8e5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 16:13:33 +0000 Subject: [PATCH 254/710] Updated to pmmp/BedrockProtocol@146498c279b3dc645ab6b8cdf45f7b96d8a33f8b --- composer.lock | 8 ++++---- src/network/mcpe/NetworkSession.php | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 34c1f14b0..543a9524c 100644 --- a/composer.lock +++ b/composer.lock @@ -253,12 +253,12 @@ "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "c8d891b4dff9817d5fcd373dfec0608b20be3b0a" + "reference": "146498c279b3dc645ab6b8cdf45f7b96d8a33f8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/c8d891b4dff9817d5fcd373dfec0608b20be3b0a", - "reference": "c8d891b4dff9817d5fcd373dfec0608b20be3b0a", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/146498c279b3dc645ab6b8cdf45f7b96d8a33f8b", + "reference": "146498c279b3dc645ab6b8cdf45f7b96d8a33f8b", "shasum": "" }, "require": { @@ -293,7 +293,7 @@ "issues": "https://github.com/pmmp/BedrockProtocol/issues", "source": "https://github.com/pmmp/BedrockProtocol/tree/master" }, - "time": "2021-10-29T20:54:42+00:00" + "time": "2021-11-01T15:46:55+00:00" }, { "name": "pocketmine/binaryutils", diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 82f1516b6..4a7cfe259 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -348,6 +348,10 @@ class NetworkSession{ try{ foreach($stream->getPackets($this->packetPool, $this->packetSerializerContext, 500) as [$packet, $buffer]){ + if($packet === null){ + $this->logger->debug("Unknown packet: " . base64_encode($buffer)); + throw new PacketHandlingException("Unknown packet received"); + } try{ $this->handleDataPacket($packet, $buffer); }catch(PacketHandlingException $e){ From d696ebcda38f70289efe5c7a6eb647e37a5c0fee Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 16:52:27 +0000 Subject: [PATCH 255/710] Level: do not use static:: to access levelIdCounter the field is private. --- src/pocketmine/level/Level.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index cc068c3e3..2c503ea0d 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -370,7 +370,7 @@ class Level implements ChunkManager, Metadatable{ */ public function __construct(Server $server, string $name, LevelProvider $provider){ $this->blockStates = BlockFactory::getBlockStatesArray(); - $this->levelId = static::$levelIdCounter++; + $this->levelId = self::$levelIdCounter++; $this->blockMetadata = new BlockMetadataStore($this); $this->server = $server; $this->autoSave = $server->getAutoSave(); From 0babe0a1ab3d5b7f0cb605e00f2ca9b4bd4d0e23 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 16:55:05 +0000 Subject: [PATCH 256/710] LevelDB: remove unused private method --- src/pocketmine/level/format/io/leveldb/LevelDB.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pocketmine/level/format/io/leveldb/LevelDB.php b/src/pocketmine/level/format/io/leveldb/LevelDB.php index 01ede0fb1..12a144c03 100644 --- a/src/pocketmine/level/format/io/leveldb/LevelDB.php +++ b/src/pocketmine/level/format/io/leveldb/LevelDB.php @@ -545,10 +545,6 @@ class LevelDB extends BaseLevelProvider{ return Binary::writeLInt($chunkX) . Binary::writeLInt($chunkZ); } - private function chunkExists(int $chunkX, int $chunkZ) : bool{ - return $this->db->get(LevelDB::chunkIndex($chunkX, $chunkZ) . self::TAG_VERSION) !== false; - } - public function close(){ unset($this->db); } From 4d4362801feba21ed3c176b45d165e955415f795 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 17:01:26 +0000 Subject: [PATCH 257/710] AvailableCommandsPacket: remove dead code --- .../mcpe/protocol/AvailableCommandsPacket.php | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php index e47f713f8..5b2d4c3d9 100644 --- a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php @@ -359,49 +359,6 @@ class AvailableCommandsPacket extends DataPacket{ } } - /** - * @param string[] $postfixes - * @phpstan-param array $postfixes - */ - private function argTypeToString(int $argtype, array $postfixes) : string{ - if(($argtype & self::ARG_FLAG_VALID) !== 0){ - if(($argtype & self::ARG_FLAG_ENUM) !== 0){ - return "stringenum (" . ($argtype & 0xffff) . ")"; - } - - switch($argtype & 0xffff){ - case self::ARG_TYPE_INT: - return "int"; - case self::ARG_TYPE_FLOAT: - return "float"; - case self::ARG_TYPE_VALUE: - return "mixed"; - case self::ARG_TYPE_TARGET: - return "target"; - case self::ARG_TYPE_STRING: - return "string"; - case self::ARG_TYPE_POSITION: - return "xyz"; - case self::ARG_TYPE_MESSAGE: - return "message"; - case self::ARG_TYPE_RAWTEXT: - return "text"; - case self::ARG_TYPE_JSON: - return "json"; - case self::ARG_TYPE_COMMAND: - return "command"; - } - }elseif(($argtype & self::ARG_FLAG_POSTFIX) !== 0){ - $postfix = $postfixes[$argtype & 0xffff]; - - return "int (postfix $postfix)"; - }else{ - throw new \UnexpectedValueException("Unknown arg type 0x" . dechex($argtype)); - } - - return "unknown ($argtype)"; - } - protected function encodePayload(){ /** @var int[] $enumValueIndexes */ $enumValueIndexes = []; From ff27c5f7dbd33a6432fd19aed602bfcb7ca8f82c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 17:24:20 +0000 Subject: [PATCH 258/710] PHPStan 1.0.0 --- composer.json | 6 +- composer.lock | 54 ++--- phpstan.neon.dist | 4 +- tests/phpstan/configs/actual-problems.neon | 105 +++++++++ .../check-explicit-mixed-baseline.neon | 217 ++++++++++++++++-- tests/phpstan/configs/l7-baseline.neon | 19 +- tests/phpstan/configs/l8-baseline.neon | 5 - tests/phpstan/configs/phpstan-bugs.neon | 109 +++++---- .../phpstan/configs/runtime-type-checks.neon | 67 +----- 9 files changed, 419 insertions(+), 167 deletions(-) diff --git a/composer.json b/composer.json index 262d67a10..b835e1124 100644 --- a/composer.json +++ b/composer.json @@ -38,9 +38,9 @@ "pocketmine/spl": "^0.4.0" }, "require-dev": { - "phpstan/phpstan": "0.12.99", - "phpstan/phpstan-phpunit": "^0.12.6", - "phpstan/phpstan-strict-rules": "^0.12.2", + "phpstan/phpstan": "1.0.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.2" }, "autoload": { diff --git a/composer.lock b/composer.lock index e8c116de0..9250f7dfb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cfba71d2ad0dd961ed00520b5d52e4d7", + "content-hash": "83afdaf7b072e11090279f87f57bebb5", "packages": [ { "name": "adhocore/json-comment", @@ -1011,16 +1011,16 @@ }, { "name": "phpstan/phpstan", - "version": "0.12.99", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7" + "reference": "0d13a99513182e521271d46bde8f28caa4f84d97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b4d40f1d759942f523be267a1bab6884f46ca3f7", - "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d13a99513182e521271d46bde8f28caa4f84d97", + "reference": "0d13a99513182e521271d46bde8f28caa4f84d97", "shasum": "" }, "require": { @@ -1036,7 +1036,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "0.12-dev" + "dev-master": "1.0-dev" } }, "autoload": { @@ -1051,7 +1051,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/0.12.99" + "source": "https://github.com/phpstan/phpstan/tree/1.0.0" }, "funding": [ { @@ -1071,38 +1071,39 @@ "type": "tidelift" } ], - "time": "2021-09-12T20:09:55+00:00" + "time": "2021-11-01T06:38:20+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "0.12.22", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "7c01ef93bf128b4ac8bdad38c54b2a4fd6b0b3cc" + "reference": "9eb88c9f689003a8a2a5ae9e010338ee94dc39b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/7c01ef93bf128b4ac8bdad38c54b2a4fd6b0b3cc", - "reference": "7c01ef93bf128b4ac8bdad38c54b2a4fd6b0b3cc", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/9eb88c9f689003a8a2a5ae9e010338ee94dc39b3", + "reference": "9eb88c9f689003a8a2a5ae9e010338ee94dc39b3", "shasum": "" }, "require": { "php": "^7.1 || ^8.0", - "phpstan/phpstan": "^0.12.92" + "phpstan/phpstan": "^1.0" }, "conflict": { "phpunit/phpunit": "<7.0" }, "require-dev": { + "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-strict-rules": "^0.12.6", + "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": "^9.5" }, "type": "phpstan-extension", "extra": { "branch-alias": { - "dev-master": "0.12-dev" + "dev-master": "1.0-dev" }, "phpstan": { "includes": [ @@ -1123,37 +1124,38 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.22" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.0.0" }, - "time": "2021-08-12T10:53:43+00:00" + "time": "2021-10-14T08:03:54+00:00" }, { "name": "phpstan/phpstan-strict-rules", - "version": "0.12.11", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "2b72e8e17d2034145f239126e876e5fb659675e2" + "reference": "7f50eb112f37fda2ef956813d3f1e9b1e69d7940" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/2b72e8e17d2034145f239126e876e5fb659675e2", - "reference": "2b72e8e17d2034145f239126e876e5fb659675e2", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/7f50eb112f37fda2ef956813d3f1e9b1e69d7940", + "reference": "7f50eb112f37fda2ef956813d3f1e9b1e69d7940", "shasum": "" }, "require": { "php": "^7.1 || ^8.0", - "phpstan/phpstan": "^0.12.96" + "phpstan/phpstan": "^1.0" }, "require-dev": { + "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-phpunit": "^0.12.16", + "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^9.5" }, "type": "phpstan-extension", "extra": { "branch-alias": { - "dev-master": "0.12-dev" + "dev-master": "1.0-dev" }, "phpstan": { "includes": [ @@ -1173,9 +1175,9 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/0.12.11" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.0.0" }, - "time": "2021-08-21T11:36:27+00:00" + "time": "2021-10-11T06:57:58+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/phpstan.neon.dist b/phpstan.neon.dist index df2c4a10b..54e7cd6f6 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -15,9 +15,9 @@ includes: - vendor/phpstan/phpstan-strict-rules/rules.neon parameters: - level: 8 - checkExplicitMixed: true + level: 9 checkMissingCallableSignature: true + treatPhpDocTypesAsCertain: false bootstrapFiles: - tests/phpstan/bootstrap.php scanDirectories: diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index bd6e4784d..12a6a1251 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -5,11 +5,21 @@ parameters: count: 1 path: ../../../src/pocketmine/CrashDump.php + - + message: "#^Only booleans are allowed in &&, mixed given on the right side\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + - message: "#^pocketmine\\\\Player\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\entity\\\\Human\\.$#" count: 1 path: ../../../src/pocketmine/Player.php + - + message: "#^Do\\-while loop condition is always false\\.$#" + count: 1 + path: ../../../src/pocketmine/PocketMine.php + - message: "#^Instanceof between pocketmine\\\\command\\\\CommandReader and pocketmine\\\\command\\\\CommandReader will always evaluate to true\\.$#" count: 1 @@ -705,16 +715,46 @@ parameters: count: 1 path: ../../../src/pocketmine/event/entity/EntityShootBowEvent.php + - + message: "#^PHPDoc type pocketmine\\\\level\\\\Position of property pocketmine\\\\inventory\\\\AnvilInventory\\:\\:\\$holder is not the same as PHPDoc type pocketmine\\\\math\\\\Vector3 of overridden property pocketmine\\\\inventory\\\\ContainerInventory\\:\\:\\$holder\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/AnvilInventory.php + + - + message: "#^PHPDoc type pocketmine\\\\tile\\\\Chest of property pocketmine\\\\inventory\\\\ChestInventory\\:\\:\\$holder is not the same as PHPDoc type pocketmine\\\\math\\\\Vector3 of overridden property pocketmine\\\\inventory\\\\ContainerInventory\\:\\:\\$holder\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/ChestInventory.php + - message: "#^pocketmine\\\\inventory\\\\DoubleChestInventory\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\inventory\\\\ChestInventory\\.$#" count: 1 path: ../../../src/pocketmine/inventory/DoubleChestInventory.php + - + message: "#^PHPDoc type pocketmine\\\\level\\\\Position of property pocketmine\\\\inventory\\\\EnchantInventory\\:\\:\\$holder is not the same as PHPDoc type pocketmine\\\\math\\\\Vector3 of overridden property pocketmine\\\\inventory\\\\ContainerInventory\\:\\:\\$holder\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/EnchantInventory.php + + - + message: "#^PHPDoc type pocketmine\\\\level\\\\Position of property pocketmine\\\\inventory\\\\EnderChestInventory\\:\\:\\$holder is not the same as PHPDoc type pocketmine\\\\tile\\\\Chest of overridden property pocketmine\\\\inventory\\\\ChestInventory\\:\\:\\$holder\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/EnderChestInventory.php + - message: "#^pocketmine\\\\inventory\\\\EnderChestInventory\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\inventory\\\\ChestInventory\\.$#" count: 1 path: ../../../src/pocketmine/inventory/EnderChestInventory.php + - + message: "#^PHPDoc type pocketmine\\\\tile\\\\Furnace of property pocketmine\\\\inventory\\\\FurnaceInventory\\:\\:\\$holder is not the same as PHPDoc type pocketmine\\\\math\\\\Vector3 of overridden property pocketmine\\\\inventory\\\\ContainerInventory\\:\\:\\$holder\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/FurnaceInventory.php + + - + message: "#^Property pocketmine\\\\inventory\\\\MultiRecipe\\:\\:\\$uuid is never read, only written\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/MultiRecipe.php + - message: "#^pocketmine\\\\item\\\\GoldenAppleEnchanted\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\item\\\\GoldenApple\\.$#" count: 1 @@ -725,6 +765,31 @@ parameters: count: 1 path: ../../../src/pocketmine/item/WrittenBook.php + - + message: "#^Only booleans are allowed in &&, mixed given on the right side\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Only booleans are allowed in \\|\\|, bool\\|null given on the right side\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Only booleans are allowed in \\|\\|, bool\\|null given on the right side\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/Chunk.php + + - + message: "#^Parameter \\#2 \\$length of function fread expects int\\<0, max\\>, int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php + + - + message: "#^Parameter \\#2 \\$size of function ftruncate expects int\\<0, max\\>, int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php + - message: "#^Variable property access on \\$this\\(pocketmine\\\\level\\\\generator\\\\PopulationTask\\)\\.$#" count: 4 @@ -740,16 +805,56 @@ parameters: count: 1 path: ../../../src/pocketmine/level/generator/normal/Normal.php + - + message: "#^Property pocketmine\\\\level\\\\generator\\\\object\\\\Pond\\:\\:\\$random is never read, only written\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/object/Pond.php + + - + message: "#^Property pocketmine\\\\level\\\\generator\\\\populator\\\\Pond\\:\\:\\$lavaOdd is never read, only written\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/populator/Pond.php + + - + message: "#^Property pocketmine\\\\level\\\\generator\\\\populator\\\\Pond\\:\\:\\$lavaSurfaceOdd is never read, only written\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/populator/Pond.php + - message: "#^Method pocketmine\\\\metadata\\\\MetadataStore\\:\\:getMetadataInternal\\(\\) should return array\\ but returns SplObjectStorage\\\\.$#" count: 1 path: ../../../src/pocketmine/metadata/MetadataStore.php + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AvailableActorIdentifiersPacket\\:\\:\\$namedtag \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/AvailableActorIdentifiersPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BiomeDefinitionListPacket\\:\\:\\$namedtag \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/BiomeDefinitionListPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UnknownPacket\\:\\:\\$payload \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/UnknownPacket.php + - message: "#^Variable method call on pocketmine\\\\event\\\\Listener\\.$#" count: 1 path: ../../../src/pocketmine/plugin/MethodEventExecutor.php + - + message: "#^Parameter \\#2 \\$length of function fread expects int\\<0, max\\>, int given\\.$#" + count: 1 + path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + + - + message: "#^PHPDoc type pocketmine\\\\scheduler\\\\AsyncWorker\\|null of property pocketmine\\\\scheduler\\\\AsyncTask\\:\\:\\$worker is not the same as PHPDoc type Worker of overridden property Threaded\\:\\:\\$worker\\.$#" + count: 1 + path: ../../../src/pocketmine/scheduler/AsyncTask.php + - message: "#^Constructor of class pocketmine\\\\scheduler\\\\TaskScheduler has an unused parameter \\$logger\\.$#" count: 1 diff --git a/tests/phpstan/configs/check-explicit-mixed-baseline.neon b/tests/phpstan/configs/check-explicit-mixed-baseline.neon index 9c7492962..eda18a112 100644 --- a/tests/phpstan/configs/check-explicit-mixed-baseline.neon +++ b/tests/phpstan/configs/check-explicit-mixed-baseline.neon @@ -25,6 +25,66 @@ parameters: count: 3 path: ../../../src/pocketmine/Player.php + - + message: "#^Cannot access offset 'AnimationExpression' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'Colors' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'Frames' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'Image' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'ImageHeight' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'ImageWidth' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'IsDefault' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'PackId' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'PieceId' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'PieceType' on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'ProductId' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'Type' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + - message: "#^Cannot cast mixed to int\\.$#" count: 1 @@ -32,7 +92,17 @@ parameters: - message: "#^Parameter \\#1 \\$height of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects int, mixed given\\.$#" - count: 2 + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\$pieceId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\$pieceType of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaPieceTintColor constructor expects string, mixed given\\.$#" + count: 1 path: ../../../src/pocketmine/Player.php - @@ -42,7 +112,7 @@ parameters: - message: "#^Parameter \\#1 \\$string of function base64_decode expects string, mixed given\\.$#" - count: 6 + count: 7 path: ../../../src/pocketmine/Player.php - @@ -80,14 +150,54 @@ parameters: count: 1 path: ../../../src/pocketmine/Player.php + - + message: "#^Parameter \\#2 \\$colors of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaPieceTintColor constructor expects array\\, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#2 \\$pieceType of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + - message: "#^Parameter \\#2 \\$playFabId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" count: 1 path: ../../../src/pocketmine/Player.php + - + message: "#^Parameter \\#2 \\$type of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinAnimation constructor expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + - message: "#^Parameter \\#2 \\$width of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects int, mixed given\\.$#" - count: 2 + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#3 \\$frames of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinAnimation constructor expects float, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#3 \\$packId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#4 \\$expressionType of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinAnimation constructor expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#4 \\$isDefaultPiece of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects bool, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#5 \\$productId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" + count: 1 path: ../../../src/pocketmine/Player.php - @@ -157,6 +267,11 @@ parameters: - message: "#^Cannot access offset 0 on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/command/defaults/TimingsCommand.php + + - + message: "#^Parameter \\#1 \\$json of function json_decode expects string, mixed given\\.$#" count: 1 path: ../../../src/pocketmine/command/defaults/TimingsCommand.php @@ -200,6 +315,11 @@ parameters: count: 1 path: ../../../src/pocketmine/item/Item.php + - + message: "#^Parameter \\#1 \\$data of static method pocketmine\\\\item\\\\Item\\:\\:jsonDeserialize\\(\\) expects array\\{id\\: int, damage\\?\\: int, count\\?\\: int, nbt\\?\\: string, nbt_hex\\?\\: string, nbt_b64\\?\\: string\\}, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/Item.php + - message: "#^Parameter \\#1 \\$id of static method pocketmine\\\\item\\\\ItemFactory\\:\\:get\\(\\) expects int, mixed given\\.$#" count: 1 @@ -330,6 +450,16 @@ parameters: count: 1 path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php + - + message: "#^Parameter \\#1 \\$upload of method pocketmine\\\\network\\\\Network\\:\\:addStatistics\\(\\) expects float, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php + + - + message: "#^Parameter \\#2 \\$download of method pocketmine\\\\network\\\\Network\\:\\:addStatistics\\(\\) expects float, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php + - message: "#^Cannot access offset 'exp' on mixed\\.$#" count: 2 @@ -350,6 +480,16 @@ parameters: count: 2 path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + - + message: "#^Cannot use array destructuring on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Parameter \\#1 \\$string of function wordwrap expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + - message: "#^Cannot access offset string on mixed\\.$#" count: 1 @@ -361,20 +501,30 @@ parameters: path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddActorPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" + message: "#^Parameter \\#2 \\$legacyId of static method pocketmine\\\\network\\\\mcpe\\\\convert\\\\RuntimeBlockMapping\\:\\:registerMapping\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddActorPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/AddActorPacket.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddItemActorPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddItemActorPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/AddItemActorPacket.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddPlayerPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddPlayerPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/AddPlayerPacket.php + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + - message: "#^Cannot access offset 'XUID' on mixed\\.$#" count: 2 @@ -396,7 +546,12 @@ parameters: path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$chainData \\(array\\(\\?'chain' \\=\\> array\\\\)\\) does not accept mixed\\.$#" + message: "#^Parameter \\#1 \\$token of static method pocketmine\\\\utils\\\\Utils\\:\\:decodeJWT\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$chainData \\(array\\{chain\\?\\: array\\\\}\\) does not accept mixed\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php @@ -405,6 +560,11 @@ parameters: count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$clientUUID \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$identityPublicKey \\(string\\) does not accept mixed\\.$#" count: 1 @@ -421,7 +581,17 @@ parameters: path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\SetActorDataPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$username \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$xuid \\(string\\|null\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\SetActorDataPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/SetActorDataPacket.php @@ -442,7 +612,7 @@ parameters: - message: "#^Array \\(array\\\\) does not accept mixed\\.$#" - count: 1 + count: 2 path: ../../../src/pocketmine/plugin/PluginDescription.php - @@ -480,6 +650,16 @@ parameters: count: 1 path: ../../../src/pocketmine/plugin/PluginDescription.php + - + message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$depend \\(array\\\\) does not accept array\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$loadBefore \\(array\\\\) does not accept array\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + - message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$main \\(string\\) does not accept mixed\\.$#" count: 1 @@ -495,6 +675,11 @@ parameters: count: 1 path: ../../../src/pocketmine/plugin/PluginDescription.php + - + message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$softDepend \\(array\\\\) does not accept array\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + - message: "#^Parameter \\#1 \\$description of method pocketmine\\\\command\\\\Command\\:\\:setDescription\\(\\) expects string, mixed given\\.$#" count: 1 @@ -550,6 +735,11 @@ parameters: count: 1 path: ../../../src/pocketmine/updater/AutoUpdater.php + - + message: "#^Cannot access offset string on mixed\\.$#" + count: 3 + path: ../../../src/pocketmine/utils/Config.php + - message: "#^Parameter \\#2 \\$offset of function substr expects int, mixed given\\.$#" count: 1 @@ -561,14 +751,9 @@ parameters: path: ../../../src/pocketmine/utils/Internet.php - - message: "#^Cannot access offset 'status' on mixed\\.$#" + message: "#^Cannot cast mixed to string\\.$#" count: 1 - path: ../../../src/pocketmine/utils/Timezone.php - - - - message: "#^Cannot access offset 'timezone' on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/utils/Timezone.php + path: ../../../src/pocketmine/utils/Utils.php - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Utils\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" diff --git a/tests/phpstan/configs/l7-baseline.neon b/tests/phpstan/configs/l7-baseline.neon index 52ea0cd26..f0962404d 100644 --- a/tests/phpstan/configs/l7-baseline.neon +++ b/tests/phpstan/configs/l7-baseline.neon @@ -25,6 +25,11 @@ parameters: count: 1 path: ../../../src/pocketmine/MemoryManager.php + - + message: "#^Parameter \\#1 \\$start of method pocketmine\\\\resourcepacks\\\\ResourcePack\\:\\:getPackChunk\\(\\) expects int\\<0, max\\>, int given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + - message: "#^Parameter \\#3 \\$data of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects string, string\\|false given\\.$#" count: 3 @@ -196,7 +201,7 @@ parameters: path: ../../../src/pocketmine/block/Sugarcane.php - - message: "#^Cannot access offset 'mode' on array\\(0 \\=\\> int, 1 \\=\\> int, 2 \\=\\> int, 3 \\=\\> int, 4 \\=\\> int, 5 \\=\\> int, 6 \\=\\> int, 7 \\=\\> int, \\.\\.\\.\\)\\|false\\.$#" + message: "#^Cannot access offset 'mode' on array\\{0\\: int, 1\\: int, 2\\: int, 3\\: int, 4\\: int, 5\\: int, 6\\: int, 7\\: int, \\.\\.\\.\\}\\|false\\.$#" count: 1 path: ../../../src/pocketmine/command/CommandReader.php @@ -396,12 +401,12 @@ parameters: path: ../../../src/pocketmine/level/Explosion.php - - message: "#^Cannot access offset 'data' on array\\('priority' \\=\\> int, 'data' \\=\\> pocketmine\\\\math\\\\Vector3\\)\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" + message: "#^Cannot access offset 'data' on array\\{priority\\: int, data\\: pocketmine\\\\math\\\\Vector3\\}\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" count: 1 path: ../../../src/pocketmine/level/Level.php - - message: "#^Cannot access offset 'priority' on array\\('priority' \\=\\> int, 'data' \\=\\> pocketmine\\\\math\\\\Vector3\\)\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" + message: "#^Cannot access offset 'priority' on array\\{priority\\: int, data\\: pocketmine\\\\math\\\\Vector3\\}\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" count: 1 path: ../../../src/pocketmine/level/Level.php @@ -551,7 +556,7 @@ parameters: path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - message: "#^Only numeric types are allowed in %%, int\\|false given on the left side\\.$#" + message: "#^Only numeric types are allowed in %%, int\\<0, max\\>\\|false given on the left side\\.$#" count: 1 path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php @@ -581,7 +586,7 @@ parameters: path: ../../../src/pocketmine/level/generator/object/TallGrass.php - - message: "#^Method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:getGameRules\\(\\) should return array\\ but returns array\\\\.$#" + message: "#^Method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:getGameRules\\(\\) should return array\\ but returns array\\\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -606,7 +611,7 @@ parameters: path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - message: "#^Offset 'chain' does not exist on array\\(\\?'chain' \\=\\> array\\\\)\\.$#" + message: "#^Offset 'chain' does not exist on array\\{chain\\?\\: array\\\\}\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php @@ -716,7 +721,7 @@ parameters: path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getPackSize\\(\\) should return int but returns int\\|false\\.$#" + message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getPackSize\\(\\) should return int but returns int\\<0, max\\>\\|false\\.$#" count: 1 path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php diff --git a/tests/phpstan/configs/l8-baseline.neon b/tests/phpstan/configs/l8-baseline.neon index 636f93250..19ca8fa1f 100644 --- a/tests/phpstan/configs/l8-baseline.neon +++ b/tests/phpstan/configs/l8-baseline.neon @@ -970,11 +970,6 @@ parameters: count: 1 path: ../../../src/pocketmine/item/PoisonousPotato.php - - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" - count: 32 - path: ../../../src/pocketmine/item/Potion.php - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" count: 3 diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index d538a89ca..4291463fa 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -1,75 +1,100 @@ parameters: ignoreErrors: - - message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\Player\\)\\: bool given\\.$#" + message: "#^Cannot access offset 'base_version' on mixed\\.$#" count: 1 - path: ../../../src/pocketmine/Server.php + path: ../../../src/pocketmine/CrashDump.php - - message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(string\\)\\: bool given\\.$#" + message: "#^Cannot access offset 'build' on mixed\\.$#" count: 1 - path: ../../../src/pocketmine/Server.php + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset 'composer_libraries' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset 'git' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset 'is_dev' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset 'os' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset 'php' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset 'php_os' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset 'protocol' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset 'uname' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset 'zend' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php - message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#" - count: 3 + count: 2 path: ../../../src/pocketmine/command/CommandReader.php - - - message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\Player\\)\\: bool given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/ListCommand.php - - - - message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\entity\\\\Attribute\\)\\: bool given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/AttributeMap.php - - - - message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\item\\\\Item\\)\\: bool given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Human.php - - message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#" count: 1 path: ../../../src/pocketmine/entity/projectile/Projectile.php - - message: "#^Parameter \\#2 \\$callback of function usort expects callable\\(mixed, mixed\\)\\: int, array\\('pocketmine\\\\\\\\inventory\\\\\\\\CraftingManager', 'sort'\\) given\\.$#" + message: "#^Dead catch \\- ReflectionException is never thrown in the try block\\.$#" count: 1 - path: ../../../src/pocketmine/inventory/CraftingManager.php - - - - message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(string\\)\\: bool given\\.$#" - count: 1 - path: ../../../src/pocketmine/lang/BaseLang.php - - - - message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(pocketmine\\\\entity\\\\Entity\\)\\: bool given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/Chunk.php - - - - message: "#^Parameter \\#2 \\$callback of function array_filter expects \\(callable\\(mixed, mixed\\)\\: bool\\)\\|null, Closure\\(string\\)\\: bool given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php + path: ../../../src/pocketmine/level/format/io/LevelProviderManager.php - message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#" count: 2 path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php - - - message: "#^Parameter \\#2 \\$count of function array_fill expects int\\<0, max\\>, int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/generator/noise/Noise.php - - message: "#^Call to function method_exists\\(\\) with pocketmine\\\\network\\\\mcpe\\\\CachedEncapsulatedPacket and '__toString' will always evaluate to true\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/DataPacket.php + - + message: "#^Parameter \\#1 \\$array of function array_values expects array, array given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Parameter \\#2 \\$array of function array_map expects array, array given\\.$#" + count: 3 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Dead catch \\- ReflectionException is never thrown in the try block\\.$#" + count: 2 + path: ../../../src/pocketmine/utils/Utils.php + - message: "#^Strict comparison using \\=\\=\\= between string and false will always evaluate to false\\.$#" count: 1 diff --git a/tests/phpstan/configs/runtime-type-checks.neon b/tests/phpstan/configs/runtime-type-checks.neon index 8383e39fa..88459daaf 100644 --- a/tests/phpstan/configs/runtime-type-checks.neon +++ b/tests/phpstan/configs/runtime-type-checks.neon @@ -1,77 +1,12 @@ parameters: ignoreErrors: - - - message: "#^Call to function is_subclass_of\\(\\) with class\\-string\\ and 'pocketmine\\\\\\\\level\\\\\\\\generator\\\\\\\\Generator' will always evaluate to true\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^If condition is always true\\.$#" - count: 2 - path: ../../../src/pocketmine/ThreadManager.php - - - - message: "#^Instanceof between pocketmine\\\\Worker and pocketmine\\\\Worker will always evaluate to true\\.$#" - count: 2 - path: ../../../src/pocketmine/ThreadManager.php - - - - message: "#^Instanceof between pocketmine\\\\plugin\\\\RegisteredListener and pocketmine\\\\plugin\\\\RegisteredListener will always evaluate to true\\.$#" - count: 1 - path: ../../../src/pocketmine/event/HandlerList.php - - message: "#^Casting to int something that's already int\\.$#" - count: 3 + count: 2 path: ../../../src/pocketmine/item/Item.php - - - message: "#^Call to function is_object\\(\\) with \\*NEVER\\* will always evaluate to true\\.$#" - count: 1 - path: ../../../src/pocketmine/item/ItemFactory.php - - - - message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" - count: 1 - path: ../../../src/pocketmine/item/ItemFactory.php - - - - message: "#^If condition is always false\\.$#" - count: 1 - path: ../../../src/pocketmine/item/ItemFactory.php - - - - message: "#^Strict comparison using \\!\\=\\= between null and null will always evaluate to false\\.$#" - count: 1 - path: ../../../src/pocketmine/item/ItemFactory.php - - - - message: "#^Call to function is_object\\(\\) with \\*NEVER\\* will always evaluate to true\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Instanceof between pocketmine\\\\math\\\\Vector3 and pocketmine\\\\math\\\\Vector3 will always evaluate to true\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Call to function is_subclass_of\\(\\) with class\\-string\\ and 'pocketmine\\\\\\\\level\\\\\\\\generator\\\\\\\\Generator' will always evaluate to true\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/GeneratorManager.php - - message: "#^Call to function is_array\\(\\) with array\\ will always evaluate to true\\.$#" count: 1 path: ../../../src/pocketmine/plugin/PluginManager.php - - - message: "#^Call to function is_subclass_of\\(\\) with class\\-string\\ and 'pocketmine\\\\\\\\event\\\\\\\\Event' will always evaluate to true\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginManager.php - From 794142fe49d9e602b29d4e835403ddb9d1362bb4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 17:27:31 +0000 Subject: [PATCH 259/710] Merge l7/l8/l9 baselines into actual-problems it doesn't serve any practical purpose to keep these separated, particularly since it's getting so difficult to figure out which errors are coming from which levels (since we always use 9, it doesn't really make any difference). --- phpstan.neon.dist | 3 - tests/phpstan/configs/actual-problems.neon | 3170 +++++++++++++++++ .../check-explicit-mixed-baseline.neon | 767 ---- tests/phpstan/configs/l7-baseline.neon | 807 ----- tests/phpstan/configs/l8-baseline.neon | 1607 --------- 5 files changed, 3170 insertions(+), 3184 deletions(-) delete mode 100644 tests/phpstan/configs/check-explicit-mixed-baseline.neon delete mode 100644 tests/phpstan/configs/l7-baseline.neon delete mode 100644 tests/phpstan/configs/l8-baseline.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 54e7cd6f6..6b559cd86 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,9 +1,6 @@ includes: - tests/phpstan/configs/actual-problems.neon - - tests/phpstan/configs/check-explicit-mixed-baseline.neon - tests/phpstan/configs/gc-hacks.neon - - tests/phpstan/configs/l7-baseline.neon - - tests/phpstan/configs/l8-baseline.neon - tests/phpstan/configs/php-bugs.neon - tests/phpstan/configs/phpstan-bugs.neon - tests/phpstan/configs/phpunit-wiring-tests.neon diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 12a6a1251..796ecf18c 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -1,25 +1,570 @@ parameters: ignoreErrors: + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false given\\.$#" + count: 1 + path: ../../../build/make-release.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" + count: 2 + path: ../../../build/make-release.php + + - + message: "#^Parameter \\#1 \\$pharPath of function pocketmine\\\\build\\\\server_phar\\\\buildPhar expects string, array\\\\|string\\|false given\\.$#" + count: 1 + path: ../../../build/server-phar.php + + - + message: "#^Parameter \\#1 \\$strings of function pocketmine\\\\build\\\\server_phar\\\\preg_quote_array expects array\\, array\\ given\\.$#" + count: 1 + path: ../../../build/server-phar.php + + - + message: "#^Cannot access offset \\(float\\|int\\) on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot access offset string on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + - message: "#^Instanceof between pocketmine\\\\plugin\\\\PluginManager and pocketmine\\\\plugin\\\\PluginManager will always evaluate to true\\.$#" count: 1 path: ../../../src/pocketmine/CrashDump.php + - + message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Utils\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/CrashDump.php + + - + message: "#^Cannot cast mixed to int\\.$#" + count: 7 + path: ../../../src/pocketmine/MemoryManager.php + + - + message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/MemoryManager.php + + - + message: "#^Parameter \\#1 \\$stream of function fwrite expects resource, resource\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/MemoryManager.php + + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'AnimationExpression' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'Colors' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'Frames' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'Image' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'ImageHeight' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'ImageWidth' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'IsDefault' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'PackId' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'PieceId' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'PieceType' on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'ProductId' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access offset 'Type' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access property \\$x on pocketmine\\\\level\\\\Position\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access property \\$y on pocketmine\\\\level\\\\Position\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot access property \\$z on pocketmine\\\\level\\\\Position\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method checkSpawnProtection\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method dropExperience\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method dropItem\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 4 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method equals\\(\\) on pocketmine\\\\utils\\\\UUID\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getAllValues\\(\\) on pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 6 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getChunkEntities\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 4 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getCollisionBlocks\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getDifficulty\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getFloorX\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getFloorY\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getFloorZ\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getFolderName\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getLevelNonNull\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getName\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getNearbyEntities\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getSafeSpawn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getTileAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method getTime\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method isChunkGenerated\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method isInLoadedTerrain\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method populateChunk\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method registerChunkLoader\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method requestChunk\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method sendBlocks\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method sendDifficulty\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method sendTime\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method setSleepTicks\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method unregisterChunkLoader\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot call method useItemOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Cannot cast mixed to int\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Method pocketmine\\\\Player\\:\\:getSpawn\\(\\) should return pocketmine\\\\level\\\\Position but returns pocketmine\\\\level\\\\Position\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + - message: "#^Only booleans are allowed in &&, mixed given on the right side\\.$#" count: 1 path: ../../../src/pocketmine/Player.php + - + message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Only numeric types are allowed in \\-, int\\|null given on the right side\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\$height of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects int, mixed given\\.$#" + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\$level of method pocketmine\\\\entity\\\\Human\\:\\:__construct\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\$pieceId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\$pieceType of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaPieceTintColor constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\$skinId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\$string of function base64_decode expects string, mixed given\\.$#" + count: 7 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\$uuid of method pocketmine\\\\Server\\:\\:updatePlayerListData\\(\\) expects pocketmine\\\\utils\\\\UUID, pocketmine\\\\utils\\\\UUID\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#1 \\.\\.\\.\\$slots of method pocketmine\\\\inventory\\\\BaseInventory\\:\\:addItem\\(\\) expects pocketmine\\\\item\\\\Item, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#10 \\$capeId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#12 \\$armSize of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#13 \\$skinColor of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#17 \\$premium of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#18 \\$persona of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#19 \\$personaCapeOnClassic of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#2 \\$colors of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaPieceTintColor constructor expects array\\, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#2 \\$pieceType of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#2 \\$playFabId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#2 \\$type of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinAnimation constructor expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#2 \\$width of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects int, mixed given\\.$#" + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#3 \\$data of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects string, string\\|false given\\.$#" + count: 3 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#3 \\$frames of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinAnimation constructor expects float, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#3 \\$packId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#3 \\$resourcePatch of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#4 \\$expressionType of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinAnimation constructor expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#4 \\$isDefaultPiece of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects bool, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#5 \\$productId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#7 \\$geometryData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#8 \\$geometryDataEngineVersion of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + + - + message: "#^Parameter \\#9 \\$animationData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/Player.php + - message: "#^pocketmine\\\\Player\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\entity\\\\Human\\.$#" count: 1 path: ../../../src/pocketmine/Player.php + - + message: "#^Binary operation \"\\.\" between array\\\\|string\\|false and '/'\\|'\\\\\\\\' results in an error\\.$#" + count: 2 + path: ../../../src/pocketmine/PocketMine.php + + - + message: "#^Cannot access offset 'git' on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/PocketMine.php + - message: "#^Do\\-while loop condition is always false\\.$#" count: 1 path: ../../../src/pocketmine/PocketMine.php + - + message: "#^Parameter \\#1 \\$haystack of function substr_count expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/PocketMine.php + + - + message: "#^Parameter \\#1 \\$path of function realpath expects string, array\\\\|string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/PocketMine.php + + - + message: "#^Parameter \\#1 \\$path of function realpath expects string, string\\|false given\\.$#" + count: 2 + path: ../../../src/pocketmine/PocketMine.php + + - + message: "#^Parameter \\#1 \\$version1 of function version_compare expects string, string\\|false given\\.$#" + count: 2 + path: ../../../src/pocketmine/PocketMine.php + + - + message: "#^Cannot access offset 'type' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Cannot call method getFolderName\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Cannot call method getSafeSpawn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Cannot call method wait\\(\\) on Threaded\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Cannot cast array\\\\|string\\|false to string\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Cannot cast mixed to float\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Cannot cast mixed to int\\.$#" + count: 7 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Cannot cast mixed to string\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + - message: "#^Instanceof between pocketmine\\\\command\\\\CommandReader and pocketmine\\\\command\\\\CommandReader will always evaluate to true\\.$#" count: 1 @@ -40,6 +585,71 @@ parameters: count: 1 path: ../../../src/pocketmine/Server.php + - + message: "#^Only numeric types are allowed in \\+, int\\|false given on the left side\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#1 \\$array of function array_filter expects array, array\\\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#1 \\$buffer of method pocketmine\\\\nbt\\\\NBTStream\\:\\:readCompressed\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#1 \\$name of static method pocketmine\\\\level\\\\format\\\\io\\\\LevelProviderManager\\:\\:getProviderByName\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#1 \\$string of function strtolower expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#1 \\$uuid of method pocketmine\\\\Server\\:\\:removePlayerListData\\(\\) expects pocketmine\\\\utils\\\\UUID, pocketmine\\\\utils\\\\UUID\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#1 \\$uuid of method pocketmine\\\\Server\\:\\:updatePlayerListData\\(\\) expects pocketmine\\\\utils\\\\UUID, pocketmine\\\\utils\\\\UUID\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#1 \\$uuid of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PlayerListEntry\\:\\:createAdditionEntry\\(\\) expects pocketmine\\\\utils\\\\UUID, pocketmine\\\\utils\\\\UUID\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#2 \\$defaultValue of method pocketmine\\\\Server\\:\\:getConfigString\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#2 \\$endpoint of class pocketmine\\\\updater\\\\AutoUpdater constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#2 \\$reason of method pocketmine\\\\Player\\:\\:close\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/Server.php + + - + message: "#^Method pocketmine\\\\ThreadManager\\:\\:getAll\\(\\) should return array\\ but returns array\\.$#" + count: 1 + path: ../../../src/pocketmine/ThreadManager.php + - message: "#^pocketmine\\\\block\\\\Air\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -50,11 +660,21 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Anvil.php + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/BaseRail.php + - message: "#^pocketmine\\\\block\\\\BaseRail\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 path: ../../../src/pocketmine/block/BaseRail.php + - + message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Bed.php + - message: "#^pocketmine\\\\block\\\\Bed\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -70,11 +690,46 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Beetroot.php + - + message: "#^Cannot call method getBlockMetadata\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 4 + path: ../../../src/pocketmine/block/Block.php + - message: "#^pocketmine\\\\block\\\\Block\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\level\\\\Position\\.$#" count: 1 path: ../../../src/pocketmine/block/Block.php + - + message: "#^Cannot access property \\$level on pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/BlockFactory.php + + - + message: "#^Cannot access property \\$x on pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/BlockFactory.php + + - + message: "#^Cannot access property \\$y on pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/BlockFactory.php + + - + message: "#^Cannot access property \\$z on pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/BlockFactory.php + + - + message: "#^Cannot clone pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/BlockFactory.php + + - + message: "#^Method pocketmine\\\\block\\\\BlockFactory\\:\\:get\\(\\) should return pocketmine\\\\block\\\\Block but returns pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/BlockFactory.php + - message: "#^pocketmine\\\\block\\\\BoneBlock\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -105,16 +760,41 @@ parameters: count: 1 path: ../../../src/pocketmine/block/BurningFurnace.php + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Button.php + - message: "#^pocketmine\\\\block\\\\Button\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 path: ../../../src/pocketmine/block/Button.php + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Cactus.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Cactus.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Cactus.php + - message: "#^pocketmine\\\\block\\\\Cactus\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 path: ../../../src/pocketmine/block/Cactus.php + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Cake.php + - message: "#^pocketmine\\\\block\\\\Cake\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -180,6 +860,11 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Concrete.php + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/ConcretePowder.php + - message: "#^pocketmine\\\\block\\\\ConcretePowder\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -220,6 +905,26 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Dirt.php + - + message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Door.php + + - + message: "#^Cannot call method getDirection\\(\\) on pocketmine\\\\Player\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Door.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Door.php + + - + message: "#^Only numeric types are allowed in \\+, int\\|null given on the left side\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Door.php + - message: "#^pocketmine\\\\block\\\\DoublePlant\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -250,6 +955,11 @@ parameters: count: 1 path: ../../../src/pocketmine/block/EndPortalFrame.php + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/EndRod.php + - message: "#^pocketmine\\\\block\\\\EndRod\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -265,6 +975,21 @@ parameters: count: 1 path: ../../../src/pocketmine/block/EndStoneBricks.php + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Fallable.php + + - + message: "#^Cannot call method getBlockIdAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Farmland.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 4 + path: ../../../src/pocketmine/block/Farmland.php + - message: "#^pocketmine\\\\block\\\\Farmland\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -275,6 +1000,26 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Fence.php + - + message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/FenceGate.php + + - + message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" + count: 2 + path: ../../../src/pocketmine/block/FenceGate.php + + - + message: "#^Cannot call method scheduleDelayedBlockUpdate\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Fire.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Fire.php + - message: "#^pocketmine\\\\block\\\\Fire\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -300,6 +1045,11 @@ parameters: count: 1 path: ../../../src/pocketmine/block/GlassPane.php + - + message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" + count: 1 + path: ../../../src/pocketmine/block/GlazedTerracotta.php + - message: "#^pocketmine\\\\block\\\\GlowingObsidian\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -320,11 +1070,51 @@ parameters: count: 1 path: ../../../src/pocketmine/block/GoldOre.php + - + message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Grass.php + + - + message: "#^Cannot call method getBlockDataAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Grass.php + + - + message: "#^Cannot call method getBlockIdAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Grass.php + + - + message: "#^Cannot call method getFullLightAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Grass.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Grass.php + + - + message: "#^Parameter \\#1 \\$min of function mt_rand expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Grass.php + + - + message: "#^Parameter \\#2 \\$max of function mt_rand expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Grass.php + - message: "#^pocketmine\\\\block\\\\Grass\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 path: ../../../src/pocketmine/block/Grass.php + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/GrassPath.php + - message: "#^pocketmine\\\\block\\\\GrassPath\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -345,6 +1135,16 @@ parameters: count: 1 path: ../../../src/pocketmine/block/HayBale.php + - + message: "#^Cannot call method getHighestAdjacentBlockLight\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Ice.php + + - + message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Ice.php + - message: "#^pocketmine\\\\block\\\\Ice\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -375,11 +1175,31 @@ parameters: count: 1 path: ../../../src/pocketmine/block/IronOre.php + - + message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/block/ItemFrame.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/ItemFrame.php + + - + message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/ItemFrame.php + - message: "#^pocketmine\\\\block\\\\ItemFrame\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 path: ../../../src/pocketmine/block/ItemFrame.php + - + message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Ladder.php + - message: "#^pocketmine\\\\block\\\\Ladder\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -405,11 +1225,76 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Leaves.php + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Lever.php + + - + message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Lever.php + - message: "#^pocketmine\\\\block\\\\Lever\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 path: ../../../src/pocketmine/block/Lever.php + - + message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 25 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Cannot call method scheduleDelayedBlockUpdate\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 4 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Parameter \\#1 \\$blockX of method pocketmine\\\\block\\\\Liquid\\:\\:calculateFlowCost\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Parameter \\#2 \\$blockY of method pocketmine\\\\block\\\\Liquid\\:\\:calculateFlowCost\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Parameter \\#3 \\$blockZ of method pocketmine\\\\block\\\\Liquid\\:\\:calculateFlowCost\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Liquid.php + + - + message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Liquid.php + - message: "#^pocketmine\\\\block\\\\Magma\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -430,6 +1315,16 @@ parameters: count: 1 path: ../../../src/pocketmine/block/MonsterSpawner.php + - + message: "#^Parameter \\#1 \\$min of function mt_rand expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Mycelium.php + + - + message: "#^Parameter \\#2 \\$max of function mt_rand expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/block/Mycelium.php + - message: "#^pocketmine\\\\block\\\\Mycelium\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -565,6 +1460,26 @@ parameters: count: 1 path: ../../../src/pocketmine/block/SandstoneStairs.php + - + message: "#^Cannot call method getFullLightAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Sapling.php + + - + message: "#^Parameter \\#2 \\$x of static method pocketmine\\\\level\\\\generator\\\\object\\\\Tree\\:\\:growTree\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Sapling.php + + - + message: "#^Parameter \\#3 \\$y of static method pocketmine\\\\level\\\\generator\\\\object\\\\Tree\\:\\:growTree\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Sapling.php + + - + message: "#^Parameter \\#4 \\$z of static method pocketmine\\\\level\\\\generator\\\\object\\\\Tree\\:\\:growTree\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Sapling.php + - message: "#^pocketmine\\\\block\\\\Sapling\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -580,6 +1495,11 @@ parameters: count: 1 path: ../../../src/pocketmine/block/SignPost.php + - + message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Skull.php + - message: "#^pocketmine\\\\block\\\\Skull\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -595,6 +1515,11 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Snow.php + - + message: "#^Cannot call method getBlockLightAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/SnowLayer.php + - message: "#^pocketmine\\\\block\\\\SnowLayer\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -610,6 +1535,11 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Sponge.php + - + message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/StandingBanner.php + - message: "#^pocketmine\\\\block\\\\StandingBanner\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -640,6 +1570,21 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Stonecutter.php + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Sugarcane.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Sugarcane.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/block/Sugarcane.php + - message: "#^pocketmine\\\\block\\\\Sugarcane\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -660,6 +1605,11 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Torch.php + - + message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Trapdoor.php + - message: "#^pocketmine\\\\block\\\\Trapdoor\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -675,6 +1625,16 @@ parameters: count: 1 path: ../../../src/pocketmine/block/TripwireHook.php + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Vine.php + + - + message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/block/Vine.php + - message: "#^pocketmine\\\\block\\\\Vine\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\block\\\\Block\\.$#" count: 1 @@ -710,6 +1670,551 @@ parameters: count: 1 path: ../../../src/pocketmine/block/Wool.php + - + message: "#^Parameter \\#2 \\$replace of function str_replace expects array\\|string, string\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/Command.php + + - + message: "#^Cannot access offset 'mode' on array\\{0\\: int, 1\\: int, 2\\: int, 3\\: int, 4\\: int, 5\\: int, 6\\: int, 7\\: int, \\.\\.\\.\\}\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/command/CommandReader.php + + - + message: "#^Cannot cast mixed to string\\.$#" + count: 1 + path: ../../../src/pocketmine/command/CommandReader.php + + - + message: "#^Parameter \\#1 \\$stream of method pocketmine\\\\command\\\\CommandReader\\:\\:isPipe\\(\\) expects resource, resource\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/CommandReader.php + + - + message: "#^Static property pocketmine\\\\command\\\\CommandReader\\:\\:\\$stdin \\(resource\\) does not accept resource\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/command/CommandReader.php + + - + message: "#^Cannot call method startTiming\\(\\) on pocketmine\\\\timings\\\\TimingsHandler\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/command/SimpleCommandMap.php + + - + message: "#^Cannot call method stopTiming\\(\\) on pocketmine\\\\timings\\\\TimingsHandler\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/command/SimpleCommandMap.php + + - + message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/BanIpCommand.php + + - + message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/PardonIpCommand.php + + - + message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/ParticleCommand.php + + - + message: "#^Cannot call method getSeed\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/SeedCommand.php + + - + message: "#^Cannot call method setSpawnLocation\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/SetWorldSpawnCommand.php + + - + message: "#^Parameter \\#1 \\$num of function round expects float\\|int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/StatusCommand.php + + - + message: "#^Cannot call method getTime\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/TimeCommand.php + + - + message: "#^Cannot access offset 0 on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/command/defaults/TimingsCommand.php + + - + message: "#^Parameter \\#1 \\$fp of static method pocketmine\\\\timings\\\\TimingsHandler\\:\\:printTimings\\(\\) expects resource, resource\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/TimingsCommand.php + + - + message: "#^Parameter \\#1 \\$json of function json_decode expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/TimingsCommand.php + + - + message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" + count: 2 + path: ../../../src/pocketmine/command/defaults/TimingsCommand.php + + - + message: "#^Parameter \\#1 \\$stream of function fseek expects resource, resource\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/TimingsCommand.php + + - + message: "#^Parameter \\#1 \\$stream of function stream_get_contents expects resource, resource\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/TimingsCommand.php + + - + message: "#^Parameter \\#2 \\$host of class class@anonymous/src/pocketmine/command/defaults/TimingsCommand\\.php\\:126 constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/TimingsCommand.php + + - + message: "#^Parameter \\#4 \\$data of class class@anonymous/src/pocketmine/command/defaults/TimingsCommand\\.php\\:126 constructor expects array\\, array\\ given\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/TimingsCommand.php + + - + message: "#^Cannot cast mixed to float\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/VanillaCommand.php + + - + message: "#^Cannot cast mixed to int\\.$#" + count: 1 + path: ../../../src/pocketmine/command/defaults/VanillaCommand.php + + - + message: "#^Cannot call method getValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 4 + path: ../../../src/pocketmine/entity/Effect.php + + - + message: "#^Cannot call method setValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 4 + path: ../../../src/pocketmine/entity/Effect.php + + - + message: "#^Parameter \\#1 \\$id of static method pocketmine\\\\entity\\\\Effect\\:\\:getEffect\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Effect.php + + - + message: "#^Array \\(array\\, string\\>\\) does not accept string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot access property \\$updateEntities on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method addEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method addEntity\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method broadcastPacketToViewers\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getAllValues\\(\\) on pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 4 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getBlockIdAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 7 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getChunk\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getChunkAtPosition\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getCollisionBlocks\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getCollisionCubes\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 4 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getTickRateTime\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method getViewersForPosition\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method removeEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method setValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot cast mixed to int\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Method pocketmine\\\\entity\\\\Entity\\:\\:getNameTag\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Method pocketmine\\\\entity\\\\Entity\\:\\:getScale\\(\\) should return float but returns float\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Only booleans are allowed in a negated boolean, bool\\|null given\\.$#" + count: 6 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Only booleans are allowed in an if condition, bool\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Parameter \\#1 \\$fireTicks of method pocketmine\\\\entity\\\\Entity\\:\\:setFireTicks\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Parameter \\#2 \\$originLevel of class pocketmine\\\\event\\\\entity\\\\EntityLevelChangeEvent constructor expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setShort\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Entity.php + + - + message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Cannot call method getDifficulty\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Cannot call method getMaxValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Cannot call method getMinValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Cannot call method getValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 8 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Cannot call method setValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 6 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Parameter \\#1 \\$attribute of method pocketmine\\\\entity\\\\AttributeMap\\:\\:addAttribute\\(\\) expects pocketmine\\\\entity\\\\Attribute, pocketmine\\\\entity\\\\Attribute\\|null given\\.$#" + count: 5 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" + count: 3 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Parameter \\#1 \\$index of method pocketmine\\\\inventory\\\\BaseInventory\\:\\:setItem\\(\\) expects int, int\\|string given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddPlayerPacket\\:\\:\\$uuid \\(pocketmine\\\\utils\\\\UUID\\) does not accept pocketmine\\\\utils\\\\UUID\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\PlayerSkinPacket\\:\\:\\$uuid \\(pocketmine\\\\utils\\\\UUID\\) does not accept pocketmine\\\\utils\\\\UUID\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Human.php + + - + message: "#^Cannot call method attack\\(\\) on pocketmine\\\\entity\\\\Entity\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Cannot call method dropExperience\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Cannot call method getEffectLevel\\(\\) on pocketmine\\\\entity\\\\EffectInstance\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Cannot call method getMaxValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Cannot call method getValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Cannot call method setMaxValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Cannot call method setValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Method pocketmine\\\\entity\\\\Living\\:\\:getAirSupplyTicks\\(\\) should return int but returns int\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Method pocketmine\\\\entity\\\\Living\\:\\:getMaxAirSupplyTicks\\(\\) should return int but returns int\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Parameter \\#1 \\$attribute of method pocketmine\\\\entity\\\\AttributeMap\\:\\:addAttribute\\(\\) expects pocketmine\\\\entity\\\\Attribute, pocketmine\\\\entity\\\\Attribute\\|null given\\.$#" + count: 6 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Parameter \\#2 \\$entity of class pocketmine\\\\event\\\\entity\\\\EntityDamageByEntityEvent constructor expects pocketmine\\\\entity\\\\Entity, pocketmine\\\\entity\\\\Entity\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Living.php + + - + message: "#^Method pocketmine\\\\entity\\\\Villager\\:\\:getProfession\\(\\) should return int but returns int\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/Villager.php + + - + message: "#^Cannot call method getEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/ExperienceOrb.php + + - + message: "#^Cannot call method getNearestEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/ExperienceOrb.php + + - + message: "#^Cannot call method getBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/FallingBlock.php + + - + message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/Painting.php + + - + message: "#^Cannot call method dropItem\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/Painting.php + + - + message: "#^Method pocketmine\\\\entity\\\\object\\\\Painting\\:\\:getMotive\\(\\) should return pocketmine\\\\entity\\\\object\\\\PaintingMotive but returns pocketmine\\\\entity\\\\object\\\\PaintingMotive\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/Painting.php + + - + message: "#^Parameter \\#1 \\$level of static method pocketmine\\\\entity\\\\object\\\\Painting\\:\\:canFit\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/Painting.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/Painting.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/Painting.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/Painting.php + + - + message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/object/PrimedTNT.php + + - + message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/Arrow.php + + - + message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/Egg.php + + - + message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/projectile/EnderPearl.php + + - + message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/EnderPearl.php + + - + message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/ExperienceBottle.php + + - + message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/ExperienceBottle.php + + - + message: "#^Cannot call method dropExperience\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/ExperienceBottle.php + + - + message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/projectile/Projectile.php + + - + message: "#^Cannot call method getCollidingEntities\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/Projectile.php + + - + message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setByte\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/Projectile.php + + - + message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/entity/projectile/Projectile.php + + - + message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/Projectile.php + + - + message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/Snowball.php + + - + message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/SplashPotion.php + + - + message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/SplashPotion.php + + - + message: "#^Cannot call method getNearbyEntities\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/entity/projectile/SplashPotion.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/entity/projectile/SplashPotion.php + + - + message: "#^Method pocketmine\\\\event\\\\EventPriority\\:\\:fromString\\(\\) should return int but returns mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/event/EventPriority.php + + - + message: "#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\\\|T of object, string given\\.$#" + count: 1 + path: ../../../src/pocketmine/event/HandlerList.php + + - + message: "#^Cannot call method getEffectLevel\\(\\) on pocketmine\\\\entity\\\\EffectInstance\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/event/entity/EntityDamageByEntityEvent.php + - message: "#^Property pocketmine\\\\event\\\\entity\\\\EntityShootBowEvent\\:\\:\\$projectile \\(pocketmine\\\\entity\\\\projectile\\\\Projectile\\) does not accept pocketmine\\\\entity\\\\Entity\\.$#" count: 1 @@ -725,6 +2230,21 @@ parameters: count: 1 path: ../../../src/pocketmine/inventory/ChestInventory.php + - + message: "#^Method pocketmine\\\\inventory\\\\CraftingManager\\:\\:getCraftingDataPacket\\(\\) should return pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket but returns pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/CraftingManager.php + + - + message: "#^Method pocketmine\\\\inventory\\\\CraftingManager\\:\\:hashOutputs\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/CraftingManager.php + + - + message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/CraftingManager.php + - message: "#^pocketmine\\\\inventory\\\\DoubleChestInventory\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\inventory\\\\ChestInventory\\.$#" count: 1 @@ -755,16 +2275,366 @@ parameters: count: 1 path: ../../../src/pocketmine/inventory/MultiRecipe.php + - + message: "#^Parameter \\#2 \\$recipe of class pocketmine\\\\event\\\\inventory\\\\CraftItemEvent constructor expects pocketmine\\\\inventory\\\\CraftingRecipe, pocketmine\\\\inventory\\\\CraftingRecipe\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/transaction/CraftingTransaction.php + + - + message: "#^Parameter \\#3 \\$repetitions of class pocketmine\\\\event\\\\inventory\\\\CraftItemEvent constructor expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/inventory/transaction/CraftingTransaction.php + + - + message: "#^Cannot call method count\\(\\) on pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/item/Banner.php + + - + message: "#^Cannot call method isset\\(\\) on pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/item/Banner.php + + - + message: "#^Cannot call method spawnToAll\\(\\) on pocketmine\\\\entity\\\\Entity\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/item/Bow.php + + - + message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" + count: 2 + path: ../../../src/pocketmine/item/GoldenApple.php + + - + message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" + count: 4 + path: ../../../src/pocketmine/item/GoldenAppleEnchanted.php + - message: "#^pocketmine\\\\item\\\\GoldenAppleEnchanted\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\item\\\\GoldenApple\\.$#" count: 1 path: ../../../src/pocketmine/item/GoldenAppleEnchanted.php + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../../src/pocketmine/item/Item.php + + - + message: "#^Method pocketmine\\\\item\\\\Item\\:\\:writeCompoundTag\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/item/Item.php + + - + message: "#^Parameter \\#1 \\$data of static method pocketmine\\\\item\\\\Item\\:\\:jsonDeserialize\\(\\) expects array\\{id\\: int, damage\\?\\: int, count\\?\\: int, nbt\\?\\: string, nbt_hex\\?\\: string, nbt_b64\\?\\: string\\}, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/Item.php + + - + message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/Item.php + + - + message: "#^Parameter \\#1 \\$object of function get_class expects object, pocketmine\\\\nbt\\\\tag\\\\NamedTag\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/Item.php + + - + message: "#^Parameter \\#1 \\$id of static method pocketmine\\\\item\\\\ItemFactory\\:\\:get\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/ItemFactory.php + + - + message: "#^Parameter \\#1 \\$level of static method pocketmine\\\\entity\\\\object\\\\Painting\\:\\:canFit\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/PaintingItem.php + + - + message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/PoisonousPotato.php + + - + message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" + count: 3 + path: ../../../src/pocketmine/item/Pufferfish.php + + - + message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/RawChicken.php + + - + message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/RottenFlesh.php + + - + message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/SpiderEye.php + + - + message: "#^Parameter \\#2 \\$pageText of method pocketmine\\\\item\\\\WritableBook\\:\\:setPageText\\(\\) expects string, string\\|null given\\.$#" + count: 2 + path: ../../../src/pocketmine/item/WritableBook.php + - message: "#^pocketmine\\\\item\\\\WrittenBook\\:\\:__construct\\(\\) does not call parent constructor from pocketmine\\\\item\\\\WritableBook\\.$#" count: 1 path: ../../../src/pocketmine/item/WrittenBook.php + - + message: "#^Parameter \\#1 \\$id of static method pocketmine\\\\item\\\\enchantment\\\\Enchantment\\:\\:getEnchantment\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/item/enchantment/Enchantment.php + + - + message: "#^Method pocketmine\\\\item\\\\enchantment\\\\EnchantmentList\\:\\:getSlot\\(\\) should return pocketmine\\\\item\\\\enchantment\\\\EnchantmentEntry but returns pocketmine\\\\item\\\\enchantment\\\\EnchantmentEntry\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/item/enchantment/EnchantmentList.php + + - + message: "#^Parameter \\#2 \\$array of function array_map expects array, array\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/lang/BaseLang.php + + - + message: "#^Cannot call method getBlockData\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Cannot call method getBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Only numeric types are allowed in /, float\\|null given on the left side\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:setBlockDataAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:setBlockIdAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:setBlockDataAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:setBlockIdAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:setBlockDataAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:setBlockIdAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Explosion.php + + - + message: "#^Cannot access offset 'data' on array\\{priority\\: int, data\\: pocketmine\\\\math\\\\Vector3\\}\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot access offset 'priority' on array\\{priority\\: int, data\\: pocketmine\\\\math\\\\Vector3\\}\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot access property \\$level on pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot access property \\$x on pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot access property \\$y on pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot access property \\$z on pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method getBlockData\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method getBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method getBlockLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method getBlockSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method getFullBlock\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method getHeightMap\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method getHighestBlockAt\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method isPopulated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method recalculateHeightMapColumn\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method setBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method setBlockData\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method setBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method setBlockLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method setBlockSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot call method setHeightMap\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot cast mixed to int\\.$#" + count: 3 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Cannot clone pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) should return pocketmine\\\\block\\\\Block but returns pocketmine\\\\block\\\\Block\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + - message: "#^Only booleans are allowed in &&, mixed given on the right side\\.$#" count: 1 @@ -775,11 +2645,341 @@ parameters: count: 1 path: ../../../src/pocketmine/level/Level.php + - + message: "#^Only numeric types are allowed in \\-, int\\|null given on the right side\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#1 \\$chunk of method pocketmine\\\\Player\\:\\:onChunkChanged\\(\\) expects pocketmine\\\\level\\\\format\\\\Chunk, pocketmine\\\\level\\\\format\\\\Chunk\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#1 \\$keys of function array_fill_keys expects array, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getFullBlock\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + count: 4 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:updateBlockLight\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:updateBlockSkyLight\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:chunkBlockHash\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#2 \\$chunk of class pocketmine\\\\level\\\\generator\\\\PopulationTask constructor expects pocketmine\\\\level\\\\format\\\\Chunk, pocketmine\\\\level\\\\format\\\\Chunk\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getFullBlock\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + count: 4 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:updateBlockLight\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:updateBlockSkyLight\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\level\\\\Level\\:\\:chunkBlockHash\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getFullBlock\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + count: 4 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:updateBlockLight\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:updateBlockSkyLight\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\level\\\\Level\\:\\:chunkBlockHash\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Parameter \\#4 \\$newLevel of method pocketmine\\\\level\\\\light\\\\LightUpdate\\:\\:setAndUpdateLight\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UpdateBlockPacket\\:\\:\\$x \\(int\\) does not accept float\\|int\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UpdateBlockPacket\\:\\:\\$y \\(int\\) does not accept float\\|int\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UpdateBlockPacket\\:\\:\\$z \\(int\\) does not accept float\\|int\\.$#" + count: 2 + path: ../../../src/pocketmine/level/Level.php + + - + message: "#^Method pocketmine\\\\level\\\\biome\\\\Biome\\:\\:getBiome\\(\\) should return pocketmine\\\\level\\\\biome\\\\Biome but returns pocketmine\\\\level\\\\biome\\\\Biome\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/biome/Biome.php + + - + message: "#^Cannot call method networkSerialize\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/Chunk.php + + - + message: "#^Method pocketmine\\\\level\\\\format\\\\Chunk\\:\\:getHeightMap\\(\\) should return int but returns int\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/Chunk.php + + - + message: "#^Method pocketmine\\\\level\\\\format\\\\Chunk\\:\\:getSubChunk\\(\\) should return pocketmine\\\\level\\\\format\\\\SubChunkInterface but returns pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/Chunk.php + - message: "#^Only booleans are allowed in \\|\\|, bool\\|null given on the right side\\.$#" count: 1 path: ../../../src/pocketmine/level/format/Chunk.php + - + message: "#^Property pocketmine\\\\level\\\\format\\\\io\\\\BaseLevelProvider\\:\\:\\$levelData \\(pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\) does not accept pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/BaseLevelProvider.php + + - + message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/ChunkRequestTask.php + + - + message: "#^Cannot cast mixed to string\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Parameter \\#2 \\$string of function explode expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Parameter \\#2 \\$value of class pocketmine\\\\nbt\\\\tag\\\\StringTag constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Parameter \\#2 \\$value of method LevelDB\\:\\:put\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Cannot call method getByte\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/region/Anvil.php + + - + message: "#^Cannot call method getByteArray\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/Anvil.php + + - + message: "#^Cannot call method getInt\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/region/Anvil.php + + - + message: "#^Cannot call method getIntArray\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/region/Anvil.php + + - + message: "#^Cannot call method getListTag\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/level/format/io/region/Anvil.php + + - + message: "#^Cannot call method hasTag\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/level/format/io/region/Anvil.php + + - + message: "#^Method pocketmine\\\\level\\\\format\\\\io\\\\region\\\\Anvil\\:\\:nbtSerialize\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/Anvil.php + + - + message: "#^Parameter \\#2 \\$list of static method pocketmine\\\\level\\\\format\\\\io\\\\region\\\\McRegion\\:\\:getCompoundList\\(\\) expects pocketmine\\\\nbt\\\\tag\\\\ListTag, pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/region/Anvil.php + + - + message: "#^Cannot call method getBlockDataColumn\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method getBlockIdColumn\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method getBlockLightColumn\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method getBlockSkyLightColumn\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method getByte\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method getByteArray\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 6 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method getInt\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method getIntArray\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method getListTag\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method hasTag\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + count: 10 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method readChunk\\(\\) on pocketmine\\\\level\\\\format\\\\io\\\\region\\\\RegionLoader\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot call method writeChunk\\(\\) on pocketmine\\\\level\\\\format\\\\io\\\\region\\\\RegionLoader\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Cannot cast mixed to string\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Method pocketmine\\\\level\\\\format\\\\io\\\\region\\\\McRegion\\:\\:nbtSerialize\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Parameter \\#1 \\$array of function array_filter expects array, array\\\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Parameter \\#2 \\$list of static method pocketmine\\\\level\\\\format\\\\io\\\\region\\\\McRegion\\:\\:getCompoundList\\(\\) expects pocketmine\\\\nbt\\\\tag\\\\ListTag, pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Parameter \\#2 \\$value of class pocketmine\\\\nbt\\\\tag\\\\StringTag constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/McRegion.php + + - + message: "#^Only numeric types are allowed in %%, int\\<0, max\\>\\|false given on the left side\\.$#" + count: 1 + path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php + - message: "#^Parameter \\#2 \\$length of function fread expects int\\<0, max\\>, int given\\.$#" count: 1 @@ -790,26 +2990,181 @@ parameters: count: 1 path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php + - + message: "#^Property pocketmine\\\\level\\\\generator\\\\Flat\\:\\:\\$preset \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/Flat.php + + - + message: "#^Cannot call method fastSerialize\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method getAsyncWorkerId\\(\\) on pocketmine\\\\scheduler\\\\AsyncWorker\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method getX\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 5 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method getZ\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 5 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method hasChanged\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method isGenerated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method populateSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method recalculateHeightMap\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method setGenerated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method setLightPopulated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + + - + message: "#^Cannot call method setPopulated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/PopulationTask.php + - message: "#^Variable property access on \\$this\\(pocketmine\\\\level\\\\generator\\\\PopulationTask\\)\\.$#" count: 4 path: ../../../src/pocketmine/level/generator/PopulationTask.php + - + message: "#^Method pocketmine\\\\level\\\\generator\\\\biome\\\\BiomeSelector\\:\\:pickBiome\\(\\) should return pocketmine\\\\level\\\\biome\\\\Biome but returns pocketmine\\\\level\\\\biome\\\\Biome\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/biome/BiomeSelector.php + + - + message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/hell/Nether.php + + - + message: "#^Cannot call method setBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/hell/Nether.php + + - + message: "#^Cannot call method setBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/level/generator/hell/Nether.php + - message: "#^Constructor of class pocketmine\\\\level\\\\generator\\\\hell\\\\Nether has an unused parameter \\$options\\.$#" count: 1 path: ../../../src/pocketmine/level/generator/hell/Nether.php + - + message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/normal/Normal.php + + - + message: "#^Cannot call method setBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/normal/Normal.php + + - + message: "#^Cannot call method setBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 3 + path: ../../../src/pocketmine/level/generator/normal/Normal.php + - message: "#^Constructor of class pocketmine\\\\level\\\\generator\\\\normal\\\\Normal has an unused parameter \\$options\\.$#" count: 1 path: ../../../src/pocketmine/level/generator/normal/Normal.php + - + message: "#^Offset int does not exist on array\\\\>\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/normal/Normal.php + - message: "#^Property pocketmine\\\\level\\\\generator\\\\object\\\\Pond\\:\\:\\$random is never read, only written\\.$#" count: 1 path: ../../../src/pocketmine/level/generator/object/Pond.php + - + message: "#^Only booleans are allowed in a negated boolean, bool\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/object/SpruceTree.php + + - + message: "#^Parameter \\#1 \\$start of method pocketmine\\\\utils\\\\Random\\:\\:nextRange\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/generator/object/TallGrass.php + + - + message: "#^Parameter \\#2 \\$end of method pocketmine\\\\utils\\\\Random\\:\\:nextRange\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/generator/object/TallGrass.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\ChunkManager\\:\\:getBlockIdAt\\(\\) expects int, float\\|int given\\.$#" + count: 2 + path: ../../../src/pocketmine/level/generator/object/TallGrass.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\ChunkManager\\:\\:setBlockDataAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/object/TallGrass.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\ChunkManager\\:\\:setBlockIdAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/object/TallGrass.php + + - + message: "#^Only booleans are allowed in a negated boolean, bool\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/object/Tree.php + + - + message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/populator/GroundCover.php + + - + message: "#^Cannot call method getBlockIdColumn\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/populator/GroundCover.php + + - + message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/populator/GroundCover.php + + - + message: "#^Cannot call method setBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/generator/populator/GroundCover.php + - message: "#^Property pocketmine\\\\level\\\\generator\\\\populator\\\\Pond\\:\\:\\$lavaOdd is never read, only written\\.$#" count: 1 @@ -820,43 +3175,858 @@ parameters: count: 1 path: ../../../src/pocketmine/level/generator/populator/Pond.php + - + message: "#^Cannot call method getBlockLight\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/light/BlockLightUpdate.php + + - + message: "#^Cannot call method setBlockLight\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/light/BlockLightUpdate.php + + - + message: "#^Cannot call method getBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/light/LightUpdate.php + + - + message: "#^Only numeric types are allowed in \\-, int\\|null given on the right side\\.$#" + count: 1 + path: ../../../src/pocketmine/level/light/LightUpdate.php + + - + message: "#^Cannot call method getBlockSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/light/SkyLightUpdate.php + + - + message: "#^Cannot call method setBlockSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/level/light/SkyLightUpdate.php + - message: "#^Method pocketmine\\\\metadata\\\\MetadataStore\\:\\:getMetadataInternal\\(\\) should return array\\ but returns SplObjectStorage\\\\.$#" count: 1 path: ../../../src/pocketmine/metadata/MetadataStore.php + - + message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/CompressBatchedTask.php + + - + message: "#^Cannot access property \\$x on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Cannot access property \\$y on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Cannot access property \\$z on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:getGameRules\\(\\) should return array\\ but returns array\\\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$data of method pocketmine\\\\nbt\\\\NBTStream\\:\\:write\\(\\) expects array\\\\|pocketmine\\\\nbt\\\\tag\\\\NamedTag, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" + count: 2 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putString\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putBool\\(\\) expects bool, bool\\|float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putByte\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putLFloat\\(\\) expects float, bool\\|float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putLFloat\\(\\) expects float, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putLShort\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putUnsignedVarInt\\(\\) expects int, bool\\|float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putVarInt\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putVarLong\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Parameter \\#1 \\$vector of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putVector3Nullable\\(\\) expects pocketmine\\\\math\\\\Vector3\\|null, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php + + - + message: "#^Cannot access offset 'down' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php + + - + message: "#^Cannot access offset 'up' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php + + - + message: "#^Cannot cast mixed to int\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php + + - + message: "#^Parameter \\#1 \\$upload of method pocketmine\\\\network\\\\Network\\:\\:addStatistics\\(\\) expects float, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php + + - + message: "#^Parameter \\#2 \\$download of method pocketmine\\\\network\\\\Network\\:\\:addStatistics\\(\\) expects float, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php + + - + message: "#^Cannot access offset 'exp' on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Cannot access offset 'identityPublicKey' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Cannot access offset 'nbf' on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Cannot access offset 'x5u' on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Cannot use array destructuring on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Offset 'chain' does not exist on array\\{chain\\?\\: array\\\\}\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" + count: 2 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Parameter \\#1 \\$string of function str_split expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" + count: 2 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Parameter \\#1 \\$string of function wordwrap expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php + + - + message: "#^Argument of an invalid type array\\\\|null supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php + + - + message: "#^Cannot access offset string on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php + + - + message: "#^Method pocketmine\\\\network\\\\mcpe\\\\convert\\\\RuntimeBlockMapping\\:\\:getBedrockKnownStates\\(\\) should return array\\ but returns array\\\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php + + - + message: "#^Offset mixed does not exist on array\\\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php + + - + message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream constructor expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php + + - + message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php + + - + message: "#^Parameter \\#2 \\$legacyId of static method pocketmine\\\\network\\\\mcpe\\\\convert\\\\RuntimeBlockMapping\\:\\:registerMapping\\(\\) expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddActorPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/AddActorPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddItemActorPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/AddItemActorPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddPlayerPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/AddPlayerPacket.php + + - + message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/AddVolumeEntityPacket.php + + - + message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/AvailableActorIdentifiersPacket.php + - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AvailableActorIdentifiersPacket\\:\\:\\$namedtag \\(string\\) on left side of \\?\\? is not nullable\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/AvailableActorIdentifiersPacket.php + - + message: "#^Static property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AvailableActorIdentifiersPacket\\:\\:\\$DEFAULT_NBT_CACHE \\(string\\|null\\) does not accept string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/AvailableActorIdentifiersPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket\\:\\:\\$payload \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/BatchPacket.php + + - + message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/BiomeDefinitionListPacket.php + - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BiomeDefinitionListPacket\\:\\:\\$namedtag \\(string\\) on left side of \\?\\? is not nullable\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/BiomeDefinitionListPacket.php + - + message: "#^Static property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BiomeDefinitionListPacket\\:\\:\\$DEFAULT_NBT_CACHE \\(string\\|null\\) does not accept string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/BiomeDefinitionListPacket.php + + - + message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/ItemComponentPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LevelEventGenericPacket\\:\\:\\$eventData \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LevelEventGenericPacket.php + + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Cannot access offset 'XUID' on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Cannot access offset 'chain' on mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Cannot access offset 'displayName' on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Cannot access offset 'identity' on mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Parameter \\#1 \\$token of static method pocketmine\\\\utils\\\\Utils\\:\\:decodeJWT\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$chainData \\(array\\{chain\\?\\: array\\\\}\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$clientId \\(int\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$clientUUID \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$identityPublicKey \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$locale \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$serverAddress \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$username \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$xuid \\(string\\|null\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php + + - + message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/PositionTrackingDBServerBroadcastPacket.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\SetActorDataPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/SetActorDataPacket.php + + - + message: "#^Parameter \\#1 \\$eid of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putEntityUniqueId\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/SetScorePacket.php + + - + message: "#^Parameter \\#1 \\$v of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putString\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/SetScorePacket.php + + - + message: "#^Parameter \\#1 \\$eid of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putEntityUniqueId\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/SetScoreboardIdentityPacket.php + + - + message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/StartGamePacket.php + + - + message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/SyncActorPropertyPacket.php + - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UnknownPacket\\:\\:\\$payload \\(string\\) on left side of \\?\\? is not nullable\\.$#" count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/UnknownPacket.php + - + message: "#^Parameter \\#3 \\$resourcePatch of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/types/LegacySkinAdapter.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putBlockPosition\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/types/inventory/UseItemTransactionData.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putBlockPosition\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/types/inventory/UseItemTransactionData.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putBlockPosition\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/protocol/types/inventory/UseItemTransactionData.php + + - + message: "#^Cannot call method wakeupSleeper\\(\\) on pocketmine\\\\snooze\\\\SleeperNotifier\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/network/rcon/RCONInstance.php + + - + message: "#^Method pocketmine\\\\permission\\\\DefaultPermissions\\:\\:registerPermission\\(\\) should return pocketmine\\\\permission\\\\Permission but returns pocketmine\\\\permission\\\\Permission\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/permission/DefaultPermissions.php + + - + message: "#^Parameter \\#1 \\$value of static method pocketmine\\\\permission\\\\Permission\\:\\:getByName\\(\\) expects bool\\|string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/permission/Permission.php + + - + message: "#^Parameter \\#2 \\$description of class pocketmine\\\\permission\\\\Permission constructor expects string\\|null, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/permission/Permission.php + - message: "#^Variable method call on pocketmine\\\\event\\\\Listener\\.$#" count: 1 path: ../../../src/pocketmine/plugin/MethodEventExecutor.php + - + message: "#^Method pocketmine\\\\plugin\\\\PluginBase\\:\\:getConfig\\(\\) should return pocketmine\\\\utils\\\\Config but returns pocketmine\\\\utils\\\\Config\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginBase.php + + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Array \\(array\\\\) does not accept mixed\\.$#" + count: 2 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Cannot cast mixed to string\\.$#" + count: 4 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Parameter \\#1 \\$data of static method pocketmine\\\\permission\\\\Permission\\:\\:loadPermissions\\(\\) expects array\\\\>, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Parameter \\#1 \\$haystack of function stripos expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Parameter \\#1 \\$plugin of method pocketmine\\\\plugin\\\\PluginDescription\\:\\:loadMap\\(\\) expects array, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Parameter \\#1 \\$string of function mb_strtoupper expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$depend \\(array\\\\) does not accept array\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$loadBefore \\(array\\\\) does not accept array\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$main \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$name \\(string\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$order \\(int\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$softDepend \\(array\\\\) does not accept array\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginDescription.php + + - + message: "#^Parameter \\#1 \\$description of method pocketmine\\\\command\\\\Command\\:\\:setDescription\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginManager.php + + - + message: "#^Parameter \\#1 \\$permissionMessage of method pocketmine\\\\command\\\\Command\\:\\:setPermissionMessage\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginManager.php + + - + message: "#^Parameter \\#1 \\$usage of method pocketmine\\\\command\\\\Command\\:\\:setUsage\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/PluginManager.php + + - + message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getPackChunk\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + + - + message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getPackSize\\(\\) should return int but returns int\\<0, max\\>\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + + - + message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getSha256\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + + - + message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" + count: 2 + path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + + - + message: "#^Parameter \\#2 \\$code of class pocketmine\\\\resourcepacks\\\\ResourcePackException constructor expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + - message: "#^Parameter \\#2 \\$length of function fread expects int\\<0, max\\>, int given\\.$#" count: 1 path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + + - + message: "#^Property pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:\\$fileResource \\(resource\\) does not accept resource\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + + - + message: "#^Property pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:\\$sha256 \\(string\\|null\\) does not accept string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php + + - + message: "#^Cannot call method handleException\\(\\) on pocketmine\\\\scheduler\\\\AsyncWorker\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/scheduler/AsyncTask.php + - message: "#^PHPDoc type pocketmine\\\\scheduler\\\\AsyncWorker\\|null of property pocketmine\\\\scheduler\\\\AsyncTask\\:\\:\\$worker is not the same as PHPDoc type Worker of overridden property Threaded\\:\\:\\$worker\\.$#" count: 1 path: ../../../src/pocketmine/scheduler/AsyncTask.php + - + message: "#^Parameter \\#1 \\$data of function unserialize expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/scheduler/AsyncTask.php + + - + message: "#^Property pocketmine\\\\scheduler\\\\AsyncTask\\:\\:\\$result \\(bool\\|float\\|int\\|string\\|null\\) does not accept mixed\\.$#" + count: 1 + path: ../../../src/pocketmine/scheduler/AsyncTask.php + + - + message: "#^Cannot call method getAsyncWorkerId\\(\\) on pocketmine\\\\scheduler\\\\AsyncWorker\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/scheduler/DumpWorkerMemoryTask.php + + - + message: "#^Cannot call method getLogger\\(\\) on pocketmine\\\\scheduler\\\\AsyncWorker\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/scheduler/DumpWorkerMemoryTask.php + + - + message: "#^Cannot call method toBinary\\(\\) on pocketmine\\\\utils\\\\UUID\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/scheduler/SendUsageTask.php + + - + message: "#^Cannot call method getNextRun\\(\\) on array\\\\|int\\|pocketmine\\\\scheduler\\\\TaskHandler\\.$#" + count: 1 + path: ../../../src/pocketmine/scheduler/TaskScheduler.php + - message: "#^Constructor of class pocketmine\\\\scheduler\\\\TaskScheduler has an unused parameter \\$logger\\.$#" count: 1 path: ../../../src/pocketmine/scheduler/TaskScheduler.php + - + message: "#^Parameter \\#1 \\$tag of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setTag\\(\\) expects pocketmine\\\\nbt\\\\tag\\\\NamedTag, pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Banner.php + + - + message: "#^Argument of an invalid type pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Cannot call method isChunkLoaded\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Parameter \\#1 \\$x of class pocketmine\\\\math\\\\Vector3 constructor expects float\\|int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, int\\|null given\\.$#" + count: 4 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Parameter \\#3 \\$z of class pocketmine\\\\math\\\\Vector3 constructor expects float\\|int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Property pocketmine\\\\tile\\\\Chest\\:\\:\\$pairX \\(int\\|null\\) does not accept float\\|int\\.$#" + count: 2 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Property pocketmine\\\\tile\\\\Chest\\:\\:\\$pairZ \\(int\\|null\\) does not accept float\\|int\\.$#" + count: 2 + path: ../../../src/pocketmine/tile/Chest.php + + - + message: "#^Argument of an invalid type pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Furnace.php + + - + message: "#^Cannot call method broadcastPacketToViewers\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Spawnable.php + + - + message: "#^Cannot call method clearChunkCache\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Spawnable.php + + - + message: "#^Parameter \\#2 \\$value of class pocketmine\\\\nbt\\\\tag\\\\IntTag constructor expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/tile/Spawnable.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BlockActorDataPacket\\:\\:\\$x \\(int\\) does not accept float\\|int\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Spawnable.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BlockActorDataPacket\\:\\:\\$y \\(int\\) does not accept float\\|int\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Spawnable.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BlockActorDataPacket\\:\\:\\$z \\(int\\) does not accept float\\|int\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Spawnable.php + + - + message: "#^Array \\(array\\, string\\>\\) does not accept string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Tile.php + + - + message: "#^Cannot access property \\$updateTiles on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Tile.php + + - + message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Tile.php + + - + message: "#^Cannot call method removeTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/tile/Tile.php + + - + message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, float\\|int given\\.$#" + count: 3 + path: ../../../src/pocketmine/tile/Tile.php + + - + message: "#^Cannot call method getFullVersion\\(\\) on pocketmine\\\\utils\\\\VersionString\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/updater/AutoUpdater.php + + - + message: "#^Offset 'date' does not exist on array\\\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/updater/AutoUpdater.php + + - + message: "#^Offset 'details_url' does not exist on array\\\\|null\\.$#" + count: 2 + path: ../../../src/pocketmine/updater/AutoUpdater.php + + - + message: "#^Offset 'download_url' does not exist on array\\\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/updater/AutoUpdater.php + + - + message: "#^Parameter \\#1 \\$baseVersion of class pocketmine\\\\utils\\\\VersionString constructor expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/updater/AutoUpdater.php + + - + message: "#^Parameter \\#1 \\$string of function strtolower expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/updater/AutoUpdater.php + + - + message: "#^Parameter \\#2 \\$isDevBuild of class pocketmine\\\\utils\\\\VersionString constructor expects bool, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/updater/AutoUpdater.php + + - + message: "#^Parameter \\#2 \\$timestamp of function date expects int\\|null, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/updater/AutoUpdater.php + + - + message: "#^Parameter \\#3 \\$buildNumber of class pocketmine\\\\utils\\\\VersionString constructor expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/updater/AutoUpdater.php + + - + message: "#^Cannot access offset string on mixed\\.$#" + count: 3 + path: ../../../src/pocketmine/utils/Config.php + + - + message: "#^Method pocketmine\\\\utils\\\\Config\\:\\:fixYAMLIndexes\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/Config.php + + - + message: "#^Parameter \\#2 \\$offset of function substr expects int, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/Internet.php + + - + message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/Internet.php + + - + message: "#^Method pocketmine\\\\utils\\\\MainLogger\\:\\:getLogger\\(\\) should return pocketmine\\\\utils\\\\MainLogger but returns pocketmine\\\\utils\\\\MainLogger\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/MainLogger.php + + - + message: "#^Parameter \\#1 \\$string of function trim expects string, string\\|false given\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/Timezone.php + + - + message: "#^Cannot cast mixed to string\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/Utils.php + + - + message: "#^Method pocketmine\\\\utils\\\\Utils\\:\\:printable\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/Utils.php + + - + message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Utils\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/Utils.php + + - + message: "#^Parameter \\#2 \\$array of function array_map expects array, mixed given\\.$#" + count: 1 + path: ../../../src/pocketmine/utils/Utils.php + + - + message: "#^Parameter \\#1 \\$enchantment of class pocketmine\\\\item\\\\enchantment\\\\EnchantmentInstance constructor expects pocketmine\\\\item\\\\enchantment\\\\Enchantment, pocketmine\\\\item\\\\enchantment\\\\Enchantment\\|null given\\.$#" + count: 1 + path: ../../phpunit/item/ItemTest.php + + - + message: "#^Cannot call method cancel\\(\\) on pocketmine\\\\scheduler\\\\TaskHandler\\|null\\.$#" + count: 1 + path: ../../plugins/TesterPlugin/src/pmmp/TesterPlugin/CheckTestCompletionTask.php + diff --git a/tests/phpstan/configs/check-explicit-mixed-baseline.neon b/tests/phpstan/configs/check-explicit-mixed-baseline.neon deleted file mode 100644 index eda18a112..000000000 --- a/tests/phpstan/configs/check-explicit-mixed-baseline.neon +++ /dev/null @@ -1,767 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Cannot access offset \\(float\\|int\\) on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/CrashDump.php - - - - message: "#^Cannot access offset string on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/CrashDump.php - - - - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Utils\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/CrashDump.php - - - - message: "#^Cannot cast mixed to int\\.$#" - count: 7 - path: ../../../src/pocketmine/MemoryManager.php - - - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" - count: 3 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'AnimationExpression' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'Colors' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'Frames' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'Image' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'ImageHeight' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'ImageWidth' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'IsDefault' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'PackId' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'PieceId' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'PieceType' on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'ProductId' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'Type' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot cast mixed to int\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#1 \\$height of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects int, mixed given\\.$#" - count: 3 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#1 \\$pieceId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#1 \\$pieceType of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaPieceTintColor constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#1 \\$skinId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#1 \\$string of function base64_decode expects string, mixed given\\.$#" - count: 7 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#1 \\.\\.\\.\\$slots of method pocketmine\\\\inventory\\\\BaseInventory\\:\\:addItem\\(\\) expects pocketmine\\\\item\\\\Item, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#10 \\$capeId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#12 \\$armSize of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#13 \\$skinColor of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#17 \\$premium of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#18 \\$persona of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#19 \\$personaCapeOnClassic of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects bool, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#2 \\$colors of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaPieceTintColor constructor expects array\\, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#2 \\$pieceType of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#2 \\$playFabId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#2 \\$type of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinAnimation constructor expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#2 \\$width of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects int, mixed given\\.$#" - count: 3 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#3 \\$frames of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinAnimation constructor expects float, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#3 \\$packId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#4 \\$expressionType of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinAnimation constructor expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#4 \\$isDefaultPiece of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects bool, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#5 \\$productId of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PersonaSkinPiece constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access offset 'git' on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/PocketMine.php - - - - message: "#^Cannot access offset 'type' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Cannot cast mixed to float\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Cannot cast mixed to int\\.$#" - count: 7 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Cannot cast mixed to string\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$name of static method pocketmine\\\\level\\\\format\\\\io\\\\LevelProviderManager\\:\\:getProviderByName\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$string of function strtolower expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#2 \\$defaultValue of method pocketmine\\\\Server\\:\\:getConfigString\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#2 \\$endpoint of class pocketmine\\\\updater\\\\AutoUpdater constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#2 \\$reason of method pocketmine\\\\Player\\:\\:close\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Method pocketmine\\\\ThreadManager\\:\\:getAll\\(\\) should return array\\ but returns array\\.$#" - count: 1 - path: ../../../src/pocketmine/ThreadManager.php - - - - message: "#^Cannot cast mixed to string\\.$#" - count: 1 - path: ../../../src/pocketmine/command/CommandReader.php - - - - message: "#^Parameter \\#1 \\$num of function round expects float\\|int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/StatusCommand.php - - - - message: "#^Cannot access offset 0 on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Parameter \\#2 \\$host of class class@anonymous/src/pocketmine/command/defaults/TimingsCommand\\.php\\:126 constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Cannot cast mixed to float\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/VanillaCommand.php - - - - message: "#^Cannot cast mixed to int\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/VanillaCommand.php - - - - message: "#^Parameter \\#1 \\$id of static method pocketmine\\\\entity\\\\Effect\\:\\:getEffect\\(\\) expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Effect.php - - - - message: "#^Cannot cast mixed to int\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Parameter \\#1 \\$fireTicks of method pocketmine\\\\entity\\\\Entity\\:\\:setFireTicks\\(\\) expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Method pocketmine\\\\event\\\\EventPriority\\:\\:fromString\\(\\) should return int but returns mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/event/EventPriority.php - - - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Item.php - - - - message: "#^Parameter \\#1 \\$data of static method pocketmine\\\\item\\\\Item\\:\\:jsonDeserialize\\(\\) expects array\\{id\\: int, damage\\?\\: int, count\\?\\: int, nbt\\?\\: string, nbt_hex\\?\\: string, nbt_b64\\?\\: string\\}, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Item.php - - - - message: "#^Parameter \\#1 \\$id of static method pocketmine\\\\item\\\\ItemFactory\\:\\:get\\(\\) expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/ItemFactory.php - - - - message: "#^Parameter \\#1 \\$id of static method pocketmine\\\\item\\\\enchantment\\\\Enchantment\\:\\:getEnchantment\\(\\) expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/enchantment/Enchantment.php - - - - message: "#^Cannot cast mixed to int\\.$#" - count: 3 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$keys of function array_fill_keys expects array, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/ChunkRequestTask.php - - - - message: "#^Cannot cast mixed to string\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php - - - - message: "#^Parameter \\#2 \\$string of function explode expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php - - - - message: "#^Parameter \\#2 \\$value of class pocketmine\\\\nbt\\\\tag\\\\StringTag constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php - - - - message: "#^Cannot cast mixed to string\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Parameter \\#2 \\$value of class pocketmine\\\\nbt\\\\tag\\\\StringTag constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Property pocketmine\\\\level\\\\generator\\\\Flat\\:\\:\\$preset \\(string\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/Flat.php - - - - message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/CompressBatchedTask.php - - - - message: "#^Cannot access property \\$x on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Cannot access property \\$y on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Cannot access property \\$z on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$data of method pocketmine\\\\nbt\\\\NBTStream\\:\\:write\\(\\) expects array\\\\|pocketmine\\\\nbt\\\\tag\\\\NamedTag, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putString\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putByte\\(\\) expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putLFloat\\(\\) expects float, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putLShort\\(\\) expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putVarInt\\(\\) expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putVarLong\\(\\) expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$vector of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putVector3Nullable\\(\\) expects pocketmine\\\\math\\\\Vector3\\|null, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Cannot access offset 'down' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php - - - - message: "#^Cannot access offset 'up' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php - - - - message: "#^Cannot cast mixed to int\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php - - - - message: "#^Parameter \\#1 \\$upload of method pocketmine\\\\network\\\\Network\\:\\:addStatistics\\(\\) expects float, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php - - - - message: "#^Parameter \\#2 \\$download of method pocketmine\\\\network\\\\Network\\:\\:addStatistics\\(\\) expects float, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/RakLibInterface.php - - - - message: "#^Cannot access offset 'exp' on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Cannot access offset 'identityPublicKey' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Cannot access offset 'nbf' on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Cannot access offset 'x5u' on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Cannot use array destructuring on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Parameter \\#1 \\$string of function wordwrap expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Cannot access offset string on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php - - - - message: "#^Offset mixed does not exist on array\\\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php - - - - message: "#^Parameter \\#2 \\$legacyId of static method pocketmine\\\\network\\\\mcpe\\\\convert\\\\RuntimeBlockMapping\\:\\:registerMapping\\(\\) expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddActorPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/AddActorPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddItemActorPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/AddItemActorPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddPlayerPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/AddPlayerPacket.php - - - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Cannot access offset 'XUID' on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Cannot access offset 'chain' on mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Cannot access offset 'displayName' on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Cannot access offset 'identity' on mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Parameter \\#1 \\$token of static method pocketmine\\\\utils\\\\Utils\\:\\:decodeJWT\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$chainData \\(array\\{chain\\?\\: array\\\\}\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$clientId \\(int\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$clientUUID \\(string\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$identityPublicKey \\(string\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$locale \\(string\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$serverAddress \\(string\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$username \\(string\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LoginPacket\\:\\:\\$xuid \\(string\\|null\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LoginPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\SetActorDataPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/SetActorDataPacket.php - - - - message: "#^Parameter \\#1 \\$value of static method pocketmine\\\\permission\\\\Permission\\:\\:getByName\\(\\) expects bool\\|string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/permission/Permission.php - - - - message: "#^Parameter \\#2 \\$description of class pocketmine\\\\permission\\\\Permission constructor expects string\\|null, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/permission/Permission.php - - - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Array \\(array\\\\) does not accept mixed\\.$#" - count: 2 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Cannot cast mixed to string\\.$#" - count: 4 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#1 \\$data of static method pocketmine\\\\permission\\\\Permission\\:\\:loadPermissions\\(\\) expects array\\\\>, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#1 \\$haystack of function stripos expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#1 \\$plugin of method pocketmine\\\\plugin\\\\PluginDescription\\:\\:loadMap\\(\\) expects array, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#1 \\$string of function mb_strtoupper expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$depend \\(array\\\\) does not accept array\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$loadBefore \\(array\\\\) does not accept array\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$main \\(string\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$name \\(string\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$order \\(int\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$softDepend \\(array\\\\) does not accept array\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#1 \\$description of method pocketmine\\\\command\\\\Command\\:\\:setDescription\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginManager.php - - - - message: "#^Parameter \\#1 \\$permissionMessage of method pocketmine\\\\command\\\\Command\\:\\:setPermissionMessage\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginManager.php - - - - message: "#^Parameter \\#1 \\$usage of method pocketmine\\\\command\\\\Command\\:\\:setUsage\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginManager.php - - - - message: "#^Parameter \\#2 \\$code of class pocketmine\\\\resourcepacks\\\\ResourcePackException constructor expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - - message: "#^Parameter \\#1 \\$data of function unserialize expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/AsyncTask.php - - - - message: "#^Property pocketmine\\\\scheduler\\\\AsyncTask\\:\\:\\$result \\(bool\\|float\\|int\\|string\\|null\\) does not accept mixed\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/AsyncTask.php - - - - message: "#^Parameter \\#1 \\$baseVersion of class pocketmine\\\\utils\\\\VersionString constructor expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Parameter \\#1 \\$string of function strtolower expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Parameter \\#2 \\$isDevBuild of class pocketmine\\\\utils\\\\VersionString constructor expects bool, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Parameter \\#2 \\$timestamp of function date expects int\\|null, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Parameter \\#3 \\$buildNumber of class pocketmine\\\\utils\\\\VersionString constructor expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Cannot access offset string on mixed\\.$#" - count: 3 - path: ../../../src/pocketmine/utils/Config.php - - - - message: "#^Parameter \\#2 \\$offset of function substr expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Internet.php - - - - message: "#^Cannot cast mixed to string\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Utils\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#2 \\$array of function array_map expects array, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - diff --git a/tests/phpstan/configs/l7-baseline.neon b/tests/phpstan/configs/l7-baseline.neon deleted file mode 100644 index f0962404d..000000000 --- a/tests/phpstan/configs/l7-baseline.neon +++ /dev/null @@ -1,807 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false given\\.$#" - count: 1 - path: ../../../build/make-release.php - - - - message: "#^Parameter \\#1 \\$pharPath of function pocketmine\\\\build\\\\server_phar\\\\buildPhar expects string, array\\\\|string\\|false given\\.$#" - count: 1 - path: ../../../build/server-phar.php - - - - message: "#^Parameter \\#1 \\$strings of function pocketmine\\\\build\\\\server_phar\\\\preg_quote_array expects array\\, array\\ given\\.$#" - count: 1 - path: ../../../build/server-phar.php - - - - message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - - - - message: "#^Parameter \\#1 \\$stream of function fwrite expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - - - - message: "#^Parameter \\#1 \\$start of method pocketmine\\\\resourcepacks\\\\ResourcePack\\:\\:getPackChunk\\(\\) expects int\\<0, max\\>, int given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#3 \\$data of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinImage constructor expects string, string\\|false given\\.$#" - count: 3 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#3 \\$resourcePatch of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#7 \\$geometryData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#8 \\$geometryDataEngineVersion of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#9 \\$animationData of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Binary operation \"\\.\" between array\\\\|string\\|false and '/'\\|'\\\\\\\\' results in an error\\.$#" - count: 2 - path: ../../../src/pocketmine/PocketMine.php - - - - message: "#^Parameter \\#1 \\$haystack of function substr_count expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/PocketMine.php - - - - message: "#^Parameter \\#1 \\$path of function realpath expects string, array\\\\|string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/PocketMine.php - - - - message: "#^Parameter \\#1 \\$path of function realpath expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/PocketMine.php - - - - message: "#^Parameter \\#1 \\$version1 of function version_compare expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/PocketMine.php - - - - message: "#^Cannot cast array\\\\|string\\|false to string\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Only numeric types are allowed in \\+, int\\|false given on the left side\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$array of function array_filter expects array, array\\\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$buffer of method pocketmine\\\\nbt\\\\NBTStream\\:\\:readCompressed\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Cactus.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Cactus.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Cactus.php - - - - message: "#^Parameter \\#1 \\$min of function mt_rand expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Grass.php - - - - message: "#^Parameter \\#2 \\$max of function mt_rand expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Grass.php - - - - message: "#^Parameter \\#1 \\$blockX of method pocketmine\\\\block\\\\Liquid\\:\\:calculateFlowCost\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Parameter \\#2 \\$blockY of method pocketmine\\\\block\\\\Liquid\\:\\:calculateFlowCost\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Parameter \\#3 \\$blockZ of method pocketmine\\\\block\\\\Liquid\\:\\:calculateFlowCost\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Parameter \\#1 \\$min of function mt_rand expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Mycelium.php - - - - message: "#^Parameter \\#2 \\$max of function mt_rand expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Mycelium.php - - - - message: "#^Parameter \\#2 \\$x of static method pocketmine\\\\level\\\\generator\\\\object\\\\Tree\\:\\:growTree\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Sapling.php - - - - message: "#^Parameter \\#3 \\$y of static method pocketmine\\\\level\\\\generator\\\\object\\\\Tree\\:\\:growTree\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Sapling.php - - - - message: "#^Parameter \\#4 \\$z of static method pocketmine\\\\level\\\\generator\\\\object\\\\Tree\\:\\:growTree\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Sapling.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Sugarcane.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Sugarcane.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Sugarcane.php - - - - message: "#^Cannot access offset 'mode' on array\\{0\\: int, 1\\: int, 2\\: int, 3\\: int, 4\\: int, 5\\: int, 6\\: int, 7\\: int, \\.\\.\\.\\}\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/command/CommandReader.php - - - - message: "#^Parameter \\#1 \\$stream of method pocketmine\\\\command\\\\CommandReader\\:\\:isPipe\\(\\) expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/CommandReader.php - - - - message: "#^Static property pocketmine\\\\command\\\\CommandReader\\:\\:\\$stdin \\(resource\\) does not accept resource\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/command/CommandReader.php - - - - message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/BanIpCommand.php - - - - message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/PardonIpCommand.php - - - - message: "#^Parameter \\#1 \\$fp of static method pocketmine\\\\timings\\\\TimingsHandler\\:\\:printTimings\\(\\) expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Parameter \\#1 \\$stream of function fseek expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Parameter \\#1 \\$stream of function stream_get_contents expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Parameter \\#4 \\$data of class class@anonymous/src/pocketmine/command/defaults/TimingsCommand\\.php\\:126 constructor expects array\\, array\\ given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/TimingsCommand.php - - - - message: "#^Array \\(array\\, string\\>\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Parameter \\#1 \\$index of method pocketmine\\\\inventory\\\\BaseInventory\\:\\:setItem\\(\\) expects int, int\\|string given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/Painting.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/Painting.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/Painting.php - - - - message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/entity/projectile/Projectile.php - - - - message: "#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\\\|T of object, string given\\.$#" - count: 1 - path: ../../../src/pocketmine/event/HandlerList.php - - - - message: "#^Method pocketmine\\\\inventory\\\\CraftingManager\\:\\:hashOutputs\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/inventory/CraftingManager.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/inventory/CraftingManager.php - - - - message: "#^Method pocketmine\\\\item\\\\Item\\:\\:writeCompoundTag\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Item.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Item.php - - - - message: "#^Parameter \\#2 \\$array of function array_map expects array, array\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/lang/BaseLang.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:setBlockDataAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:setBlockIdAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:setBlockDataAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:setBlockIdAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:setBlockDataAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:setBlockIdAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Cannot access offset 'data' on array\\{priority\\: int, data\\: pocketmine\\\\math\\\\Vector3\\}\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot access offset 'priority' on array\\{priority\\: int, data\\: pocketmine\\\\math\\\\Vector3\\}\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getFullBlock\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" - count: 4 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:updateBlockLight\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:updateBlockSkyLight\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$x of static method pocketmine\\\\level\\\\Level\\:\\:chunkBlockHash\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getFullBlock\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" - count: 4 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:updateBlockLight\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:updateBlockSkyLight\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#2 \\$y of static method pocketmine\\\\level\\\\Level\\:\\:chunkBlockHash\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getFullBlock\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" - count: 4 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:updateBlockLight\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:updateBlockSkyLight\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\level\\\\Level\\:\\:blockHash\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#3 \\$z of static method pocketmine\\\\level\\\\Level\\:\\:chunkBlockHash\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UpdateBlockPacket\\:\\:\\$x \\(int\\) does not accept float\\|int\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UpdateBlockPacket\\:\\:\\$y \\(int\\) does not accept float\\|int\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\UpdateBlockPacket\\:\\:\\$z \\(int\\) does not accept float\\|int\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php - - - - message: "#^Parameter \\#2 \\$value of method LevelDB\\:\\:put\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/leveldb/LevelDB.php - - - - message: "#^Method pocketmine\\\\level\\\\format\\\\io\\\\region\\\\Anvil\\:\\:nbtSerialize\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/Anvil.php - - - - message: "#^Method pocketmine\\\\level\\\\format\\\\io\\\\region\\\\McRegion\\:\\:nbtSerialize\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Parameter \\#1 \\$array of function array_filter expects array, array\\\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Only numeric types are allowed in %%, int\\<0, max\\>\\|false given on the left side\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/RegionLoader.php - - - - message: "#^Parameter \\#1 \\$start of method pocketmine\\\\utils\\\\Random\\:\\:nextRange\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/generator/object/TallGrass.php - - - - message: "#^Parameter \\#2 \\$end of method pocketmine\\\\utils\\\\Random\\:\\:nextRange\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/generator/object/TallGrass.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\ChunkManager\\:\\:getBlockIdAt\\(\\) expects int, float\\|int given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/generator/object/TallGrass.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\ChunkManager\\:\\:setBlockDataAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/object/TallGrass.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\ChunkManager\\:\\:setBlockIdAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/object/TallGrass.php - - - - message: "#^Method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:getGameRules\\(\\) should return array\\ but returns array\\\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putBool\\(\\) expects bool, bool\\|float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putLFloat\\(\\) expects float, bool\\|float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\utils\\\\BinaryStream\\:\\:putUnsignedVarInt\\(\\) expects int, bool\\|float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php - - - - message: "#^Offset 'chain' does not exist on array\\{chain\\?\\: array\\\\}\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Parameter \\#1 \\$string of function str_split expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php - - - - message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream constructor expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php - - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php - - - - message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/AddVolumeEntityPacket.php - - - - message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/AvailableActorIdentifiersPacket.php - - - - message: "#^Static property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AvailableActorIdentifiersPacket\\:\\:\\$DEFAULT_NBT_CACHE \\(string\\|null\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/AvailableActorIdentifiersPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket\\:\\:\\$payload \\(string\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/BatchPacket.php - - - - message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/BiomeDefinitionListPacket.php - - - - message: "#^Static property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BiomeDefinitionListPacket\\:\\:\\$DEFAULT_NBT_CACHE \\(string\\|null\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/BiomeDefinitionListPacket.php - - - - message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/ItemComponentPacket.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\LevelEventGenericPacket\\:\\:\\$eventData \\(string\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/LevelEventGenericPacket.php - - - - message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/PositionTrackingDBServerBroadcastPacket.php - - - - message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/StartGamePacket.php - - - - message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/SyncActorPropertyPacket.php - - - - message: "#^Parameter \\#3 \\$resourcePatch of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\SkinData constructor expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/types/LegacySkinAdapter.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putBlockPosition\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/types/inventory/UseItemTransactionData.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putBlockPosition\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/types/inventory/UseItemTransactionData.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putBlockPosition\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/types/inventory/UseItemTransactionData.php - - - - message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getPackChunk\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - - message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getPackSize\\(\\) should return int but returns int\\<0, max\\>\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - - message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getSha256\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - - message: "#^Property pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:\\$fileResource \\(resource\\) does not accept resource\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - - message: "#^Property pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:\\$sha256 \\(string\\|null\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - - message: "#^Cannot call method getNextRun\\(\\) on array\\\\|int\\|pocketmine\\\\scheduler\\\\TaskHandler\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/TaskScheduler.php - - - - message: "#^Parameter \\#2 \\$y of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Property pocketmine\\\\tile\\\\Chest\\:\\:\\$pairX \\(int\\|null\\) does not accept float\\|int\\.$#" - count: 2 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Property pocketmine\\\\tile\\\\Chest\\:\\:\\$pairZ \\(int\\|null\\) does not accept float\\|int\\.$#" - count: 2 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Parameter \\#2 \\$value of class pocketmine\\\\nbt\\\\tag\\\\IntTag constructor expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/tile/Spawnable.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BlockActorDataPacket\\:\\:\\$x \\(int\\) does not accept float\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Spawnable.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BlockActorDataPacket\\:\\:\\$y \\(int\\) does not accept float\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Spawnable.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BlockActorDataPacket\\:\\:\\$z \\(int\\) does not accept float\\|int\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Spawnable.php - - - - message: "#^Array \\(array\\, string\\>\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Tile.php - - - - message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, float\\|int given\\.$#" - count: 3 - path: ../../../src/pocketmine/tile/Tile.php - - - - message: "#^Parameter \\#1 \\$string of function trim expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Timezone.php - diff --git a/tests/phpstan/configs/l8-baseline.neon b/tests/phpstan/configs/l8-baseline.neon deleted file mode 100644 index 19ca8fa1f..000000000 --- a/tests/phpstan/configs/l8-baseline.neon +++ /dev/null @@ -1,1607 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" - count: 2 - path: ../../../build/make-release.php - - - - message: "#^Cannot access property \\$x on pocketmine\\\\level\\\\Position\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access property \\$y on pocketmine\\\\level\\\\Position\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot access property \\$z on pocketmine\\\\level\\\\Position\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method checkSpawnProtection\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method dropExperience\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method dropItem\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method equals\\(\\) on pocketmine\\\\utils\\\\UUID\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getAllValues\\(\\) on pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 6 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getChunkEntities\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getCollisionBlocks\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getDifficulty\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getFloorX\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getFloorY\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getFloorZ\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getFolderName\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getLevelNonNull\\(\\) on pocketmine\\\\level\\\\Position\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getName\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getNearbyEntities\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getSafeSpawn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getTileAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getTime\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method isChunkGenerated\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method isInLoadedTerrain\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method populateChunk\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method registerChunkLoader\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method requestChunk\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method sendBlocks\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method sendDifficulty\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method sendTime\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method setSleepTicks\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method unregisterChunkLoader\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method useItemOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Method pocketmine\\\\Player\\:\\:getSpawn\\(\\) should return pocketmine\\\\level\\\\Position but returns pocketmine\\\\level\\\\Position\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Only numeric types are allowed in \\-, int\\|null given on the right side\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#1 \\$level of method pocketmine\\\\entity\\\\Human\\:\\:__construct\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Parameter \\#1 \\$uuid of method pocketmine\\\\Server\\:\\:updatePlayerListData\\(\\) expects pocketmine\\\\utils\\\\UUID, pocketmine\\\\utils\\\\UUID\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/Player.php - - - - message: "#^Cannot call method getFolderName\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Cannot call method getSafeSpawn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Cannot call method wait\\(\\) on Threaded\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$uuid of method pocketmine\\\\Server\\:\\:removePlayerListData\\(\\) expects pocketmine\\\\utils\\\\UUID, pocketmine\\\\utils\\\\UUID\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$uuid of method pocketmine\\\\Server\\:\\:updatePlayerListData\\(\\) expects pocketmine\\\\utils\\\\UUID, pocketmine\\\\utils\\\\UUID\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Parameter \\#1 \\$uuid of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\PlayerListEntry\\:\\:createAdditionEntry\\(\\) expects pocketmine\\\\utils\\\\UUID, pocketmine\\\\utils\\\\UUID\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/Server.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BaseRail.php - - - - message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Bed.php - - - - message: "#^Cannot call method getBlockMetadata\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/block/Block.php - - - - message: "#^Cannot access property \\$level on pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BlockFactory.php - - - - message: "#^Cannot access property \\$x on pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BlockFactory.php - - - - message: "#^Cannot access property \\$y on pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BlockFactory.php - - - - message: "#^Cannot access property \\$z on pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BlockFactory.php - - - - message: "#^Cannot clone pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BlockFactory.php - - - - message: "#^Method pocketmine\\\\block\\\\BlockFactory\\:\\:get\\(\\) should return pocketmine\\\\block\\\\Block but returns pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/BlockFactory.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Button.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Cake.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/ConcretePowder.php - - - - message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Door.php - - - - message: "#^Cannot call method getDirection\\(\\) on pocketmine\\\\Player\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Door.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Door.php - - - - message: "#^Only numeric types are allowed in \\+, int\\|null given on the left side\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Door.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/EndRod.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Fallable.php - - - - message: "#^Cannot call method getBlockIdAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Farmland.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/block/Farmland.php - - - - message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/FenceGate.php - - - - message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" - count: 2 - path: ../../../src/pocketmine/block/FenceGate.php - - - - message: "#^Cannot call method scheduleDelayedBlockUpdate\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Fire.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Fire.php - - - - message: "#^Only numeric types are allowed in \\-, int\\|null given on the left side\\.$#" - count: 1 - path: ../../../src/pocketmine/block/GlazedTerracotta.php - - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Grass.php - - - - message: "#^Cannot call method getBlockDataAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Grass.php - - - - message: "#^Cannot call method getBlockIdAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Grass.php - - - - message: "#^Cannot call method getFullLightAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Grass.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/Grass.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/GrassPath.php - - - - message: "#^Cannot call method getHighestAdjacentBlockLight\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Ice.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Ice.php - - - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/block/ItemFrame.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/ItemFrame.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/ItemFrame.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Ladder.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Lever.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Lever.php - - - - message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 25 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Cannot call method scheduleDelayedBlockUpdate\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Liquid.php - - - - message: "#^Cannot call method getFullLightAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Sapling.php - - - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Skull.php - - - - message: "#^Cannot call method getBlockLightAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/SnowLayer.php - - - - message: "#^Cannot call method getTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/StandingBanner.php - - - - message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Trapdoor.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Vine.php - - - - message: "#^Cannot call method useBreakOn\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/block/Vine.php - - - - message: "#^Parameter \\#2 \\$replace of function str_replace expects array\\|string, string\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/command/Command.php - - - - message: "#^Cannot call method startTiming\\(\\) on pocketmine\\\\timings\\\\TimingsHandler\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/command/SimpleCommandMap.php - - - - message: "#^Cannot call method stopTiming\\(\\) on pocketmine\\\\timings\\\\TimingsHandler\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/command/SimpleCommandMap.php - - - - message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/ParticleCommand.php - - - - message: "#^Cannot call method getSeed\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/SeedCommand.php - - - - message: "#^Cannot call method setSpawnLocation\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/SetWorldSpawnCommand.php - - - - message: "#^Cannot call method getTime\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/command/defaults/TimeCommand.php - - - - message: "#^Cannot call method getValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/entity/Effect.php - - - - message: "#^Cannot call method setValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/entity/Effect.php - - - - message: "#^Cannot access property \\$updateEntities on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method addEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method addEntity\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method broadcastPacketToViewers\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getAllValues\\(\\) on pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getBlockIdAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 7 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getChunk\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getChunkAtPosition\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getCollisionBlocks\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getCollisionCubes\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 4 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getTickRateTime\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method getViewersForPosition\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method removeEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method setValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Method pocketmine\\\\entity\\\\Entity\\:\\:getNameTag\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Method pocketmine\\\\entity\\\\Entity\\:\\:getScale\\(\\) should return float but returns float\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Only booleans are allowed in a negated boolean, bool\\|null given\\.$#" - count: 6 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Only booleans are allowed in an if condition, bool\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Parameter \\#2 \\$originLevel of class pocketmine\\\\event\\\\entity\\\\EntityLevelChangeEvent constructor expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setShort\\(\\) expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Entity.php - - - - message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Cannot call method getDifficulty\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Cannot call method getMaxValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Cannot call method getMinValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Cannot call method getValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 8 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Cannot call method setValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 6 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Parameter \\#1 \\$attribute of method pocketmine\\\\entity\\\\AttributeMap\\:\\:addAttribute\\(\\) expects pocketmine\\\\entity\\\\Attribute, pocketmine\\\\entity\\\\Attribute\\|null given\\.$#" - count: 5 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" - count: 3 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddPlayerPacket\\:\\:\\$uuid \\(pocketmine\\\\utils\\\\UUID\\) does not accept pocketmine\\\\utils\\\\UUID\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\PlayerSkinPacket\\:\\:\\$uuid \\(pocketmine\\\\utils\\\\UUID\\) does not accept pocketmine\\\\utils\\\\UUID\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Human.php - - - - message: "#^Cannot call method attack\\(\\) on pocketmine\\\\entity\\\\Entity\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Cannot call method dropExperience\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Cannot call method getEffectLevel\\(\\) on pocketmine\\\\entity\\\\EffectInstance\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Cannot call method getMaxValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Cannot call method getValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Cannot call method setMaxValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Cannot call method setValue\\(\\) on pocketmine\\\\entity\\\\Attribute\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Method pocketmine\\\\entity\\\\Living\\:\\:getAirSupplyTicks\\(\\) should return int but returns int\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Method pocketmine\\\\entity\\\\Living\\:\\:getMaxAirSupplyTicks\\(\\) should return int but returns int\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Parameter \\#1 \\$attribute of method pocketmine\\\\entity\\\\AttributeMap\\:\\:addAttribute\\(\\) expects pocketmine\\\\entity\\\\Attribute, pocketmine\\\\entity\\\\Attribute\\|null given\\.$#" - count: 6 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Parameter \\#2 \\$entity of class pocketmine\\\\event\\\\entity\\\\EntityDamageByEntityEvent constructor expects pocketmine\\\\entity\\\\Entity, pocketmine\\\\entity\\\\Entity\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Living.php - - - - message: "#^Method pocketmine\\\\entity\\\\Villager\\:\\:getProfession\\(\\) should return int but returns int\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/Villager.php - - - - message: "#^Cannot call method getEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/ExperienceOrb.php - - - - message: "#^Cannot call method getNearestEntity\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/ExperienceOrb.php - - - - message: "#^Cannot call method getBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/FallingBlock.php - - - - message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/Painting.php - - - - message: "#^Cannot call method dropItem\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/Painting.php - - - - message: "#^Method pocketmine\\\\entity\\\\object\\\\Painting\\:\\:getMotive\\(\\) should return pocketmine\\\\entity\\\\object\\\\PaintingMotive but returns pocketmine\\\\entity\\\\object\\\\PaintingMotive\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/Painting.php - - - - message: "#^Parameter \\#1 \\$level of static method pocketmine\\\\entity\\\\object\\\\Painting\\:\\:canFit\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/Painting.php - - - - message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/object/PrimedTNT.php - - - - message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/Arrow.php - - - - message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/Egg.php - - - - message: "#^Cannot call method addSound\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/projectile/EnderPearl.php - - - - message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/EnderPearl.php - - - - message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/ExperienceBottle.php - - - - message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/ExperienceBottle.php - - - - message: "#^Cannot call method dropExperience\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/ExperienceBottle.php - - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/projectile/Projectile.php - - - - message: "#^Cannot call method getCollidingEntities\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/Projectile.php - - - - message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setByte\\(\\) expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/Projectile.php - - - - message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/Projectile.php - - - - message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/Snowball.php - - - - message: "#^Cannot call method broadcastLevelEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/SplashPotion.php - - - - message: "#^Cannot call method broadcastLevelSoundEvent\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/SplashPotion.php - - - - message: "#^Cannot call method getNearbyEntities\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/entity/projectile/SplashPotion.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/entity/projectile/SplashPotion.php - - - - message: "#^Cannot call method getEffectLevel\\(\\) on pocketmine\\\\entity\\\\EffectInstance\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/event/entity/EntityDamageByEntityEvent.php - - - - message: "#^Method pocketmine\\\\inventory\\\\CraftingManager\\:\\:getCraftingDataPacket\\(\\) should return pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket but returns pocketmine\\\\network\\\\mcpe\\\\protocol\\\\BatchPacket\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/inventory/CraftingManager.php - - - - message: "#^Parameter \\#2 \\$recipe of class pocketmine\\\\event\\\\inventory\\\\CraftItemEvent constructor expects pocketmine\\\\inventory\\\\CraftingRecipe, pocketmine\\\\inventory\\\\CraftingRecipe\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/inventory/transaction/CraftingTransaction.php - - - - message: "#^Parameter \\#3 \\$repetitions of class pocketmine\\\\event\\\\inventory\\\\CraftItemEvent constructor expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/inventory/transaction/CraftingTransaction.php - - - - message: "#^Cannot call method count\\(\\) on pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Banner.php - - - - message: "#^Cannot call method isset\\(\\) on pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Banner.php - - - - message: "#^Cannot call method spawnToAll\\(\\) on pocketmine\\\\entity\\\\Entity\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Bow.php - - - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/item/GoldenApple.php - - - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" - count: 4 - path: ../../../src/pocketmine/item/GoldenAppleEnchanted.php - - - - message: "#^Parameter \\#1 \\$object of function get_class expects object, pocketmine\\\\nbt\\\\tag\\\\NamedTag\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/Item.php - - - - message: "#^Parameter \\#1 \\$level of static method pocketmine\\\\entity\\\\object\\\\Painting\\:\\:canFit\\(\\) expects pocketmine\\\\level\\\\Level, pocketmine\\\\level\\\\Level\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/PaintingItem.php - - - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/PoisonousPotato.php - - - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" - count: 3 - path: ../../../src/pocketmine/item/Pufferfish.php - - - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/RawChicken.php - - - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/RottenFlesh.php - - - - message: "#^Parameter \\#1 \\$effectType of class pocketmine\\\\entity\\\\EffectInstance constructor expects pocketmine\\\\entity\\\\Effect, pocketmine\\\\entity\\\\Effect\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/item/SpiderEye.php - - - - message: "#^Parameter \\#2 \\$pageText of method pocketmine\\\\item\\\\WritableBook\\:\\:setPageText\\(\\) expects string, string\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/item/WritableBook.php - - - - message: "#^Method pocketmine\\\\item\\\\enchantment\\\\EnchantmentList\\:\\:getSlot\\(\\) should return pocketmine\\\\item\\\\enchantment\\\\EnchantmentEntry but returns pocketmine\\\\item\\\\enchantment\\\\EnchantmentEntry\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/item/enchantment/EnchantmentList.php - - - - message: "#^Cannot call method getBlockData\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Cannot call method getBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Only numeric types are allowed in /, float\\|null given on the left side\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Explosion.php - - - - message: "#^Cannot access property \\$level on pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot access property \\$x on pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot access property \\$y on pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot access property \\$z on pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method getBlockData\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method getBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method getBlockLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method getBlockSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method getFullBlock\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method getHeightMap\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method getHighestBlockAt\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method isPopulated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method recalculateHeightMapColumn\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method setBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method setBlockData\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method setBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method setBlockLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method setBlockSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot call method setHeightMap\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Cannot clone pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Method pocketmine\\\\level\\\\Level\\:\\:getBlockAt\\(\\) should return pocketmine\\\\block\\\\Block but returns pocketmine\\\\block\\\\Block\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Only numeric types are allowed in \\-, int\\|null given on the right side\\.$#" - count: 2 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#1 \\$chunk of method pocketmine\\\\Player\\:\\:onChunkChanged\\(\\) expects pocketmine\\\\level\\\\format\\\\Chunk, pocketmine\\\\level\\\\format\\\\Chunk\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#2 \\$chunk of class pocketmine\\\\level\\\\generator\\\\PopulationTask constructor expects pocketmine\\\\level\\\\format\\\\Chunk, pocketmine\\\\level\\\\format\\\\Chunk\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Parameter \\#4 \\$newLevel of method pocketmine\\\\level\\\\light\\\\LightUpdate\\:\\:setAndUpdateLight\\(\\) expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/Level.php - - - - message: "#^Method pocketmine\\\\level\\\\biome\\\\Biome\\:\\:getBiome\\(\\) should return pocketmine\\\\level\\\\biome\\\\Biome but returns pocketmine\\\\level\\\\biome\\\\Biome\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/biome/Biome.php - - - - message: "#^Cannot call method networkSerialize\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/Chunk.php - - - - message: "#^Method pocketmine\\\\level\\\\format\\\\Chunk\\:\\:getHeightMap\\(\\) should return int but returns int\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/Chunk.php - - - - message: "#^Method pocketmine\\\\level\\\\format\\\\Chunk\\:\\:getSubChunk\\(\\) should return pocketmine\\\\level\\\\format\\\\SubChunkInterface but returns pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/Chunk.php - - - - message: "#^Property pocketmine\\\\level\\\\format\\\\io\\\\BaseLevelProvider\\:\\:\\$levelData \\(pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\) does not accept pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/BaseLevelProvider.php - - - - message: "#^Cannot call method getByte\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/region/Anvil.php - - - - message: "#^Cannot call method getByteArray\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/Anvil.php - - - - message: "#^Cannot call method getInt\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/region/Anvil.php - - - - message: "#^Cannot call method getIntArray\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/region/Anvil.php - - - - message: "#^Cannot call method getListTag\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/level/format/io/region/Anvil.php - - - - message: "#^Cannot call method hasTag\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/level/format/io/region/Anvil.php - - - - message: "#^Parameter \\#2 \\$list of static method pocketmine\\\\level\\\\format\\\\io\\\\region\\\\McRegion\\:\\:getCompoundList\\(\\) expects pocketmine\\\\nbt\\\\tag\\\\ListTag, pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/region/Anvil.php - - - - message: "#^Cannot call method getBlockDataColumn\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method getBlockIdColumn\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method getBlockLightColumn\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method getBlockSkyLightColumn\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method getByte\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method getByteArray\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 6 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method getInt\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method getIntArray\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method getListTag\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method hasTag\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 10 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method readChunk\\(\\) on pocketmine\\\\level\\\\format\\\\io\\\\region\\\\RegionLoader\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method writeChunk\\(\\) on pocketmine\\\\level\\\\format\\\\io\\\\region\\\\RegionLoader\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Parameter \\#2 \\$list of static method pocketmine\\\\level\\\\format\\\\io\\\\region\\\\McRegion\\:\\:getCompoundList\\(\\) expects pocketmine\\\\nbt\\\\tag\\\\ListTag, pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null given\\.$#" - count: 2 - path: ../../../src/pocketmine/level/format/io/region/McRegion.php - - - - message: "#^Cannot call method fastSerialize\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method getAsyncWorkerId\\(\\) on pocketmine\\\\scheduler\\\\AsyncWorker\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method getX\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 5 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method getZ\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 5 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method hasChanged\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method isGenerated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method populateSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method recalculateHeightMap\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method setGenerated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method setLightPopulated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Cannot call method setPopulated\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/PopulationTask.php - - - - message: "#^Method pocketmine\\\\level\\\\generator\\\\biome\\\\BiomeSelector\\:\\:pickBiome\\(\\) should return pocketmine\\\\level\\\\biome\\\\Biome but returns pocketmine\\\\level\\\\biome\\\\Biome\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/biome/BiomeSelector.php - - - - message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/hell/Nether.php - - - - message: "#^Cannot call method setBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/hell/Nether.php - - - - message: "#^Cannot call method setBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/level/generator/hell/Nether.php - - - - message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/normal/Normal.php - - - - message: "#^Cannot call method setBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/normal/Normal.php - - - - message: "#^Cannot call method setBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 3 - path: ../../../src/pocketmine/level/generator/normal/Normal.php - - - - message: "#^Offset int does not exist on array\\\\>\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/normal/Normal.php - - - - message: "#^Only booleans are allowed in a negated boolean, bool\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/object/SpruceTree.php - - - - message: "#^Only booleans are allowed in a negated boolean, bool\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/object/Tree.php - - - - message: "#^Cannot call method getBiomeId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/populator/GroundCover.php - - - - message: "#^Cannot call method getBlockIdColumn\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/populator/GroundCover.php - - - - message: "#^Cannot call method setBlock\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/populator/GroundCover.php - - - - message: "#^Cannot call method setBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/generator/populator/GroundCover.php - - - - message: "#^Cannot call method getBlockLight\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/light/BlockLightUpdate.php - - - - message: "#^Cannot call method setBlockLight\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/light/BlockLightUpdate.php - - - - message: "#^Cannot call method getBlockId\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/light/LightUpdate.php - - - - message: "#^Only numeric types are allowed in \\-, int\\|null given on the right side\\.$#" - count: 1 - path: ../../../src/pocketmine/level/light/LightUpdate.php - - - - message: "#^Cannot call method getBlockSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/light/SkyLightUpdate.php - - - - message: "#^Cannot call method setBlockSkyLight\\(\\) on pocketmine\\\\level\\\\format\\\\SubChunkInterface\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/level/light/SkyLightUpdate.php - - - - message: "#^Argument of an invalid type array\\\\|null supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php - - - - message: "#^Method pocketmine\\\\network\\\\mcpe\\\\convert\\\\RuntimeBlockMapping\\:\\:getBedrockKnownStates\\(\\) should return array\\ but returns array\\\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php - - - - message: "#^Parameter \\#1 \\$eid of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putEntityUniqueId\\(\\) expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/SetScorePacket.php - - - - message: "#^Parameter \\#1 \\$v of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putString\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/SetScorePacket.php - - - - message: "#^Parameter \\#1 \\$eid of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putEntityUniqueId\\(\\) expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/network/mcpe/protocol/SetScoreboardIdentityPacket.php - - - - message: "#^Cannot call method wakeupSleeper\\(\\) on pocketmine\\\\snooze\\\\SleeperNotifier\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/network/rcon/RCONInstance.php - - - - message: "#^Method pocketmine\\\\permission\\\\DefaultPermissions\\:\\:registerPermission\\(\\) should return pocketmine\\\\permission\\\\Permission but returns pocketmine\\\\permission\\\\Permission\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/permission/DefaultPermissions.php - - - - message: "#^Method pocketmine\\\\plugin\\\\PluginBase\\:\\:getConfig\\(\\) should return pocketmine\\\\utils\\\\Config but returns pocketmine\\\\utils\\\\Config\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginBase.php - - - - message: "#^Cannot call method handleException\\(\\) on pocketmine\\\\scheduler\\\\AsyncWorker\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/AsyncTask.php - - - - message: "#^Cannot call method getAsyncWorkerId\\(\\) on pocketmine\\\\scheduler\\\\AsyncWorker\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/DumpWorkerMemoryTask.php - - - - message: "#^Cannot call method getLogger\\(\\) on pocketmine\\\\scheduler\\\\AsyncWorker\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/DumpWorkerMemoryTask.php - - - - message: "#^Cannot call method toBinary\\(\\) on pocketmine\\\\utils\\\\UUID\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/scheduler/SendUsageTask.php - - - - message: "#^Parameter \\#1 \\$tag of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setTag\\(\\) expects pocketmine\\\\nbt\\\\tag\\\\NamedTag, pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Banner.php - - - - message: "#^Argument of an invalid type pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Cannot call method isChunkLoaded\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Parameter \\#1 \\$x of class pocketmine\\\\math\\\\Vector3 constructor expects float\\|int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Parameter \\#2 \\$value of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:setInt\\(\\) expects int, int\\|null given\\.$#" - count: 4 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Parameter \\#3 \\$z of class pocketmine\\\\math\\\\Vector3 constructor expects float\\|int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Parameter \\#3 \\$z of method pocketmine\\\\level\\\\Level\\:\\:getTileAt\\(\\) expects int, int\\|null given\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Chest.php - - - - message: "#^Argument of an invalid type pocketmine\\\\nbt\\\\tag\\\\ListTag\\|null supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Furnace.php - - - - message: "#^Cannot call method broadcastPacketToViewers\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Spawnable.php - - - - message: "#^Cannot call method clearChunkCache\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Spawnable.php - - - - message: "#^Cannot access property \\$updateTiles on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Tile.php - - - - message: "#^Cannot call method getBlockAt\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Tile.php - - - - message: "#^Cannot call method removeTile\\(\\) on pocketmine\\\\level\\\\Level\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/tile/Tile.php - - - - message: "#^Cannot call method getFullVersion\\(\\) on pocketmine\\\\utils\\\\VersionString\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Offset 'date' does not exist on array\\\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Offset 'details_url' does not exist on array\\\\|null\\.$#" - count: 2 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Offset 'download_url' does not exist on array\\\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/updater/AutoUpdater.php - - - - message: "#^Method pocketmine\\\\utils\\\\Config\\:\\:fixYAMLIndexes\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Config.php - - - - message: "#^Method pocketmine\\\\utils\\\\MainLogger\\:\\:getLogger\\(\\) should return pocketmine\\\\utils\\\\MainLogger but returns pocketmine\\\\utils\\\\MainLogger\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/MainLogger.php - - - - message: "#^Method pocketmine\\\\utils\\\\Utils\\:\\:printable\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: ../../../src/pocketmine/utils/Utils.php - - - - message: "#^Parameter \\#1 \\$enchantment of class pocketmine\\\\item\\\\enchantment\\\\EnchantmentInstance constructor expects pocketmine\\\\item\\\\enchantment\\\\Enchantment, pocketmine\\\\item\\\\enchantment\\\\Enchantment\\|null given\\.$#" - count: 1 - path: ../../phpunit/item/ItemTest.php - - - - message: "#^Cannot call method cancel\\(\\) on pocketmine\\\\scheduler\\\\TaskHandler\\|null\\.$#" - count: 1 - path: ../../plugins/TesterPlugin/src/pmmp/TesterPlugin/CheckTestCompletionTask.php - From 3214da8642c7dd5306525165d0a1d1c3b2e23f2e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 21:01:59 +0000 Subject: [PATCH 260/710] pthreads 4.0.0 --- build/php | 2 +- composer.json | 2 +- composer.lock | 66 +++++++++++++++++------------------ src/pocketmine/PocketMine.php | 4 +-- tests/gh-actions/build.sh | 2 +- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/build/php b/build/php index fab0cbeaa..365356dec 160000 --- a/build/php +++ b/build/php @@ -1 +1 @@ -Subproject commit fab0cbeaae7de58ea78a02c7505719d04a0325a3 +Subproject commit 365356dec1d184b858907d1208fe84d824b6541e diff --git a/composer.json b/composer.json index b835e1124..fccbfaccc 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ "ext-openssl": "*", "ext-pcre": "*", "ext-phar": "*", - "ext-pthreads": "~3.2.0", + "ext-pthreads": "^4.0", "ext-reflection": "*", "ext-simplexml": "*", "ext-sockets": "*", diff --git a/composer.lock b/composer.lock index 9250f7dfb..399d6141b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "83afdaf7b072e11090279f87f57bebb5", + "content-hash": "c55df4140fb828ab8add33e0a0e84136", "packages": [ { "name": "adhocore/json-comment", @@ -153,20 +153,20 @@ }, { "name": "pocketmine/classloader", - "version": "0.1.2", + "version": "0.1.3", "source": { "type": "git", "url": "https://github.com/pmmp/ClassLoader.git", - "reference": "9757928424652393b178a3760073113aa7c9911b" + "reference": "3c484a27787f7732ce842ed694928a29ba340961" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/9757928424652393b178a3760073113aa7c9911b", - "reference": "9757928424652393b178a3760073113aa7c9911b", + "url": "https://api.github.com/repos/pmmp/ClassLoader/zipball/3c484a27787f7732ce842ed694928a29ba340961", + "reference": "3c484a27787f7732ce842ed694928a29ba340961", "shasum": "" }, "require": { - "ext-pthreads": "~3.2.0", + "ext-pthreads": "~3.2.0 || ^4.0", "ext-reflection": "*", "php": "^7.2 || ^8.0" }, @@ -175,7 +175,7 @@ }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.66", + "phpstan/phpstan": "0.12.99", "phpstan/phpstan-strict-rules": "^0.12.4" }, "type": "library", @@ -191,9 +191,9 @@ "description": "Ad-hoc autoloading components used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/ClassLoader/issues", - "source": "https://github.com/pmmp/ClassLoader/tree/0.1.2" + "source": "https://github.com/pmmp/ClassLoader/tree/0.1.3" }, - "time": "2021-01-15T00:40:47+00:00" + "time": "2021-11-01T20:13:55+00:00" }, { "name": "pocketmine/log", @@ -238,20 +238,20 @@ }, { "name": "pocketmine/log-pthreads", - "version": "0.1.3", + "version": "0.1.4", "source": { "type": "git", "url": "https://github.com/pmmp/LogPthreads.git", - "reference": "e477ecf6ec214fdd4415ea1da3fdd9d73bf699ea" + "reference": "01620c3628cdaa6b4a21122cff4c5d2f70b5c1d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/e477ecf6ec214fdd4415ea1da3fdd9d73bf699ea", - "reference": "e477ecf6ec214fdd4415ea1da3fdd9d73bf699ea", + "url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/01620c3628cdaa6b4a21122cff4c5d2f70b5c1d3", + "reference": "01620c3628cdaa6b4a21122cff4c5d2f70b5c1d3", "shasum": "" }, "require": { - "ext-pthreads": "~3.2.0", + "ext-pthreads": "~3.2.0 || ^4.0", "php": "^7.2 || ^8.0", "pocketmine/log": "^0.2.0" }, @@ -260,7 +260,7 @@ }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.66", + "phpstan/phpstan": "0.12.80", "phpstan/phpstan-strict-rules": "^0.12.4" }, "type": "library", @@ -276,9 +276,9 @@ "description": "Logging components specialized for pthreads used by PocketMine-MP and related projects", "support": { "issues": "https://github.com/pmmp/LogPthreads/issues", - "source": "https://github.com/pmmp/LogPthreads/tree/0.1.3" + "source": "https://github.com/pmmp/LogPthreads/tree/0.1.4" }, - "time": "2021-01-15T00:35:49+00:00" + "time": "2021-11-01T20:36:53+00:00" }, { "name": "pocketmine/math", @@ -365,20 +365,20 @@ }, { "name": "pocketmine/raklib", - "version": "0.12.11", + "version": "0.12.12", "source": { "type": "git", "url": "https://github.com/pmmp/RakLib.git", - "reference": "9cce458b8bfde3e4dfdbf70c659fc7b7fe26b5c4" + "reference": "5abe22043352e94099e4edfcef5fb3644578ddc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/RakLib/zipball/9cce458b8bfde3e4dfdbf70c659fc7b7fe26b5c4", - "reference": "9cce458b8bfde3e4dfdbf70c659fc7b7fe26b5c4", + "url": "https://api.github.com/repos/pmmp/RakLib/zipball/5abe22043352e94099e4edfcef5fb3644578ddc1", + "reference": "5abe22043352e94099e4edfcef5fb3644578ddc1", "shasum": "" }, "require": { - "ext-pthreads": "~3.2.0", + "ext-pthreads": "~3.2.0 || ^4.0", "ext-sockets": "*", "php": "^7.2 || ^8.0", "php-64bit": "*", @@ -389,7 +389,7 @@ "pocketmine/snooze": "^0.1.0" }, "require-dev": { - "phpstan/phpstan": "0.12.76", + "phpstan/phpstan": "0.12.87", "phpstan/phpstan-strict-rules": "^0.12.2" }, "type": "library", @@ -405,26 +405,26 @@ "description": "A RakNet server implementation written in PHP", "support": { "issues": "https://github.com/pmmp/RakLib/issues", - "source": "https://github.com/pmmp/RakLib/tree/0.12.11" + "source": "https://github.com/pmmp/RakLib/tree/0.12.12" }, - "time": "2021-02-15T11:21:05+00:00" + "time": "2021-11-01T20:52:51+00:00" }, { "name": "pocketmine/snooze", - "version": "0.1.5", + "version": "0.1.6", "source": { "type": "git", "url": "https://github.com/pmmp/Snooze.git", - "reference": "70b5e7937a06878dd321a3182ceb76d56298f2cd" + "reference": "92abf1e988c71635d466abb777f61f89e5a9c990" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Snooze/zipball/70b5e7937a06878dd321a3182ceb76d56298f2cd", - "reference": "70b5e7937a06878dd321a3182ceb76d56298f2cd", + "url": "https://api.github.com/repos/pmmp/Snooze/zipball/92abf1e988c71635d466abb777f61f89e5a9c990", + "reference": "92abf1e988c71635d466abb777f61f89e5a9c990", "shasum": "" }, "require": { - "ext-pthreads": ">=3.1.7dev", + "ext-pthreads": "~3.2.0 || ^4.0", "php-64bit": "^7.2 || ^8.0" }, "require-dev": { @@ -445,9 +445,9 @@ "description": "Thread notification management library for code using the pthreads extension", "support": { "issues": "https://github.com/pmmp/Snooze/issues", - "source": "https://github.com/pmmp/Snooze/tree/0.1.5" + "source": "https://github.com/pmmp/Snooze/tree/0.1.6" }, - "time": "2021-02-22T16:16:12+00:00" + "time": "2021-11-01T20:48:46+00:00" }, { "name": "pocketmine/spl", @@ -2769,7 +2769,7 @@ "ext-openssl": "*", "ext-pcre": "*", "ext-phar": "*", - "ext-pthreads": "~3.2.0", + "ext-pthreads": "^4.0", "ext-reflection": "*", "ext-simplexml": "*", "ext-sockets": "*", diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index fd648140d..d9bb9cde7 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -103,8 +103,8 @@ namespace pocketmine { if(substr_count($pthreads_version, ".") < 2){ $pthreads_version = "0.$pthreads_version"; } - if(version_compare($pthreads_version, "3.2.0") < 0){ - $messages[] = "pthreads >= 3.2.0 is required, while you have $pthreads_version."; + if(version_compare($pthreads_version, "4.0.0") < 0 || version_compare($pthreads_version, "5.0.0") > 0){ + $messages[] = "pthreads ^4.0.0 is required, while you have $pthreads_version."; } } diff --git a/tests/gh-actions/build.sh b/tests/gh-actions/build.sh index 4dd13b8fe..89638dd0a 100755 --- a/tests/gh-actions/build.sh +++ b/tests/gh-actions/build.sh @@ -21,5 +21,5 @@ git clone https://github.com/pmmp/php-build.git cd php-build ./install-dependencies.sh echo '"pthreads",,"https://github.com/pmmp/pthreads.git",,,"extension",' >> share/php-build/extension/definition -PHP_BUILD_INSTALL_EXTENSION='pthreads=@a6afc0434f91c1e9541444aef6ac7a1f16c595be yaml=2.2.1' PHP_BUILD_ZTS_ENABLE=on ./bin/php-build "$VERSION" "$INSTALL_DIR" || exit 1 +PHP_BUILD_INSTALL_EXTENSION='pthreads=@4.0.0 yaml=2.2.1' PHP_BUILD_ZTS_ENABLE=on ./bin/php-build "$VERSION" "$INSTALL_DIR" || exit 1 rm "$INSTALL_DIR/etc/conf.d/xdebug.ini" || true From 5257755dc547a6347e5d69bbba48d3dfd053e116 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 21:15:58 +0000 Subject: [PATCH 261/710] shut --- tests/phpstan/configs/actual-problems.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 796ecf18c..8b5c5b192 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -522,7 +522,7 @@ parameters: - message: "#^Parameter \\#1 \\$version1 of function version_compare expects string, string\\|false given\\.$#" - count: 2 + count: 3 path: ../../../src/pocketmine/PocketMine.php - From f6cb4f9597c703d32f8454138125a0c0b9d05ae5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 21:32:02 +0000 Subject: [PATCH 262/710] Updated BedrockProtocol --- composer.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.lock b/composer.lock index ece09d478..568e498ea 100644 --- a/composer.lock +++ b/composer.lock @@ -253,12 +253,12 @@ "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "146498c279b3dc645ab6b8cdf45f7b96d8a33f8b" + "reference": "c76e31fc948f58ad2b788679c84335684396d025" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/146498c279b3dc645ab6b8cdf45f7b96d8a33f8b", - "reference": "146498c279b3dc645ab6b8cdf45f7b96d8a33f8b", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/c76e31fc948f58ad2b788679c84335684396d025", + "reference": "c76e31fc948f58ad2b788679c84335684396d025", "shasum": "" }, "require": { @@ -272,9 +272,9 @@ "ramsey/uuid": "^4.1" }, "require-dev": { - "phpstan/phpstan": "0.12.99", - "phpstan/phpstan-phpunit": "^0.12.21", - "phpstan/phpstan-strict-rules": "^0.12.10", + "phpstan/phpstan": "1.0.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.5" }, "default-branch": true, @@ -293,7 +293,7 @@ "issues": "https://github.com/pmmp/BedrockProtocol/issues", "source": "https://github.com/pmmp/BedrockProtocol/tree/master" }, - "time": "2021-11-01T15:46:55+00:00" + "time": "2021-11-01T18:59:44+00:00" }, { "name": "pocketmine/binaryutils", From f2912fcdd827bceb559a4ee02901688917237231 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 1 Nov 2021 22:22:22 +0000 Subject: [PATCH 263/710] Updated pocketmine/log and pocketmine/log-pthreads (BC breaks included) AttachableLogger deals with Closures now instead of LoggerAttachment objects ThreadedLoggerAttachment no longer implements LoggerAttachment --- composer.json | 4 ++-- composer.lock | 30 +++++++++++++++--------------- src/plugin/PluginLogger.php | 20 ++++++++++++++++---- src/utils/MainLogger.php | 2 +- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/composer.json b/composer.json index 14f5046be..35adb7adc 100644 --- a/composer.json +++ b/composer.json @@ -40,8 +40,8 @@ "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", "pocketmine/errorhandler": "^0.3.0", - "pocketmine/log": "^0.3.0", - "pocketmine/log-pthreads": "^0.2.0", + "pocketmine/log": "^0.4.0", + "pocketmine/log-pthreads": "^0.4.0", "pocketmine/math": "^0.4.0", "pocketmine/nbt": "^0.3.0", "pocketmine/raklib": "^0.14.2", diff --git a/composer.lock b/composer.lock index 568e498ea..6f587ce0f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3aab4c7b78ea85bf5e68e8b953cd9e1f", + "content-hash": "9b3c01e7b850d45218b81a436f463011", "packages": [ { "name": "adhocore/json-comment", @@ -508,16 +508,16 @@ }, { "name": "pocketmine/log", - "version": "0.3.0", + "version": "0.4.0", "source": { "type": "git", "url": "https://github.com/pmmp/Log.git", - "reference": "03ab1316da0b1978a7a1c8dd73e1c2a973cb62ec" + "reference": "e6c912c0f9055c81d23108ec2d179b96f404c043" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Log/zipball/03ab1316da0b1978a7a1c8dd73e1c2a973cb62ec", - "reference": "03ab1316da0b1978a7a1c8dd73e1c2a973cb62ec", + "url": "https://api.github.com/repos/pmmp/Log/zipball/e6c912c0f9055c81d23108ec2d179b96f404c043", + "reference": "e6c912c0f9055c81d23108ec2d179b96f404c043", "shasum": "" }, "require": { @@ -527,7 +527,7 @@ "pocketmine/spl": "<0.4" }, "require-dev": { - "phpstan/phpstan": "0.12.80", + "phpstan/phpstan": "0.12.88", "phpstan/phpstan-strict-rules": "^0.12.2" }, "type": "library", @@ -543,28 +543,28 @@ "description": "Logging components used by PocketMine-MP and related projects", "support": { "issues": "https://github.com/pmmp/Log/issues", - "source": "https://github.com/pmmp/Log/tree/0.3.0" + "source": "https://github.com/pmmp/Log/tree/0.4.0" }, - "time": "2021-05-18T21:00:49+00:00" + "time": "2021-06-18T19:08:09+00:00" }, { "name": "pocketmine/log-pthreads", - "version": "0.2.1", + "version": "0.4.0", "source": { "type": "git", "url": "https://github.com/pmmp/LogPthreads.git", - "reference": "26f51ed44b1884f6dd72c06a883d9d07613af4f1" + "reference": "61f709e8cf36bcc24e4efe02acded680a1ce23cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/26f51ed44b1884f6dd72c06a883d9d07613af4f1", - "reference": "26f51ed44b1884f6dd72c06a883d9d07613af4f1", + "url": "https://api.github.com/repos/pmmp/LogPthreads/zipball/61f709e8cf36bcc24e4efe02acded680a1ce23cd", + "reference": "61f709e8cf36bcc24e4efe02acded680a1ce23cd", "shasum": "" }, "require": { "ext-pthreads": "~3.2.0 || ^4.0", "php": "^7.4 || ^8.0", - "pocketmine/log": "^0.2.0 || ^0.3.0" + "pocketmine/log": "^0.4.0" }, "conflict": { "pocketmine/spl": "<0.4" @@ -587,9 +587,9 @@ "description": "Logging components specialized for pthreads used by PocketMine-MP and related projects", "support": { "issues": "https://github.com/pmmp/LogPthreads/issues", - "source": "https://github.com/pmmp/LogPthreads/tree/0.2.1" + "source": "https://github.com/pmmp/LogPthreads/tree/0.4.0" }, - "time": "2021-11-01T20:41:37+00:00" + "time": "2021-11-01T21:42:09+00:00" }, { "name": "pocketmine/math", diff --git a/src/plugin/PluginLogger.php b/src/plugin/PluginLogger.php index ba310563b..1a1ab9cdb 100644 --- a/src/plugin/PluginLogger.php +++ b/src/plugin/PluginLogger.php @@ -25,16 +25,28 @@ namespace pocketmine\plugin; use function spl_object_id; +/** + * @phpstan-import-type LoggerAttachment from \AttachableLogger + */ class PluginLogger extends \PrefixedLogger implements \AttachableLogger{ - /** @var \LoggerAttachment[] */ + /** + * @var \Closure[] + * @phpstan-var LoggerAttachment[] + */ private $attachments = []; - public function addAttachment(\LoggerAttachment $attachment){ + /** + * @phpstan-param LoggerAttachment $attachment + */ + public function addAttachment(\Closure $attachment){ $this->attachments[spl_object_id($attachment)] = $attachment; } - public function removeAttachment(\LoggerAttachment $attachment){ + /** + * @phpstan-param LoggerAttachment $attachment + */ + public function removeAttachment(\Closure $attachment){ unset($this->attachments[spl_object_id($attachment)]); } @@ -49,7 +61,7 @@ class PluginLogger extends \PrefixedLogger implements \AttachableLogger{ public function log($level, $message){ parent::log($level, $message); foreach($this->attachments as $attachment){ - $attachment->log($level, $message); + $attachment($level, $message); } } } diff --git a/src/utils/MainLogger.php b/src/utils/MainLogger.php index 1e5c53044..c7290f0d2 100644 --- a/src/utils/MainLogger.php +++ b/src/utils/MainLogger.php @@ -210,7 +210,7 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ $this->logWriterThread->write($time->format("Y-m-d") . " " . TextFormat::clean($message) . PHP_EOL); foreach($this->attachments as $attachment){ - $attachment->call($level, $message); + $attachment->log($level, $message); } }); } From 0f6b7e48cb29f1abc2cb957c546077398f5b8a05 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 01:37:56 +0000 Subject: [PATCH 264/710] Updated BedrockProtocol: it's weirdly satisfying that LevelChunkPacket::create() with the extra parameter turns out to be exactly the same length as the old way. --- composer.lock | 8 ++++---- src/network/mcpe/ChunkRequestTask.php | 2 +- src/network/mcpe/NetworkSession.php | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 6f587ce0f..b2878d494 100644 --- a/composer.lock +++ b/composer.lock @@ -253,12 +253,12 @@ "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "c76e31fc948f58ad2b788679c84335684396d025" + "reference": "67c0c15b4044cab2190501933912c3d02c5f63ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/c76e31fc948f58ad2b788679c84335684396d025", - "reference": "c76e31fc948f58ad2b788679c84335684396d025", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/67c0c15b4044cab2190501933912c3d02c5f63ab", + "reference": "67c0c15b4044cab2190501933912c3d02c5f63ab", "shasum": "" }, "require": { @@ -293,7 +293,7 @@ "issues": "https://github.com/pmmp/BedrockProtocol/issues", "source": "https://github.com/pmmp/BedrockProtocol/tree/master" }, - "time": "2021-11-01T18:59:44+00:00" + "time": "2021-11-02T01:27:05+00:00" }, { "name": "pocketmine/binaryutils", diff --git a/src/network/mcpe/ChunkRequestTask.php b/src/network/mcpe/ChunkRequestTask.php index 676a480a9..8279fc00e 100644 --- a/src/network/mcpe/ChunkRequestTask.php +++ b/src/network/mcpe/ChunkRequestTask.php @@ -72,7 +72,7 @@ class ChunkRequestTask extends AsyncTask{ $subCount = ChunkSerializer::getSubChunkCount($chunk); $encoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()); $payload = ChunkSerializer::serializeFullChunk($chunk, RuntimeBlockMapping::getInstance(), $encoderContext, $this->tiles); - $this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $subCount, $payload))->getBuffer())); + $this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::create($this->chunkX, $this->chunkZ, $subCount, null, $payload))->getBuffer())); } public function onError() : void{ diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 4a7cfe259..ed910c45e 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -563,7 +563,7 @@ class NetworkSession{ */ private function doServerDisconnect(string $reason, bool $notify = true) : void{ if($notify){ - $this->sendDataPacket($reason === "" ? DisconnectPacket::silent() : DisconnectPacket::message($reason), true); + $this->sendDataPacket(DisconnectPacket::create($reason !== "" ? $reason : null), true); } $this->sender->close($notify ? $reason : ""); From c17587d436c36d5fc801999768e090d223899ee9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 03:00:00 +0000 Subject: [PATCH 265/710] World: use new Vector3() instead of Block->getPosition() When profiling this, I noticed that we spend a stupidly large amount of time creating useless Position objects in the case of update=true, because Vector3->sides() calls Position->getSide(), which calls Position::fromObject(parent::getSide()). This is stupid because the update logic doesn't require Positions anywhere (as evidenced by this change needing no other alterations. A rough profile shows that this improves setBlock() performance by about 25% in the update=true case, which is a pretty big margin. As an added bonus, it gets rid of some unrealized cyclic dependencies in World->changedBlocks. --- src/world/World.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/World.php b/src/world/World.php index a6c71cd6f..43768cfc3 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -1600,7 +1600,7 @@ class World implements ChunkManager{ $block->position($this, $x, $y, $z); $block->writeStateToWorld(); - $pos = $block->getPosition(); + $pos = new Vector3($x, $y, $z); $chunkHash = World::chunkHash($chunkX, $chunkZ); $relativeBlockHash = World::chunkBlockHash($x, $y, $z); From 7e4be29fc44c2a7298b5b803c3f805be940c3439 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 13:51:01 +0000 Subject: [PATCH 266/710] Gracefully force-shutdown on failure to start RakLib this now won't generate a crashdump. --- resources/locale | 2 +- src/Server.php | 15 ++++- src/lang/KnownTranslationFactory.php | 8 +++ src/lang/KnownTranslationKeys.php | 1 + src/network/Network.php | 3 + src/network/NetworkInterface.php | 1 + .../NetworkInterfaceStartException.php | 32 ++++++++++ src/network/mcpe/raklib/RakLibInterface.php | 11 +++- src/network/mcpe/raklib/RakLibServer.php | 30 ++++++--- .../mcpe/raklib/RakLibThreadCrashInfo.php | 61 +++++++++++++++++++ 10 files changed, 150 insertions(+), 14 deletions(-) create mode 100644 src/network/NetworkInterfaceStartException.php create mode 100644 src/network/mcpe/raklib/RakLibThreadCrashInfo.php diff --git a/resources/locale b/resources/locale index 09c709f24..f9076e4a6 160000 --- a/resources/locale +++ b/resources/locale @@ -1 +1 @@ -Subproject commit 09c709f2426cb8d21d2a4851ad6df5a254a40fd4 +Subproject commit f9076e4a6e3049aeaf7abd30d39a482a1392eafe diff --git a/src/Server.php b/src/Server.php index 475a4385b..277a56ad6 100644 --- a/src/Server.php +++ b/src/Server.php @@ -64,6 +64,7 @@ use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\serializer\PacketBatch; use pocketmine\network\mcpe\raklib\RakLibInterface; use pocketmine\network\Network; +use pocketmine\network\NetworkInterfaceStartException; use pocketmine\network\query\DedicatedQueryNetworkInterface; use pocketmine\network\query\QueryHandler; use pocketmine\network\query\QueryInfo; @@ -980,6 +981,7 @@ class Server{ $this->enablePlugins(PluginEnableOrder::POSTWORLD()); if(!$this->startupPrepareNetworkInterfaces()){ + $this->forceShutdown(); return; } @@ -1113,7 +1115,18 @@ class Server{ private function startupPrepareNetworkInterfaces() : bool{ $useQuery = $this->configGroup->getConfigBool("enable-query", true); - if(!$this->network->registerInterface(new RakLibInterface($this)) && $useQuery){ + + try{ + $rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this)); + }catch(NetworkInterfaceStartException $e){ + $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed( + $this->getIp(), + (string) $this->getPort(), + $e->getMessage() + ))); + return false; + } + if(!$rakLibRegistered && $useQuery){ //RakLib would normally handle the transport for Query packets //if it's not registered we need to make sure Query still works $this->network->registerInterface(new DedicatedQueryNetworkInterface($this->getIp(), $this->getPort(), new \PrefixedLogger($this->logger, "Dedicated Query Interface"))); diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index a08e87f5c..04b644f83 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1950,6 +1950,14 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_server_networkStartFailed(Translatable|string $ipAddress, Translatable|string $port, Translatable|string $errorMessage) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_NETWORKSTARTFAILED, [ + "ipAddress" => $ipAddress, + "port" => $port, + "errorMessage" => $errorMessage, + ]); + } + public static function pocketmine_server_query_running(Translatable|string $param0, Translatable|string $param1) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_QUERY_RUNNING, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index cf4aca555..2a609c8d8 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -401,6 +401,7 @@ final class KnownTranslationKeys{ public const POCKETMINE_SERVER_INFO_EXTENDED = "pocketmine.server.info.extended"; public const POCKETMINE_SERVER_LICENSE = "pocketmine.server.license"; public const POCKETMINE_SERVER_NETWORKSTART = "pocketmine.server.networkStart"; + public const POCKETMINE_SERVER_NETWORKSTARTFAILED = "pocketmine.server.networkStartFailed"; public const POCKETMINE_SERVER_QUERY_RUNNING = "pocketmine.server.query.running"; public const POCKETMINE_SERVER_START = "pocketmine.server.start"; public const POCKETMINE_SERVER_STARTFINISHED = "pocketmine.server.startFinished"; diff --git a/src/network/Network.php b/src/network/Network.php index 22c1b2f39..fc65e3aca 100644 --- a/src/network/Network.php +++ b/src/network/Network.php @@ -91,6 +91,9 @@ class Network{ $this->sessionManager->tick(); } + /** + * @throws NetworkInterfaceStartException + */ public function registerInterface(NetworkInterface $interface) : bool{ $ev = new NetworkInterfaceRegisterEvent($interface); $ev->call(); diff --git a/src/network/NetworkInterface.php b/src/network/NetworkInterface.php index 146a7351c..a6beddbae 100644 --- a/src/network/NetworkInterface.php +++ b/src/network/NetworkInterface.php @@ -33,6 +33,7 @@ interface NetworkInterface{ /** * Performs actions needed to start the interface after it is registered. + * @throws NetworkInterfaceStartException */ public function start() : void; diff --git a/src/network/NetworkInterfaceStartException.php b/src/network/NetworkInterfaceStartException.php new file mode 100644 index 000000000..3dfd2b0a7 --- /dev/null +++ b/src/network/NetworkInterfaceStartException.php @@ -0,0 +1,32 @@ +eventReceiver->handle($this)); }); $this->server->getLogger()->debug("Waiting for RakLib to start..."); - $this->rakLib->startAndWait(); + try{ + $this->rakLib->startAndWait(); + }catch(SocketException $e){ + throw new NetworkInterfaceStartException($e->getMessage(), 0, $e); + } $this->server->getLogger()->debug("RakLib booted successfully"); } @@ -132,7 +139,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{ if(!$this->rakLib->isRunning()){ $e = $this->rakLib->getCrashInfo(); if($e !== null){ - throw new \RuntimeException("RakLib crashed: $e"); + throw new \RuntimeException("RakLib crashed: " . $e->makePrettyMessage()); } throw new \Exception("RakLib Thread crashed without crash information"); } diff --git a/src/network/mcpe/raklib/RakLibServer.php b/src/network/mcpe/raklib/RakLibServer.php index 7591475ee..94ea2c973 100644 --- a/src/network/mcpe/raklib/RakLibServer.php +++ b/src/network/mcpe/raklib/RakLibServer.php @@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\raklib; use pocketmine\snooze\SleeperNotifier; use pocketmine\thread\Thread; use raklib\generic\Socket; +use raklib\generic\SocketException; use raklib\server\ipc\RakLibToUserThreadMessageSender; use raklib\server\ipc\UserToRakLibThreadMessageReceiver; use raklib\server\Server; @@ -68,7 +69,7 @@ class RakLibServer extends Thread{ /** @var SleeperNotifier */ protected $mainThreadNotifier; - /** @var string|null */ + /** @var RakLibThreadCrashInfo|null */ public $crashInfo = null; public function __construct( @@ -102,24 +103,24 @@ class RakLibServer extends Thread{ * @return void */ public function shutdownHandler(){ - if($this->cleanShutdown !== true){ + if($this->cleanShutdown !== true && $this->crashInfo === null){ $error = error_get_last(); if($error !== null){ $this->logger->emergency("Fatal error: " . $error["message"] . " in " . $error["file"] . " on line " . $error["line"]); - $this->setCrashInfo($error['message']); + $this->setCrashInfo(RakLibThreadCrashInfo::fromLastErrorInfo($error)); }else{ $this->logger->emergency("RakLib shutdown unexpectedly"); } } } - public function getCrashInfo() : ?string{ + public function getCrashInfo() : ?RakLibThreadCrashInfo{ return $this->crashInfo; } - private function setCrashInfo(string $info) : void{ - $this->synchronized(function(string $info) : void{ + private function setCrashInfo(RakLibThreadCrashInfo $info) : void{ + $this->synchronized(function(RakLibThreadCrashInfo $info) : void{ $this->crashInfo = $info; $this->notify(); }, $info); @@ -131,8 +132,12 @@ class RakLibServer extends Thread{ while(!$this->ready and $this->crashInfo === null){ $this->wait(); } - if($this->crashInfo !== null){ - throw new \RuntimeException("RakLib failed to start: $this->crashInfo"); + $crashInfo = $this->crashInfo; + if($crashInfo !== null){ + if($crashInfo->getClass() === SocketException::class){ + throw new SocketException($crashInfo->getMessage()); + } + throw new \RuntimeException("RakLib failed to start: " . $crashInfo->makePrettyMessage()); } }); } @@ -145,7 +150,12 @@ class RakLibServer extends Thread{ register_shutdown_function([$this, "shutdownHandler"]); - $socket = new Socket($this->address); + try{ + $socket = new Socket($this->address); + }catch(SocketException $e){ + $this->setCrashInfo(RakLibThreadCrashInfo::fromThrowable($e)); + return; + } $manager = new Server( $this->serverId, $this->logger, @@ -166,7 +176,7 @@ class RakLibServer extends Thread{ $manager->waitShutdown(); $this->cleanShutdown = true; }catch(\Throwable $e){ - $this->setCrashInfo($e->getMessage()); + $this->setCrashInfo(RakLibThreadCrashInfo::fromThrowable($e)); $this->logger->logException($e); } } diff --git a/src/network/mcpe/raklib/RakLibThreadCrashInfo.php b/src/network/mcpe/raklib/RakLibThreadCrashInfo.php new file mode 100644 index 000000000..826cdc42d --- /dev/null +++ b/src/network/mcpe/raklib/RakLibThreadCrashInfo.php @@ -0,0 +1,61 @@ +getMessage(), $e->getFile(), $e->getLine()); + } + + /** + * @phpstan-param array{message: string, file: string, line: int} $info + */ + public static function fromLastErrorInfo(array $info) : self{ + return new self(null, $info["message"], $info["file"], $info["line"]); + } + + /** @return string|null */ + public function getClass() : ?string{ return $this->class; } + + public function getMessage() : string{ return $this->message; } + + public function getFile() : string{ return $this->file; } + + public function getLine() : int{ return $this->line; } + + public function makePrettyMessage() : string{ + return sprintf("%s: \"%s\" in %s on line %d", $this->class ?? "Fatal error", $this->message, Filesystem::cleanPath($this->file), $this->line); + } +} \ No newline at end of file From 32a857b8b4a45ec6945e6b91b1679ffc16c450e4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 14:09:16 +0000 Subject: [PATCH 267/710] fix CS --- src/network/mcpe/raklib/RakLibInterface.php | 1 - src/network/mcpe/raklib/RakLibThreadCrashInfo.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/mcpe/raklib/RakLibInterface.php b/src/network/mcpe/raklib/RakLibInterface.php index 097236013..4bfee2258 100644 --- a/src/network/mcpe/raklib/RakLibInterface.php +++ b/src/network/mcpe/raklib/RakLibInterface.php @@ -36,7 +36,6 @@ use pocketmine\network\NetworkInterfaceStartException; use pocketmine\network\PacketHandlingException; use pocketmine\Server; use pocketmine\snooze\SleeperNotifier; -use pocketmine\utils\Filesystem; use pocketmine\utils\Utils; use raklib\generic\SocketException; use raklib\protocol\EncapsulatedPacket; diff --git a/src/network/mcpe/raklib/RakLibThreadCrashInfo.php b/src/network/mcpe/raklib/RakLibThreadCrashInfo.php index 826cdc42d..806aebc85 100644 --- a/src/network/mcpe/raklib/RakLibThreadCrashInfo.php +++ b/src/network/mcpe/raklib/RakLibThreadCrashInfo.php @@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe\raklib; use pocketmine\utils\Filesystem; use function get_class; +use function sprintf; final class RakLibThreadCrashInfo{ From 1775699f05ee44094353fc13f815b1026d56ad47 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 14:20:42 +0000 Subject: [PATCH 268/710] World: make sure that chunks locked by PopulationTask always get unlocked, no matter what fixes #4527 --- src/world/World.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 43768cfc3..3725da08e 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2908,21 +2908,17 @@ class World implements ChunkManager{ public function generateChunkCallback(ChunkLockId $chunkLockId, int $x, int $z, Chunk $chunk, array $adjacentChunks, ChunkLoader $temporaryChunkLoader) : void{ Timings::$generationCallback->startTiming(); + $dirtyChunks = 0; for($xx = -1; $xx <= 1; ++$xx){ for($zz = -1; $zz <= 1; ++$zz){ $this->unregisterChunkLoader($temporaryChunkLoader, $x + $xx, $z + $zz); + if(!$this->unlockChunk($x + $xx, $z + $zz, $chunkLockId)){ + $dirtyChunks++; + } } } if(isset($this->chunkPopulationRequestMap[$index = World::chunkHash($x, $z)]) && isset($this->activeChunkPopulationTasks[$index])){ - $dirtyChunks = 0; - for($xx = -1; $xx <= 1; ++$xx){ - for($zz = -1; $zz <= 1; ++$zz){ - if(!$this->unlockChunk($x + $xx, $z + $zz, $chunkLockId)){ - $dirtyChunks++; - } - } - } if($dirtyChunks === 0){ $oldChunk = $this->loadChunk($x, $z); $this->setChunk($x, $z, $chunk); From 34ea199fb0da75890930f019d28dc78dc2b0e26a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 14:30:23 +0000 Subject: [PATCH 269/710] World: fixed additional edge case - population promise rejected before task completion if this happened, the index would stay set in activeChunkPopulationTasks, eventually causing the generation queue to jam up completely and non-forced generation to come to a standstill. --- src/world/World.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/world/World.php b/src/world/World.php index 3725da08e..cb4039b89 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2918,7 +2918,11 @@ class World implements ChunkManager{ } } - if(isset($this->chunkPopulationRequestMap[$index = World::chunkHash($x, $z)]) && isset($this->activeChunkPopulationTasks[$index])){ + $index = World::chunkHash($x, $z); + if(!isset($this->chunkPopulationRequestMap[$index])){ + $this->logger->debug("Discarding population result for chunk x=$x,z=$z - promise was already broken"); + unset($this->activeChunkPopulationTasks[$index]); + }elseif(isset($this->activeChunkPopulationTasks[$index])){ if($dirtyChunks === 0){ $oldChunk = $this->loadChunk($x, $z); $this->setChunk($x, $z, $chunk); From ede4157814829e1afa1f97ca187baaa0e326fab8 Mon Sep 17 00:00:00 2001 From: Rush2929 <76860328+Rush2929@users.noreply.github.com> Date: Tue, 2 Nov 2021 23:36:16 +0900 Subject: [PATCH 270/710] Check to see if the player can start using the Releasable item. (#4532) --- src/item/Bow.php | 4 ++++ src/item/Food.php | 5 +++++ src/item/MilkBucket.php | 5 +++++ src/item/Potion.php | 5 +++++ src/item/Releasable.php | 4 ++++ src/player/Player.php | 2 +- 6 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/item/Bow.php b/src/item/Bow.php index fd6364e84..41777e0a6 100644 --- a/src/item/Bow.php +++ b/src/item/Bow.php @@ -123,4 +123,8 @@ class Bow extends Tool implements Releasable{ return ItemUseResult::SUCCESS(); } + + public function canStartUsingItem(Player $player) : bool{ + return !$player->hasFiniteResources() || $player->getOffHandInventory()->contains($arrow = VanillaItems::ARROW()) || $player->getInventory()->contains($arrow); + } } diff --git a/src/item/Food.php b/src/item/Food.php index ff737e329..ddaa77da6 100644 --- a/src/item/Food.php +++ b/src/item/Food.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\item; use pocketmine\entity\Living; +use pocketmine\player\Player; abstract class Food extends Item implements FoodSourceItem{ public function requiresHunger() : bool{ @@ -41,4 +42,8 @@ abstract class Food extends Item implements FoodSourceItem{ public function onConsume(Living $consumer) : void{ } + + public function canStartUsingItem(Player $player) : bool{ + return !$this->requiresHunger() || $player->getHungerManager()->isHungry(); + } } diff --git a/src/item/MilkBucket.php b/src/item/MilkBucket.php index 4419a510f..f8c8b3ddf 100644 --- a/src/item/MilkBucket.php +++ b/src/item/MilkBucket.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\item; use pocketmine\entity\Living; +use pocketmine\player\Player; class MilkBucket extends Item implements ConsumableItem{ @@ -42,4 +43,8 @@ class MilkBucket extends Item implements ConsumableItem{ public function onConsume(Living $consumer) : void{ $consumer->getEffects()->clear(); } + + public function canStartUsingItem(Player $player) : bool{ + return true; + } } diff --git a/src/item/Potion.php b/src/item/Potion.php index 5b2bbc17e..5be216e96 100644 --- a/src/item/Potion.php +++ b/src/item/Potion.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\item; use pocketmine\entity\Living; +use pocketmine\player\Player; class Potion extends Item implements ConsumableItem{ @@ -52,4 +53,8 @@ class Potion extends Item implements ConsumableItem{ public function getResidue() : Item{ return VanillaItems::GLASS_BOTTLE(); } + + public function canStartUsingItem(Player $player) : bool{ + return true; + } } diff --git a/src/item/Releasable.php b/src/item/Releasable.php index 07e77cf28..acb9d65c8 100644 --- a/src/item/Releasable.php +++ b/src/item/Releasable.php @@ -23,9 +23,13 @@ declare(strict_types=1); namespace pocketmine\item; +use pocketmine\player\Player; + /** * Interface implemented by objects that can be used. */ interface Releasable{ + public function canStartUsingItem(Player $player) : bool; + } diff --git a/src/player/Player.php b/src/player/Player.php index 3b74b27c7..a568ba644 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1374,7 +1374,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->inventory->setItemInHand($item); } - $this->setUsingItem($item instanceof Releasable); + $this->setUsingItem($item instanceof Releasable && $item->canStartUsingItem($this)); return true; } From 4dc13ab3dafd1e008325e6232085dfe0efc2f59f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 15:11:10 +0000 Subject: [PATCH 271/710] ConsoleReaderThread: strip control characters this fixes a bug I encountered when accidentally pressing ctrl+a+d (which inserts a chr(1) character), because it made the server unable to find the command - but still reported an error containing what looked like a valid command (character isn't printable). --- src/console/ConsoleReaderThread.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/console/ConsoleReaderThread.php b/src/console/ConsoleReaderThread.php index fde505f3c..dbf3770d3 100644 --- a/src/console/ConsoleReaderThread.php +++ b/src/console/ConsoleReaderThread.php @@ -114,7 +114,9 @@ final class ConsoleReaderThread extends Thread{ break; } - $buffer[] = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", trim($command)); + $command = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", trim($command)) ?? throw new AssumptionFailedError("This regex is assumed to be valid"); + $command = preg_replace('/[[:cntrl:]]/', '', $command) ?? throw new AssumptionFailedError("This regex is assumed to be valid"); + $buffer[] = $command; if($notifier !== null){ $notifier->wakeupSleeper(); } From 65ef9f786adfbcbcd14bd103b491b6458e9249a2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 15:25:03 +0000 Subject: [PATCH 272/710] Use standard chunkHash() to index population chunks --- src/world/World.php | 15 +++++++-------- src/world/generator/PopulationTask.php | 19 +++++++------------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index cb4039b89..27444ad6a 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2082,13 +2082,12 @@ class World implements ChunkManager{ */ public function getAdjacentChunks(int $x, int $z) : array{ $result = []; - for($xx = 0; $xx <= 2; ++$xx){ - for($zz = 0; $zz <= 2; ++$zz){ - $i = $zz * 3 + $xx; - if($i === 4){ + for($xx = -1; $xx <= 1; ++$xx){ + for($zz = -1; $zz <= 1; ++$zz){ + if($xx === 0 && $zz === 0){ continue; //center chunk } - $result[$i] = $this->loadChunk($x + $xx - 1, $z + $zz - 1); + $result[World::chunkHash($xx, $zz)] = $this->loadChunk($x + $xx, $z + $zz); } } @@ -2927,9 +2926,9 @@ class World implements ChunkManager{ $oldChunk = $this->loadChunk($x, $z); $this->setChunk($x, $z, $chunk); - foreach($adjacentChunks as $adjacentChunkHash => $adjacentChunk){ - World::getXZ($adjacentChunkHash, $xAdjacentChunk, $zAdjacentChunk); - $this->setChunk($xAdjacentChunk, $zAdjacentChunk, $adjacentChunk); + foreach($adjacentChunks as $relativeChunkHash => $adjacentChunk){ + World::getXZ($relativeChunkHash, $relativeX, $relativeZ); + $this->setChunk($x + $relativeX, $z + $relativeZ, $adjacentChunk); } if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 5a628248d..55b612a8a 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -36,7 +36,6 @@ use pocketmine\world\World; use function array_map; use function igbinary_serialize; use function igbinary_unserialize; -use function intdiv; class PopulationTask extends AsyncTask{ private const TLS_KEY_WORLD = "world"; @@ -92,10 +91,9 @@ class PopulationTask extends AsyncTask{ /** @var Chunk[] $resultChunks */ $resultChunks = []; //this is just to keep phpstan's type inference happy - foreach($chunks as $i => $c){ - $cX = (-1 + $i % 3) + $this->chunkX; - $cZ = (-1 + intdiv($i, 3)) + $this->chunkZ; - $resultChunks[$i] = self::setOrGenerateChunk($manager, $generator, $cX, $cZ, $c); + foreach($chunks as $relativeChunkHash => $c){ + World::getXZ($relativeChunkHash, $relativeX, $relativeZ); + $resultChunks[$relativeChunkHash] = self::setOrGenerateChunk($manager, $generator, $this->chunkX + $relativeX, $this->chunkZ + $relativeZ, $c); } $chunks = $resultChunks; @@ -109,8 +107,8 @@ class PopulationTask extends AsyncTask{ $this->chunk = FastChunkSerializer::serializeTerrain($chunk); $serialChunks = []; - foreach($chunks as $i => $c){ - $serialChunks[$i] = $c->isTerrainDirty() ? FastChunkSerializer::serializeTerrain($c) : null; + foreach($chunks as $relativeChunkHash => $c){ + $serialChunks[$relativeChunkHash] = $c->isTerrainDirty() ? FastChunkSerializer::serializeTerrain($c) : null; } $this->adjacentChunks = igbinary_serialize($serialChunks) ?? throw new AssumptionFailedError("igbinary_serialize() returned null"); } @@ -147,12 +145,9 @@ class PopulationTask extends AsyncTask{ */ $serialAdjacentChunks = igbinary_unserialize($this->adjacentChunks); $adjacentChunks = []; - foreach($serialAdjacentChunks as $i => $c){ + foreach($serialAdjacentChunks as $relativeChunkHash => $c){ if($c !== null){ - $xx = -1 + $i % 3; - $zz = -1 + intdiv($i, 3); - - $adjacentChunks[World::chunkHash($this->chunkX + $xx, $this->chunkZ + $zz)] = FastChunkSerializer::deserializeTerrain($c); + $adjacentChunks[$relativeChunkHash] = FastChunkSerializer::deserializeTerrain($c); } } From facfd7c04a25ef8c79bad8547e493b97cae2e7ad Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 15:26:54 +0000 Subject: [PATCH 273/710] sanity check --- src/world/World.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/world/World.php b/src/world/World.php index 27444ad6a..a54065035 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2928,6 +2928,9 @@ class World implements ChunkManager{ foreach($adjacentChunks as $relativeChunkHash => $adjacentChunk){ World::getXZ($relativeChunkHash, $relativeX, $relativeZ); + if($relativeX < -1 || $relativeX > 1 || $relativeZ < -1 || $relativeZ > 1){ + throw new AssumptionFailedError("Adjacent chunks should be in range -1 ... +1 coordinates"); + } $this->setChunk($x + $relativeX, $z + $relativeZ, $adjacentChunk); } From 8b3565b75db9877dfbf0dcd789e39fa5b57905e5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 15:40:51 +0000 Subject: [PATCH 274/710] PopulationTask no longer depends on a World object this means it's now possible to test generation offline without too much hassle. World::generateChunkCallback() has been removed from public API. --- src/world/World.php | 19 +++++++- src/world/generator/PopulationTask.php | 66 +++++++++++++------------- 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index a54065035..246799a85 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2889,7 +2889,22 @@ class World implements ChunkManager{ } } - $task = new PopulationTask($this, $chunkX, $chunkZ, $this->loadChunk($chunkX, $chunkZ), $temporaryChunkLoader, $chunkPopulationLockId); + $centerChunk = $this->loadChunk($chunkX, $chunkZ); + $adjacentChunks = $this->getAdjacentChunks($chunkX, $chunkZ); + $task = new PopulationTask( + $this->worldId, + $chunkX, + $chunkZ, + $centerChunk, + $adjacentChunks, + function(Chunk $centerChunk, array $adjacentChunks) use ($chunkPopulationLockId, $chunkX, $chunkZ, $temporaryChunkLoader) : void{ + if(!$this->isLoaded()){ + return; + } + + $this->generateChunkCallback($chunkPopulationLockId, $chunkX, $chunkZ, $centerChunk, $adjacentChunks, $temporaryChunkLoader); + } + ); $workerId = $this->workerPool->selectWorker(); if(!isset($this->generatorRegisteredWorkers[$workerId])){ $this->registerGeneratorToWorker($workerId); @@ -2904,7 +2919,7 @@ class World implements ChunkManager{ * @param Chunk[] $adjacentChunks chunkHash => chunk * @phpstan-param array $adjacentChunks */ - public function generateChunkCallback(ChunkLockId $chunkLockId, int $x, int $z, Chunk $chunk, array $adjacentChunks, ChunkLoader $temporaryChunkLoader) : void{ + private function generateChunkCallback(ChunkLockId $chunkLockId, int $x, int $z, Chunk $chunk, array $adjacentChunks, ChunkLoader $temporaryChunkLoader) : void{ Timings::$generationCallback->startTiming(); $dirtyChunks = 0; diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 55b612a8a..f1f2d3858 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -26,8 +26,6 @@ namespace pocketmine\world\generator; use pocketmine\data\bedrock\BiomeIds; use pocketmine\scheduler\AsyncTask; use pocketmine\utils\AssumptionFailedError; -use pocketmine\world\ChunkLoader; -use pocketmine\world\ChunkLockId; use pocketmine\world\format\BiomeArray; use pocketmine\world\format\Chunk; use pocketmine\world\format\io\FastChunkSerializer; @@ -37,10 +35,11 @@ use function array_map; use function igbinary_serialize; use function igbinary_unserialize; +/** + * @phpstan-type OnCompletion \Closure(Chunk $centerChunk, array $adjacentChunks) : void + */ class PopulationTask extends AsyncTask{ - private const TLS_KEY_WORLD = "world"; - private const TLS_KEY_CHUNK_LOADER = "chunkLoader"; - private const TLS_KEY_LOCK_ID = "chunkLockId"; + private const TLS_KEY_ON_COMPLETION = "onCompletion"; /** @var int */ public $worldId; @@ -54,20 +53,23 @@ class PopulationTask extends AsyncTask{ private string $adjacentChunks; - public function __construct(World $world, int $chunkX, int $chunkZ, ?Chunk $chunk, ChunkLoader $temporaryChunkLoader, ChunkLockId $chunkLockId){ - $this->worldId = $world->getId(); + /** + * @param Chunk[]|null[] $adjacentChunks + * @phpstan-param array $adjacentChunks + * @phpstan-param OnCompletion $onCompletion + */ + public function __construct(int $worldId, int $chunkX, int $chunkZ, ?Chunk $chunk, array $adjacentChunks, \Closure $onCompletion){ + $this->worldId = $worldId; $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; $this->chunk = $chunk !== null ? FastChunkSerializer::serializeTerrain($chunk) : null; $this->adjacentChunks = igbinary_serialize(array_map( fn(?Chunk $c) => $c !== null ? FastChunkSerializer::serializeTerrain($c) : null, - $world->getAdjacentChunks($chunkX, $chunkZ) + $adjacentChunks )) ?? throw new AssumptionFailedError("igbinary_serialize() returned null"); - $this->storeLocal(self::TLS_KEY_WORLD, $world); - $this->storeLocal(self::TLS_KEY_CHUNK_LOADER, $temporaryChunkLoader); - $this->storeLocal(self::TLS_KEY_LOCK_ID, $chunkLockId); + $this->storeLocal(self::TLS_KEY_ON_COMPLETION, $onCompletion); } public function onRun() : void{ @@ -128,30 +130,28 @@ class PopulationTask extends AsyncTask{ } public function onCompletion() : void{ - /** @var World $world */ - $world = $this->fetchLocal(self::TLS_KEY_WORLD); - /** @var ChunkLoader $temporaryChunkLoader */ - $temporaryChunkLoader = $this->fetchLocal(self::TLS_KEY_CHUNK_LOADER); - /** @var ChunkLockId $lockId */ - $lockId = $this->fetchLocal(self::TLS_KEY_LOCK_ID); - if($world->isLoaded()){ - $chunk = $this->chunk !== null ? - FastChunkSerializer::deserializeTerrain($this->chunk) : - throw new AssumptionFailedError("Center chunk should never be null"); + /** + * @var \Closure $onCompletion + * @phpstan-var OnCompletion $onCompletion + */ + $onCompletion = $this->fetchLocal(self::TLS_KEY_ON_COMPLETION); - /** - * @var string[]|null[] $serialAdjacentChunks - * @phpstan-var array $serialAdjacentChunks - */ - $serialAdjacentChunks = igbinary_unserialize($this->adjacentChunks); - $adjacentChunks = []; - foreach($serialAdjacentChunks as $relativeChunkHash => $c){ - if($c !== null){ - $adjacentChunks[$relativeChunkHash] = FastChunkSerializer::deserializeTerrain($c); - } + $chunk = $this->chunk !== null ? + FastChunkSerializer::deserializeTerrain($this->chunk) : + throw new AssumptionFailedError("Center chunk should never be null"); + + /** + * @var string[]|null[] $serialAdjacentChunks + * @phpstan-var array $serialAdjacentChunks + */ + $serialAdjacentChunks = igbinary_unserialize($this->adjacentChunks); + $adjacentChunks = []; + foreach($serialAdjacentChunks as $relativeChunkHash => $c){ + if($c !== null){ + $adjacentChunks[$relativeChunkHash] = FastChunkSerializer::deserializeTerrain($c); } - - $world->generateChunkCallback($lockId, $this->chunkX, $this->chunkZ, $chunk, $adjacentChunks, $temporaryChunkLoader); } + + $onCompletion($chunk, $adjacentChunks); } } From 4eef458d29feceea0a6814f7ad641939b022171b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 16:03:43 +0000 Subject: [PATCH 275/710] Config: throw AssumptionFailedError if config type is invalid or DETECT during save() this should never happen ... it was already checked in load() --- src/utils/Config.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/utils/Config.php b/src/utils/Config.php index 696269a1b..f65f77190 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -205,8 +205,6 @@ class Config{ /** * Flushes the config to disk in the appropriate format. - * - * @throws \InvalidStateException if config type is not valid */ public function save() : void{ $content = null; @@ -227,7 +225,7 @@ class Config{ $content = self::writeList(array_keys($this->config)); break; default: - throw new \InvalidStateException("Config type is unknown, has not been set or not detected"); + throw new AssumptionFailedError("Config type is unknown, has not been set or not detected"); } file_put_contents($this->file, $content); From e34364412b783710720738a9b53eac4034cc7126 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 16:05:54 +0000 Subject: [PATCH 276/710] Replace InvalidStateException usages with InvalidArgument or LogicException --- src/Server.php | 2 +- src/block/Block.php | 2 +- src/crafting/CraftingGrid.php | 2 +- src/entity/Entity.php | 2 +- src/event/HandlerList.php | 2 +- src/event/entity/EntityEffectRemoveEvent.php | 2 +- src/network/mcpe/compression/CompressBatchPromise.php | 6 +++--- src/permission/PermissibleInternal.php | 2 +- src/player/Player.php | 4 ++-- src/scheduler/AsyncWorker.php | 6 +++--- src/scheduler/TaskScheduler.php | 5 +---- src/utils/Config.php | 5 ++--- src/utils/PromiseResolver.php | 4 ++-- src/utils/Terminal.php | 2 +- src/world/World.php | 8 +++----- 15 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/Server.php b/src/Server.php index 277a56ad6..afe240446 100644 --- a/src/Server.php +++ b/src/Server.php @@ -739,7 +739,7 @@ class Server{ public function __construct(\DynamicClassLoader $autoloader, \AttachableThreadedLogger $logger, string $dataPath, string $pluginPath){ if(self::$instance !== null){ - throw new \InvalidStateException("Only one server instance can exist at once"); + throw new \LogicException("Only one server instance can exist at once"); } self::$instance = $this; $this->startTime = microtime(true); diff --git a/src/block/Block.php b/src/block/Block.php index 2de12ce58..414d9b649 100644 --- a/src/block/Block.php +++ b/src/block/Block.php @@ -493,7 +493,7 @@ class Block{ return $this->position->getWorld()->getBlock($this->position->getSide($side, $step)); } - throw new \InvalidStateException("Block does not have a valid world"); + throw new \LogicException("Block does not have a valid world"); } /** diff --git a/src/crafting/CraftingGrid.php b/src/crafting/CraftingGrid.php index 5c84c9b47..a8d4f6ebe 100644 --- a/src/crafting/CraftingGrid.php +++ b/src/crafting/CraftingGrid.php @@ -111,7 +111,7 @@ class CraftingGrid extends SimpleInventory{ return $this->getItem(($y + $this->startY) * $this->gridWidth + ($x + $this->startX)); } - throw new \InvalidStateException("No ingredients found in grid"); + throw new \LogicException("No ingredients found in grid"); } /** diff --git a/src/entity/Entity.php b/src/entity/Entity.php index b4cc59c17..e483b4348 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -980,7 +980,7 @@ abstract class Entity{ final public function scheduleUpdate() : void{ if($this->closed){ - throw new \InvalidStateException("Cannot schedule update on garbage entity " . get_class($this)); + throw new \LogicException("Cannot schedule update on garbage entity " . get_class($this)); } $this->getWorld()->updateEntities[$this->id] = $this; } diff --git a/src/event/HandlerList.php b/src/event/HandlerList.php index b452a382c..b135a53cd 100644 --- a/src/event/HandlerList.php +++ b/src/event/HandlerList.php @@ -47,7 +47,7 @@ class HandlerList{ */ public function register(RegisteredListener $listener) : void{ if(isset($this->handlerSlots[$listener->getPriority()][spl_object_id($listener)])){ - throw new \InvalidStateException("This listener is already registered to priority {$listener->getPriority()} of event {$this->class}"); + throw new \InvalidArgumentException("This listener is already registered to priority {$listener->getPriority()} of event {$this->class}"); } $this->handlerSlots[$listener->getPriority()][spl_object_id($listener)] = $listener; } diff --git a/src/event/entity/EntityEffectRemoveEvent.php b/src/event/entity/EntityEffectRemoveEvent.php index afd2ef631..35e59023c 100644 --- a/src/event/entity/EntityEffectRemoveEvent.php +++ b/src/event/entity/EntityEffectRemoveEvent.php @@ -29,7 +29,7 @@ namespace pocketmine\event\entity; class EntityEffectRemoveEvent extends EntityEffectEvent{ public function cancel() : void{ if($this->getEffect()->getDuration() <= 0){ - throw new \InvalidStateException("Removal of expired effects cannot be cancelled"); + throw new \LogicException("Removal of expired effects cannot be cancelled"); } parent::cancel(); } diff --git a/src/network/mcpe/compression/CompressBatchPromise.php b/src/network/mcpe/compression/CompressBatchPromise.php index 8fa8b12ae..c62388f6a 100644 --- a/src/network/mcpe/compression/CompressBatchPromise.php +++ b/src/network/mcpe/compression/CompressBatchPromise.php @@ -59,7 +59,7 @@ class CompressBatchPromise{ public function resolve(string $result) : void{ if(!$this->cancelled){ if($this->result !== null){ - throw new \InvalidStateException("Cannot resolve promise more than once"); + throw new \LogicException("Cannot resolve promise more than once"); } $this->result = $result; foreach($this->callbacks as $callback){ @@ -80,7 +80,7 @@ class CompressBatchPromise{ public function getResult() : string{ $this->checkCancelled(); if($this->result === null){ - throw new \InvalidStateException("Promise has not yet been resolved"); + throw new \LogicException("Promise has not yet been resolved"); } return $this->result; } @@ -95,7 +95,7 @@ class CompressBatchPromise{ public function cancel() : void{ if($this->hasResult()){ - throw new \InvalidStateException("Cannot cancel a resolved promise"); + throw new \LogicException("Cannot cancel a resolved promise"); } $this->cancelled = true; } diff --git a/src/permission/PermissibleInternal.php b/src/permission/PermissibleInternal.php index c9484085e..0d14d7943 100644 --- a/src/permission/PermissibleInternal.php +++ b/src/permission/PermissibleInternal.php @@ -146,7 +146,7 @@ class PermissibleInternal implements Permissible{ foreach($this->rootPermissions as $name => $isGranted){ $perm = $permManager->getPermission($name); if($perm === null){ - throw new \InvalidStateException("Unregistered root permission $name"); + throw new \LogicException("Unregistered root permission $name"); } $this->permissions[$name] = new PermissionAttachmentInfo($name, null, $isGranted, null); $permManager->subscribeToPermission($name, $this); diff --git a/src/player/Player.php b/src/player/Player.php index a568ba644..1ca3faee8 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -475,7 +475,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ public function getNetworkSession() : NetworkSession{ if($this->networkSession === null){ - throw new \InvalidStateException("Player is not connected"); + throw new \LogicException("Player is not connected"); } return $this->networkSession; } @@ -1941,7 +1941,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ */ public function onPostDisconnect(string $reason, Translatable|string|null $quitMessage) : void{ if($this->isConnected()){ - throw new \InvalidStateException("Player is still connected"); + throw new \LogicException("Player is still connected"); } //prevent the player receiving their own disconnect message diff --git a/src/scheduler/AsyncWorker.php b/src/scheduler/AsyncWorker.php index eedb7ea5c..3dc8c2e68 100644 --- a/src/scheduler/AsyncWorker.php +++ b/src/scheduler/AsyncWorker.php @@ -92,7 +92,7 @@ class AsyncWorker extends Worker{ */ public function saveToThreadStore(string $identifier, $value) : void{ if(\Thread::getCurrentThread() !== $this){ - throw new \InvalidStateException("Thread-local data can only be stored in the thread context"); + throw new \LogicException("Thread-local data can only be stored in the thread context"); } self::$store[$identifier] = $value; } @@ -109,7 +109,7 @@ class AsyncWorker extends Worker{ */ public function getFromThreadStore(string $identifier){ if(\Thread::getCurrentThread() !== $this){ - throw new \InvalidStateException("Thread-local data can only be fetched in the thread context"); + throw new \LogicException("Thread-local data can only be fetched in the thread context"); } return self::$store[$identifier] ?? null; } @@ -119,7 +119,7 @@ class AsyncWorker extends Worker{ */ public function removeFromThreadStore(string $identifier) : void{ if(\Thread::getCurrentThread() !== $this){ - throw new \InvalidStateException("Thread-local data can only be removed in the thread context"); + throw new \LogicException("Thread-local data can only be removed in the thread context"); } unset(self::$store[$identifier]); } diff --git a/src/scheduler/TaskScheduler.php b/src/scheduler/TaskScheduler.php index 22317573d..a1ed6a261 100644 --- a/src/scheduler/TaskScheduler.php +++ b/src/scheduler/TaskScheduler.php @@ -88,12 +88,9 @@ class TaskScheduler{ return $this->tasks->contains($task); } - /** - * @throws \InvalidStateException - */ private function addTask(Task $task, int $delay, int $period) : TaskHandler{ if(!$this->enabled){ - throw new \InvalidStateException("Tried to schedule task to disabled scheduler"); + throw new \LogicException("Tried to schedule task to disabled scheduler"); } if($delay <= 0){ diff --git a/src/utils/Config.php b/src/utils/Config.php index f65f77190..562d614f8 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -144,8 +144,7 @@ class Config{ * @param mixed[] $default * @phpstan-param array $default * - * @throws \InvalidArgumentException if config type could not be auto-detected - * @throws \InvalidStateException if config type is invalid + * @throws \InvalidArgumentException if config type is invalid or could not be auto-detected */ private function load(string $file, int $type = Config::DETECT, array $default = []) : void{ $this->file = $file; @@ -187,7 +186,7 @@ class Config{ $config = array_fill_keys(self::parseList($content), true); break; default: - throw new \InvalidStateException("Config type is unknown"); + throw new \InvalidArgumentException("Invalid config type specified"); } $this->config = is_array($config) ? $config : $default; if($this->fillDefaults($default, $this->config) > 0){ diff --git a/src/utils/PromiseResolver.php b/src/utils/PromiseResolver.php index 860d683b0..81ed05201 100644 --- a/src/utils/PromiseResolver.php +++ b/src/utils/PromiseResolver.php @@ -43,7 +43,7 @@ final class PromiseResolver{ */ public function resolve($value) : void{ if($this->shared->resolved){ - throw new \InvalidStateException("Promise has already been resolved/rejected"); + throw new \LogicException("Promise has already been resolved/rejected"); } $this->shared->resolved = true; $this->shared->result = $value; @@ -56,7 +56,7 @@ final class PromiseResolver{ public function reject() : void{ if($this->shared->resolved){ - throw new \InvalidStateException("Promise has already been resolved/rejected"); + throw new \LogicException("Promise has already been resolved/rejected"); } $this->shared->resolved = true; foreach($this->shared->onFailure as $c){ diff --git a/src/utils/Terminal.php b/src/utils/Terminal.php index 4280f94d8..73e350a2c 100644 --- a/src/utils/Terminal.php +++ b/src/utils/Terminal.php @@ -64,7 +64,7 @@ abstract class Terminal{ public static function hasFormattingCodes() : bool{ if(self::$formattingCodes === null){ - throw new \InvalidStateException("Formatting codes have not been initialized"); + throw new \LogicException("Formatting codes have not been initialized"); } return self::$formattingCodes; } diff --git a/src/world/World.php b/src/world/World.php index 246799a85..bdb8d9fbb 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -516,7 +516,7 @@ class World implements ChunkManager{ */ public function onUnload() : void{ if($this->unloaded){ - throw new \InvalidStateException("Tried to close a world which is already closed"); + throw new \LogicException("Tried to close a world which is already closed"); } foreach($this->unloadCallbacks as $callback){ @@ -770,7 +770,7 @@ class World implements ChunkManager{ */ public function doTick(int $currentTick) : void{ if($this->unloaded){ - throw new \InvalidStateException("Attempted to tick a world which has been closed"); + throw new \LogicException("Attempted to tick a world which has been closed"); } $this->timings->doTick->startTiming(); @@ -2374,7 +2374,7 @@ class World implements ChunkManager{ if(isset($this->chunks[$hash = World::chunkHash($chunkX, $chunkZ)])){ $this->chunks[$hash]->addTile($tile); }else{ - throw new \InvalidStateException("Attempted to create tile " . get_class($tile) . " in unloaded chunk $chunkX $chunkZ"); + throw new \InvalidArgumentException("Attempted to create tile " . get_class($tile) . " in unloaded chunk $chunkX $chunkZ"); } //delegate tile ticking to the corresponding block @@ -2411,8 +2411,6 @@ class World implements ChunkManager{ * returned directly. * * @return Chunk|null the requested chunk, or null on failure. - * - * @throws \InvalidStateException */ public function loadChunk(int $x, int $z) : ?Chunk{ if(isset($this->chunks[$chunkHash = World::chunkHash($x, $z)])){ From e131c2cefa39af4c68c681c564923ff72fcd2373 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 16:08:29 +0000 Subject: [PATCH 277/710] Drop pocketmine/spl --- composer.json | 1 - composer.lock | 42 ++------------------------- src/network/mcpe/InventoryManager.php | 2 +- src/network/mcpe/NetworkSession.php | 2 -- 4 files changed, 3 insertions(+), 44 deletions(-) diff --git a/composer.json b/composer.json index 35adb7adc..866935722 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,6 @@ "pocketmine/raklib": "^0.14.2", "pocketmine/raklib-ipc": "^0.1.0", "pocketmine/snooze": "^0.3.0", - "pocketmine/spl": "dev-master", "ramsey/uuid": "^4.1", "webmozart/path-util": "^2.3" }, diff --git a/composer.lock b/composer.lock index b2878d494..ffed79405 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9b3c01e7b850d45218b81a436f463011", + "content-hash": "94aedb2c8c81dd851b775b7b4e1467cb", "packages": [ { "name": "adhocore/json-comment", @@ -798,43 +798,6 @@ }, "time": "2021-11-01T20:50:08+00:00" }, - { - "name": "pocketmine/spl", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/pmmp/SPL.git", - "reference": "b7a8904f912c1f6d38ad867ff1120614ccb80171" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pmmp/SPL/zipball/b7a8904f912c1f6d38ad867ff1120614ccb80171", - "reference": "b7a8904f912c1f6d38ad867ff1120614ccb80171", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.8" - }, - "type": "library", - "autoload": { - "classmap": [ - "./src" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0" - ], - "description": "Standard library files required by PocketMine-MP and related projects", - "support": { - "issues": "https://github.com/pmmp/SPL/issues", - "source": "https://github.com/pmmp/SPL/tree/master" - }, - "time": "2021-01-15T15:19:34+00:00" - }, { "name": "ramsey/collection", "version": "1.2.2", @@ -3493,8 +3456,7 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "pocketmine/bedrock-protocol": 20, - "pocketmine/spl": 20 + "pocketmine/bedrock-protocol": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/src/network/mcpe/InventoryManager.php b/src/network/mcpe/InventoryManager.php index b5271f5f9..07092d2ed 100644 --- a/src/network/mcpe/InventoryManager.php +++ b/src/network/mcpe/InventoryManager.php @@ -151,7 +151,7 @@ class InventoryManager{ return; } } - throw new \UnsupportedOperationException("Unsupported inventory type"); + throw new \LogicException("Unsupported inventory type"); } /** @phpstan-return ObjectSet */ diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index ed910c45e..cf189d875 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -536,8 +536,6 @@ class NetworkSession{ /** * Instructs the remote client to connect to a different server. - * - * @throws \UnsupportedOperationException */ public function transfer(string $ip, int $port, string $reason = "transfer") : void{ $this->tryDisconnect(function() use ($ip, $port, $reason) : void{ From 6b07f7a5ecb2ac089719abd686beead98a8018d2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 16:22:56 +0000 Subject: [PATCH 278/710] pmmp/BedrockProtocol@5.0.0+bedrock-1.17.40 --- composer.json | 2 +- composer.lock | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 866935722..a1158e02a 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "adhocore/json-comment": "^1.1", "fgrosse/phpasn1": "^2.3", "netresearch/jsonmapper": "^4.0", - "pocketmine/bedrock-protocol": "dev-master", + "pocketmine/bedrock-protocol": "^5.0.0+bedrock-1.17.40", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "^0.2.0", diff --git a/composer.lock b/composer.lock index ffed79405..8aa4a764a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "94aedb2c8c81dd851b775b7b4e1467cb", + "content-hash": "ea2d9321ba41afb67761c8f0cf3afe22", "packages": [ { "name": "adhocore/json-comment", @@ -249,7 +249,7 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "dev-master", + "version": "5.0.0+bedrock-1.17.40", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", @@ -277,7 +277,6 @@ "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.5" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -291,7 +290,7 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/master" + "source": "https://github.com/pmmp/BedrockProtocol/tree/5.0.0+bedrock-1.17.40" }, "time": "2021-11-02T01:27:05+00:00" }, @@ -3455,9 +3454,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "pocketmine/bedrock-protocol": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From 275f145418afa22b762efcfd77dfa82ffac3c449 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 16:45:45 +0000 Subject: [PATCH 279/710] BedrockData is now a Composer dependency this should put a stop to people nagging me about incorrect blocks (we have a check to make sure composer dependencies are up to date). --- .gitmodules | 3 -- composer.json | 1 + composer.lock | 28 ++++++++++++++++++- resources/vanilla | 1 - src/CoreConstants.php | 1 + src/Server.php | 2 +- .../bedrock/LegacyBlockIdToStringIdMap.php | 2 +- .../bedrock/LegacyEntityIdToStringIdMap.php | 2 +- .../bedrock/LegacyItemIdToStringIdMap.php | 2 +- src/inventory/CreativeInventory.php | 2 +- src/network/mcpe/cache/StaticPacketCache.php | 4 +-- .../mcpe/convert/GlobalItemTypeDictionary.php | 2 +- src/network/mcpe/convert/ItemTranslator.php | 4 +-- .../mcpe/convert/RuntimeBlockMapping.php | 4 +-- 14 files changed, 41 insertions(+), 17 deletions(-) delete mode 160000 resources/vanilla diff --git a/.gitmodules b/.gitmodules index ec6560fd1..71a80c00a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,3 @@ [submodule "build/php"] path = build/php url = https://github.com/pmmp/php-build-scripts.git -[submodule "resources/vanilla"] - path = resources/vanilla - url = https://github.com/pmmp/BedrockData.git diff --git a/composer.json b/composer.json index a1158e02a..c31ed6144 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,7 @@ "adhocore/json-comment": "^1.1", "fgrosse/phpasn1": "^2.3", "netresearch/jsonmapper": "^4.0", + "pocketmine/bedrock-data": "^1.4.0+bedrock-1.17.40", "pocketmine/bedrock-protocol": "^5.0.0+bedrock-1.17.40", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", diff --git a/composer.lock b/composer.lock index 8aa4a764a..b5214753a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ea2d9321ba41afb67761c8f0cf3afe22", + "content-hash": "3fa50836a0e8560fe59ba9e73cc50c44", "packages": [ { "name": "adhocore/json-comment", @@ -247,6 +247,32 @@ }, "time": "2020-12-01T19:48:11+00:00" }, + { + "name": "pocketmine/bedrock-data", + "version": "1.4.0+bedrock-1.17.40", + "source": { + "type": "git", + "url": "https://github.com/pmmp/BedrockData.git", + "reference": "f29b7be8fa3046d2ee4c6421485b97b3f5b07774" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/f29b7be8fa3046d2ee4c6421485b97b3f5b07774", + "reference": "f29b7be8fa3046d2ee4c6421485b97b3f5b07774", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0" + ], + "description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP", + "support": { + "issues": "https://github.com/pmmp/BedrockData/issues", + "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.17.40" + }, + "time": "2021-10-19T16:55:41+00:00" + }, { "name": "pocketmine/bedrock-protocol", "version": "5.0.0+bedrock-1.17.40", diff --git a/resources/vanilla b/resources/vanilla deleted file mode 160000 index f29b7be8f..000000000 --- a/resources/vanilla +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f29b7be8fa3046d2ee4c6421485b97b3f5b07774 diff --git a/src/CoreConstants.php b/src/CoreConstants.php index 63913e941..91b9b95b9 100644 --- a/src/CoreConstants.php +++ b/src/CoreConstants.php @@ -35,4 +35,5 @@ define('pocketmine\_CORE_CONSTANTS_INCLUDED', true); define('pocketmine\PATH', dirname(__DIR__) . '/'); define('pocketmine\RESOURCE_PATH', dirname(__DIR__) . '/resources/'); +define('pocketmine\BEDROCK_DATA_PATH', dirname(__DIR__) . '/vendor/pocketmine/bedrock-data/'); define('pocketmine\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__) . '/vendor/autoload.php'); diff --git a/src/Server.php b/src/Server.php index afe240446..69cdc9f18 100644 --- a/src/Server.php +++ b/src/Server.php @@ -932,7 +932,7 @@ class Server{ $this->commandMap = new SimpleCommandMap($this); - $this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "recipes.json")); + $this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes.json")); $this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger); diff --git a/src/data/bedrock/LegacyBlockIdToStringIdMap.php b/src/data/bedrock/LegacyBlockIdToStringIdMap.php index c9e0212b0..5c52fa972 100644 --- a/src/data/bedrock/LegacyBlockIdToStringIdMap.php +++ b/src/data/bedrock/LegacyBlockIdToStringIdMap.php @@ -30,6 +30,6 @@ final class LegacyBlockIdToStringIdMap extends LegacyToStringBidirectionalIdMap{ use SingletonTrait; public function __construct(){ - parent::__construct(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'block_id_map.json')); + parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'block_id_map.json')); } } diff --git a/src/data/bedrock/LegacyEntityIdToStringIdMap.php b/src/data/bedrock/LegacyEntityIdToStringIdMap.php index fa37bfbd9..23852b925 100644 --- a/src/data/bedrock/LegacyEntityIdToStringIdMap.php +++ b/src/data/bedrock/LegacyEntityIdToStringIdMap.php @@ -30,6 +30,6 @@ final class LegacyEntityIdToStringIdMap extends LegacyToStringBidirectionalIdMap use SingletonTrait; public function __construct(){ - parent::__construct(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'entity_id_map.json')); + parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'entity_id_map.json')); } } diff --git a/src/data/bedrock/LegacyItemIdToStringIdMap.php b/src/data/bedrock/LegacyItemIdToStringIdMap.php index 083f2024b..86cd83bf8 100644 --- a/src/data/bedrock/LegacyItemIdToStringIdMap.php +++ b/src/data/bedrock/LegacyItemIdToStringIdMap.php @@ -30,6 +30,6 @@ final class LegacyItemIdToStringIdMap extends LegacyToStringBidirectionalIdMap{ use SingletonTrait; public function __construct(){ - parent::__construct(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'item_id_map.json')); + parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'item_id_map.json')); } } diff --git a/src/inventory/CreativeInventory.php b/src/inventory/CreativeInventory.php index 99ad5f60e..e71966f44 100644 --- a/src/inventory/CreativeInventory.php +++ b/src/inventory/CreativeInventory.php @@ -37,7 +37,7 @@ final class CreativeInventory{ private $creative = []; private function __construct(){ - $creativeItems = json_decode(file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "creativeitems.json")), true); + $creativeItems = json_decode(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "creativeitems.json")), true); foreach($creativeItems as $data){ $item = Item::jsonDeserialize($data); diff --git a/src/network/mcpe/cache/StaticPacketCache.php b/src/network/mcpe/cache/StaticPacketCache.php index 901fe875c..39b8ea774 100644 --- a/src/network/mcpe/cache/StaticPacketCache.php +++ b/src/network/mcpe/cache/StaticPacketCache.php @@ -50,8 +50,8 @@ class StaticPacketCache{ private static function make() : self{ return new self( - BiomeDefinitionListPacket::create(self::loadCompoundFromFile(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'biome_definitions.nbt'))), - AvailableActorIdentifiersPacket::create(self::loadCompoundFromFile(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'entity_identifiers.nbt'))) + BiomeDefinitionListPacket::create(self::loadCompoundFromFile(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'biome_definitions.nbt'))), + AvailableActorIdentifiersPacket::create(self::loadCompoundFromFile(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'entity_identifiers.nbt'))) ); } diff --git a/src/network/mcpe/convert/GlobalItemTypeDictionary.php b/src/network/mcpe/convert/GlobalItemTypeDictionary.php index c1537fa7c..d3ab00f53 100644 --- a/src/network/mcpe/convert/GlobalItemTypeDictionary.php +++ b/src/network/mcpe/convert/GlobalItemTypeDictionary.php @@ -39,7 +39,7 @@ final class GlobalItemTypeDictionary{ use SingletonTrait; private static function make() : self{ - $data = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'required_item_list.json')); + $data = file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'required_item_list.json')); if($data === false) throw new AssumptionFailedError("Missing required resource file"); $table = json_decode($data, true); if(!is_array($table)){ diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index c7cba0226..bffa6cb18 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -66,14 +66,14 @@ final class ItemTranslator{ private $complexNetToCoreMapping = []; private static function make() : self{ - $data = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'r16_to_current_item_map.json')); + $data = file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'r16_to_current_item_map.json')); if($data === false) throw new AssumptionFailedError("Missing required resource file"); $json = json_decode($data, true); if(!is_array($json) or !isset($json["simple"], $json["complex"]) || !is_array($json["simple"]) || !is_array($json["complex"])){ throw new AssumptionFailedError("Invalid item table format"); } - $legacyStringToIntMapRaw = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, 'vanilla', 'item_id_map.json')); + $legacyStringToIntMapRaw = file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'item_id_map.json')); if($legacyStringToIntMapRaw === false){ throw new AssumptionFailedError("Missing required resource file"); } diff --git a/src/network/mcpe/convert/RuntimeBlockMapping.php b/src/network/mcpe/convert/RuntimeBlockMapping.php index 45affea44..dfa69168e 100644 --- a/src/network/mcpe/convert/RuntimeBlockMapping.php +++ b/src/network/mcpe/convert/RuntimeBlockMapping.php @@ -49,7 +49,7 @@ final class RuntimeBlockMapping{ private $bedrockKnownStates; private function __construct(){ - $canonicalBlockStatesFile = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "canonical_block_states.nbt")); + $canonicalBlockStatesFile = file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "canonical_block_states.nbt")); if($canonicalBlockStatesFile === false){ throw new AssumptionFailedError("Missing required resource file"); } @@ -67,7 +67,7 @@ final class RuntimeBlockMapping{ $legacyIdMap = LegacyBlockIdToStringIdMap::getInstance(); /** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */ $legacyStateMap = []; - $legacyStateMapReader = PacketSerializer::decoder(file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "vanilla", "r12_to_current_block_map.bin")), 0, new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())); + $legacyStateMapReader = PacketSerializer::decoder(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "r12_to_current_block_map.bin")), 0, new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())); $nbtReader = new NetworkNbtSerializer(); while(!$legacyStateMapReader->feof()){ $id = $legacyStateMapReader->getString(); From 38f97bed5257f9bdbf04b8ddc12231209c6e96c6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 16:58:14 +0000 Subject: [PATCH 280/710] World: fixed PopulationTask failed assumption that generator is always registered if the worker selected previously had a generator registered, but has since been shutdown, the workerStartHook that cleans up generatorRegisteredWorkers won't yet have been called. This results in the worker being started by the submission of PopulationTask, and the generator doesn't get preemptively registered. --- src/world/World.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/world/World.php b/src/world/World.php index bdb8d9fbb..6d3af4190 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2904,6 +2904,10 @@ class World implements ChunkManager{ } ); $workerId = $this->workerPool->selectWorker(); + if(!isset($this->workerPool->getRunningWorkers()[$workerId]) && isset($this->generatorRegisteredWorkers[$workerId])){ + $this->logger->debug("Selected worker $workerId previously had generator registered, but is now offline"); + unset($this->generatorRegisteredWorkers[$workerId]); + } if(!isset($this->generatorRegisteredWorkers[$workerId])){ $this->registerGeneratorToWorker($workerId); } From ead8ccf08d3d3792224795728d225e949f33ab9f Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 2 Nov 2021 18:05:07 +0100 Subject: [PATCH 281/710] CocoaBlock: call BlockGrowEvent when growing for any reason (#4536) --- src/block/CocoaBlock.php | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/block/CocoaBlock.php b/src/block/CocoaBlock.php index 82b514172..efcc4590f 100644 --- a/src/block/CocoaBlock.php +++ b/src/block/CocoaBlock.php @@ -26,6 +26,7 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\TreeType; +use pocketmine\event\block\BlockGrowEvent; use pocketmine\item\Fertilizer; use pocketmine\item\Item; use pocketmine\item\VanillaItems; @@ -94,10 +95,7 @@ class CocoaBlock extends Transparent{ } public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($this->age < 2 and $item instanceof Fertilizer){ - $this->age++; - $this->position->getWorld()->setBlock($this->position, $this); - + if($item instanceof Fertilizer && $this->grow()){ $item->pop(); return true; @@ -117,12 +115,25 @@ class CocoaBlock extends Transparent{ } public function onRandomTick() : void{ - if($this->age < 2 and mt_rand(1, 5) === 1){ - $this->age++; - $this->position->getWorld()->setBlock($this->position, $this); + if(mt_rand(1, 5) === 1){ + $this->grow(); } } + private function grow() : bool{ + if($this->age < 2){ + $block = clone $this; + $block->age++; + $ev = new BlockGrowEvent($this, $block); + $ev->call(); + if(!$ev->isCancelled()){ + $this->position->getWorld()->setBlock($this->position, $ev->getNewState()); + return true; + } + } + return false; + } + public function getDropsForCompatibleTool(Item $item) : array{ return [ VanillaItems::COCOA_BEANS()->setCount($this->age === 2 ? mt_rand(2, 3) : 1) From d184838ba0196305a0f1ab6a9f46734292516551 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 17:10:07 +0000 Subject: [PATCH 282/710] Move Promise classes to their own namespace --- src/Server.php | 4 ++-- src/{utils => promise}/Promise.php | 2 +- src/{utils => promise}/PromiseResolver.php | 2 +- src/{utils => promise}/PromiseSharedData.php | 2 +- src/world/World.php | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) rename src/{utils => promise}/Promise.php (98%) rename src/{utils => promise}/PromiseResolver.php (98%) rename src/{utils => promise}/PromiseSharedData.php (97%) diff --git a/src/Server.php b/src/Server.php index 69cdc9f18..753556ff8 100644 --- a/src/Server.php +++ b/src/Server.php @@ -82,6 +82,8 @@ use pocketmine\plugin\PluginGraylist; use pocketmine\plugin\PluginManager; use pocketmine\plugin\PluginOwned; use pocketmine\plugin\ScriptPluginLoader; +use pocketmine\promise\Promise; +use pocketmine\promise\PromiseResolver; use pocketmine\resourcepacks\ResourcePackManager; use pocketmine\scheduler\AsyncPool; use pocketmine\snooze\SleeperHandler; @@ -98,8 +100,6 @@ use pocketmine\utils\MainLogger; use pocketmine\utils\NotCloneable; use pocketmine\utils\NotSerializable; use pocketmine\utils\Process; -use pocketmine\utils\Promise; -use pocketmine\utils\PromiseResolver; use pocketmine\utils\SignalHandler; use pocketmine\utils\Terminal; use pocketmine\utils\TextFormat; diff --git a/src/utils/Promise.php b/src/promise/Promise.php similarity index 98% rename from src/utils/Promise.php rename to src/promise/Promise.php index d9ae9c563..28666917e 100644 --- a/src/utils/Promise.php +++ b/src/promise/Promise.php @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace pocketmine\utils; +namespace pocketmine\promise; use function spl_object_id; diff --git a/src/utils/PromiseResolver.php b/src/promise/PromiseResolver.php similarity index 98% rename from src/utils/PromiseResolver.php rename to src/promise/PromiseResolver.php index 81ed05201..0f447693f 100644 --- a/src/utils/PromiseResolver.php +++ b/src/promise/PromiseResolver.php @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace pocketmine\utils; +namespace pocketmine\promise; /** * @phpstan-template TValue diff --git a/src/utils/PromiseSharedData.php b/src/promise/PromiseSharedData.php similarity index 97% rename from src/utils/PromiseSharedData.php rename to src/promise/PromiseSharedData.php index 05c5ab007..bccf56cc2 100644 --- a/src/utils/PromiseSharedData.php +++ b/src/promise/PromiseSharedData.php @@ -21,7 +21,7 @@ declare(strict_types=1); -namespace pocketmine\utils; +namespace pocketmine\promise; /** * @internal diff --git a/src/world/World.php b/src/world/World.php index 6d3af4190..978bd8a42 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -66,13 +66,13 @@ use pocketmine\network\mcpe\protocol\ClientboundPacket; use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\UpdateBlockPacket; use pocketmine\player\Player; +use pocketmine\promise\Promise; +use pocketmine\promise\PromiseResolver; use pocketmine\scheduler\AsyncPool; use pocketmine\Server; use pocketmine\timings\Timings; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Limits; -use pocketmine\utils\Promise; -use pocketmine\utils\PromiseResolver; use pocketmine\utils\ReversePriorityQueue; use pocketmine\world\biome\Biome; use pocketmine\world\biome\BiomeRegistry; From 3dae87373154ad52ff6c27874f3fd93c9845a8af Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 17:21:44 +0000 Subject: [PATCH 283/710] Release 3.25.2 --- changelogs/3.25.md | 7 +++++++ src/pocketmine/VersionInfo.php | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelogs/3.25.md b/changelogs/3.25.md index 360729e3c..45ee75ca4 100644 --- a/changelogs/3.25.md +++ b/changelogs/3.25.md @@ -14,3 +14,10 @@ Plugin developers should **only** update their required API to this version if y - Fixed autosave bug that caused unmodified chunks to be saved at least once (during the first autosave after they were loaded). - `Entity->spawnTo()` now has an additional sanity check for matching worlds (might expose a few new errors in plugins). - Fixed a missing field in `CraftRecipeAuto` item stack request type. + +# 3.25.2 +- Now analysed using level 9 on PHPStan 1.0.0. +- `ext-pthreads` v4.0.0 or newer is now required. +- Fixed crash in `Player->showPlayer()` when the target is not in the same world. +- `Human->setLifetimeTotalXp()` now limits the maximum value to 2^31. +- Fixed players, who died in hardcore mode and were unbanned, getting re-banned on next server join. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 46aca0d7a..689a6ea99 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,6 +34,6 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.25.2"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = ""; +const BUILD_CHANNEL = "stable"; From f75a05d7fa2b0cd60515bf7540d466dbfe1c6bc2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 17:21:49 +0000 Subject: [PATCH 284/710] 3.25.3 is next --- src/pocketmine/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 689a6ea99..bc70f8a57 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.25.2"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.25.3"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = "stable"; +const BUILD_CHANNEL = ""; From 4ca7c29cde281a28fdfa3adfccae5e04e2561860 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 19:14:12 +0000 Subject: [PATCH 285/710] Release 4.0.0-BETA9 --- changelogs/4.0.md | 74 +++++++++++++++++++++++++++++++++++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 12f7fff64..41392cac2 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1527,3 +1527,77 @@ Released 29th October 2021. - All parameters are now mandatory. - Reverted addition of chunk modification counters in previous beta. - `Chunk::DIRTY_FLAG_TERRAIN` has been renamed to `Chunk::DIRTY_FLAG_BLOCKS`. + +# 4.0.0-BETA9 +Released 2nd November 2021. + +## General +- Now analysed using level 9 on PHPStan 1.0.0. +- `ext-pthreads` v4.0.0 or newer is now required. +- `resources/vanilla` submodule has been removed. BedrockData is now included via Composer dependency [`pocketmine/bedrock-data`](https://packagist.org/packages/pocketmine/bedrock-data). +- `pocketmine/spl` Composer dependency has been dropped. +- The following Composer dependency versions are now required: + - [`pocketmine/bedrock-protocol` v5.0.0](https://github.com/pmmp/BedrockProtocol/tree/5.0.0+bedrock-1.17.40) features substantial changes to its API compared to 3.0.1, which was used in 4.0.0-BETA8. Please see its [release notes](https://github.com/pmmp/BedrockData/releases/tag/5.0.0+bedrock-1.17.40). + - [`pocketmine/log` v0.4.0](https://github.com/pmmp/Log/tree/0.4.0) removes the `LoggerAttachment` interface and replaces logger attachment objects with closures. + - [`pocketmine/log-pthreads` v0.4.0](https://github.com/pmmp/LogPthreads/tree/0.4.0) + - [`pocketmine/classloader` v0.2.0](https://github.com/pmmp/ClassLoader/tree/0.2.0) +- A noisy debug message in `World->updateAllLight()` has been removed. + +## API +### Entity +- `Human->setLifetimeTotalXp()` now limits the maximum value to 2^31. + +### Event +- `BlockGrowEvent` is now called when cocoa pods grow. + +### Item +- Added `Releasable->canStartUsingItem()`. + +### Network +- Added `NetworkInterfaceStartException`, which may be thrown by `Network->registerInterface()` and `NetworkInterface->start()`. + +### Player +- `SurvivalBlockBreakHandler::createIfNecessary()` has been removed. +- `SurvivalBlockBreakHandler->__construct()` is now public. +- `UsedChunkStatus::REQUESTED()` has been renamed to `REQUESTED_SENDING`. +- `UsedChunkStatus::REQUESTED_GENERATION()` has been added. + +### Utils +- `Promise` API has changed: + - Promise-related classes have been moved to `pocketmine\promise` namespace. + - It's now split into `Promise` and `PromiseResolver`. + - `PromiseResolver` provides only `resolve()` and `reject()`. It should be used by callbacks to resolve a promise. + - `Promise` now provides only `onCompletion()` and `isResolved()` APIs. This should be given to consumers to allow them to handle the result of the async operation. + - `PromiseResolver` must not be created directly. Use `new PromiseResolver` and `PromiseResolver->getPromise()`. + +### World +- Improved performance of `setBlock()` by around 35% when the `$update` parameter is set to `true`. +- Improved performance of `setBlock()` by around 30% when the `$update` parameter is set to `false`. +- `World->generateChunkCallback()` is no longer exposed to public API. +- `World->getAdjacentChunks()` now returns an array indexed using `World::chunkHash()`, where the `x` and `z` components are the relative offsets from the target chunk (range -1 to +1). +- `World->lockChunk()` now requires `ChunkLockId $lockId` parameter. +- `World->unlockChunk()` now requires a `?ChunkLockId $lockId` parameter. If a non-null lockID is given, the lock on the chunk will only be removed if it matches the given lockID. +- `World->unlockChunk()` now returns `bool` instead of `void` (to signal whether unlocking succeded or not). +- Added `ChunkLockId` class. + +## Fixes +### World +- Fixed server crash when tiles with colliding positions are loaded from saved data. Now, an error is logged, but the server won't crash. +- Fixed server crash when liquids and other items flow into terrain locked for population. Now, an advisory locking mechanism is used, and population results will be discarded and recalculated if modifications are detected. +- Fixed various crashes that could occur if a chunk was flagged with `setPopulated(true)` after a promise had already been created for its population. +- Fixed `AssumptionFailedError` in `PopulationTask` when workers previously used for generation are shutdown, and then restarted on the fly by a generation request. +- Fixed assertion failure in `World->drainPopulationRequestQueue()` when requesting, cancelling and then re-requesting generation of a chunk while the generator was busy. +- Fixed generation potentially getting stuck if a population request was cancelled while the population task was running (failure to remove locks from used chunks). +- Fixed `World->requestChunkPopulation()` not taking into account that the target chunk may already be populated. This caused a variety of strange bugs and performance issues. +- Fixed potential memory leak caused by `World->unregisterChunkListenerFromAll()` not taking players into account. +- Fixed debug spam of `chunk has no loaders registered` messages during chunk generation. + +### Other fixes +- Fixed server crash when unable to bind to the desired port. Now, the server will show an error and gracefully stop without a crashdump instead. +- Fixed server crash in `Player->showPlayer()` when the target is not in the same world. +- Fixed players, who died in hardcore mode and were unbanned, getting re-banned on next server join. +- Fixed cake block desync when attempting to eat in creative (eating in creative is not yet supported, but the block rollback was missing). +- Fixed players being able to eat items more quickly by dropping them while eating. +- Fixed arrows getting added to creative players' inventories when picked up. +- Fixed players re-requesting the same ungenerated chunks multiple times before they were sent. +- Fixed commands not working in some cases after using some control sequences on the console. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 10d2f6e4b..5431c30e6 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,7 +30,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA9"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From f50f26d52e4d7283c53a89c8415d9b308715bc1a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 19:14:15 +0000 Subject: [PATCH 286/710] 4.0.0-BETA10 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 5431c30e6..69254d79d 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,8 +29,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA9"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA10"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From 102277c6366ae4843a69cef41448cfe21be13d27 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 19:16:36 +0000 Subject: [PATCH 287/710] draft-release: fixed BedrockData JSON minification --- .github/workflows/draft-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index 6c3d25996..6c3caf748 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -42,7 +42,7 @@ jobs: sed -i "s/const BUILD_NUMBER = 0/const BUILD_NUMBER = ${BUILD_NUMBER}/" src/VersionInfo.php - name: Minify BedrockData JSON files - run: php resources/vanilla/.minify_json.php + run: php vendor/pocketmine/bedrock-data/.minify_json.php - name: Build PocketMine-MP.phar run: php -dphar.readonly=0 build/server-phar.php --git ${{ github.sha }} From fa6a432d5816bb8c5d5546549ac3988fede14728 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 19:18:19 +0000 Subject: [PATCH 288/710] Release 4.0.0-BETA10 --- changelogs/4.0.md | 6 ++++++ src/VersionInfo.php | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 41392cac2..2ef72ea0b 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1601,3 +1601,9 @@ Released 2nd November 2021. - Fixed arrows getting added to creative players' inventories when picked up. - Fixed players re-requesting the same ungenerated chunks multiple times before they were sent. - Fixed commands not working in some cases after using some control sequences on the console. + +# 4.0.0-BETA10 +Released 2nd November 2021. + +## Fixes +- Fixed an issue with BedrockData JSON minification which broke the release build of 4.0.0-BETA9. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 69254d79d..d220afe32 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,7 +30,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA10"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From a0e9eec652623b6eb6d9244708994961c009c067 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 19:18:20 +0000 Subject: [PATCH 289/710] 4.0.0-BETA11 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index d220afe32..f394d85d9 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,8 +29,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA10"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA11"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From f0661999717abc3ed5cefceb4c47b732915761f3 Mon Sep 17 00:00:00 2001 From: Hashim <13991048+Prim69@users.noreply.github.com> Date: Tue, 2 Nov 2021 19:04:55 -0400 Subject: [PATCH 290/710] Implement emote support (#4523) --- src/event/player/PlayerEmoteEvent.php | 51 +++++++++++++++++++ src/network/mcpe/NetworkSession.php | 5 ++ .../mcpe/handler/InGamePacketHandler.php | 6 +++ src/player/Player.php | 14 +++++ 4 files changed, 76 insertions(+) create mode 100644 src/event/player/PlayerEmoteEvent.php diff --git a/src/event/player/PlayerEmoteEvent.php b/src/event/player/PlayerEmoteEvent.php new file mode 100644 index 000000000..b10a3171e --- /dev/null +++ b/src/event/player/PlayerEmoteEvent.php @@ -0,0 +1,51 @@ +player = $player; + } + + public function getEmoteId() : string{ + return $this->emoteId; + } + + public function setEmoteId(string $emoteId) : void{ + $this->emoteId = $emoteId; + } + +} diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index cf189d875..ee7c34997 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -62,6 +62,7 @@ use pocketmine\network\mcpe\protocol\AvailableCommandsPacket; use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket; use pocketmine\network\mcpe\protocol\ClientboundPacket; use pocketmine\network\mcpe\protocol\DisconnectPacket; +use pocketmine\network\mcpe\protocol\EmotePacket; use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket; use pocketmine\network\mcpe\protocol\MobEffectPacket; use pocketmine\network\mcpe\protocol\MobEquipmentPacket; @@ -1043,6 +1044,10 @@ class NetworkSession{ $this->sendDataPacket(SetTitlePacket::setAnimationTimes($fadeIn, $stay, $fadeOut)); } + public function onEmote(Player $from, string $emoteId) : void{ + $this->sendDataPacket(EmotePacket::create($from->getId(), $emoteId, EmotePacket::FLAG_SERVER)); + } + public function tick() : void{ if($this->info === null){ if(time() >= $this->connectTime + 10){ diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index a884bf7c2..ad8b001c0 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -59,6 +59,7 @@ use pocketmine\network\mcpe\protocol\CommandRequestPacket; use pocketmine\network\mcpe\protocol\ContainerClosePacket; use pocketmine\network\mcpe\protocol\ContainerOpenPacket; use pocketmine\network\mcpe\protocol\CraftingEventPacket; +use pocketmine\network\mcpe\protocol\EmotePacket; use pocketmine\network\mcpe\protocol\InteractPacket; use pocketmine\network\mcpe\protocol\InventoryTransactionPacket; use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket; @@ -890,4 +891,9 @@ class InGamePacketHandler extends PacketHandler{ */ return true; } + + public function handleEmote(EmotePacket $packet) : bool{ + $this->player->emote($packet->getEmoteId()); + return true; + } } diff --git a/src/player/Player.php b/src/player/Player.php index 1ca3faee8..ef48c5b2b 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -53,6 +53,7 @@ use pocketmine\event\player\PlayerChatEvent; use pocketmine\event\player\PlayerCommandPreprocessEvent; use pocketmine\event\player\PlayerDeathEvent; use pocketmine\event\player\PlayerDisplayNameChangeEvent; +use pocketmine\event\player\PlayerEmoteEvent; use pocketmine\event\player\PlayerEntityInteractEvent; use pocketmine\event\player\PlayerExhaustEvent; use pocketmine\event\player\PlayerGameModeChangeEvent; @@ -234,6 +235,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ /** @var int[] ID => ticks map */ protected array $usedItemsCooldown = []; + private int $lastEmoteTick = 0; + protected int $formIdCounter = 0; /** @var Form[] */ protected array $forms = []; @@ -1727,6 +1730,17 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ return true; } + public function emote(string $emoteId) : void{ + $event = new PlayerEmoteEvent($this, $emoteId); + $event->call(); + if(!$event->isCancelled() && $this->getServer()->getTick() - $this->lastEmoteTick > 5){ + $this->lastEmoteTick = $this->getServer()->getTick(); + foreach($this->getViewers() as $player){ + $player->getNetworkSession()->onEmote($this, $emoteId); + } + } + } + /** * Drops an item on the ground in front of the player. */ From 87031627bfd1ba0d1df0ba5697eead31592d5f80 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 23:09:43 +0000 Subject: [PATCH 291/710] Do not call PlayerEmoteEvent if rate limit was reached --- src/player/Player.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/player/Player.php b/src/player/Player.php index ef48c5b2b..a9df0d04f 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1731,12 +1731,15 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function emote(string $emoteId) : void{ - $event = new PlayerEmoteEvent($this, $emoteId); - $event->call(); - if(!$event->isCancelled() && $this->getServer()->getTick() - $this->lastEmoteTick > 5){ - $this->lastEmoteTick = $this->getServer()->getTick(); - foreach($this->getViewers() as $player){ - $player->getNetworkSession()->onEmote($this, $emoteId); + $currentTick = $this->server->getTick(); + if($currentTick - $this->lastEmoteTick > 5){ + $this->lastEmoteTick = $currentTick; + $event = new PlayerEmoteEvent($this, $emoteId); + $event->call(); + if(!$event->isCancelled()){ + foreach($this->getViewers() as $player){ + $player->getNetworkSession()->onEmote($this, $emoteId); + } } } } From ef82a2cd7997e8b4a665a7e9ee8ba768a45b9c23 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Nov 2021 23:10:26 +0000 Subject: [PATCH 292/710] Fixed PlayerEmoteEvent::setEmoteId() being useless --- src/player/Player.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/player/Player.php b/src/player/Player.php index a9df0d04f..2f27430ac 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1737,6 +1737,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $event = new PlayerEmoteEvent($this, $emoteId); $event->call(); if(!$event->isCancelled()){ + $emoteId = $event->getEmoteId(); foreach($this->getViewers() as $player){ $player->getNetworkSession()->onEmote($this, $emoteId); } From 29e2d92098736d397c5f38efc8e1fc96cfd9575f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Nov 2021 11:27:42 +0000 Subject: [PATCH 293/710] Bump phpstan/phpstan from 1.0.0 to 1.0.1 (#4541) Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.0.0 to 1.0.1. - [Release notes](https://github.com/phpstan/phpstan/releases) - [Commits](https://github.com/phpstan/phpstan/compare/1.0.0...1.0.1) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index fccbfaccc..01c384bcc 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "pocketmine/spl": "^0.4.0" }, "require-dev": { - "phpstan/phpstan": "1.0.0", + "phpstan/phpstan": "1.0.1", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index 399d6141b..48796f4b5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c55df4140fb828ab8add33e0a0e84136", + "content-hash": "9600d7526f3a45137fc4ba7030b2d58d", "packages": [ { "name": "adhocore/json-comment", @@ -1011,16 +1011,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0d13a99513182e521271d46bde8f28caa4f84d97" + "reference": "0eb6ecdfbcebf2207668087dfb2e215581a75023" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d13a99513182e521271d46bde8f28caa4f84d97", - "reference": "0d13a99513182e521271d46bde8f28caa4f84d97", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0eb6ecdfbcebf2207668087dfb2e215581a75023", + "reference": "0eb6ecdfbcebf2207668087dfb2e215581a75023", "shasum": "" }, "require": { @@ -1051,7 +1051,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.0.0" + "source": "https://github.com/phpstan/phpstan/tree/1.0.1" }, "funding": [ { @@ -1071,7 +1071,7 @@ "type": "tidelift" } ], - "time": "2021-11-01T06:38:20+00:00" + "time": "2021-11-02T10:25:31+00:00" }, { "name": "phpstan/phpstan-phpunit", From 1ebb2067627c298834a60b992ee42a98091a38fd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 3 Nov 2021 14:58:58 +0000 Subject: [PATCH 294/710] World: fixed yet another edge case in drainPopulationRequestQueue() leading to assertion failure really had to go fucking nuclear on it :( --- src/world/World.php | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 978bd8a42..a06f2ad5e 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -263,6 +263,12 @@ class World implements ChunkManager{ * @phpstan-var \SplQueue */ private \SplQueue $chunkPopulationRequestQueue; + /** + * @var true[] chunkHash => dummy + * @phpstan-var array + */ + private array $chunkPopulationRequestQueueIndex = []; + /** @var bool[] */ private $generatorRegisteredWorkers = []; @@ -2733,12 +2739,19 @@ class World implements ChunkManager{ } } + private function addChunkHashToPopulationRequestQueue(int $chunkHash) : void{ + if(!isset($this->chunkPopulationRequestQueueIndex[$chunkHash])){ + $this->chunkPopulationRequestQueue->enqueue($chunkHash); + $this->chunkPopulationRequestQueueIndex[$chunkHash] = true; + } + } + /** * @phpstan-return Promise */ private function enqueuePopulationRequest(int $chunkX, int $chunkZ, ?ChunkLoader $associatedChunkLoader) : Promise{ $chunkHash = World::chunkHash($chunkX, $chunkZ); - $this->chunkPopulationRequestQueue->enqueue($chunkHash); + $this->addChunkHashToPopulationRequestQueue($chunkHash); $resolver = $this->chunkPopulationRequestMap[$chunkHash] = new PromiseResolver(); if($associatedChunkLoader === null){ $temporaryLoader = new class implements ChunkLoader{}; @@ -2753,17 +2766,9 @@ class World implements ChunkManager{ private function drainPopulationRequestQueue() : void{ $failed = []; - $seen = []; while(count($this->activeChunkPopulationTasks) < $this->maxConcurrentChunkPopulationTasks && !$this->chunkPopulationRequestQueue->isEmpty()){ $nextChunkHash = $this->chunkPopulationRequestQueue->dequeue(); - if(isset($seen[$nextChunkHash])){ - //We may have previously requested this, decided we didn't want it, and then decided we did want it - //again, all before the generation request got executed. In that case, the chunk hash may appear in the - //queue multiple times (it can't be quickly removed from the queue when the request is cancelled, so we - //leave it in the queue). - continue; - } - $seen[$nextChunkHash] = true; + unset($this->chunkPopulationRequestQueueIndex[$nextChunkHash]); World::getXZ($nextChunkHash, $nextChunkX, $nextChunkZ); if(isset($this->chunkPopulationRequestMap[$nextChunkHash])){ assert(!isset($this->activeChunkPopulationTasks[$nextChunkHash]), "Population for chunk $nextChunkX $nextChunkZ already running"); @@ -2779,7 +2784,7 @@ class World implements ChunkManager{ //these requests failed even though they weren't rate limited; we can't directly re-add them to the back of the //queue because it would result in an infinite loop foreach($failed as $hash){ - $this->chunkPopulationRequestQueue->enqueue($hash); + $this->addChunkHashToPopulationRequestQueue($hash); } } @@ -2978,7 +2983,7 @@ class World implements ChunkManager{ //request failed, stick it back on the queue //we didn't resolve the promise or touch it in any way, so any fake chunk loaders are still valid and //don't need to be added a second time. - $this->chunkPopulationRequestQueue->enqueue($index); + $this->addChunkHashToPopulationRequestQueue($index); } $this->drainPopulationRequestQueue(); From 5c81b0481306f428934bffbdae34eed9bd19c575 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 3 Nov 2021 15:22:49 +0000 Subject: [PATCH 295/710] PopulationTask: use typed properties --- src/world/generator/PopulationTask.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index f1f2d3858..4ba21312f 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -41,15 +41,11 @@ use function igbinary_unserialize; class PopulationTask extends AsyncTask{ private const TLS_KEY_ON_COMPLETION = "onCompletion"; - /** @var int */ - public $worldId; - /** @var int */ - private $chunkX; - /** @var int */ - private $chunkZ; + public int $worldId; + private int $chunkX; + private int $chunkZ; - /** @var string|null */ - public $chunk; + public ?string $chunk; private string $adjacentChunks; From 0356716e8e7f1b9d8ca87645b577d0dcf505cfd0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 3 Nov 2021 15:23:43 +0000 Subject: [PATCH 296/710] PopulationTask: do not expose internal fields as public this code dates back to pthreads v2, when visibility on Threaded object fields meant different things (wtf, krakjoe??) --- src/world/generator/PopulationTask.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/world/generator/PopulationTask.php b/src/world/generator/PopulationTask.php index 4ba21312f..a50f884fc 100644 --- a/src/world/generator/PopulationTask.php +++ b/src/world/generator/PopulationTask.php @@ -41,11 +41,11 @@ use function igbinary_unserialize; class PopulationTask extends AsyncTask{ private const TLS_KEY_ON_COMPLETION = "onCompletion"; - public int $worldId; + private int $worldId; private int $chunkX; private int $chunkZ; - public ?string $chunk; + private ?string $chunk; private string $adjacentChunks; From 729f831b8f1d9627edfcd8cea255ed214e1f5920 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 3 Nov 2021 20:26:32 +0000 Subject: [PATCH 297/710] PHPStan 1.0.2 --- composer.json | 2 +- composer.lock | 14 +++++++------- tests/phpstan/configs/phpstan-bugs.neon | 10 ---------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/composer.json b/composer.json index 01c384bcc..15ee28133 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "pocketmine/spl": "^0.4.0" }, "require-dev": { - "phpstan/phpstan": "1.0.1", + "phpstan/phpstan": "1.0.2", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index 48796f4b5..6ef7a0726 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9600d7526f3a45137fc4ba7030b2d58d", + "content-hash": "352902efd3a960977acfb3ae7bda38da", "packages": [ { "name": "adhocore/json-comment", @@ -1011,16 +1011,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "0eb6ecdfbcebf2207668087dfb2e215581a75023" + "reference": "e9e2a501102ba0b126b2f63a7f0a3b151056fe91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0eb6ecdfbcebf2207668087dfb2e215581a75023", - "reference": "0eb6ecdfbcebf2207668087dfb2e215581a75023", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e9e2a501102ba0b126b2f63a7f0a3b151056fe91", + "reference": "e9e2a501102ba0b126b2f63a7f0a3b151056fe91", "shasum": "" }, "require": { @@ -1051,7 +1051,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.0.1" + "source": "https://github.com/phpstan/phpstan/tree/1.0.2" }, "funding": [ { @@ -1071,7 +1071,7 @@ "type": "tidelift" } ], - "time": "2021-11-02T10:25:31+00:00" + "time": "2021-11-03T16:09:51+00:00" }, { "name": "phpstan/phpstan-phpunit", diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 4291463fa..fdc5a57df 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -80,16 +80,6 @@ parameters: count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/DataPacket.php - - - message: "#^Parameter \\#1 \\$array of function array_values expects array, array given\\.$#" - count: 1 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - - - message: "#^Parameter \\#2 \\$array of function array_map expects array, array given\\.$#" - count: 3 - path: ../../../src/pocketmine/plugin/PluginDescription.php - - message: "#^Dead catch \\- ReflectionException is never thrown in the try block\\.$#" count: 2 From e0b07ff3087b652407439a29c941f3b66ca92c86 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 3 Nov 2021 20:45:55 +0000 Subject: [PATCH 298/710] Human: do not add more XP if totalXp limit was already reached this matches the vanilla behaviour. For some reason it doesn't consider levels (so you can have a level higher or lower than this without actually having that amount of XP), but this matches Java behaviour as of 1.10. fixes #4543 --- src/pocketmine/entity/Human.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 9d590db0c..5036415bd 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -403,6 +403,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ * @param bool $playSound Whether to play level-up and XP gained sounds. */ public function addXp(int $amount, bool $playSound = true) : bool{ + $amount = min($amount, INT32_MAX - $this->totalXp); $oldLevel = $this->getXpLevel(); $oldTotal = $this->getCurrentTotalXp(); From 2405e45b357caf7e0284ffd7d91c302260d10722 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 3 Nov 2021 21:26:20 +0000 Subject: [PATCH 299/710] Player: mark as not using item when held item slot is changed closes #4538 --- src/player/Player.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/player/Player.php b/src/player/Player.php index 2f27430ac..fdbb60391 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -73,6 +73,7 @@ use pocketmine\event\player\PlayerToggleSprintEvent; use pocketmine\event\player\PlayerTransferEvent; use pocketmine\form\Form; use pocketmine\form\FormValidationException; +use pocketmine\inventory\CallbackInventoryListener; use pocketmine\inventory\Inventory; use pocketmine\inventory\PlayerCursorInventory; use pocketmine\inventory\transaction\action\DropItemAction; @@ -291,6 +292,17 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ parent::initEntity($nbt); $this->addDefaultWindows(); + $this->inventory->getListeners()->add(new CallbackInventoryListener( + function(Inventory $unused, int $slot) : void{ + if($slot === $this->inventory->getHeldItemIndex()){ + $this->setUsingItem(false); + } + }, + function() : void{ + $this->setUsingItem(false); + } + )); + $this->firstPlayed = $nbt->getLong("firstPlayed", $now = (int) (microtime(true) * 1000)); $this->lastPlayed = $nbt->getLong("lastPlayed", $now); From 4f8501ff34fc0cb4f8f64c09a7a149421598c414 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 4 Nov 2021 14:14:55 +0000 Subject: [PATCH 300/710] Added a tool to visualise behaviour of ChunkSelector I actually intended to write a tool for debugging generation, but it turns out this, as an intermediary step, is also useful and a whole bunch of fun to play with. --- tools/simulate-chunk-selector.php | 171 ++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 tools/simulate-chunk-selector.php diff --git a/tools/simulate-chunk-selector.php b/tools/simulate-chunk-selector.php new file mode 100644 index 000000000..9ae7a1161 --- /dev/null +++ b/tools/simulate-chunk-selector.php @@ -0,0 +1,171 @@ +selectChunks($radius, $baseX, $baseZ); + + $middleOffsetX = $scale * ($radius + $offsetX); + $middleOffsetZ = $scale * ($radius + $offsetZ); + + $frame = 0; + $seen = []; + while($iterator->valid()){ + $frame++; + + $black = imagecolorallocate($image, 0, 0, 0); + $yellow = imagecolorallocate($image, 255, 255, 51); + $red = imagecolorallocate($image, 255, 0, 0); + if($black === false || $yellow === false || $red === false) throw new AssumptionFailedError(); + + for($i = 0; $i < $chunksPerStep; ++$i){ + $chunkHash = $iterator->current(); + if(!isset($seen[$chunkHash])){ + $color = $chunkColor; + $seen[$chunkHash] = true; + }else{ + $color = $yellow; + } + World::getXZ($chunkHash, $chunkX, $chunkZ); + $imageX = $middleOffsetX + (($chunkX - $baseX) * $scale); + $imageZ = $middleOffsetZ + (($chunkZ - $baseZ) * $scale); + + imagefilledrectangle($image, $imageX, $imageZ, $imageX + $scale, $imageZ + $scale, $color); + imagerectangle($image, $imageX, $imageZ, $imageX + $scale, $imageZ + $scale, $black); + + $iterator->next(); + if(!$iterator->valid()){ + break; + } + } + imagearc($image, $middleOffsetX, $middleOffsetZ, $radius * $scale * 2, $radius * $scale * 2, 0, 360, $red); + + imagepng($image, Path::join($outputFolder, "frame" . str_pad(strval($frame), 5, "0", STR_PAD_LEFT) . ".png")); + echo "\rRendered step $frame"; + } + echo "\n"; +} + +$radius = null; +$baseX = 10000 >> Chunk::COORD_BIT_SIZE; +$baseZ = 10000 >> Chunk::COORD_BIT_SIZE; + +$nChunksPerStep = 32; +$scale = 10; + +if(count(getopt("", ["help"])) !== 0){ + echo "Required parameters:\n"; + echo "--output=path/to/dir: Output folder to put the generated images into (will attempt to create if it doesn't exist)\n"; + echo "--radius=N: Radius of chunks to render (default $radius)\n"; + echo "\n"; + echo "Optional parameters:\n"; + echo "--baseX=N: Base X coordinate to use for simulation (default $baseX\n"; + echo "--baseZ=N: Base Z coordinate to use for simulation (default $baseZ)\n"; + echo "--scale=N: Height/width of square of pixels to use for each chunk (default $scale)\n"; + echo "--chunksPerStep=N: Number of chunks to process in each frame (default $nChunksPerStep)\n"; + exit(0); +} + +foreach(getopt("", ["radius:", "baseX:", "baseZ:", "scale:", "chunksPerStep:"]) as $name => $value){ + if(!is_string($value) || (string) ((int) $value) !== $value){ + fwrite(STDERR, "Value for --$name must be an integer\n"); + exit(1); + } + $value = (int) $value; + match($name){ + "radius" => ($radius = $value), + "baseX" => ($baseX = $value), + "baseZ" => ($baseZ = $value), + "scale" => ($scale = $value), + "chunksPerStep" => ($nChunksPerStep = $value), + default => throw new AssumptionFailedError("getopt() returned unknown option") + }; +} +if($radius === null){ + fwrite(STDERR, "Please specify a radius using --radius\n"); + exit(1); +} + +$outputDirectory = null; +foreach(getopt("", ["output:"]) as $name => $value){ + assert($name === "output"); + if(!is_string($value)){ + fwrite(STDERR, "Value for --$name must be a string\n"); + exit(1); + } + if(!@mkdir($value) && !is_dir($value)){ + fwrite(STDERR, "Output directory $value could not be created\n"); + exit(1); + } + $files = scandir($value, SCANDIR_SORT_NONE); + if($files !== false && count($files) > 2){ //always returns . and .. + fwrite(STDERR, "Output directory $value is not empty\n"); + exit(1); + } + $realPath = realpath($value); + if($realPath === false){ + throw new AssumptionFailedError(); + } + $outputDirectory = $realPath; +} +if($outputDirectory === null){ + fwrite(STDERR, "Please specify an output directory using --output\n"); + exit(1); +} +$image = newImage($scale, $radius); + +$black = imagecolorallocate($image, 0, 0, 0); +$green = imagecolorallocate($image, 0, 220, 0); +if($black === false || $green === false){ + throw new AssumptionFailedError(); +} +render($radius, $baseX, $baseZ, $nChunksPerStep, $scale, $image, $green, 0, 0, $outputDirectory); From 8ac999cbd4fb7d0049a31b83f54a1147aab41fad Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 4 Nov 2021 16:55:04 +0000 Subject: [PATCH 301/710] Use object models for crashdump generation --- src/CrashDump.php | 120 ++++++++++++------------- src/Server.php | 6 +- src/crash/CrashDumpData.php | 84 +++++++++++++++++ src/crash/CrashDumpDataGeneral.php | 46 ++++++++++ src/crash/CrashDumpDataPluginEntry.php | 45 ++++++++++ 5 files changed, 233 insertions(+), 68 deletions(-) create mode 100644 src/crash/CrashDumpData.php create mode 100644 src/crash/CrashDumpDataGeneral.php create mode 100644 src/crash/CrashDumpDataPluginEntry.php diff --git a/src/CrashDump.php b/src/CrashDump.php index d6cf5caf0..b18d09021 100644 --- a/src/CrashDump.php +++ b/src/CrashDump.php @@ -24,6 +24,9 @@ declare(strict_types=1); namespace pocketmine; use Composer\InstalledVersions; +use pocketmine\crash\CrashDumpData; +use pocketmine\crash\CrashDumpDataGeneral; +use pocketmine\crash\CrashDumpDataPluginEntry; use pocketmine\errorhandler\ErrorTypeToStringMap; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\plugin\PluginBase; @@ -69,6 +72,7 @@ use const FILE_IGNORE_NEW_LINES; use const JSON_UNESCAPED_SLASHES; use const PHP_EOL; use const PHP_OS; +use const PHP_VERSION; use const SORT_STRING; class CrashDump{ @@ -91,13 +95,9 @@ class CrashDump{ private $fp; /** @var float */ private $time; - /** - * @var mixed[] - * @phpstan-var array - */ - private $data = []; + private CrashDumpData $data; /** @var string */ - private $encodedData = ""; + private $encodedData; /** @var string */ private $path; @@ -118,9 +118,10 @@ class CrashDump{ throw new \RuntimeException("Could not create Crash Dump"); } $this->fp = $fp; - $this->data["format_version"] = self::FORMAT_VERSION; - $this->data["time"] = $this->time; - $this->data["uptime"] = $this->time - $this->server->getStartTime(); + $this->data = new CrashDumpData(); + $this->data->format_version = self::FORMAT_VERSION; + $this->data->time = $this->time; + $this->data->uptime = $this->time - $this->server->getStartTime(); $this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", (int) $this->time)); $this->addLine(); $this->baseCrash(); @@ -142,11 +143,7 @@ class CrashDump{ return $this->encodedData; } - /** - * @return mixed[] - * @phpstan-return array - */ - public function getData() : array{ + public function getData() : CrashDumpData{ return $this->data; } @@ -173,22 +170,21 @@ class CrashDump{ $plugins = $this->pluginManager->getPlugins(); $this->addLine(); $this->addLine("Loaded plugins:"); - $this->data["plugins"] = []; ksort($plugins, SORT_STRING); foreach($plugins as $p){ $d = $p->getDescription(); - $this->data["plugins"][$d->getName()] = [ - "name" => $d->getName(), - "version" => $d->getVersion(), - "authors" => $d->getAuthors(), - "api" => $d->getCompatibleApis(), - "enabled" => $p->isEnabled(), - "depends" => $d->getDepend(), - "softDepends" => $d->getSoftDepend(), - "main" => $d->getMain(), - "load" => mb_strtoupper($d->getOrder()->name()), - "website" => $d->getWebsite() - ]; + $this->data->plugins[$d->getName()] = new CrashDumpDataPluginEntry( + name: $d->getName(), + version: $d->getVersion(), + authors: $d->getAuthors(), + api: $d->getCompatibleApis(), + enabled: $p->isEnabled(), + depends: $d->getDepend(), + softDepends: $d->getSoftDepend(), + main: $d->getMain(), + load: mb_strtoupper($d->getOrder()->name()), + website: $d->getWebsite() + ); $this->addLine($d->getName() . " " . $d->getVersion() . " by " . implode(", ", $d->getAuthors()) . " for API(s) " . implode(", ", $d->getCompatibleApis())); } } @@ -198,32 +194,26 @@ class CrashDump{ global $argv; if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-settings", true)){ - $this->data["parameters"] = (array) $argv; + $this->data->parameters = (array) $argv; if(($serverDotProperties = @file_get_contents(Path::join($this->server->getDataPath(), "server.properties"))) !== false){ - $this->data["server.properties"] = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $serverDotProperties); - }else{ - $this->data["server.properties"] = $serverDotProperties; + $this->data->serverDotProperties = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $serverDotProperties) ?? throw new AssumptionFailedError("Pattern is valid"); } if(($pocketmineDotYml = @file_get_contents(Path::join($this->server->getDataPath(), "pocketmine.yml"))) !== false){ - $this->data["pocketmine.yml"] = $pocketmineDotYml; - }else{ - $this->data["pocketmine.yml"] = ""; + $this->data->pocketmineDotYml = $pocketmineDotYml; } - }else{ - $this->data["pocketmine.yml"] = ""; - $this->data["server.properties"] = ""; - $this->data["parameters"] = []; } $extensions = []; foreach(get_loaded_extensions() as $ext){ - $extensions[$ext] = phpversion($ext); + $version = phpversion($ext); + if($version === false) throw new AssumptionFailedError(); + $extensions[$ext] = $version; } - $this->data["extensions"] = $extensions; + $this->data->extensions = $extensions; if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-phpinfo", true)){ ob_start(); phpinfo(); - $this->data["phpinfo"] = ob_get_contents(); + $this->data->phpinfo = ob_get_contents(); // @phpstan-ignore-line ob_end_clean(); } } @@ -255,18 +245,18 @@ class CrashDump{ if(isset($lastError["trace"])){ $lastError["trace"] = Utils::printableTrace($lastError["trace"]); } - $this->data["lastError"] = $lastError; + $this->data->lastError = $lastError; } - $this->data["error"] = $error; - unset($this->data["error"]["fullFile"]); - unset($this->data["error"]["trace"]); + $this->data->error = $error; + unset($this->data->error["fullFile"]); + unset($this->data->error["trace"]); $this->addLine("Error: " . $error["message"]); $this->addLine("File: " . $error["file"]); $this->addLine("Line: " . $error["line"]); $this->addLine("Type: " . $error["type"]); - $this->data["plugin_involvement"] = self::PLUGIN_INVOLVEMENT_NONE; + $this->data->plugin_involvement = self::PLUGIN_INVOLVEMENT_NONE; if(!$this->determinePluginFromFile($error["fullFile"], true)){ //fatal errors won't leave any stack trace foreach($error["trace"] as $frame){ if(!isset($frame["file"])){ @@ -280,21 +270,20 @@ class CrashDump{ $this->addLine(); $this->addLine("Code:"); - $this->data["code"] = []; if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-code", true) and file_exists($error["fullFile"])){ $file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES); if($file !== false){ for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){ $this->addLine("[" . ($l + 1) . "] " . $file[$l]); - $this->data["code"][$l + 1] = $file[$l]; + $this->data->code[$l + 1] = $file[$l]; } } } $this->addLine(); $this->addLine("Backtrace:"); - foreach(($this->data["trace"] = Utils::printableTrace($error["trace"])) as $line){ + foreach(($this->data->trace = Utils::printableTrace($error["trace"])) as $line){ $this->addLine($line); } $this->addLine(); @@ -306,10 +295,10 @@ class CrashDump{ $this->addLine(); if($crashFrame){ $this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN"); - $this->data["plugin_involvement"] = self::PLUGIN_INVOLVEMENT_DIRECT; + $this->data->plugin_involvement = self::PLUGIN_INVOLVEMENT_DIRECT; }else{ $this->addLine("A PLUGIN WAS INVOLVED IN THIS CRASH"); - $this->data["plugin_involvement"] = self::PLUGIN_INVOLVEMENT_INDIRECT; + $this->data->plugin_involvement = self::PLUGIN_INVOLVEMENT_INDIRECT; } if(file_exists($filePath)){ @@ -319,7 +308,7 @@ class CrashDump{ foreach($this->server->getPluginManager()->getPlugins() as $plugin){ $filePath = Filesystem::cleanPath($file->getValue($plugin)); if(strpos($frameCleanPath, $filePath) === 0){ - $this->data["plugin"] = $plugin->getName(); + $this->data->plugin = $plugin->getName(); $this->addLine("BAD PLUGIN: " . $plugin->getDescription()->getFullName()); break; } @@ -341,19 +330,20 @@ class CrashDump{ ); } - $this->data["general"] = []; - $this->data["general"]["name"] = $this->server->getName(); - $this->data["general"]["base_version"] = VersionInfo::BASE_VERSION; - $this->data["general"]["build"] = VersionInfo::BUILD_NUMBER; - $this->data["general"]["is_dev"] = VersionInfo::IS_DEVELOPMENT_BUILD; - $this->data["general"]["protocol"] = ProtocolInfo::CURRENT_PROTOCOL; - $this->data["general"]["git"] = VersionInfo::GIT_HASH(); - $this->data["general"]["uname"] = php_uname("a"); - $this->data["general"]["php"] = phpversion(); - $this->data["general"]["zend"] = zend_version(); - $this->data["general"]["php_os"] = PHP_OS; - $this->data["general"]["os"] = Utils::getOS(); - $this->data["general"]["composer_libraries"] = $composerLibraries; + $this->data->general = new CrashDumpDataGeneral( + name: $this->server->getName(), + base_version: VersionInfo::BASE_VERSION, + build: VersionInfo::BUILD_NUMBER, + is_dev: VersionInfo::IS_DEVELOPMENT_BUILD, + protocol: ProtocolInfo::CURRENT_PROTOCOL, + git: VersionInfo::GIT_HASH(), + uname: php_uname("a"), + php: PHP_VERSION, + zend: zend_version(), + php_os: PHP_OS, + os: Utils::getOS(), + composer_libraries: $composerLibraries, + ); $this->addLine($this->server->getName() . " version: " . $version->getFullVersion(true) . " [Protocol " . ProtocolInfo::CURRENT_PROTOCOL . "]"); $this->addLine("Git commit: " . VersionInfo::GIT_HASH()); $this->addLine("uname -a: " . php_uname("a")); diff --git a/src/Server.php b/src/Server.php index 753556ff8..30fba8f25 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1504,8 +1504,8 @@ class Server{ } @touch($stamp); //update file timestamp - $plugin = $dump->getData()["plugin"]; - if(is_string($plugin)){ + $plugin = $dump->getData()->plugin; + if($plugin !== ""){ $p = $this->pluginManager->getPlugin($plugin); if($p instanceof Plugin and !($p->getPluginLoader() instanceof PharPluginLoader)){ $this->logger->debug("Not sending crashdump due to caused by non-phar plugin"); @@ -1513,7 +1513,7 @@ class Server{ } } - if($dump->getData()["error"]["type"] === \ParseError::class){ + if($dump->getData()->error["type"] === \ParseError::class){ $report = false; } diff --git a/src/crash/CrashDumpData.php b/src/crash/CrashDumpData.php new file mode 100644 index 000000000..a3f13f2ca --- /dev/null +++ b/src/crash/CrashDumpData.php @@ -0,0 +1,84 @@ + + */ + public array $plugins = []; + + /** @var string[] */ + public array $parameters = []; + + public string $serverDotProperties = ""; + + public string $pocketmineDotYml = ""; + + /** + * @var string[] + * @phpstan-var array + */ + public array $extensions = []; + + public string $phpinfo = ""; + + public CrashDumpDataGeneral $general; + + /** + * @return mixed[] + */ + public function jsonSerialize() : array{ + $result = (array) $this; + unset($result["serverDotProperties"]); + unset($result["pocketmineDotYml"]); + $result["pocketmine.yml"] = $this->pocketmineDotYml; + $result["server.properties"] = $this->serverDotProperties; + return $result; + } +} \ No newline at end of file diff --git a/src/crash/CrashDumpDataGeneral.php b/src/crash/CrashDumpDataGeneral.php new file mode 100644 index 000000000..33e41ce01 --- /dev/null +++ b/src/crash/CrashDumpDataGeneral.php @@ -0,0 +1,46 @@ + $composer_libraries + */ + public function __construct( + public string $name, + public string $base_version, + public int $build, + public bool $is_dev, + public int $protocol, + public string $git, + public string $uname, + public string $php, + public string $zend, + public string $php_os, + public string $os, + public array $composer_libraries, + ){} +} \ No newline at end of file diff --git a/src/crash/CrashDumpDataPluginEntry.php b/src/crash/CrashDumpDataPluginEntry.php new file mode 100644 index 000000000..21139f431 --- /dev/null +++ b/src/crash/CrashDumpDataPluginEntry.php @@ -0,0 +1,45 @@ + Date: Thu, 4 Nov 2021 19:18:29 +0000 Subject: [PATCH 302/710] Regenerate PHPStan bugs baseline --- tests/phpstan/configs/phpstan-bugs.neon | 52 +------------------------ 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 5fc2c433a..b6b928870 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -1,57 +1,7 @@ parameters: ignoreErrors: - - message: "#^Cannot access offset 'base_version' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'build' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'composer_libraries' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'git' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'is_dev' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'os' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'php' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'php_os' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'protocol' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'uname' on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset 'zend' on mixed\\.$#" + message: "#^Property pocketmine\\\\crash\\\\CrashDumpData\\:\\:\\$extensions \\(array\\\\) does not accept array\\\\.$#" count: 1 path: ../../../src/CrashDump.php From 15fca84f3b76699e2915a509048b0023e38930c1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 4 Nov 2021 19:22:49 +0000 Subject: [PATCH 303/710] remove some PHPStan error patterns --- tests/phpstan/configs/actual-problems.neon | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index fe984f020..5c1237f80 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -20,16 +20,6 @@ parameters: count: 1 path: ../../../build/server-phar.php - - - message: "#^Cannot access offset \\(float\\|int\\) on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - - - message: "#^Cannot access offset string on mixed\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" count: 1 @@ -70,11 +60,6 @@ parameters: count: 3 path: ../../../src/PocketMine.php - - - message: "#^Cannot access offset 'type' on mixed\\.$#" - count: 1 - path: ../../../src/Server.php - - message: "#^Cannot cast mixed to string\\.$#" count: 1 From 84f8b3eb2dbe9c4e8b7659d7b1001e829579b21c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 4 Nov 2021 19:23:45 +0000 Subject: [PATCH 304/710] Move CrashDump to pocketmine\crash namespace --- src/Server.php | 1 + src/{ => crash}/CrashDump.php | 7 +++---- tests/phpstan/configs/actual-problems.neon | 10 +++++----- tests/phpstan/configs/phpstan-bugs.neon | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) rename src/{ => crash}/CrashDump.php (98%) diff --git a/src/Server.php b/src/Server.php index 30fba8f25..731860d4a 100644 --- a/src/Server.php +++ b/src/Server.php @@ -34,6 +34,7 @@ use pocketmine\console\ConsoleCommandSender; use pocketmine\console\ConsoleReaderThread; use pocketmine\crafting\CraftingManager; use pocketmine\crafting\CraftingManagerFromDataHelper; +use pocketmine\crash\CrashDump; use pocketmine\data\java\GameModeIdMap; use pocketmine\entity\EntityDataHelper; use pocketmine\entity\Location; diff --git a/src/CrashDump.php b/src/crash/CrashDump.php similarity index 98% rename from src/CrashDump.php rename to src/crash/CrashDump.php index b18d09021..1d595402e 100644 --- a/src/CrashDump.php +++ b/src/crash/CrashDump.php @@ -21,19 +21,18 @@ declare(strict_types=1); -namespace pocketmine; +namespace pocketmine\crash; use Composer\InstalledVersions; -use pocketmine\crash\CrashDumpData; -use pocketmine\crash\CrashDumpDataGeneral; -use pocketmine\crash\CrashDumpDataPluginEntry; use pocketmine\errorhandler\ErrorTypeToStringMap; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\plugin\PluginBase; use pocketmine\plugin\PluginManager; +use pocketmine\Server; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Filesystem; use pocketmine\utils\Utils; +use pocketmine\VersionInfo; use Webmozart\PathUtil\Path; use function base64_encode; use function date; diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 5c1237f80..badcc3e0e 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -20,11 +20,6 @@ parameters: count: 1 path: ../../../build/server-phar.php - - - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" count: 1 @@ -530,6 +525,11 @@ parameters: count: 1 path: ../../../src/crafting/CraftingManagerFromDataHelper.php + - + message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" + count: 1 + path: ../../../src/crash/CrashDump.php + - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" count: 1 diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index b6b928870..0a580dcf0 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -1,10 +1,5 @@ parameters: ignoreErrors: - - - message: "#^Property pocketmine\\\\crash\\\\CrashDumpData\\:\\:\\$extensions \\(array\\\\) does not accept array\\\\.$#" - count: 1 - path: ../../../src/CrashDump.php - - message: "#^Instanceof between pocketmine\\\\block\\\\utils\\\\BannerPatternLayer and pocketmine\\\\block\\\\utils\\\\BannerPatternLayer will always evaluate to true\\.$#" count: 1 @@ -25,6 +20,11 @@ parameters: count: 1 path: ../../../src/crafting/CraftingManager.php + - + message: "#^Property pocketmine\\\\crash\\\\CrashDumpData\\:\\:\\$extensions \\(array\\\\) does not accept array\\\\.$#" + count: 1 + path: ../../../src/crash/CrashDump.php + - message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#" count: 1 From 4c3a5fdd731b8df37620ae19172654b4855a9636 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 4 Nov 2021 19:28:52 +0000 Subject: [PATCH 305/710] Clean PHPStan baselines from 1.0.2 --- tests/phpstan/configs/phpstan-bugs.neon | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 0a580dcf0..8baae94f1 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -30,16 +30,6 @@ parameters: count: 1 path: ../../../src/entity/projectile/Projectile.php - - - message: "#^Parameter \\#1 \\$array of function array_values expects array, array given\\.$#" - count: 1 - path: ../../../src/plugin/PluginDescription.php - - - - message: "#^Parameter \\#2 \\$array of function array_map expects array, array given\\.$#" - count: 3 - path: ../../../src/plugin/PluginDescription.php - - message: "#^Dead catch \\- RuntimeException is never thrown in the try block\\.$#" count: 1 From 8abc952c74da426257ef4fff25be1b72ffeb1eb4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 4 Nov 2021 19:38:40 +0000 Subject: [PATCH 306/710] simulate-chunk-selector: do not reallocate colours on every frame --- tools/simulate-chunk-selector.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/simulate-chunk-selector.php b/tools/simulate-chunk-selector.php index 9ae7a1161..b4af186e2 100644 --- a/tools/simulate-chunk-selector.php +++ b/tools/simulate-chunk-selector.php @@ -57,16 +57,16 @@ function render(int $radius, int $baseX, int $baseZ, int $chunksPerStep, int $sc $middleOffsetX = $scale * ($radius + $offsetX); $middleOffsetZ = $scale * ($radius + $offsetZ); + $black = imagecolorallocate($image, 0, 0, 0); + $yellow = imagecolorallocate($image, 255, 255, 51); + $red = imagecolorallocate($image, 255, 0, 0); + if($black === false || $yellow === false || $red === false) throw new AssumptionFailedError(); + $frame = 0; $seen = []; while($iterator->valid()){ $frame++; - $black = imagecolorallocate($image, 0, 0, 0); - $yellow = imagecolorallocate($image, 255, 255, 51); - $red = imagecolorallocate($image, 255, 0, 0); - if($black === false || $yellow === false || $red === false) throw new AssumptionFailedError(); - for($i = 0; $i < $chunksPerStep; ++$i){ $chunkHash = $iterator->current(); if(!isset($seen[$chunkHash])){ From 579ef63663e71dbdd9a819bb6e82ea1e17a3f710 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 4 Nov 2021 20:46:34 +0000 Subject: [PATCH 307/710] EntityDataHelper: accept FloatTag for vector3 as well as Double MCPE uses Float for entity positions. --- src/entity/EntityDataHelper.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/entity/EntityDataHelper.php b/src/entity/EntityDataHelper.php index f58fef743..2038f47d4 100644 --- a/src/entity/EntityDataHelper.php +++ b/src/entity/EntityDataHelper.php @@ -59,10 +59,10 @@ final class EntityDataHelper{ if($pos === null and $optional){ return new Vector3(0, 0, 0); } - if(!($pos instanceof ListTag) or $pos->getTagType() !== NBT::TAG_Double){ - throw new \UnexpectedValueException("'$tagName' should be a List"); + if(!($pos instanceof ListTag) or ($pos->getTagType() !== NBT::TAG_Double && $pos->getTagType() !== NBT::TAG_Float)){ + throw new \UnexpectedValueException("'$tagName' should be a List or List"); } - /** @var DoubleTag[] $values */ + /** @var DoubleTag[]|FloatTag[] $values */ $values = $pos->getValue(); if(count($values) !== 3){ throw new \UnexpectedValueException("Expected exactly 3 entries in '$tagName' tag"); From 5107d0df4e71d9cd5dd11516c6c0faf2186dcb52 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 5 Nov 2021 15:09:42 +0000 Subject: [PATCH 308/710] Player: cap maximum number of active generation requests this fixes the horrible spotty chunk loading seen in https://twitter.com/dktapps/status/1456397007946461190?s=20. In practice, this made chunks invisible on teleport for several tens of seconds after teleporting. Having a larger chunks-per-tick with large render distance compounded to worsen the problem. It wasn't really noticeable on small render distances, but very obvious on large ones with fast chunk sending and slow generation. This also fixes #4187 (at least to the extent that it works on PM3, anyway). --- src/player/Player.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/player/Player.php b/src/player/Player.php index fdbb60391..866cbb967 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -195,6 +195,11 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * @phpstan-var array */ protected array $usedChunks = []; + /** + * @var true[] + * @phpstan-var array + */ + private array $activeChunkGenerationRequests = []; /** * @var true[] chunkHash => dummy * @phpstan-var array @@ -643,6 +648,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } $this->getNetworkSession()->stopUsingChunk($x, $z); unset($this->usedChunks[$index]); + unset($this->activeChunkGenerationRequests[$index]); } $world->unregisterChunkLoader($this->chunkLoader, $x, $z); $world->unregisterChunkListener($this, $x, $z); @@ -680,7 +686,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $count = 0; $world = $this->getWorld(); foreach($this->loadQueue as $index => $distance){ - if($count >= $this->chunksPerTick){ + if($count >= $this->chunksPerTick || count($this->activeChunkGenerationRequests) >= $this->chunksPerTick){ break; } @@ -692,6 +698,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ ++$count; $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_GENERATION(); + $this->activeChunkGenerationRequests[$index] = true; unset($this->loadQueue[$index]); $this->getWorld()->registerChunkLoader($this->chunkLoader, $X, $Z, true); $this->getWorld()->registerChunkListener($this, $X, $Z); @@ -707,6 +714,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ //multiple callbacks for this player. In that case, only the first one matters. return; } + unset($this->activeChunkGenerationRequests[$index]); $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_SENDING(); $this->getNetworkSession()->startUsingChunk($X, $Z, function() use ($X, $Z, $index) : void{ From 0989c77037f87654382f209c709b4e17f82549a0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 5 Nov 2021 15:46:55 +0000 Subject: [PATCH 309/710] Player: check that horizontal distance travelled is > 0 before adding exhaustion, or triggering a new chunk order closes #4548 --- src/player/Player.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/player/Player.php b/src/player/Player.php index 866cbb967..0a00b4010 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1186,16 +1186,18 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->lastLocation = $to; $this->broadcastMovement(); - $distance = sqrt((($from->x - $to->x) ** 2) + (($from->z - $to->z) ** 2)); - //TODO: check swimming (adds 0.015 exhaustion in MCPE) - if($this->isSprinting()){ - $this->hungerManager->exhaust(0.1 * $distance, PlayerExhaustEvent::CAUSE_SPRINTING); - }else{ - $this->hungerManager->exhaust(0.01 * $distance, PlayerExhaustEvent::CAUSE_WALKING); - } + $horizontalDistanceTravelled = sqrt((($from->x - $to->x) ** 2) + (($from->z - $to->z) ** 2)); + if($horizontalDistanceTravelled > 0){ + //TODO: check swimming (adds 0.015 exhaustion in MCPE) + if($this->isSprinting()){ + $this->hungerManager->exhaust(0.1 * $horizontalDistanceTravelled, PlayerExhaustEvent::CAUSE_SPRINTING); + }else{ + $this->hungerManager->exhaust(0.01 * $horizontalDistanceTravelled, PlayerExhaustEvent::CAUSE_WALKING); + } - if($this->nextChunkOrderRun > 20){ - $this->nextChunkOrderRun = 20; + if($this->nextChunkOrderRun > 20){ + $this->nextChunkOrderRun = 20; + } } } From 07b1cff30609e3e11360cdb4403d4757918559c7 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 5 Nov 2021 17:15:55 +0100 Subject: [PATCH 310/710] Bonemeal is no longer consumed when cancelling plant growth events (#4551) --- src/block/Crops.php | 3 +-- src/block/Sapling.php | 11 +++++------ src/block/Sugarcane.php | 11 ++++++----- src/block/SweetBerryBush.php | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/block/Crops.php b/src/block/Crops.php index 47cb33897..c7f201b41 100644 --- a/src/block/Crops.php +++ b/src/block/Crops.php @@ -80,10 +80,9 @@ abstract class Crops extends Flowable{ $ev->call(); if(!$ev->isCancelled()){ $this->position->getWorld()->setBlock($this->position, $ev->getNewState()); + $item->pop(); } - $item->pop(); - return true; } diff --git a/src/block/Sapling.php b/src/block/Sapling.php index d2ae0b5a7..85e092451 100644 --- a/src/block/Sapling.php +++ b/src/block/Sapling.php @@ -76,9 +76,7 @@ class Sapling extends Flowable{ } public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($item instanceof Fertilizer){ - $this->grow($player); - + if($item instanceof Fertilizer && $this->grow($player)){ $item->pop(); return true; @@ -108,19 +106,20 @@ class Sapling extends Flowable{ } } - private function grow(?Player $player) : void{ + private function grow(?Player $player) : bool{ $random = new Random(mt_rand()); $tree = TreeFactory::get($random, $this->treeType); $transaction = $tree?->getBlockTransaction($this->position->getWorld(), $this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ(), $random); if($transaction === null){ - return; + return false; } $ev = new StructureGrowEvent($this, $transaction, $player); $ev->call(); if(!$ev->isCancelled()){ - $transaction->apply(); + return $transaction->apply(); } + return false; } public function getFuelTime() : int{ diff --git a/src/block/Sugarcane.php b/src/block/Sugarcane.php index eadf9c1ff..90eef3d4b 100644 --- a/src/block/Sugarcane.php +++ b/src/block/Sugarcane.php @@ -48,7 +48,8 @@ class Sugarcane extends Flowable{ return 0b1111; } - private function grow() : void{ + private function grow() : bool{ + $grew = false; for($y = 1; $y < 3; ++$y){ if(!$this->position->getWorld()->isInWorld($this->position->x, $this->position->y + $y, $this->position->z)){ break; @@ -61,12 +62,14 @@ class Sugarcane extends Flowable{ break; } $this->position->getWorld()->setBlock($b->position, $ev->getNewState()); + $grew = true; }else{ break; } } $this->age = 0; $this->position->getWorld()->setBlock($this->position, $this); + return $grew; } public function getAge() : int{ return $this->age; } @@ -82,12 +85,10 @@ class Sugarcane extends Flowable{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($item instanceof Fertilizer){ - if(!$this->getSide(Facing::DOWN)->isSameType($this)){ - $this->grow(); + if(!$this->getSide(Facing::DOWN)->isSameType($this) && $this->grow()){ + $item->pop(); } - $item->pop(); - return true; } diff --git a/src/block/SweetBerryBush.php b/src/block/SweetBerryBush.php index efb35845e..4412d0cff 100644 --- a/src/block/SweetBerryBush.php +++ b/src/block/SweetBerryBush.php @@ -99,9 +99,9 @@ class SweetBerryBush extends Flowable{ if(!$ev->isCancelled()){ $this->position->getWorld()->setBlock($this->position, $ev->getNewState()); + $item->pop(); } - $item->pop(); }elseif(($dropAmount = $this->getBerryDropAmount()) > 0){ $this->position->getWorld()->setBlock($this->position, $this->setAge(self::STAGE_BUSH_NO_BERRIES)); $this->position->getWorld()->dropItem($this->position, $this->asItem()->setCount($dropAmount)); From dbf9a331600b1e0daa90d2ee05d54415b2939e22 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 00:06:08 +0000 Subject: [PATCH 311/710] ChunkSelector: Improve algorithm to send chunks in proper circles, instead of squares this ensures that the edge of loaded terain is always the same distance away in any direction. This also means that when flying parallel to X or Z axes, you now have about 12% more chunks directly in front of you, instead of to your left and right, which gives the impression that chunks are loading faster (they aren't, they are just being ordered in a more sensible way). --- src/player/ChunkSelector.php | 59 +++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/src/player/ChunkSelector.php b/src/player/ChunkSelector.php index 31bbf08e4..3ba314215 100644 --- a/src/player/ChunkSelector.php +++ b/src/player/ChunkSelector.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\player; use pocketmine\world\World; +use const M_SQRT2; //TODO: turn this into an interface? final class ChunkSelector{ @@ -33,34 +34,44 @@ final class ChunkSelector{ * @phpstan-return \Generator */ public function selectChunks(int $radius, int $centerX, int $centerZ) : \Generator{ - $radiusSquared = $radius ** 2; + for($subRadius = 0; $subRadius < $radius; $subRadius++){ + $subRadiusSquared = $subRadius ** 2; + $nextSubRadiusSquared = ($subRadius + 1) ** 2; + $minX = (int) ($subRadius / M_SQRT2); - for($x = 0; $x < $radius; ++$x){ - for($z = 0; $z <= $x; ++$z){ - if(($x ** 2 + $z ** 2) > $radiusSquared){ - break; //skip to next band - } + $lastZ = 0; - //If the chunk is in the radius, others at the same offsets in different quadrants are also guaranteed to be. + for($x = $subRadius; $x >= $minX; --$x){ + for($z = $lastZ; $z <= $x; ++$z){ + $distanceSquared = ($x ** 2 + $z ** 2); + if($distanceSquared < $subRadiusSquared){ + continue; + }elseif($distanceSquared >= $nextSubRadiusSquared){ + break; //skip to next X + } - /* Top right quadrant */ - yield World::chunkHash($centerX + $x, $centerZ + $z); - /* Top left quadrant */ - yield World::chunkHash($centerX - $x - 1, $centerZ + $z); - /* Bottom right quadrant */ - yield World::chunkHash($centerX + $x, $centerZ - $z - 1); - /* Bottom left quadrant */ - yield World::chunkHash($centerX - $x - 1, $centerZ - $z - 1); + $lastZ = $z; + //If the chunk is in the radius, others at the same offsets in different quadrants are also guaranteed to be. - if($x !== $z){ - /* Top right quadrant mirror */ - yield World::chunkHash($centerX + $z, $centerZ + $x); - /* Top left quadrant mirror */ - yield World::chunkHash($centerX - $z - 1, $centerZ + $x); - /* Bottom right quadrant mirror */ - yield World::chunkHash($centerX + $z, $centerZ - $x - 1); - /* Bottom left quadrant mirror */ - yield World::chunkHash($centerX - $z - 1, $centerZ - $x - 1); + /* Top right quadrant */ + yield World::chunkHash($centerX + $x, $centerZ + $z); + /* Top left quadrant */ + yield World::chunkHash($centerX - $x - 1, $centerZ + $z); + /* Bottom right quadrant */ + yield World::chunkHash($centerX + $x, $centerZ - $z - 1); + /* Bottom left quadrant */ + yield World::chunkHash($centerX - $x - 1, $centerZ - $z - 1); + + if($x !== $z){ + /* Top right quadrant mirror */ + yield World::chunkHash($centerX + $z, $centerZ + $x); + /* Top left quadrant mirror */ + yield World::chunkHash($centerX - $z - 1, $centerZ + $x); + /* Bottom right quadrant mirror */ + yield World::chunkHash($centerX + $z, $centerZ - $x - 1); + /* Bottom left quadrant mirror */ + yield World::chunkHash($centerX - $z - 1, $centerZ - $x - 1); + } } } } From 3c754b079c440764a7ae59046c47764f4c6b914f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 00:32:58 +0000 Subject: [PATCH 312/710] Move resources/locale to Composer dependency all remaining submodules are now non-essential to running a server. They are also versioned and updates can be done automatically using 'composer update'. Finally, we can also put an end to the issue of translations being rendered incorrectly or being missing due to outdated submodules. --- .gitmodules | 3 --- build/generate-known-translation-apis.php | 2 +- composer.json | 1 + composer.lock | 25 ++++++++++++++++++++++- resources/locale | 1 - src/CoreConstants.php | 1 + src/lang/Language.php | 4 ++-- 7 files changed, 29 insertions(+), 8 deletions(-) delete mode 160000 resources/locale diff --git a/.gitmodules b/.gitmodules index 71a80c00a..0b2349472 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "resources/locale"] - path = resources/locale - url = https://github.com/pmmp/Language.git [submodule "tests/plugins/DevTools"] path = tests/plugins/DevTools url = https://github.com/pmmp/DevTools.git diff --git a/build/generate-known-translation-apis.php b/build/generate-known-translation-apis.php index 04dbe37a6..b2703b513 100644 --- a/build/generate-known-translation-apis.php +++ b/build/generate-known-translation-apis.php @@ -172,7 +172,7 @@ HEADER; echo "Done generating KnownTranslationFactory.\n"; } -$lang = parse_ini_file(Path::join(\pocketmine\RESOURCE_PATH, "locale", "eng.ini"), false, INI_SCANNER_RAW); +$lang = parse_ini_file(Path::join(\pocketmine\LOCALE_DATA_PATH, "eng.ini"), false, INI_SCANNER_RAW); if($lang === false){ fwrite(STDERR, "Missing language files!\n"); exit(1); diff --git a/composer.json b/composer.json index 9c9898693..978a881c4 100644 --- a/composer.json +++ b/composer.json @@ -41,6 +41,7 @@ "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", "pocketmine/errorhandler": "^0.3.0", + "pocketmine/locale-data": "^1.0.3", "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", "pocketmine/math": "^0.4.0", diff --git a/composer.lock b/composer.lock index c6676bc5b..0c3b4eb90 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c0368348f30e5309e979840d1cfad409", + "content-hash": "e36db7fb94bd79034dcc599c3029a621", "packages": [ { "name": "adhocore/json-comment", @@ -531,6 +531,29 @@ }, "time": "2021-02-12T18:56:22+00:00" }, + { + "name": "pocketmine/locale-data", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/pmmp/Language.git", + "reference": "7342b4eb593036c739e7f0c0ed95299ada69ff19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pmmp/Language/zipball/7342b4eb593036c739e7f0c0ed95299ada69ff19", + "reference": "7342b4eb593036c739e7f0c0ed95299ada69ff19", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "description": "Language resources used by PocketMine-MP", + "support": { + "issues": "https://github.com/pmmp/Language/issues", + "source": "https://github.com/pmmp/Language/tree/1.0.3" + }, + "time": "2021-11-06T00:27:03+00:00" + }, { "name": "pocketmine/log", "version": "0.4.0", diff --git a/resources/locale b/resources/locale deleted file mode 160000 index f9076e4a6..000000000 --- a/resources/locale +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f9076e4a6e3049aeaf7abd30d39a482a1392eafe diff --git a/src/CoreConstants.php b/src/CoreConstants.php index 91b9b95b9..46e00a2a3 100644 --- a/src/CoreConstants.php +++ b/src/CoreConstants.php @@ -36,4 +36,5 @@ define('pocketmine\_CORE_CONSTANTS_INCLUDED', true); define('pocketmine\PATH', dirname(__DIR__) . '/'); define('pocketmine\RESOURCE_PATH', dirname(__DIR__) . '/resources/'); define('pocketmine\BEDROCK_DATA_PATH', dirname(__DIR__) . '/vendor/pocketmine/bedrock-data/'); +define('pocketmine\LOCALE_DATA_PATH', dirname(__DIR__) . '/vendor/pocketmine/locale-data/'); define('pocketmine\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__) . '/vendor/autoload.php'); diff --git a/src/lang/Language.php b/src/lang/Language.php index f3e966704..33ad93888 100644 --- a/src/lang/Language.php +++ b/src/lang/Language.php @@ -52,7 +52,7 @@ class Language{ */ public static function getLanguageList(string $path = "") : array{ if($path === ""){ - $path = Path::join(\pocketmine\RESOURCE_PATH, "locale"); + $path = \pocketmine\LOCALE_DATA_PATH; } if(is_dir($path)){ @@ -101,7 +101,7 @@ class Language{ $this->langName = strtolower($lang); if($path === null){ - $path = Path::join(\pocketmine\RESOURCE_PATH, "locale"); + $path = \pocketmine\LOCALE_DATA_PATH; } $this->lang = self::loadLang($path, $this->langName); From 566c57bcd388d3c94b9ccbbbf165709318b78b90 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 00:35:39 +0000 Subject: [PATCH 313/710] we no longer need submodules for these jobs --- .github/workflows/main.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aa42903b7..e3f2d182e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -91,8 +91,6 @@ jobs: steps: - uses: actions/checkout@v2 - with: - submodules: true - name: Restore PHP build cache id: php-build-cache @@ -195,8 +193,6 @@ jobs: steps: - uses: actions/checkout@v2 - with: - submodules: true - name: Restore PHP build cache id: php-build-cache From 6cd272c9e17680439ca8886b594046154f043877 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 00:55:13 +0000 Subject: [PATCH 314/710] Update transient composer dependencies --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 0c3b4eb90..7b021777b 100644 --- a/composer.lock +++ b/composer.lock @@ -1503,16 +1503,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.0", + "version": "v4.13.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "50953a2691a922aa1769461637869a0a2faa3f53" + "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", - "reference": "50953a2691a922aa1769461637869a0a2faa3f53", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd", + "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd", "shasum": "" }, "require": { @@ -1553,9 +1553,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1" }, - "time": "2021-09-20T12:20:58+00:00" + "time": "2021-11-03T20:52:16+00:00" }, { "name": "phar-io/manifest", From 640e88009b6b66d9822c0da1eb6718375720b0c0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 00:57:37 +0000 Subject: [PATCH 315/710] Player: fixed a mistake in generation rate limit we don't want to allow sending further chunks when we haven't generated near ones, because we won't be able to see them anyway, and we might end up not needing them. This now fully matches the results of PM3. --- src/player/Player.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/player/Player.php b/src/player/Player.php index 0a00b4010..4d46cfac6 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -686,7 +686,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $count = 0; $world = $this->getWorld(); foreach($this->loadQueue as $index => $distance){ - if($count >= $this->chunksPerTick || count($this->activeChunkGenerationRequests) >= $this->chunksPerTick){ + if($count >= $this->chunksPerTick - count($this->activeChunkGenerationRequests)){ break; } From b8523f7a18ed83888e8f66c659bc77eea6985b63 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 01:00:35 +0000 Subject: [PATCH 316/710] Player: fix the fix which just degraded performance if a chunk was requested for generation, count++ and count(activeRequests)++, which means that we would only get to submit half as many generation requests as we're allowed to. Calculate the limit at the start and remember it instead. --- src/player/Player.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/player/Player.php b/src/player/Player.php index 4d46cfac6..1839adc09 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -685,8 +685,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $count = 0; $world = $this->getWorld(); + + $limit = $this->chunksPerTick - count($this->activeChunkGenerationRequests); foreach($this->loadQueue as $index => $distance){ - if($count >= $this->chunksPerTick - count($this->activeChunkGenerationRequests)){ + if($count >= $limit){ break; } From 002feacf8e2ea9084bf3e13b42f5b2eaf2730116 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 01:16:58 +0000 Subject: [PATCH 317/710] Release 4.0.0-BETA11 --- changelogs/4.0.md | 27 +++++++++++++++++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 2ef72ea0b..9e9faad62 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1607,3 +1607,30 @@ Released 2nd November 2021. ## Fixes - Fixed an issue with BedrockData JSON minification which broke the release build of 4.0.0-BETA9. + +# 4.0.0-BETA11 +Released 6th November 2021. + +## General +- `resources/locale` submodule has been removed. Language files are now included via Composer dependency [`pocketmine/locale-data`](https://packagist.org/packages/pocketmine/locale-data). + - This means it's now possible to run a server from git sources without cloning submodules :) + - All remaining submodules (DevTools, build/php) are non-essential for building and running a server. +- Added a tool `tools/simulate-chunk-sending.php` to visualise the behaviour of `ChunkSelector`. + +## Fixes +- Fixed server crash on saving when player XP has reached int32 max (XP is now capped, similar to Java Edition). +- Fixed another edge case in chunk generation that led to assertion failures. +- Fixed server crash when finding a list of `TAG_Float` for entity positions instead of `TAG_Double`. +- Fixed fast eating when picking up items. +- Fixed terrain being invisible for a long time when teleporting into ungenerated terrain. +- Fixed weird chunk loading when teleporting into ungenerated terrain (sometimes farther chunks would render before closer ones, leaving holes in the map temporarily). +- Fixed players re-requesting chunks when turning their heads or jumping. +- Fixed bonemeal sometimes being consumed even when cancelling `BlockGrowEvent` and `StructureGrowEvent`. + +## API +### Event +- Added `PlayerEmoteEvent`. + +### Gameplay +- Chunks are now sent in proper circles. This improves the experience when flying quickly parallel to X or Z axis, since now more chunks in front of the player will load sooner. +- Added support for emotes. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index f394d85d9..37435fb15 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,7 +30,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA11"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From f81c55ce6c76972f7828f17a16ea68d7c8eb37c5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 01:17:03 +0000 Subject: [PATCH 318/710] 4.0.0-BETA12 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 37435fb15..5216a6650 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,8 +29,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA11"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA12"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From b392651354abd554cc1948007201228ee8f4b644 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 02:22:14 +0000 Subject: [PATCH 319/710] pocketmine.yml: always refer to worlds as worlds in config comments, not levels --- src/pocketmine/resources/pocketmine.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index 666da755b..f12769bdf 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -108,7 +108,7 @@ player: allow-movement-cheats: true level-settings: - #The default format that levels will use when created + #The default format that worlds will use when created default-format: pmanvil chunk-sending: @@ -176,7 +176,7 @@ aliases: #savestop: [save-all, stop] worlds: - #These settings will override the generator set in server.properties and allows loading multiple levels + #These settings will override the generator set in server.properties and allows loading multiple worlds #Example: #world: # seed: 404 From 4cb6c7dc1e8c34761929913d6c301e748a2c23b0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 16:32:19 +0000 Subject: [PATCH 320/710] PluginManager: fixed plugins being able to alter groups of other plugins' permissions this could happen if a plugin declared a permission already declared by another plugin, and then declared a different default for it (e.g. true instead of op). --- src/plugin/PluginManager.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 1b02e082a..eb4ab5555 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -172,7 +172,9 @@ class PluginManager{ $everyoneRoot = $permManager->getPermission(DefaultPermissions::ROOT_USER); foreach($description->getPermissions() as $default => $perms){ foreach($perms as $perm){ - $permManager->addPermission($perm); + if(!$permManager->addPermission($perm)){ + continue; //TODO: this should be reported as an error and prevent the plugin from loading + } switch($default){ case PermissionParser::DEFAULT_TRUE: $everyoneRoot->addChild($perm->getName(), true); From d9d37f7fa6f4b7a0a7d7a7972f892beed061fa48 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 16:45:14 +0000 Subject: [PATCH 321/710] ResourcePacksPacketHandler: fixed a mistake from c773e43eda0da159b181ef1c79f29a6c8986e697 fixes #4557 Note: you may need to clear your local pack cache in order to get it working again. --- src/network/mcpe/handler/ResourcePacksPacketHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/mcpe/handler/ResourcePacksPacketHandler.php b/src/network/mcpe/handler/ResourcePacksPacketHandler.php index 8f93e2547..f82ed1232 100644 --- a/src/network/mcpe/handler/ResourcePacksPacketHandler.php +++ b/src/network/mcpe/handler/ResourcePacksPacketHandler.php @@ -117,7 +117,7 @@ class ResourcePacksPacketHandler extends PacketHandler{ $pack->getPackSize(), $pack->getSha256(), false, - ResourcePackType::ADDON //TODO: this might be an addon (not behaviour pack), needed to properly support client-side custom items + ResourcePackType::RESOURCES //TODO: this might be an addon (not behaviour pack), needed to properly support client-side custom items )); } $this->session->getLogger()->debug("Player requested download of " . count($packet->packIds) . " resource packs"); From 6b316dc29abd418540ade8ee67f9329cf89004b2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 6 Nov 2021 17:05:37 +0000 Subject: [PATCH 322/710] PluginManager: Make declaration of duplicate permissions a load error --- composer.json | 2 +- composer.lock | 14 +++++++------- src/lang/KnownTranslationFactory.php | 6 ++++++ src/lang/KnownTranslationKeys.php | 1 + src/plugin/PluginManager.php | 15 ++++++++++++--- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 978a881c4..73e43f6bf 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", "pocketmine/errorhandler": "^0.3.0", - "pocketmine/locale-data": "^1.0.3", + "pocketmine/locale-data": "^1.1.4", "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", "pocketmine/math": "^0.4.0", diff --git a/composer.lock b/composer.lock index 7b021777b..0a6a2aa61 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e36db7fb94bd79034dcc599c3029a621", + "content-hash": "6de5c66b7a0f693fd30c701b0d0db3d1", "packages": [ { "name": "adhocore/json-comment", @@ -533,16 +533,16 @@ }, { "name": "pocketmine/locale-data", - "version": "1.0.3", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "7342b4eb593036c739e7f0c0ed95299ada69ff19" + "reference": "549f27f593b200d8b11ca05ffcd5a73e02a0d9fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/7342b4eb593036c739e7f0c0ed95299ada69ff19", - "reference": "7342b4eb593036c739e7f0c0ed95299ada69ff19", + "url": "https://api.github.com/repos/pmmp/Language/zipball/549f27f593b200d8b11ca05ffcd5a73e02a0d9fb", + "reference": "549f27f593b200d8b11ca05ffcd5a73e02a0d9fb", "shasum": "" }, "type": "library", @@ -550,9 +550,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/1.0.3" + "source": "https://github.com/pmmp/Language/tree/1.1.4" }, - "time": "2021-11-06T00:27:03+00:00" + "time": "2021-11-06T17:02:22+00:00" }, { "name": "pocketmine/log", diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 04b644f83..7d36320c2 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1724,6 +1724,12 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_plugin_duplicatePermissionError(Translatable|string $permissionName) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_DUPLICATEPERMISSIONERROR, [ + "permissionName" => $permissionName, + ]); + } + public static function pocketmine_plugin_emptyExtensionVersionConstraint(Translatable|string $constraintIndex, Translatable|string $extensionName) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_EMPTYEXTENSIONVERSIONCONSTRAINT, [ "constraintIndex" => $constraintIndex, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 2a609c8d8..7b77513dc 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -361,6 +361,7 @@ final class KnownTranslationKeys{ public const POCKETMINE_PLUGIN_DISALLOWEDBYBLACKLIST = "pocketmine.plugin.disallowedByBlacklist"; public const POCKETMINE_PLUGIN_DISALLOWEDBYWHITELIST = "pocketmine.plugin.disallowedByWhitelist"; public const POCKETMINE_PLUGIN_DUPLICATEERROR = "pocketmine.plugin.duplicateError"; + public const POCKETMINE_PLUGIN_DUPLICATEPERMISSIONERROR = "pocketmine.plugin.duplicatePermissionError"; public const POCKETMINE_PLUGIN_EMPTYEXTENSIONVERSIONCONSTRAINT = "pocketmine.plugin.emptyExtensionVersionConstraint"; public const POCKETMINE_PLUGIN_ENABLE = "pocketmine.plugin.enable"; public const POCKETMINE_PLUGIN_EXTENSIONNOTLOADED = "pocketmine.plugin.extensionNotLoaded"; diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index eb4ab5555..46986946c 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -168,13 +168,22 @@ class PluginManager{ } $permManager = PermissionManager::getInstance(); + foreach($description->getPermissions() as $permsGroup){ + foreach($permsGroup as $perm){ + if($permManager->getPermission($perm->getName()) !== null){ + $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( + $description->getName(), + KnownTranslationFactory::pocketmine_plugin_duplicatePermissionError($perm->getName()) + ))); + return null; + } + } + } $opRoot = $permManager->getPermission(DefaultPermissions::ROOT_OPERATOR); $everyoneRoot = $permManager->getPermission(DefaultPermissions::ROOT_USER); foreach($description->getPermissions() as $default => $perms){ foreach($perms as $perm){ - if(!$permManager->addPermission($perm)){ - continue; //TODO: this should be reported as an error and prevent the plugin from loading - } + $permManager->addPermission($perm); switch($default){ case PermissionParser::DEFAULT_TRUE: $everyoneRoot->addChild($perm->getName(), true); From 45edb946072e82bdd9d3821c4c3a2b106fa33e8a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 7 Nov 2021 16:20:07 +0000 Subject: [PATCH 323/710] Crafting tables now work the same way as anvils and enchanting tables Removing almost all special-case logic for crafting tables. --- src/block/CraftingTable.php | 4 +- .../inventory/CraftingTableInventory.php | 46 +++++++++++++++++++ src/crafting/CraftingGrid.php | 15 +----- src/inventory/PlayerCraftingInventory.php | 36 +++++++++++++++ src/network/mcpe/InventoryManager.php | 3 +- src/network/mcpe/convert/TypeConverter.php | 12 ++--- .../mcpe/handler/InGamePacketHandler.php | 21 --------- src/player/Player.php | 13 ++---- 8 files changed, 96 insertions(+), 54 deletions(-) create mode 100644 src/block/inventory/CraftingTableInventory.php create mode 100644 src/inventory/PlayerCraftingInventory.php diff --git a/src/block/CraftingTable.php b/src/block/CraftingTable.php index a3d1dc47f..a35e13e5b 100644 --- a/src/block/CraftingTable.php +++ b/src/block/CraftingTable.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; -use pocketmine\crafting\CraftingGrid; +use pocketmine\block\inventory\CraftingTableInventory; use pocketmine\item\Item; use pocketmine\math\Vector3; use pocketmine\player\Player; @@ -32,7 +32,7 @@ class CraftingTable extends Opaque{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($player instanceof Player){ - $player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG)); + $player->setCurrentWindow(new CraftingTableInventory($this->position)); } return true; diff --git a/src/block/inventory/CraftingTableInventory.php b/src/block/inventory/CraftingTableInventory.php new file mode 100644 index 000000000..493e5dec0 --- /dev/null +++ b/src/block/inventory/CraftingTableInventory.php @@ -0,0 +1,46 @@ +holder = $holder; + parent::__construct(CraftingGrid::SIZE_BIG); + } + + public function onClose(Player $who) : void{ + parent::onClose($who); + + foreach($this->getContents() as $item){ + $who->dropItem($item); + } + $this->clearAll(); + } +} \ No newline at end of file diff --git a/src/crafting/CraftingGrid.php b/src/crafting/CraftingGrid.php index a8d4f6ebe..eb3ea5f25 100644 --- a/src/crafting/CraftingGrid.php +++ b/src/crafting/CraftingGrid.php @@ -25,17 +25,14 @@ namespace pocketmine\crafting; use pocketmine\inventory\SimpleInventory; use pocketmine\item\Item; -use pocketmine\player\Player; use function max; use function min; use const PHP_INT_MAX; -class CraftingGrid extends SimpleInventory{ +abstract class CraftingGrid extends SimpleInventory{ public const SIZE_SMALL = 2; public const SIZE_BIG = 3; - /** @var Player */ - protected $holder; /** @var int */ private $gridWidth; @@ -48,8 +45,7 @@ class CraftingGrid extends SimpleInventory{ /** @var int|null */ private $yLen; - public function __construct(Player $holder, int $gridWidth){ - $this->holder = $holder; + public function __construct(int $gridWidth){ $this->gridWidth = $gridWidth; parent::__construct($this->getGridWidth() ** 2); } @@ -63,13 +59,6 @@ class CraftingGrid extends SimpleInventory{ $this->seekRecipeBounds(); } - /** - * @return Player - */ - public function getHolder(){ - return $this->holder; - } - private function seekRecipeBounds() : void{ $minX = PHP_INT_MAX; $maxX = 0; diff --git a/src/inventory/PlayerCraftingInventory.php b/src/inventory/PlayerCraftingInventory.php new file mode 100644 index 000000000..300346476 --- /dev/null +++ b/src/inventory/PlayerCraftingInventory.php @@ -0,0 +1,36 @@ +holder; } +} \ No newline at end of file diff --git a/src/network/mcpe/InventoryManager.php b/src/network/mcpe/InventoryManager.php index 07092d2ed..15127d3d4 100644 --- a/src/network/mcpe/InventoryManager.php +++ b/src/network/mcpe/InventoryManager.php @@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe; use pocketmine\block\inventory\AnvilInventory; use pocketmine\block\inventory\BlockInventory; use pocketmine\block\inventory\BrewingStandInventory; +use pocketmine\block\inventory\CraftingTableInventory; use pocketmine\block\inventory\EnchantInventory; use pocketmine\block\inventory\FurnaceInventory; use pocketmine\block\inventory\HopperInventory; @@ -67,7 +68,6 @@ class InventoryManager{ //effect on the behaviour of inventory transactions I don't currently plan to integrate these into the main system. private const RESERVED_WINDOW_ID_RANGE_START = ContainerIds::LAST - 10; private const RESERVED_WINDOW_ID_RANGE_END = ContainerIds::LAST; - public const HARDCODED_CRAFTING_GRID_WINDOW_ID = self::RESERVED_WINDOW_ID_RANGE_START + 1; public const HARDCODED_INVENTORY_WINDOW_ID = self::RESERVED_WINDOW_ID_RANGE_START + 2; /** @var Player */ @@ -178,6 +178,7 @@ class InventoryManager{ $inv instanceof BrewingStandInventory => WindowTypes::BREWING_STAND, $inv instanceof AnvilInventory => WindowTypes::ANVIL, $inv instanceof HopperInventory => WindowTypes::HOPPER, + $inv instanceof CraftingTableInventory => WindowTypes::WORKBENCH, default => WindowTypes::CONTAINER }; return [ContainerOpenPacket::blockInv($id, $windowType, $blockPosition)]; diff --git a/src/network/mcpe/convert/TypeConverter.php b/src/network/mcpe/convert/TypeConverter.php index 38bbe359a..a2f9d98ce 100644 --- a/src/network/mcpe/convert/TypeConverter.php +++ b/src/network/mcpe/convert/TypeConverter.php @@ -24,9 +24,9 @@ namespace pocketmine\network\mcpe\convert; use pocketmine\block\BlockLegacyIds; use pocketmine\block\inventory\AnvilInventory; +use pocketmine\block\inventory\CraftingTableInventory; use pocketmine\block\inventory\EnchantInventory; use pocketmine\block\inventory\LoomInventory; -use pocketmine\crafting\CraftingGrid; use pocketmine\inventory\Inventory; use pocketmine\inventory\transaction\action\CreateItemAction; use pocketmine\inventory\transaction\action\DestroyItemAction; @@ -290,11 +290,7 @@ class TypeConverter{ $pSlot = $action->inventorySlot; $craftingGrid = $player->getCraftingGrid(); - $mapped = - $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING2X2_INPUT, $craftingGrid, - function(Inventory $i) : bool{ return $i instanceof CraftingGrid && $i->getGridWidth() === CraftingGrid::SIZE_SMALL; }) ?? - $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING3X3_INPUT, $craftingGrid, - function(Inventory $i) : bool{ return $i instanceof CraftingGrid && $i->getGridWidth() === CraftingGrid::SIZE_BIG; }); + $mapped = $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING2X2_INPUT, $craftingGrid, fn() => true); if($mapped === null){ $current = $player->getCurrentWindow(); $mapped = @@ -303,7 +299,9 @@ class TypeConverter{ $this->mapUIInventory($pSlot, UIInventorySlotOffset::ENCHANTING_TABLE, $current, function(Inventory $i) : bool{ return $i instanceof EnchantInventory; }) ?? $this->mapUIInventory($pSlot, UIInventorySlotOffset::LOOM, $current, - fn(Inventory $i) => $i instanceof LoomInventory); + fn(Inventory $i) => $i instanceof LoomInventory) ?? + $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING3X3_INPUT, $current, + fn(Inventory $i) => $i instanceof CraftingTableInventory); } if($mapped === null){ throw new TypeConversionException("Unmatched UI inventory slot offset $pSlot"); diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index ad8b001c0..d2ae3108e 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -26,7 +26,6 @@ namespace pocketmine\network\mcpe\handler; use pocketmine\block\BaseSign; use pocketmine\block\ItemFrame; use pocketmine\block\utils\SignText; -use pocketmine\crafting\CraftingGrid; use pocketmine\entity\animation\ConsumingItemAnimation; use pocketmine\entity\InvalidSkinException; use pocketmine\event\player\PlayerEditBookEvent; @@ -309,14 +308,6 @@ class InGamePacketHandler extends PacketHandler{ foreach($this->craftingTransaction->getInventories() as $inventory){ $this->inventoryManager->syncContents($inventory); } - /* - * TODO: HACK! - * we can't resend the contents of the crafting window, so we force the client to close it instead. - * So people don't whine about messy desync issues when someone cancels CraftItemEvent, or when a crafting - * transaction goes wrong. - */ - $this->session->sendDataPacket(ContainerClosePacket::create(InventoryManager::HARDCODED_CRAFTING_GRID_WINDOW_ID, true)); - return false; }finally{ $this->craftingTransaction = null; @@ -380,18 +371,6 @@ class InGamePacketHandler extends PacketHandler{ $vBlockPos = new Vector3($blockPos->getX(), $blockPos->getY(), $blockPos->getZ()); if(!$this->player->interactBlock($vBlockPos, $data->getFace(), $clickPos)){ $this->onFailedBlockAction($vBlockPos, $data->getFace()); - }elseif( - !array_key_exists($windowId = InventoryManager::HARDCODED_CRAFTING_GRID_WINDOW_ID, $this->openHardcodedWindows) && - $this->player->getCraftingGrid()->getGridWidth() === CraftingGrid::SIZE_BIG - ){ - //TODO: HACK! crafting grid doesn't fit very well into the current PM container system, so this hack - //allows it to carry on working approximately the same way as it did in 1.14 - $this->openHardcodedWindows[$windowId] = true; - $this->session->sendDataPacket(ContainerOpenPacket::blockInv( - InventoryManager::HARDCODED_CRAFTING_GRID_WINDOW_ID, - WindowTypes::WORKBENCH, - $blockPos - )); } return true; case UseItemTransactionData::ACTION_BREAK_BLOCK: diff --git a/src/player/Player.php b/src/player/Player.php index 1839adc09..7f43296b1 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -75,6 +75,7 @@ use pocketmine\form\Form; use pocketmine\form\FormValidationException; use pocketmine\inventory\CallbackInventoryListener; use pocketmine\inventory\Inventory; +use pocketmine\inventory\PlayerCraftingInventory; use pocketmine\inventory\PlayerCursorInventory; use pocketmine\inventory\transaction\action\DropItemAction; use pocketmine\inventory\transaction\InventoryTransaction; @@ -182,7 +183,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ /** @var Inventory[] */ protected array $permanentWindows = []; protected PlayerCursorInventory $cursorInventory; - protected CraftingGrid $craftingGrid; + protected PlayerCraftingInventory $craftingGrid; protected int $messageCounter = 2; @@ -2301,7 +2302,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ protected function addDefaultWindows() : void{ $this->cursorInventory = new PlayerCursorInventory($this); - $this->craftingGrid = new CraftingGrid($this, CraftingGrid::SIZE_SMALL); + $this->craftingGrid = new PlayerCraftingInventory($this); $this->addPermanentInventories($this->inventory, $this->armorInventory, $this->cursorInventory, $this->offHandInventory); @@ -2316,10 +2317,6 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ return $this->craftingGrid; } - public function setCraftingGrid(CraftingGrid $grid) : void{ - $this->craftingGrid = $grid; - } - /** * @internal Called to clean up crafting grid and cursor inventory when it is detected that the player closed their * inventory. @@ -2363,10 +2360,6 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ throw new AssumptionFailedError("This server-generated transaction should never be invalid", 0, $e); } } - - if($this->craftingGrid->getGridWidth() > CraftingGrid::SIZE_SMALL){ - $this->craftingGrid = new CraftingGrid($this, CraftingGrid::SIZE_SMALL); - } } /** From b84f7c18ecf79b4d72e507ca5264de06f14d5107 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 7 Nov 2021 19:18:09 +0000 Subject: [PATCH 324/710] Install ext/crypto from PECL --- tests/gh-actions/build.sh | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/tests/gh-actions/build.sh b/tests/gh-actions/build.sh index d70be7980..3a2b733d6 100755 --- a/tests/gh-actions/build.sh +++ b/tests/gh-actions/build.sh @@ -56,17 +56,7 @@ leveldb=@60763a09bf5c7a10376d16e25b078b99a35c5c37 \ chunkutils2=@0.3.1 \ morton=@0.1.2 \ igbinary=3.2.1 \ +crypto=0.3.2 \ " PHP_BUILD_ZTS_ENABLE=on PHP_BUILD_CONFIGURE_OPTS='--with-gmp' ./bin/php-build "$VERSION" "$INSTALL_DIR" || exit 1 -rm -rf crypto -git clone --recursive https://github.com/bukka/php-crypto.git crypto -cd crypto -git checkout -qf c8867aa944fa5227eaea9d11a6ce282e64c15af9 -git submodule update --init --recursive -"$INSTALL_DIR/bin/phpize" -./configure --with-php-config="$INSTALL_DIR/bin/php-config" -make -j8 install -echo "extension=crypto.so" >> "$INSTALL_DIR/etc/conf.d/crypto.ini" -cd .. - rm "$INSTALL_DIR/etc/conf.d/xdebug.ini" || true From 4131bcef08000eccd7d3ad95c6ce8677c2e9cb2a Mon Sep 17 00:00:00 2001 From: DataLion <34657342+TheDataLion@users.noreply.github.com> Date: Sun, 7 Nov 2021 22:11:55 +0100 Subject: [PATCH 325/710] Changed "Level" string to "World" in Position::__toString() method. (#4559) --- src/world/Position.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/Position.php b/src/world/Position.php index 82df931e0..f3fe84caa 100644 --- a/src/world/Position.php +++ b/src/world/Position.php @@ -98,7 +98,7 @@ class Position extends Vector3{ } public function __toString(){ - return "Position(level=" . ($this->isValid() ? $this->getWorld()->getDisplayName() : "null") . ",x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")"; + return "Position(world=" . ($this->isValid() ? $this->getWorld()->getDisplayName() : "null") . ",x=" . $this->x . ",y=" . $this->y . ",z=" . $this->z . ")"; } public function equals(Vector3 $v) : bool{ From eb3530b6e6e689a73f8890af601d73734ca97431 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 7 Nov 2021 23:13:56 +0000 Subject: [PATCH 326/710] Use pmmp/setup-php-action to compile PHP --- .github/workflows/main.yml | 94 +++++------------------- tests/gh-actions/build.sh | 25 ------- tests/gh-actions/install-dependencies.sh | 3 - 3 files changed, 20 insertions(+), 102 deletions(-) delete mode 100755 tests/gh-actions/build.sh delete mode 100755 tests/gh-actions/install-dependencies.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 67790cea1..133254c85 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,17 +16,11 @@ jobs: php: [8.0.11] steps: - - uses: actions/checkout@v2 #needed for build.sh - - name: Check for PHP build cache - id: php-build-cache - uses: actions/cache@v2 + - name: Build and prepare PHP cache + uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636 with: - path: "./bin" - key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}" - - - name: Compile PHP - if: steps.php-build-cache.outputs.cache-hit != 'true' - run: ./tests/gh-actions/build.sh "${{ matrix.php }}" + php-version: ${{ matrix.php }} + install-path: "./bin" phpstan: name: PHPStan analysis @@ -42,23 +36,11 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Restore PHP build cache - id: php-build-cache - uses: actions/cache@v2 + - name: Setup PHP + uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636 with: - path: "./bin" - key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}" - - - name: Kill build on PHP build cache miss (should never happen) - if: steps.php-build-cache.outputs.cache-hit != 'true' - run: exit 1 - - - name: Install cached PHP's dependencies - if: steps.php-build-cache.outputs.cache-hit == 'true' - run: ./tests/gh-actions/install-dependencies.sh - - - name: Prefix PHP to PATH - run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH + php-version: ${{ matrix.php }} + install-path: "./bin" - name: Install Composer run: curl -sS https://getcomposer.org/installer | php @@ -92,23 +74,11 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Restore PHP build cache - id: php-build-cache - uses: actions/cache@v2 + - name: Setup PHP + uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636 with: - path: "./bin" - key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}" - - - name: Kill build on PHP build cache miss (should never happen) - if: steps.php-build-cache.outputs.cache-hit != 'true' - run: exit 1 - - - name: Install cached PHP's dependencies - if: steps.php-build-cache.outputs.cache-hit == 'true' - run: ./tests/gh-actions/install-dependencies.sh - - - name: Prefix PHP to PATH - run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH + php-version: ${{ matrix.php }} + install-path: "./bin" - name: Install Composer run: curl -sS https://getcomposer.org/installer | php @@ -144,23 +114,11 @@ jobs: with: submodules: true - - name: Restore PHP build cache - id: php-build-cache - uses: actions/cache@v2 + - name: Setup PHP + uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636 with: - path: "./bin" - key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}" - - - name: Kill build on PHP build cache miss (should never happen) - if: steps.php-build-cache.outputs.cache-hit != 'true' - run: exit 1 - - - name: Install cached PHP's dependencies - if: steps.php-build-cache.outputs.cache-hit == 'true' - run: ./tests/gh-actions/install-dependencies.sh - - - name: Prefix PHP to PATH - run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH + php-version: ${{ matrix.php }} + install-path: "./bin" - name: Install Composer run: curl -sS https://getcomposer.org/installer | php @@ -196,23 +154,11 @@ jobs: with: submodules: true - - name: Restore PHP build cache - id: php-build-cache - uses: actions/cache@v2 + - name: Setup PHP + uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636 with: - path: "./bin" - key: "php-build-generic-${{ matrix.php }}-${{ matrix.image }}-${{ hashFiles('./tests/gh-actions/build.sh') }}" - - - name: Kill build on PHP build cache miss (should never happen) - if: steps.php-build-cache.outputs.cache-hit != 'true' - run: exit 1 - - - name: Install cached PHP's dependencies - if: steps.php-build-cache.outputs.cache-hit == 'true' - run: ./tests/gh-actions/install-dependencies.sh - - - name: Prefix PHP to PATH - run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH + php-version: ${{ matrix.php }} + install-path: "./bin" - name: Install Composer run: curl -sS https://getcomposer.org/installer | php diff --git a/tests/gh-actions/build.sh b/tests/gh-actions/build.sh deleted file mode 100755 index 89638dd0a..000000000 --- a/tests/gh-actions/build.sh +++ /dev/null @@ -1,25 +0,0 @@ -VERSION="$1" - -sudo apt update && sudo apt install -y \ - re2c \ - libtool \ - libtool-bin \ - zlib1g-dev \ - libcurl4-openssl-dev \ - libxml2-dev \ - libyaml-dev \ - libgmp-dev \ - libzip-dev \ - libssl-dev - -INSTALL_DIR="$(pwd)/bin/php7" - -export CFLAGS="$CFLAGS -march=x86-64" -export CXXFLAGS="$CXXFLAGS -march=x86-64" - -git clone https://github.com/pmmp/php-build.git -cd php-build -./install-dependencies.sh -echo '"pthreads",,"https://github.com/pmmp/pthreads.git",,,"extension",' >> share/php-build/extension/definition -PHP_BUILD_INSTALL_EXTENSION='pthreads=@4.0.0 yaml=2.2.1' PHP_BUILD_ZTS_ENABLE=on ./bin/php-build "$VERSION" "$INSTALL_DIR" || exit 1 -rm "$INSTALL_DIR/etc/conf.d/xdebug.ini" || true diff --git a/tests/gh-actions/install-dependencies.sh b/tests/gh-actions/install-dependencies.sh deleted file mode 100755 index 368e27e3a..000000000 --- a/tests/gh-actions/install-dependencies.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -sudo apt update && sudo apt install -y \ - libzip5 From 76dad46e133dcec5c1c7d2993d5093670abb8338 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Nov 2021 13:36:06 +0000 Subject: [PATCH 327/710] Bump phpstan/phpstan from 1.0.2 to 1.1.1 (#4560) Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.0.2 to 1.1.1. - [Release notes](https://github.com/phpstan/phpstan/releases) - [Commits](https://github.com/phpstan/phpstan/compare/1.0.2...1.1.1) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 15ee28133..8d686c5d4 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "pocketmine/spl": "^0.4.0" }, "require-dev": { - "phpstan/phpstan": "1.0.2", + "phpstan/phpstan": "1.1.1", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index 6ef7a0726..77ca56a58 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "352902efd3a960977acfb3ae7bda38da", + "content-hash": "5a6a10488d889d0f844cce59e6c34809", "packages": [ { "name": "adhocore/json-comment", @@ -1011,16 +1011,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.0.2", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "e9e2a501102ba0b126b2f63a7f0a3b151056fe91" + "reference": "cb317029197236c571c1b9305b8dd12850d8d85c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e9e2a501102ba0b126b2f63a7f0a3b151056fe91", - "reference": "e9e2a501102ba0b126b2f63a7f0a3b151056fe91", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cb317029197236c571c1b9305b8dd12850d8d85c", + "reference": "cb317029197236c571c1b9305b8dd12850d8d85c", "shasum": "" }, "require": { @@ -1051,7 +1051,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.0.2" + "source": "https://github.com/phpstan/phpstan/tree/1.1.1" }, "funding": [ { @@ -1071,7 +1071,7 @@ "type": "tidelift" } ], - "time": "2021-11-03T16:09:51+00:00" + "time": "2021-11-06T22:46:47+00:00" }, { "name": "phpstan/phpstan-phpunit", From 2b0b9bd8ed73cdd809cb9a8230ad93785cf59f12 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 17:16:57 +0000 Subject: [PATCH 328/710] Update composer dependencies --- composer.lock | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index 0a6a2aa61..22868f804 100644 --- a/composer.lock +++ b/composer.lock @@ -275,16 +275,16 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "5.0.0+bedrock-1.17.40", + "version": "5.1.0+bedrock-1.17.40", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "67c0c15b4044cab2190501933912c3d02c5f63ab" + "reference": "5abbe5bc21d8a9152d46c26578bf5257526612f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/67c0c15b4044cab2190501933912c3d02c5f63ab", - "reference": "67c0c15b4044cab2190501933912c3d02c5f63ab", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/5abbe5bc21d8a9152d46c26578bf5257526612f9", + "reference": "5abbe5bc21d8a9152d46c26578bf5257526612f9", "shasum": "" }, "require": { @@ -298,7 +298,7 @@ "ramsey/uuid": "^4.1" }, "require-dev": { - "phpstan/phpstan": "1.0.0", + "phpstan/phpstan": "1.1.1", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.5" @@ -316,9 +316,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/5.0.0+bedrock-1.17.40" + "source": "https://github.com/pmmp/BedrockProtocol/tree/5.1.0+bedrock-1.17.40" }, - "time": "2021-11-02T01:27:05+00:00" + "time": "2021-11-08T16:26:25+00:00" }, { "name": "pocketmine/binaryutils", @@ -533,16 +533,16 @@ }, { "name": "pocketmine/locale-data", - "version": "1.1.4", + "version": "1.1.6", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "549f27f593b200d8b11ca05ffcd5a73e02a0d9fb" + "reference": "216b49b87e20332f0b39d1717e1e2012a40074cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/549f27f593b200d8b11ca05ffcd5a73e02a0d9fb", - "reference": "549f27f593b200d8b11ca05ffcd5a73e02a0d9fb", + "url": "https://api.github.com/repos/pmmp/Language/zipball/216b49b87e20332f0b39d1717e1e2012a40074cc", + "reference": "216b49b87e20332f0b39d1717e1e2012a40074cc", "shasum": "" }, "type": "library", @@ -550,9 +550,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/1.1.4" + "source": "https://github.com/pmmp/Language/tree/1.1.6" }, - "time": "2021-11-06T17:02:22+00:00" + "time": "2021-11-07T14:30:46+00:00" }, { "name": "pocketmine/log", @@ -1370,6 +1370,7 @@ "issues": "https://github.com/webmozart/path-util/issues", "source": "https://github.com/webmozart/path-util/tree/2.3.0" }, + "abandoned": "symfony/filesystem", "time": "2015-12-17T08:42:14+00:00" } ], From df39a1ca0777cbb089e69dab62e3dd96eb7e5923 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 17:22:01 +0000 Subject: [PATCH 329/710] TeleportCommand: do not hardcode world bounds --- src/command/defaults/TeleportCommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/command/defaults/TeleportCommand.php b/src/command/defaults/TeleportCommand.php index e3bbff7d0..4748dc2d3 100644 --- a/src/command/defaults/TeleportCommand.php +++ b/src/command/defaults/TeleportCommand.php @@ -32,6 +32,7 @@ use pocketmine\permission\DefaultPermissionNames; use pocketmine\player\Player; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat; +use pocketmine\world\World; use function array_shift; use function count; use function round; @@ -111,7 +112,7 @@ class TeleportCommand extends VanillaCommand{ } $x = $this->getRelativeDouble($base->x, $sender, $targetArgs[0]); - $y = $this->getRelativeDouble($base->y, $sender, $targetArgs[1], 0, 256); + $y = $this->getRelativeDouble($base->y, $sender, $targetArgs[1], World::Y_MIN, World::Y_MAX); $z = $this->getRelativeDouble($base->z, $sender, $targetArgs[2]); $targetLocation = new Location($x, $y, $z, $base->getWorld(), $yaw, $pitch); From c6c992a1f0fdc1734c6777d7acbd8035422f76df Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 17:28:22 +0000 Subject: [PATCH 330/710] Preparations for negative Y support --- src/entity/Entity.php | 2 +- .../mcpe/serializer/ChunkSerializer.php | 6 ++--- src/world/World.php | 2 +- src/world/format/Chunk.php | 24 ++++++++++++------- src/world/format/io/FastChunkSerializer.php | 3 ++- src/world/format/io/leveldb/LevelDB.php | 2 +- src/world/light/SkyLightUpdate.php | 15 ++++++------ src/world/utils/SubChunkExplorer.php | 2 +- 8 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index e483b4348..1631667c5 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -635,7 +635,7 @@ abstract class Entity{ $this->checkBlockIntersections(); - if($this->location->y <= -16 and $this->isAlive()){ + if($this->location->y <= World::Y_MIN - 16 and $this->isAlive()){ $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10); $this->attack($ev); $hasUpdate = true; diff --git a/src/network/mcpe/serializer/ChunkSerializer.php b/src/network/mcpe/serializer/ChunkSerializer.php index 6fe392b67..af5336465 100644 --- a/src/network/mcpe/serializer/ChunkSerializer.php +++ b/src/network/mcpe/serializer/ChunkSerializer.php @@ -46,8 +46,8 @@ final class ChunkSerializer{ * Chunks are sent in a stack, so every chunk below the top non-empty one must be sent. */ public static function getSubChunkCount(Chunk $chunk) : int{ - for($count = count($chunk->getSubChunks()); $count > 0; --$count){ - if($chunk->getSubChunk($count - 1)->isEmptyFast()){ + for($y = Chunk::MAX_SUBCHUNK_INDEX, $count = count($chunk->getSubChunks()); $y >= Chunk::MIN_SUBCHUNK_INDEX; --$y, --$count){ + if($chunk->getSubChunk($y)->isEmptyFast()){ continue; } return $count; @@ -59,7 +59,7 @@ final class ChunkSerializer{ public static function serializeFullChunk(Chunk $chunk, RuntimeBlockMapping $blockMapper, PacketSerializerContext $encoderContext, ?string $tiles = null) : string{ $stream = PacketSerializer::encoder($encoderContext); $subChunkCount = self::getSubChunkCount($chunk); - for($y = 0; $y < $subChunkCount; ++$y){ + for($y = Chunk::MIN_SUBCHUNK_INDEX, $writtenCount = 0; $writtenCount < $subChunkCount; ++$y, ++$writtenCount){ self::serializeSubChunk($chunk->getSubChunk($y), $blockMapper, $stream, false); } $stream->put($chunk->getBiomeIdArray()); diff --git a/src/world/World.php b/src/world/World.php index a06f2ad5e..dcd27805c 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -331,7 +331,7 @@ class World implements ChunkManager{ private const BLOCKHASH_Y_OFFSET = self::BLOCKHASH_Y_PADDING - self::Y_MIN; private const BLOCKHASH_Y_MASK = (1 << self::BLOCKHASH_Y_BITS) - 1; private const BLOCKHASH_XZ_MASK = (1 << self::MORTON3D_BIT_SIZE) - 1; - private const BLOCKHASH_XZ_EXTRA_BITS = 6; + private const BLOCKHASH_XZ_EXTRA_BITS = (self::MORTON3D_BIT_SIZE - self::BLOCKHASH_Y_BITS) >> 1; private const BLOCKHASH_XZ_EXTRA_MASK = (1 << self::BLOCKHASH_XZ_EXTRA_BITS) - 1; private const BLOCKHASH_XZ_SIGN_SHIFT = 64 - self::MORTON3D_BIT_SIZE - self::BLOCKHASH_XZ_EXTRA_BITS; private const BLOCKHASH_X_SHIFT = self::BLOCKHASH_Y_BITS; diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index f1b1320ae..8bb5eed9f 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -35,7 +35,9 @@ class Chunk{ public const DIRTY_FLAG_BLOCKS = 1 << 0; public const DIRTY_FLAG_BIOMES = 1 << 3; - public const MAX_SUBCHUNKS = 16; + public const MIN_SUBCHUNK_INDEX = 0; + public const MAX_SUBCHUNK_INDEX = 15; + public const MAX_SUBCHUNKS = self::MAX_SUBCHUNK_INDEX - self::MIN_SUBCHUNK_INDEX + 1; public const EDGE_LENGTH = SubChunk::EDGE_LENGTH; public const COORD_BIT_SIZE = SubChunk::COORD_BIT_SIZE; @@ -71,10 +73,10 @@ class Chunk{ $this->subChunks = new \SplFixedArray(Chunk::MAX_SUBCHUNKS); foreach($this->subChunks as $y => $null){ - $this->subChunks[$y] = $subChunks[$y] ?? new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, []); + $this->subChunks[$y] = $subChunks[$y + self::MIN_SUBCHUNK_INDEX] ?? new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, []); } - $val = ($this->subChunks->getSize() * SubChunk::EDGE_LENGTH); + $val = (self::MAX_SUBCHUNK_INDEX + 1) * SubChunk::EDGE_LENGTH; $this->heightMap = HeightArray::fill($val); //TODO: what about lazily initializing this? $this->biomeIds = $biomeIds; @@ -118,7 +120,7 @@ class Chunk{ * @return int|null 0-255, or null if there are no blocks in the column */ public function getHighestBlockAt(int $x, int $z) : ?int{ - for($y = $this->subChunks->count() - 1; $y >= 0; --$y){ + for($y = self::MAX_SUBCHUNK_INDEX; $y >= self::MIN_SUBCHUNK_INDEX; --$y){ $height = $this->getSubChunk($y)->getHighestBlockAt($x, $z); if($height !== null){ return $height | ($y << SubChunk::COORD_BIT_SIZE); @@ -280,21 +282,21 @@ class Chunk{ } public function getSubChunk(int $y) : SubChunk{ - if($y < 0 || $y >= $this->subChunks->getSize()){ + if($y < self::MIN_SUBCHUNK_INDEX || $y > self::MAX_SUBCHUNK_INDEX){ throw new \InvalidArgumentException("Invalid subchunk Y coordinate $y"); } - return $this->subChunks[$y]; + return $this->subChunks[$y - self::MIN_SUBCHUNK_INDEX]; } /** * Sets a subchunk in the chunk index */ public function setSubChunk(int $y, ?SubChunk $subChunk) : void{ - if($y < 0 or $y >= $this->subChunks->getSize()){ + if($y < self::MIN_SUBCHUNK_INDEX or $y > self::MAX_SUBCHUNK_INDEX){ throw new \InvalidArgumentException("Invalid subchunk Y coordinate $y"); } - $this->subChunks[$y] = $subChunk ?? new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, []); + $this->subChunks[$y - self::MIN_SUBCHUNK_INDEX] = $subChunk ?? new SubChunk(BlockLegacyIds::AIR << Block::INTERNAL_METADATA_BITS, []); $this->setTerrainDirtyFlag(self::DIRTY_FLAG_BLOCKS, true); } @@ -303,7 +305,11 @@ class Chunk{ * @phpstan-return array */ public function getSubChunks() : array{ - return $this->subChunks->toArray(); + $result = []; + foreach($this->subChunks as $yOffset => $subChunk){ + $result[$yOffset + self::MIN_SUBCHUNK_INDEX] = $subChunk; + } + return $result; } /** diff --git a/src/world/format/io/FastChunkSerializer.php b/src/world/format/io/FastChunkSerializer.php index bb8bec687..c8ab53a73 100644 --- a/src/world/format/io/FastChunkSerializer.php +++ b/src/world/format/io/FastChunkSerializer.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\world\format\io; +use pocketmine\utils\Binary; use pocketmine\utils\BinaryStream; use pocketmine\world\format\BiomeArray; use pocketmine\world\format\Chunk; @@ -96,7 +97,7 @@ final class FastChunkSerializer{ $count = $stream->getByte(); for($subCount = 0; $subCount < $count; ++$subCount){ - $y = $stream->getByte(); + $y = Binary::signByte($stream->getByte()); $airBlockId = $stream->getInt(); /** @var PalettedBlockArray[] $layers */ diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index a96e329b3..3fe2e359c 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -266,7 +266,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ case 3: //MCPE 1.0 $convertedLegacyExtraData = $this->deserializeLegacyExtraData($index, $chunkVersion); - for($y = 0; $y < Chunk::MAX_SUBCHUNKS; ++$y){ + for($y = Chunk::MIN_SUBCHUNK_INDEX; $y <= Chunk::MAX_SUBCHUNK_INDEX; ++$y){ if(($data = $this->db->get($index . self::TAG_SUBCHUNK_PREFIX . chr($y))) === false){ continue; } diff --git a/src/world/light/SkyLightUpdate.php b/src/world/light/SkyLightUpdate.php index 42d12be17..2c4214568 100644 --- a/src/world/light/SkyLightUpdate.php +++ b/src/world/light/SkyLightUpdate.php @@ -115,11 +115,10 @@ class SkyLightUpdate extends LightUpdate{ //have to avoid filling full light for any subchunk that contains a heightmap Y coordinate $highestHeightMapPlusOne = max($chunk->getHeightMapArray()) + 1; $lowestClearSubChunk = ($highestHeightMapPlusOne >> SubChunk::COORD_BIT_SIZE) + (($highestHeightMapPlusOne & SubChunk::COORD_MASK) !== 0 ? 1 : 0); - $chunkHeight = count($chunk->getSubChunks()); - for($y = 0; $y < $lowestClearSubChunk && $y < $chunkHeight; $y++){ + for($y = Chunk::MIN_SUBCHUNK_INDEX; $y < $lowestClearSubChunk && $y <= Chunk::MAX_SUBCHUNK_INDEX; $y++){ $chunk->getSubChunk($y)->setBlockSkyLightArray(LightArray::fill(0)); } - for($y = $lowestClearSubChunk, $yMax = $chunkHeight; $y < $yMax; $y++){ + for($y = $lowestClearSubChunk; $y <= Chunk::MAX_SUBCHUNK_INDEX; $y++){ $chunk->getSubChunk($y)->setBlockSkyLightArray(LightArray::fill(15)); } @@ -130,7 +129,7 @@ class SkyLightUpdate extends LightUpdate{ for($x = 0; $x < Chunk::EDGE_LENGTH; ++$x){ for($z = 0; $z < Chunk::EDGE_LENGTH; ++$z){ $currentHeight = $chunk->getHeightMap($x, $z); - $maxAdjacentHeight = 0; + $maxAdjacentHeight = World::Y_MIN; if($x !== 0){ $maxAdjacentHeight = max($maxAdjacentHeight, $chunk->getHeightMap($x - 1, $z)); } @@ -174,21 +173,21 @@ class SkyLightUpdate extends LightUpdate{ * @phpstan-param \SplFixedArray $directSkyLightBlockers */ private static function recalculateHeightMap(Chunk $chunk, \SplFixedArray $directSkyLightBlockers) : HeightArray{ - $maxSubChunkY = count($chunk->getSubChunks()) - 1; - for(; $maxSubChunkY >= 0; $maxSubChunkY--){ + $maxSubChunkY = Chunk::MAX_SUBCHUNK_INDEX; + for(; $maxSubChunkY >= Chunk::MIN_SUBCHUNK_INDEX; $maxSubChunkY--){ if(!$chunk->getSubChunk($maxSubChunkY)->isEmptyFast()){ break; } } $result = HeightArray::fill(World::Y_MIN); - if($maxSubChunkY === -1){ //whole column is definitely empty + if($maxSubChunkY < Chunk::MIN_SUBCHUNK_INDEX){ //whole column is definitely empty return $result; } for($z = 0; $z < Chunk::EDGE_LENGTH; ++$z){ for($x = 0; $x < Chunk::EDGE_LENGTH; ++$x){ $y = null; - for($subChunkY = $maxSubChunkY; $subChunkY >= 0; $subChunkY--){ + for($subChunkY = $maxSubChunkY; $subChunkY >= Chunk::MIN_SUBCHUNK_INDEX; $subChunkY--){ $subHighestBlockY = $chunk->getSubChunk($subChunkY)->getHighestBlockAt($x, $z); if($subHighestBlockY !== null){ $y = ($subChunkY * SubChunk::EDGE_LENGTH) + $subHighestBlockY; diff --git a/src/world/utils/SubChunkExplorer.php b/src/world/utils/SubChunkExplorer.php index 9d7faeb96..69bdb44e1 100644 --- a/src/world/utils/SubChunkExplorer.php +++ b/src/world/utils/SubChunkExplorer.php @@ -68,7 +68,7 @@ class SubChunkExplorer{ if($this->currentSubChunk === null or $this->currentY !== $newChunkY){ $this->currentY = $newChunkY; - if($this->currentY < 0 or $this->currentY >= $this->currentChunk->getHeight()){ + if($this->currentY < Chunk::MIN_SUBCHUNK_INDEX or $this->currentY > Chunk::MAX_SUBCHUNK_INDEX){ $this->currentSubChunk = null; return SubChunkExplorerStatus::INVALID; } From a6f6b60bed7f570f96ee48de79a3fa3dc2953006 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 18:02:24 +0000 Subject: [PATCH 331/710] fix CS again --- src/world/light/SkyLightUpdate.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/world/light/SkyLightUpdate.php b/src/world/light/SkyLightUpdate.php index 2c4214568..a505fde02 100644 --- a/src/world/light/SkyLightUpdate.php +++ b/src/world/light/SkyLightUpdate.php @@ -30,7 +30,6 @@ use pocketmine\world\format\SubChunk; use pocketmine\world\utils\SubChunkExplorer; use pocketmine\world\utils\SubChunkExplorerStatus; use pocketmine\world\World; -use function count; use function max; class SkyLightUpdate extends LightUpdate{ From 18f5fb66bba9f468daf9a019455be3ff1ab371f0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 18:37:05 +0000 Subject: [PATCH 332/710] Abstract the base functionality of StringToItemParser --- src/item/StringToItemParser.php | 44 ++---------------- src/utils/StringToTParser.php | 82 +++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 39 deletions(-) create mode 100644 src/utils/StringToTParser.php diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index 75b6b81aa..6d313905d 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -29,6 +29,7 @@ use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\SlabType; use pocketmine\block\VanillaBlocks; use pocketmine\utils\SingletonTrait; +use pocketmine\utils\StringToTParser; use function array_keys; use function str_replace; use function strtolower; @@ -36,18 +37,12 @@ use function trim; /** * Handles parsing items from strings. This is used to interpret names from the /give command (and others). - * Custom aliases may be registered. - * Note that the aliases should be user-friendly, i.e. easily readable and writable. + * + * @phpstan-extends StringToTParser */ -final class StringToItemParser{ +final class StringToItemParser extends StringToTParser{ use SingletonTrait; - /** - * @var \Closure[] - * @phpstan-var array - */ - private array $callbackMap = []; - private static function make() : self{ $result = new self; @@ -1325,41 +1320,12 @@ final class StringToItemParser{ return $result; } - /** @phpstan-param \Closure(string $input) : Item $callback */ - public function register(string $alias, \Closure $callback) : void{ - $key = $this->reprocess($alias); - if(isset($this->callbackMap[$key])){ - throw new \InvalidArgumentException("Alias \"$key\" is already registered"); - } - $this->callbackMap[$key] = $callback; - } - /** @phpstan-param \Closure(string $input) : Block $callback */ public function registerBlock(string $alias, \Closure $callback) : void{ $this->register($alias, fn(string $input) => $callback($input)->asItem()); } - /** @phpstan-param \Closure(string $input) : Item $callback */ - public function override(string $alias, \Closure $callback) : void{ - $this->callbackMap[$this->reprocess($alias)] = $callback; - } - - /** Tries to parse the specified string into an item. */ public function parse(string $input) : ?Item{ - $key = $this->reprocess($input); - if(isset($this->callbackMap[$key])){ - return ($this->callbackMap[$key])($input); - } - - return null; - } - - protected function reprocess(string $input) : string{ - return strtolower(str_replace([" ", "minecraft:"], ["_", ""], trim($input))); - } - - /** @return string[] */ - public function getKnownAliases() : array{ - return array_keys($this->callbackMap); + return parent::parse($input); } } diff --git a/src/utils/StringToTParser.php b/src/utils/StringToTParser.php new file mode 100644 index 000000000..598b3768d --- /dev/null +++ b/src/utils/StringToTParser.php @@ -0,0 +1,82 @@ + + */ + private array $callbackMap = []; + + /** @phpstan-param \Closure(string $input) : T $callback */ + public function register(string $alias, \Closure $callback) : void{ + $key = $this->reprocess($alias); + if(isset($this->callbackMap[$key])){ + throw new \InvalidArgumentException("Alias \"$key\" is already registered"); + } + $this->callbackMap[$key] = $callback; + } + + /** @phpstan-param \Closure(string $input) : T $callback */ + public function override(string $alias, \Closure $callback) : void{ + $this->callbackMap[$this->reprocess($alias)] = $callback; + } + + /** + * Tries to parse the specified string into an enchantment. + * @phpstan-return T|null + */ + public function parse(string $input){ + $key = $this->reprocess($input); + if(isset($this->callbackMap[$key])){ + return ($this->callbackMap[$key])($input); + } + + return null; + } + + protected function reprocess(string $input) : string{ + return strtolower(str_replace([" ", "minecraft:"], ["_", ""], trim($input))); + } + + /** @return string[] */ + public function getKnownAliases() : array{ + return array_keys($this->callbackMap); + } +} \ No newline at end of file From 08420c25564017b8aaea277b60e9e6472c290203 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 18:44:15 +0000 Subject: [PATCH 333/710] Added new dynamic StringToEnchantmentParser this should be used instead of VanillaEnchantments::fromString(), because it allows registering custom aliases. --- src/command/defaults/EnchantCommand.php | 7 +- .../enchantment/StringToEnchantmentParser.php | 66 +++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 src/item/enchantment/StringToEnchantmentParser.php diff --git a/src/command/defaults/EnchantCommand.php b/src/command/defaults/EnchantCommand.php index 08e959a4f..3e53a55fb 100644 --- a/src/command/defaults/EnchantCommand.php +++ b/src/command/defaults/EnchantCommand.php @@ -26,7 +26,7 @@ namespace pocketmine\command\defaults; use pocketmine\command\CommandSender; use pocketmine\command\utils\InvalidCommandSyntaxException; use pocketmine\item\enchantment\EnchantmentInstance; -use pocketmine\item\enchantment\VanillaEnchantments; +use pocketmine\item\enchantment\StringToEnchantmentParser; use pocketmine\lang\KnownTranslationFactory; use pocketmine\permission\DefaultPermissionNames; use pocketmine\utils\TextFormat; @@ -66,9 +66,8 @@ class EnchantCommand extends VanillaCommand{ return true; } - try{ - $enchantment = VanillaEnchantments::fromString($args[1]); - }catch(\InvalidArgumentException $e){ + $enchantment = StringToEnchantmentParser::getInstance()->parse($args[1]); + if($enchantment === null){ $sender->sendMessage(KnownTranslationFactory::commands_enchant_notFound($args[1])); return true; } diff --git a/src/item/enchantment/StringToEnchantmentParser.php b/src/item/enchantment/StringToEnchantmentParser.php new file mode 100644 index 000000000..2205f12ff --- /dev/null +++ b/src/item/enchantment/StringToEnchantmentParser.php @@ -0,0 +1,66 @@ + + */ +final class StringToEnchantmentParser extends StringToTParser{ + use SingletonTrait; + + private static function make() : self{ + $result = new self; + + $result->register("blast_protection", fn() => VanillaEnchantments::BLAST_PROTECTION()); + $result->register("efficiency", fn() => VanillaEnchantments::EFFICIENCY()); + $result->register("feather_falling", fn() => VanillaEnchantments::FEATHER_FALLING()); + $result->register("fire_aspect", fn() => VanillaEnchantments::FIRE_ASPECT()); + $result->register("fire_protection", fn() => VanillaEnchantments::FIRE_PROTECTION()); + $result->register("flame", fn() => VanillaEnchantments::FLAME()); + $result->register("infinity", fn() => VanillaEnchantments::INFINITY()); + $result->register("knockback", fn() => VanillaEnchantments::KNOCKBACK()); + $result->register("mending", fn() => VanillaEnchantments::MENDING()); + $result->register("power", fn() => VanillaEnchantments::POWER()); + $result->register("projectile_protection", fn() => VanillaEnchantments::PROJECTILE_PROTECTION()); + $result->register("protection", fn() => VanillaEnchantments::PROTECTION()); + $result->register("punch", fn() => VanillaEnchantments::PUNCH()); + $result->register("respiration", fn() => VanillaEnchantments::RESPIRATION()); + $result->register("sharpness", fn() => VanillaEnchantments::SHARPNESS()); + $result->register("silk_touch", fn() => VanillaEnchantments::SILK_TOUCH()); + $result->register("thorns", fn() => VanillaEnchantments::THORNS()); + $result->register("unbreaking", fn() => VanillaEnchantments::UNBREAKING()); + $result->register("vanishing", fn() => VanillaEnchantments::VANISHING()); + + return $result; + } + + public function parse(string $input) : ?Enchantment{ + return parent::parse($input); + } +} \ No newline at end of file From 1fb60b5b3a3931c51e26e9f181cbdb07e8d52a37 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 18:45:05 +0000 Subject: [PATCH 334/710] CS fix again --- src/item/StringToItemParser.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index 6d313905d..0d92ec428 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -30,10 +30,6 @@ use pocketmine\block\utils\SlabType; use pocketmine\block\VanillaBlocks; use pocketmine\utils\SingletonTrait; use pocketmine\utils\StringToTParser; -use function array_keys; -use function str_replace; -use function strtolower; -use function trim; /** * Handles parsing items from strings. This is used to interpret names from the /give command (and others). From f93b5be789d834af28c42449c5513ce354169774 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 18:49:28 +0000 Subject: [PATCH 335/710] Added new dynamic StringToEffectParser --- src/command/defaults/EffectCommand.php | 7 +-- src/entity/effect/StringToEffectParser.php | 73 ++++++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 src/entity/effect/StringToEffectParser.php diff --git a/src/command/defaults/EffectCommand.php b/src/command/defaults/EffectCommand.php index 84fa8585e..7b2541ea7 100644 --- a/src/command/defaults/EffectCommand.php +++ b/src/command/defaults/EffectCommand.php @@ -26,7 +26,7 @@ namespace pocketmine\command\defaults; use pocketmine\command\CommandSender; use pocketmine\command\utils\InvalidCommandSyntaxException; use pocketmine\entity\effect\EffectInstance; -use pocketmine\entity\effect\VanillaEffects; +use pocketmine\entity\effect\StringToEffectParser; use pocketmine\lang\KnownTranslationFactory; use pocketmine\permission\DefaultPermissionNames; use pocketmine\utils\Limits; @@ -69,9 +69,8 @@ class EffectCommand extends VanillaCommand{ return true; } - try{ - $effect = VanillaEffects::fromString($args[1]); - }catch(\InvalidArgumentException $e){ + $effect = StringToEffectParser::getInstance()->parse($args[1]); + if($effect === null){ $sender->sendMessage(KnownTranslationFactory::commands_effect_notFound($args[1])->prefix(TextFormat::RED)); return true; } diff --git a/src/entity/effect/StringToEffectParser.php b/src/entity/effect/StringToEffectParser.php new file mode 100644 index 000000000..b35ff68fc --- /dev/null +++ b/src/entity/effect/StringToEffectParser.php @@ -0,0 +1,73 @@ + + */ +final class StringToEffectParser extends StringToTParser{ + use SingletonTrait; + + private static function make() : self{ + $result = new self; + + $result->register("absorption", fn() => VanillaEffects::ABSORPTION()); + $result->register("blindness", fn() => VanillaEffects::BLINDNESS()); + $result->register("conduit_power", fn() => VanillaEffects::CONDUIT_POWER()); + $result->register("fatal_poison", fn() => VanillaEffects::FATAL_POISON()); + $result->register("fire_resistance", fn() => VanillaEffects::FIRE_RESISTANCE()); + $result->register("haste", fn() => VanillaEffects::HASTE()); + $result->register("health_boost", fn() => VanillaEffects::HEALTH_BOOST()); + $result->register("hunger", fn() => VanillaEffects::HUNGER()); + $result->register("instant_damage", fn() => VanillaEffects::INSTANT_DAMAGE()); + $result->register("instant_health", fn() => VanillaEffects::INSTANT_HEALTH()); + $result->register("invisibility", fn() => VanillaEffects::INVISIBILITY()); + $result->register("jump_boost", fn() => VanillaEffects::JUMP_BOOST()); + $result->register("levitation", fn() => VanillaEffects::LEVITATION()); + $result->register("mining_fatigue", fn() => VanillaEffects::MINING_FATIGUE()); + $result->register("nausea", fn() => VanillaEffects::NAUSEA()); + $result->register("night_vision", fn() => VanillaEffects::NIGHT_VISION()); + $result->register("poison", fn() => VanillaEffects::POISON()); + $result->register("regeneration", fn() => VanillaEffects::REGENERATION()); + $result->register("resistance", fn() => VanillaEffects::RESISTANCE()); + $result->register("saturation", fn() => VanillaEffects::SATURATION()); + $result->register("slowness", fn() => VanillaEffects::SLOWNESS()); + $result->register("speed", fn() => VanillaEffects::SPEED()); + $result->register("strength", fn() => VanillaEffects::STRENGTH()); + $result->register("water_breathing", fn() => VanillaEffects::WATER_BREATHING()); + $result->register("weakness", fn() => VanillaEffects::WEAKNESS()); + $result->register("wither", fn() => VanillaEffects::WITHER()); + + return $result; + } + + public function parse(string $input) : ?Effect{ + return parent::parse($input); + } +} \ No newline at end of file From a1ecdc27e5b1a4b095482f4e14f149bce1a94d41 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 18:52:14 +0000 Subject: [PATCH 336/710] Removed Vanilla*::fromString() these were misbegotten and should never have existed. If someone really needs these for some reason, they can use getAll()[name]. --- src/block/VanillaBlocks.php | 6 ------ src/entity/effect/VanillaEffects.php | 6 ------ src/item/VanillaItems.php | 6 ------ src/item/enchantment/VanillaEnchantments.php | 6 ------ 4 files changed, 24 deletions(-) diff --git a/src/block/VanillaBlocks.php b/src/block/VanillaBlocks.php index 65099ab28..f40f52d57 100644 --- a/src/block/VanillaBlocks.php +++ b/src/block/VanillaBlocks.php @@ -581,12 +581,6 @@ final class VanillaBlocks{ self::_registryRegister($name, $block); } - public static function fromString(string $name) : Block{ - $result = self::_registryFromString($name); - assert($result instanceof Block); - return $result; - } - /** * @return Block[] */ diff --git a/src/entity/effect/VanillaEffects.php b/src/entity/effect/VanillaEffects.php index a447613d4..ba2fc27cf 100644 --- a/src/entity/effect/VanillaEffects.php +++ b/src/entity/effect/VanillaEffects.php @@ -109,10 +109,4 @@ final class VanillaEffects{ $result = self::_registryGetAll(); return $result; } - - public static function fromString(string $name) : Effect{ - $result = self::_registryFromString($name); - assert($result instanceof Effect); - return $result; - } } diff --git a/src/item/VanillaItems.php b/src/item/VanillaItems.php index f9ab3ade7..eba778cba 100644 --- a/src/item/VanillaItems.php +++ b/src/item/VanillaItems.php @@ -381,12 +381,6 @@ final class VanillaItems{ self::_registryRegister($name, $item); } - public static function fromString(string $name) : Item{ - $result = self::_registryFromString($name); - assert($result instanceof Item); - return $result; - } - /** * @return Item[] */ diff --git a/src/item/enchantment/VanillaEnchantments.php b/src/item/enchantment/VanillaEnchantments.php index 37425bca1..f42039160 100644 --- a/src/item/enchantment/VanillaEnchantments.php +++ b/src/item/enchantment/VanillaEnchantments.php @@ -113,10 +113,4 @@ final class VanillaEnchantments{ $result = self::_registryGetAll(); return $result; } - - public static function fromString(string $name) : Enchantment{ - /** @var Enchantment $result */ - $result = self::_registryFromString($name); - return $result; - } } From 19a3efe8936ad8f3e484c01b213bf2b84c0a40ae Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 18:57:14 +0000 Subject: [PATCH 337/710] ....... --- src/block/VanillaBlocks.php | 1 - src/entity/effect/VanillaEffects.php | 1 - src/item/VanillaItems.php | 1 - 3 files changed, 3 deletions(-) diff --git a/src/block/VanillaBlocks.php b/src/block/VanillaBlocks.php index f40f52d57..7d2d947c5 100644 --- a/src/block/VanillaBlocks.php +++ b/src/block/VanillaBlocks.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\utils\CloningRegistryTrait; -use function assert; /** * This doc-block is generated automatically, do not modify it manually. diff --git a/src/entity/effect/VanillaEffects.php b/src/entity/effect/VanillaEffects.php index ba2fc27cf..50bddc941 100644 --- a/src/entity/effect/VanillaEffects.php +++ b/src/entity/effect/VanillaEffects.php @@ -26,7 +26,6 @@ namespace pocketmine\entity\effect; use pocketmine\color\Color; use pocketmine\lang\KnownTranslationFactory; use pocketmine\utils\RegistryTrait; -use function assert; /** * This doc-block is generated automatically, do not modify it manually. diff --git a/src/item/VanillaItems.php b/src/item/VanillaItems.php index eba778cba..c817ae686 100644 --- a/src/item/VanillaItems.php +++ b/src/item/VanillaItems.php @@ -24,7 +24,6 @@ declare(strict_types=1); namespace pocketmine\item; use pocketmine\utils\CloningRegistryTrait; -use function assert; /** * This doc-block is generated automatically, do not modify it manually. From 3b34268ed6758f5415f0098ddfe8a77a6bda1706 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 19:48:19 +0000 Subject: [PATCH 338/710] Human: try to trap this stupid float cast bug in the wild --- src/pocketmine/entity/Human.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 5036415bd..835b7baf1 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -57,6 +57,7 @@ use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; use pocketmine\network\mcpe\protocol\types\PlayerListEntry; use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton; use pocketmine\Player; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\UUID; use function array_filter; use function array_merge; @@ -69,6 +70,7 @@ use function max; use function min; use function mt_rand; use function random_int; +use function sprintf; use function strlen; use const INT32_MAX; use const INT32_MIN; @@ -393,7 +395,12 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ public function setCurrentTotalXp(int $amount) : bool{ $newLevel = ExperienceUtils::getLevelFromXp($amount); - return $this->setXpAndProgress((int) $newLevel, $newLevel - ((int) $newLevel)); + $xpLevel = (int) $newLevel; + $xpProgress = $newLevel - (int) $newLevel; + if($xpProgress > 1.0){ + throw new AssumptionFailedError(sprintf("newLevel - (int) newLevel should never be bigger than 1, but have %.53f (newLevel=%.53f)", $xpProgress, $newLevel)); + } + return $this->setXpAndProgress($xpLevel, $xpProgress); } /** From cc4bb91fcb3c671f10a2223dc1fde61f77cd60fb Mon Sep 17 00:00:00 2001 From: Dylan T Date: Mon, 8 Nov 2021 20:03:28 +0000 Subject: [PATCH 339/710] Implemented IPv6 support (#4554) --- src/PocketMine.php | 5 ++ src/Server.php | 50 +++++++++++++++---- src/command/defaults/BanIpCommand.php | 4 +- src/command/defaults/PardonIpCommand.php | 4 +- src/network/mcpe/raklib/RakLibInterface.php | 4 +- .../query/DedicatedQueryNetworkInterface.php | 10 +++- src/network/query/QueryHandler.php | 4 -- 7 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/PocketMine.php b/src/PocketMine.php index 551585bbb..e251fd614 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -34,6 +34,7 @@ namespace pocketmine { use pocketmine\utils\Timezone; use pocketmine\wizard\SetupWizard; use Webmozart\PathUtil\Path; + use function defined; use function extension_loaded; use function phpversion; use function preg_match; @@ -145,6 +146,10 @@ namespace pocketmine { $messages[] = "The native PocketMine extension is no longer supported."; } + if(!defined('AF_INET6')){ + $messages[] = "IPv6 support is required, but your PHP binary was built without IPv6 support."; + } + return $messages; } diff --git a/src/Server.php b/src/Server.php index 731860d4a..b384c2957 100644 --- a/src/Server.php +++ b/src/Server.php @@ -321,6 +321,10 @@ class Server{ return $this->configGroup->getConfigInt("server-port", 19132); } + public function getPortV6() : int{ + return $this->configGroup->getConfigInt("server-portv6", 19133); + } + public function getViewDistance() : int{ return max(2, $this->configGroup->getConfigInt("view-distance", 8)); } @@ -337,6 +341,11 @@ class Server{ return $str !== "" ? $str : "0.0.0.0"; } + public function getIpV6() : string{ + $str = $this->configGroup->getConfigString("server-ipv6"); + return $str !== "" ? $str : "::"; + } + public function getServerUniqueId() : UuidInterface{ return $this->serverID; } @@ -784,6 +793,8 @@ class Server{ new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES, [ "motd" => VersionInfo::NAME . " Server", "server-port" => 19132, + "server-portv6" => 19133, + "enable-ipv6" => true, "white-list" => false, "max-players" => 20, "gamemode" => 0, @@ -1114,25 +1125,42 @@ class Server{ return true; } - private function startupPrepareNetworkInterfaces() : bool{ - $useQuery = $this->configGroup->getConfigBool("enable-query", true); - + private function startupPrepareConnectableNetworkInterfaces(string $ip, int $port, bool $ipV6, bool $useQuery) : bool{ + $prettyIp = $ipV6 ? "[$ip]" : $ip; try{ - $rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this)); + $rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6)); }catch(NetworkInterfaceStartException $e){ $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed( - $this->getIp(), - (string) $this->getPort(), + $ip, + (string) $port, $e->getMessage() ))); return false; } - if(!$rakLibRegistered && $useQuery){ - //RakLib would normally handle the transport for Query packets - //if it's not registered we need to make sure Query still works - $this->network->registerInterface(new DedicatedQueryNetworkInterface($this->getIp(), $this->getPort(), new \PrefixedLogger($this->logger, "Dedicated Query Interface"))); + $this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port))); + if($useQuery){ + if(!$rakLibRegistered){ + //RakLib would normally handle the transport for Query packets + //if it's not registered we need to make sure Query still works + $this->network->registerInterface(new DedicatedQueryNetworkInterface($ip, $port, $ipV6, new \PrefixedLogger($this->logger, "Dedicated Query Interface"))); + } + $this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port))); + } + return true; + } + + private function startupPrepareNetworkInterfaces() : bool{ + $useQuery = $this->configGroup->getConfigBool("enable-query", true); + + if( + !$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery) || + ( + $this->configGroup->getConfigBool("enable-ipv6", true) && + !$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery) + ) + ){ + return false; } - $this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($this->getIp(), (string) $this->getPort()))); if($useQuery){ $this->network->registerRawPacketHandler(new QueryHandler($this)); diff --git a/src/command/defaults/BanIpCommand.php b/src/command/defaults/BanIpCommand.php index fca99eff6..d6e1584b9 100644 --- a/src/command/defaults/BanIpCommand.php +++ b/src/command/defaults/BanIpCommand.php @@ -32,7 +32,7 @@ use pocketmine\player\Player; use function array_shift; use function count; use function implode; -use function preg_match; +use function inet_pton; class BanIpCommand extends VanillaCommand{ @@ -57,7 +57,7 @@ class BanIpCommand extends VanillaCommand{ $value = array_shift($args); $reason = implode(" ", $args); - if(preg_match("/^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$/", $value)){ + if(inet_pton($value) !== false){ $this->processIPBan($value, $sender, $reason); Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_banip_success($value)); diff --git a/src/command/defaults/PardonIpCommand.php b/src/command/defaults/PardonIpCommand.php index 395ba1d93..f0b2c9aa5 100644 --- a/src/command/defaults/PardonIpCommand.php +++ b/src/command/defaults/PardonIpCommand.php @@ -29,7 +29,7 @@ use pocketmine\command\utils\InvalidCommandSyntaxException; use pocketmine\lang\KnownTranslationFactory; use pocketmine\permission\DefaultPermissionNames; use function count; -use function preg_match; +use function inet_pton; class PardonIpCommand extends VanillaCommand{ @@ -52,7 +52,7 @@ class PardonIpCommand extends VanillaCommand{ throw new InvalidCommandSyntaxException(); } - if(preg_match("/^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$/", $args[0])){ + if(inet_pton($args[0]) !== false){ $sender->getServer()->getIPBans()->remove($args[0]); $sender->getServer()->getNetwork()->unblockAddress($args[0]); Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_unbanip_success($args[0])); diff --git a/src/network/mcpe/raklib/RakLibInterface.php b/src/network/mcpe/raklib/RakLibInterface.php index 4bfee2258..15a8177fb 100644 --- a/src/network/mcpe/raklib/RakLibInterface.php +++ b/src/network/mcpe/raklib/RakLibInterface.php @@ -88,7 +88,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{ /** @var PacketBroadcaster */ private $broadcaster; - public function __construct(Server $server){ + public function __construct(Server $server, string $ip, int $port, bool $ipV6){ $this->server = $server; $this->rakServerId = mt_rand(0, PHP_INT_MAX); @@ -101,7 +101,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{ $this->server->getLogger(), $mainToThreadBuffer, $threadToMainBuffer, - new InternetAddress($this->server->getIp(), $this->server->getPort(), 4), + new InternetAddress($ip, $port, $ipV6 ? 6 : 4), $this->rakServerId, $this->server->getConfigGroup()->getPropertyInt("network.max-mtu-size", 1492), self::MCPE_RAKNET_PROTOCOL_VERSION, diff --git a/src/network/query/DedicatedQueryNetworkInterface.php b/src/network/query/DedicatedQueryNetworkInterface.php index d742c9e53..70a021a5a 100644 --- a/src/network/query/DedicatedQueryNetworkInterface.php +++ b/src/network/query/DedicatedQueryNetworkInterface.php @@ -34,11 +34,14 @@ use function socket_recvfrom; use function socket_select; use function socket_sendto; use function socket_set_nonblock; +use function socket_set_option; use function socket_strerror; use function strlen; use function time; use function trim; use const AF_INET; +use const IPPROTO_IPV6; +use const IPV6_V6ONLY; use const PHP_INT_MAX; use const SOCK_DGRAM; use const SOCKET_EADDRINUSE; @@ -74,15 +77,18 @@ final class DedicatedQueryNetworkInterface implements AdvancedNetworkInterface{ /** @var string[] */ private $rawPacketPatterns = []; - public function __construct(string $ip, int $port, \Logger $logger){ + public function __construct(string $ip, int $port, bool $ipV6, \Logger $logger){ $this->ip = $ip; $this->port = $port; $this->logger = $logger; - $socket = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); + $socket = @socket_create($ipV6 ? AF_INET6 : AF_INET, SOCK_DGRAM, SOL_UDP); if($socket === false){ throw new \RuntimeException("Failed to create socket"); } + if($ipV6){ + socket_set_option($socket, IPPROTO_IPV6, IPV6_V6ONLY, 1); //disable linux's cool but annoying ipv4-over-ipv6 network stack + } $this->socket = $socket; } diff --git a/src/network/query/QueryHandler.php b/src/network/query/QueryHandler.php index 1ec8a2277..1fe207969 100644 --- a/src/network/query/QueryHandler.php +++ b/src/network/query/QueryHandler.php @@ -27,7 +27,6 @@ declare(strict_types=1); */ namespace pocketmine\network\query; -use pocketmine\lang\KnownTranslationFactory; use pocketmine\network\AdvancedNetworkInterface; use pocketmine\network\RawPacketHandler; use pocketmine\Server; @@ -57,8 +56,6 @@ class QueryHandler implements RawPacketHandler{ public function __construct(Server $server){ $this->server = $server; $this->logger = new \PrefixedLogger($this->server->getLogger(), "Query Handler"); - $addr = $this->server->getIp(); - $port = $this->server->getPort(); /* The Query protocol is built on top of the existing Minecraft PE UDP network stack. @@ -71,7 +68,6 @@ class QueryHandler implements RawPacketHandler{ $this->regenerateToken(); $this->lastToken = $this->token; - $this->logger->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_query_running($addr, (string) $port))); } public function getPattern() : string{ From c33f97ae41e87b449d178c366f73ecc39e9c8cc0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 20:18:07 +0000 Subject: [PATCH 340/710] TypeConverter: clean up absurdly overcomplicated bullshit in createInventoryAction() --- src/network/mcpe/convert/TypeConverter.php | 42 ++++++++++------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/network/mcpe/convert/TypeConverter.php b/src/network/mcpe/convert/TypeConverter.php index a2f9d98ce..67c618ade 100644 --- a/src/network/mcpe/convert/TypeConverter.php +++ b/src/network/mcpe/convert/TypeConverter.php @@ -27,7 +27,6 @@ use pocketmine\block\inventory\AnvilInventory; use pocketmine\block\inventory\CraftingTableInventory; use pocketmine\block\inventory\EnchantInventory; use pocketmine\block\inventory\LoomInventory; -use pocketmine\inventory\Inventory; use pocketmine\inventory\transaction\action\CreateItemAction; use pocketmine\inventory\transaction\action\DestroyItemAction; use pocketmine\inventory\transaction\action\DropItemAction; @@ -248,17 +247,12 @@ class TypeConverter{ } /** - * @param int[] $test + * @param int[] $test * @phpstan-param array $test - * @phpstan-param \Closure(Inventory) : bool $c - * @phpstan-return array{int, Inventory} */ - protected function mapUIInventory(int $slot, array $test, ?Inventory $inventory, \Closure $c) : ?array{ - if($inventory === null){ - return null; - } - if(array_key_exists($slot, $test) && $c($inventory)){ - return [$test[$slot], $inventory]; + protected function mapUIInventory(int $slot, array $test, bool $valid) : ?int{ + if(array_key_exists($slot, $test) && $valid){ + return $test[$slot]; } return null; } @@ -283,6 +277,7 @@ class TypeConverter{ } switch($action->sourceType){ case NetworkInventoryAction::SOURCE_CONTAINER: + $window = null; if($action->windowId === ContainerIds::UI and $action->inventorySlot > 0){ if($action->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT){ return null; //useless noise @@ -290,23 +285,22 @@ class TypeConverter{ $pSlot = $action->inventorySlot; $craftingGrid = $player->getCraftingGrid(); - $mapped = $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING2X2_INPUT, $craftingGrid, fn() => true); - if($mapped === null){ - $current = $player->getCurrentWindow(); - $mapped = - $this->mapUIInventory($pSlot, UIInventorySlotOffset::ANVIL, $current, - function(Inventory $i) : bool{ return $i instanceof AnvilInventory; }) ?? - $this->mapUIInventory($pSlot, UIInventorySlotOffset::ENCHANTING_TABLE, $current, - function(Inventory $i) : bool{ return $i instanceof EnchantInventory; }) ?? - $this->mapUIInventory($pSlot, UIInventorySlotOffset::LOOM, $current, - fn(Inventory $i) => $i instanceof LoomInventory) ?? - $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING3X3_INPUT, $current, - fn(Inventory $i) => $i instanceof CraftingTableInventory); + $slot = $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING2X2_INPUT, true); + if($slot !== null){ + $window = $craftingGrid; + }elseif(($current = $player->getCurrentWindow()) !== null){ + $slot = + $this->mapUIInventory($pSlot, UIInventorySlotOffset::ANVIL, $current instanceof AnvilInventory) ?? + $this->mapUIInventory($pSlot, UIInventorySlotOffset::ENCHANTING_TABLE, $current instanceof EnchantInventory) ?? + $this->mapUIInventory($pSlot, UIInventorySlotOffset::LOOM, $current instanceof LoomInventory) ?? + $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING3X3_INPUT, $current instanceof CraftingTableInventory); + if($slot !== null){ + $window = $current; + } } - if($mapped === null){ + if($slot === null){ throw new TypeConversionException("Unmatched UI inventory slot offset $pSlot"); } - [$slot, $window] = $mapped; }else{ $window = $inventoryManager->getWindow($action->windowId); $slot = $action->inventorySlot; From 93a1e84ad9f7d7ad90d007d7002112286fb7ca83 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 20:27:53 +0000 Subject: [PATCH 341/710] TypeConverter: further simplification --- src/network/mcpe/convert/TypeConverter.php | 32 ++++++++-------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/network/mcpe/convert/TypeConverter.php b/src/network/mcpe/convert/TypeConverter.php index 67c618ade..efa4e79c0 100644 --- a/src/network/mcpe/convert/TypeConverter.php +++ b/src/network/mcpe/convert/TypeConverter.php @@ -50,7 +50,6 @@ use pocketmine\player\GameMode; use pocketmine\player\Player; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; -use function array_key_exists; class TypeConverter{ use SingletonTrait; @@ -246,17 +245,6 @@ class TypeConverter{ } } - /** - * @param int[] $test - * @phpstan-param array $test - */ - protected function mapUIInventory(int $slot, array $test, bool $valid) : ?int{ - if(array_key_exists($slot, $test) && $valid){ - return $test[$slot]; - } - return null; - } - /** * @throws TypeConversionException */ @@ -284,18 +272,20 @@ class TypeConverter{ } $pSlot = $action->inventorySlot; - $craftingGrid = $player->getCraftingGrid(); - $slot = $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING2X2_INPUT, true); + $slot = UIInventorySlotOffset::CRAFTING2X2_INPUT[$pSlot] ?? null; if($slot !== null){ - $window = $craftingGrid; + $window = $player->getCraftingGrid(); }elseif(($current = $player->getCurrentWindow()) !== null){ - $slot = - $this->mapUIInventory($pSlot, UIInventorySlotOffset::ANVIL, $current instanceof AnvilInventory) ?? - $this->mapUIInventory($pSlot, UIInventorySlotOffset::ENCHANTING_TABLE, $current instanceof EnchantInventory) ?? - $this->mapUIInventory($pSlot, UIInventorySlotOffset::LOOM, $current instanceof LoomInventory) ?? - $this->mapUIInventory($pSlot, UIInventorySlotOffset::CRAFTING3X3_INPUT, $current instanceof CraftingTableInventory); - if($slot !== null){ + $slotMap = match(true){ + $current instanceof AnvilInventory => UIInventorySlotOffset::ANVIL, + $current instanceof EnchantInventory => UIInventorySlotOffset::ENCHANTING_TABLE, + $current instanceof LoomInventory => UIInventorySlotOffset::LOOM, + $current instanceof CraftingTableInventory => UIInventorySlotOffset::CRAFTING3X3_INPUT, + default => null + }; + if($slotMap !== null){ $window = $current; + $slot = $slotMap[$pSlot] ?? null; } } if($slot === null){ From d72f6a3ac6b0657e05b5713dcb478122af541858 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 20:35:14 +0000 Subject: [PATCH 342/710] Release 3.25.3 --- changelogs/3.25.md | 4 ++++ src/pocketmine/VersionInfo.php | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/changelogs/3.25.md b/changelogs/3.25.md index 45ee75ca4..c58692963 100644 --- a/changelogs/3.25.md +++ b/changelogs/3.25.md @@ -21,3 +21,7 @@ Plugin developers should **only** update their required API to this version if y - Fixed crash in `Player->showPlayer()` when the target is not in the same world. - `Human->setLifetimeTotalXp()` now limits the maximum value to 2^31. - Fixed players, who died in hardcore mode and were unbanned, getting re-banned on next server join. + +# 3.25.3 +- Fixed crash when players try to pickup XP while already having max XP. +- Added a sanity check to `Human->setCurrentTotalXp()` to try and catch an elusive bug that's been appearing in the wild - please get in touch if you know how to reproduce it! diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index bc70f8a57..e960bc02c 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,6 +34,6 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.25.3"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = ""; +const BUILD_CHANNEL = "stable"; From 255ff63fdaec22a3bb727913b4df8547d71dbcfa Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 20:35:15 +0000 Subject: [PATCH 343/710] 3.25.4 is next --- src/pocketmine/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index e960bc02c..2ed197b2a 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.25.3"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.25.4"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = "stable"; +const BUILD_CHANNEL = ""; From 4bf338f783c729ed6143d0c33739407debb629b4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 22:29:14 +0000 Subject: [PATCH 344/710] Player: fixed removeWindow() causing all other inventories to be unopenable --- src/pocketmine/Player.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 23a382b4c..d1dbe7891 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -3124,10 +3124,22 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->removeWindow($this->windowIndex[$packet->windowId]); $this->closingWindowId = null; //removeWindow handles sending the appropriate - return true; + }else{ + /* + * TODO: HACK! + * If we told the client to remove a window on our own (e.g. a plugin called removeWindow()), our + * first ContainerClose tricks the client into behaving as if it itself asked for the window to be closed. + * This means that it will send us a ContainerClose of its own, which we must respond to the same way as if + * the client closed the window by itself. + * If we don't, the client will not be able to open any new windows. + */ + $pk = new ContainerClosePacket(); + $pk->windowId = $packet->windowId; + $pk->server = false; + $this->sendDataPacket($pk); } - return false; + return true; } public function handleAdventureSettings(AdventureSettingsPacket $packet) : bool{ From 7306a2d939105d8d91b4180de9aec42a31d9570f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 22:33:08 +0000 Subject: [PATCH 345/710] Release 3.25.4 --- changelogs/3.25.md | 3 +++ src/pocketmine/VersionInfo.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/changelogs/3.25.md b/changelogs/3.25.md index c58692963..2520f5952 100644 --- a/changelogs/3.25.md +++ b/changelogs/3.25.md @@ -25,3 +25,6 @@ Plugin developers should **only** update their required API to this version if y # 3.25.3 - Fixed crash when players try to pickup XP while already having max XP. - Added a sanity check to `Human->setCurrentTotalXp()` to try and catch an elusive bug that's been appearing in the wild - please get in touch if you know how to reproduce it! + +# 3.25.4 +- Fixed a long-standing issue with `Player->removeWindow()` breaking inventory UIs on the client. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 2ed197b2a..ff9acd8e8 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,6 +34,6 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.25.4"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = ""; +const BUILD_CHANNEL = "stable"; From 1beec348f927f103a0191c144097a01805587be8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 22:33:09 +0000 Subject: [PATCH 346/710] 3.25.5 is next --- src/pocketmine/VersionInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index ff9acd8e8..05b503d48 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,7 +33,7 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.25.4"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.25.5"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = "stable"; +const BUILD_CHANNEL = ""; From 6fdcfb01c886ca7c7464c801f9f841fe13ee8444 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 22:58:06 +0000 Subject: [PATCH 347/710] Seal up main inventory open/close logic inside InventoryManager where it belongs --- src/network/mcpe/InventoryManager.php | 39 +++++++++++++++---- .../mcpe/handler/InGamePacketHandler.php | 35 ++--------------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/network/mcpe/InventoryManager.php b/src/network/mcpe/InventoryManager.php index 15127d3d4..2c3fff30c 100644 --- a/src/network/mcpe/InventoryManager.php +++ b/src/network/mcpe/InventoryManager.php @@ -67,8 +67,7 @@ class InventoryManager{ //these IDs are used for 1.16 to restore 1.14ish crafting & inventory behaviour; since they don't seem to have any //effect on the behaviour of inventory transactions I don't currently plan to integrate these into the main system. private const RESERVED_WINDOW_ID_RANGE_START = ContainerIds::LAST - 10; - private const RESERVED_WINDOW_ID_RANGE_END = ContainerIds::LAST; - public const HARDCODED_INVENTORY_WINDOW_ID = self::RESERVED_WINDOW_ID_RANGE_START + 2; + private const HARDCODED_INVENTORY_WINDOW_ID = self::RESERVED_WINDOW_ID_RANGE_START + 2; /** @var Player */ private $player; @@ -80,6 +79,15 @@ class InventoryManager{ /** @var int */ private $lastInventoryNetworkId = ContainerIds::FIRST; + /** + * TODO: HACK! This tracks GUIs for inventories that the server considers "always open" so that the client can't + * open them twice. (1.16 hack) + * @var true[] + * @phpstan-var array + * @internal + */ + protected $openHardcodedWindows = []; + /** * @var Item[][] * @phpstan-var array> @@ -186,6 +194,21 @@ class InventoryManager{ return null; } + public function onClientOpenMainInventory() : void{ + $id = self::HARDCODED_INVENTORY_WINDOW_ID; + if(!isset($this->openHardcodedWindows[$id])){ + //TODO: HACK! this restores 1.14ish behaviour, but this should be able to be listened to and + //controlled by plugins. However, the player is always a subscriber to their own inventory so it + //doesn't integrate well with the regular container system right now. + $this->openHardcodedWindows[$id] = true; + $this->session->sendDataPacket(ContainerOpenPacket::entityInv( + InventoryManager::HARDCODED_INVENTORY_WINDOW_ID, + WindowTypes::INVENTORY, + $this->player->getId() + )); + } + } + public function onCurrentWindowRemove() : void{ if(isset($this->windowMap[$this->lastInventoryNetworkId])){ $this->remove($this->lastInventoryNetworkId); @@ -194,16 +217,18 @@ class InventoryManager{ } public function onClientRemoveWindow(int $id) : void{ - if($id >= self::RESERVED_WINDOW_ID_RANGE_START && $id <= self::RESERVED_WINDOW_ID_RANGE_END){ - //TODO: HACK! crafting grid & main inventory currently use these fake IDs - return; - } - if($id === $this->lastInventoryNetworkId){ + if(isset($this->openHardcodedWindows[$id])){ + unset($this->openHardcodedWindows[$id]); + }elseif($id === $this->lastInventoryNetworkId){ $this->remove($id); $this->player->removeCurrentWindow(); }else{ $this->session->getLogger()->debug("Attempted to close inventory with network ID $id, but current is $this->lastInventoryNetworkId"); } + + //Always send this, even if no window matches. If we told the client to close a window, it will behave as if it + //initiated the close and expect an ack. + $this->session->sendDataPacket(ContainerClosePacket::create($id, false)); } public function syncSlot(Inventory $inventory, int $slot) : void{ diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index d2ae3108e..5b63aa09d 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -56,7 +56,6 @@ use pocketmine\network\mcpe\protocol\BossEventPacket; use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket; use pocketmine\network\mcpe\protocol\CommandRequestPacket; use pocketmine\network\mcpe\protocol\ContainerClosePacket; -use pocketmine\network\mcpe\protocol\ContainerOpenPacket; use pocketmine\network\mcpe\protocol\CraftingEventPacket; use pocketmine\network\mcpe\protocol\EmotePacket; use pocketmine\network\mcpe\protocol\InteractPacket; @@ -92,12 +91,10 @@ use pocketmine\network\mcpe\protocol\types\inventory\ReleaseItemTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset; use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData; -use pocketmine\network\mcpe\protocol\types\inventory\WindowTypes; use pocketmine\network\mcpe\protocol\types\PlayerAction; use pocketmine\network\PacketHandlingException; use pocketmine\player\Player; use pocketmine\utils\AssumptionFailedError; -use function array_key_exists; use function array_push; use function base64_encode; use function count; @@ -137,15 +134,6 @@ class InGamePacketHandler extends PacketHandler{ /** @var bool */ public $forceMoveSync = false; - /** - * TODO: HACK! This tracks GUIs for inventories that the server considers "always open" so that the client can't - * open them twice. (1.16 hack) - * @var true[] - * @phpstan-var array - * @internal - */ - protected $openHardcodedWindows = []; - private InventoryManager $inventoryManager; public function __construct(Player $player, NetworkSession $session, InventoryManager $inventoryManager){ @@ -488,19 +476,8 @@ class InGamePacketHandler extends PacketHandler{ if($target === null){ return false; } - if( - $packet->action === InteractPacket::ACTION_OPEN_INVENTORY && $target === $this->player && - !array_key_exists($windowId = InventoryManager::HARDCODED_INVENTORY_WINDOW_ID, $this->openHardcodedWindows) - ){ - //TODO: HACK! this restores 1.14ish behaviour, but this should be able to be listened to and - //controlled by plugins. However, the player is always a subscriber to their own inventory so it - //doesn't integrate well with the regular container system right now. - $this->openHardcodedWindows[$windowId] = true; - $this->session->sendDataPacket(ContainerOpenPacket::entityInv( - InventoryManager::HARDCODED_INVENTORY_WINDOW_ID, - WindowTypes::INVENTORY, - $this->player->getId() - )); + if($packet->action === InteractPacket::ACTION_OPEN_INVENTORY && $target === $this->player){ + $this->inventoryManager->onClientOpenMainInventory(); return true; } return false; //TODO @@ -595,13 +572,7 @@ class InGamePacketHandler extends PacketHandler{ public function handleContainerClose(ContainerClosePacket $packet) : bool{ $this->player->doCloseInventory(); - if(array_key_exists($packet->windowId, $this->openHardcodedWindows)){ - unset($this->openHardcodedWindows[$packet->windowId]); - }else{ - $this->inventoryManager->onClientRemoveWindow($packet->windowId); - } - - $this->session->sendDataPacket(ContainerClosePacket::create($packet->windowId, false)); + $this->inventoryManager->onClientRemoveWindow($packet->windowId); return true; } From 6efb1db1076d9b2219653572933e8b834cfc41f5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 23:03:41 +0000 Subject: [PATCH 348/710] Fixed inventories not working after dying with inventory open closes #4185 closes #4177 --- src/network/mcpe/NetworkSession.php | 3 ++- src/network/mcpe/handler/DeathPacketHandler.php | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index ee7c34997..2fe44e3ac 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -111,6 +111,7 @@ use pocketmine\player\UsedChunkStatus; use pocketmine\player\XboxLivePlayerInfo; use pocketmine\Server; use pocketmine\timings\Timings; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\ObjectSet; use pocketmine\utils\TextFormat; use pocketmine\utils\Utils; @@ -714,7 +715,7 @@ class NetworkSession{ public function onServerDeath() : void{ if($this->handler instanceof InGamePacketHandler){ //TODO: this is a bad fix for pre-spawn death, this shouldn't be reachable at all at this stage :( - $this->setHandler(new DeathPacketHandler($this->player, $this)); + $this->setHandler(new DeathPacketHandler($this->player, $this, $this->invManager ?? throw new AssumptionFailedError())); } } diff --git a/src/network/mcpe/handler/DeathPacketHandler.php b/src/network/mcpe/handler/DeathPacketHandler.php index c3421f1a5..bc56729c9 100644 --- a/src/network/mcpe/handler/DeathPacketHandler.php +++ b/src/network/mcpe/handler/DeathPacketHandler.php @@ -23,7 +23,9 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\handler; +use pocketmine\network\mcpe\InventoryManager; use pocketmine\network\mcpe\NetworkSession; +use pocketmine\network\mcpe\protocol\ContainerClosePacket; use pocketmine\network\mcpe\protocol\PlayerActionPacket; use pocketmine\network\mcpe\protocol\RespawnPacket; use pocketmine\network\mcpe\protocol\types\PlayerAction; @@ -35,10 +37,12 @@ class DeathPacketHandler extends PacketHandler{ private $player; /** @var NetworkSession */ private $session; + private InventoryManager $inventoryManager; - public function __construct(Player $player, NetworkSession $session){ + public function __construct(Player $player, NetworkSession $session, InventoryManager $inventoryManager){ $this->player = $player; $this->session = $session; + $this->inventoryManager = $inventoryManager; } public function setUp() : void{ @@ -58,6 +62,11 @@ class DeathPacketHandler extends PacketHandler{ return false; } + public function handleContainerClose(ContainerClosePacket $packet) : bool{ + $this->inventoryManager->onClientRemoveWindow($packet->windowId); + return true; + } + public function handleRespawn(RespawnPacket $packet) : bool{ if($packet->respawnState === RespawnPacket::CLIENT_READY_TO_SPAWN){ $this->session->sendDataPacket(RespawnPacket::create( From ab002ca06d459077cf92cf6fcdc551bade341096 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 23:36:58 +0000 Subject: [PATCH 349/710] Improved handling of temporary inventory windows evacuation behaviour is now consistent regardless of who is doing it --- src/block/inventory/AnvilInventory.php | 13 ++----------- src/block/inventory/CraftingTableInventory.php | 13 ++----------- src/block/inventory/EnchantInventory.php | 13 ++----------- src/block/inventory/LoomInventory.php | 12 ++---------- src/inventory/PlayerCraftingInventory.php | 2 +- src/inventory/PlayerCursorInventory.php | 2 +- src/player/Player.php | 5 ++++- 7 files changed, 14 insertions(+), 46 deletions(-) diff --git a/src/block/inventory/AnvilInventory.php b/src/block/inventory/AnvilInventory.php index 2e875d3ff..1def8f913 100644 --- a/src/block/inventory/AnvilInventory.php +++ b/src/block/inventory/AnvilInventory.php @@ -24,10 +24,10 @@ declare(strict_types=1); namespace pocketmine\block\inventory; use pocketmine\inventory\SimpleInventory; -use pocketmine\player\Player; +use pocketmine\inventory\TemporaryInventory; use pocketmine\world\Position; -class AnvilInventory extends SimpleInventory implements BlockInventory{ +class AnvilInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{ use BlockInventoryTrait; public const SLOT_INPUT = 0; @@ -37,13 +37,4 @@ class AnvilInventory extends SimpleInventory implements BlockInventory{ $this->holder = $holder; parent::__construct(2); } - - public function onClose(Player $who) : void{ - parent::onClose($who); - - foreach($this->getContents() as $item){ - $who->dropItem($item); - } - $this->clearAll(); - } } diff --git a/src/block/inventory/CraftingTableInventory.php b/src/block/inventory/CraftingTableInventory.php index 493e5dec0..a885df4be 100644 --- a/src/block/inventory/CraftingTableInventory.php +++ b/src/block/inventory/CraftingTableInventory.php @@ -24,23 +24,14 @@ declare(strict_types=1); namespace pocketmine\block\inventory; use pocketmine\crafting\CraftingGrid; -use pocketmine\player\Player; +use pocketmine\inventory\TemporaryInventory; use pocketmine\world\Position; -final class CraftingTableInventory extends CraftingGrid implements BlockInventory{ +final class CraftingTableInventory extends CraftingGrid implements BlockInventory, TemporaryInventory{ use BlockInventoryTrait; public function __construct(Position $holder){ $this->holder = $holder; parent::__construct(CraftingGrid::SIZE_BIG); } - - public function onClose(Player $who) : void{ - parent::onClose($who); - - foreach($this->getContents() as $item){ - $who->dropItem($item); - } - $this->clearAll(); - } } \ No newline at end of file diff --git a/src/block/inventory/EnchantInventory.php b/src/block/inventory/EnchantInventory.php index aafc90caf..91bfcab5e 100644 --- a/src/block/inventory/EnchantInventory.php +++ b/src/block/inventory/EnchantInventory.php @@ -24,10 +24,10 @@ declare(strict_types=1); namespace pocketmine\block\inventory; use pocketmine\inventory\SimpleInventory; -use pocketmine\player\Player; +use pocketmine\inventory\TemporaryInventory; use pocketmine\world\Position; -class EnchantInventory extends SimpleInventory implements BlockInventory{ +class EnchantInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{ use BlockInventoryTrait; public const SLOT_INPUT = 0; @@ -37,13 +37,4 @@ class EnchantInventory extends SimpleInventory implements BlockInventory{ $this->holder = $holder; parent::__construct(2); } - - public function onClose(Player $who) : void{ - parent::onClose($who); - - foreach($this->getContents() as $item){ - $who->dropItem($item); - } - $this->clearAll(); - } } diff --git a/src/block/inventory/LoomInventory.php b/src/block/inventory/LoomInventory.php index 24830329a..8e1a763f1 100644 --- a/src/block/inventory/LoomInventory.php +++ b/src/block/inventory/LoomInventory.php @@ -24,10 +24,11 @@ declare(strict_types=1); namespace pocketmine\block\inventory; use pocketmine\inventory\SimpleInventory; +use pocketmine\inventory\TemporaryInventory; use pocketmine\player\Player; use pocketmine\world\Position; -final class LoomInventory extends SimpleInventory implements BlockInventory{ +final class LoomInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{ use BlockInventoryTrait; public const SLOT_BANNER = 0; @@ -38,13 +39,4 @@ final class LoomInventory extends SimpleInventory implements BlockInventory{ $this->holder = $holder; parent::__construct($size); } - - public function onClose(Player $who) : void{ - parent::onClose($who); - - foreach($this->getContents() as $item){ - $who->dropItem($item); - } - $this->clearAll(); - } } diff --git a/src/inventory/PlayerCraftingInventory.php b/src/inventory/PlayerCraftingInventory.php index 300346476..d3a817434 100644 --- a/src/inventory/PlayerCraftingInventory.php +++ b/src/inventory/PlayerCraftingInventory.php @@ -26,7 +26,7 @@ namespace pocketmine\inventory; use pocketmine\crafting\CraftingGrid; use pocketmine\player\Player; -final class PlayerCraftingInventory extends CraftingGrid{ +final class PlayerCraftingInventory extends CraftingGrid implements TemporaryInventory{ public function __construct(private Player $holder){ parent::__construct(CraftingGrid::SIZE_SMALL); diff --git a/src/inventory/PlayerCursorInventory.php b/src/inventory/PlayerCursorInventory.php index 9cd948c58..7c219fd00 100644 --- a/src/inventory/PlayerCursorInventory.php +++ b/src/inventory/PlayerCursorInventory.php @@ -25,7 +25,7 @@ namespace pocketmine\inventory; use pocketmine\player\Player; -class PlayerCursorInventory extends SimpleInventory{ +class PlayerCursorInventory extends SimpleInventory implements TemporaryInventory{ /** @var Player */ protected $holder; diff --git a/src/player/Player.php b/src/player/Player.php index 7f43296b1..b1a4034ba 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -77,6 +77,7 @@ use pocketmine\inventory\CallbackInventoryListener; use pocketmine\inventory\Inventory; use pocketmine\inventory\PlayerCraftingInventory; use pocketmine\inventory\PlayerCursorInventory; +use pocketmine\inventory\TemporaryInventory; use pocketmine\inventory\transaction\action\DropItemAction; use pocketmine\inventory\transaction\InventoryTransaction; use pocketmine\inventory\transaction\TransactionBuilderInventory; @@ -2322,8 +2323,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * inventory. */ public function doCloseInventory() : void{ - /** @var Inventory[] $inventories */ $inventories = [$this->craftingGrid, $this->cursorInventory]; + if($this->currentWindow instanceof TemporaryInventory){ + $inventories[] = $this->currentWindow; + } $transaction = new InventoryTransaction($this); $mainInventoryTransactionBuilder = new TransactionBuilderInventory($this->inventory); From 5be429a8c473f32a0595e95adb1cddaa2e8c53eb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 23:48:05 +0000 Subject: [PATCH 350/710] Ensure inventories get evacuated on server-side window close --- src/player/Player.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/player/Player.php b/src/player/Player.php index b1a4034ba..308371af7 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -2399,6 +2399,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function removeCurrentWindow() : void{ + $this->doCloseInventory(); if($this->currentWindow !== null){ (new InventoryCloseEvent($this->currentWindow, $this))->call(); From c7beb0a70258fdf5dbba6bf4f93b17cca2a88838 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 8 Nov 2021 23:51:25 +0000 Subject: [PATCH 351/710] Clean up inventory auto close mess from PM3 on PM3 there was no concept of 'current window', we had no idea which window the player was actually looking at. --- src/network/mcpe/handler/InGamePacketHandler.php | 4 +--- src/player/Player.php | 10 +++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 5b63aa09d..e4553c49b 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -193,7 +193,7 @@ class InGamePacketHandler extends PacketHandler{ //TODO HACK: EATING_ITEM is sent back to the server when the server sends it for other players (1.14 bug, maybe earlier) return $packet->actorRuntimeId === ActorEvent::EATING_ITEM; } - $this->player->doCloseInventory(); + $this->player->removeCurrentWindow(); switch($packet->eventId){ case ActorEvent::EATING_ITEM: //TODO: ignore this and handle it server-side @@ -570,8 +570,6 @@ class InGamePacketHandler extends PacketHandler{ } public function handleContainerClose(ContainerClosePacket $packet) : bool{ - $this->player->doCloseInventory(); - $this->inventoryManager->onClientRemoveWindow($packet->windowId); return true; } diff --git a/src/player/Player.php b/src/player/Player.php index 308371af7..aab421014 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1316,7 +1316,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * as a command. */ public function chat(string $message) : bool{ - $this->doCloseInventory(); + $this->removeCurrentWindow(); $message = TextFormat::clean($message, false); foreach(explode("\n", $message) as $messagePart){ @@ -1572,7 +1572,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * @return bool if the block was successfully broken, false if a rollback needs to take place. */ public function breakBlock(Vector3 $pos) : bool{ - $this->doCloseInventory(); + $this->removeCurrentWindow(); if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 7)){ $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); @@ -1991,7 +1991,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ //prevent the player receiving their own disconnect message $this->server->unsubscribeFromAllBroadcastChannels($this); - $this->doCloseInventory(); + $this->removeCurrentWindow(); $ev = new PlayerQuitEvent($this, $quitMessage ?? $this->getLeaveMessage(), $reason); $ev->call(); @@ -2104,7 +2104,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ protected function onDeath() : void{ //Crafting grid must always be evacuated even if keep-inventory is true. This dumps the contents into the //main inventory and drops the rest on the ground. - $this->doCloseInventory(); + $this->removeCurrentWindow(); $ev = new PlayerDeathEvent($this, $this->getDrops(), $this->getXpDropAmount(), null); $ev->call(); @@ -2322,7 +2322,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * @internal Called to clean up crafting grid and cursor inventory when it is detected that the player closed their * inventory. */ - public function doCloseInventory() : void{ + private function doCloseInventory() : void{ $inventories = [$this->craftingGrid, $this->cursorInventory]; if($this->currentWindow instanceof TemporaryInventory){ $inventories[] = $this->currentWindow; From fed59d3ebeac7968eeaab9c7deb62d1f5baf5fe6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 9 Nov 2021 00:11:39 +0000 Subject: [PATCH 352/710] added missing file --- src/inventory/TemporaryInventory.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/inventory/TemporaryInventory.php diff --git a/src/inventory/TemporaryInventory.php b/src/inventory/TemporaryInventory.php new file mode 100644 index 000000000..9e239dcdf --- /dev/null +++ b/src/inventory/TemporaryInventory.php @@ -0,0 +1,28 @@ + Date: Tue, 9 Nov 2021 00:20:06 +0000 Subject: [PATCH 353/710] CS AGAIN --- src/block/inventory/LoomInventory.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/block/inventory/LoomInventory.php b/src/block/inventory/LoomInventory.php index 8e1a763f1..27a8f2dbc 100644 --- a/src/block/inventory/LoomInventory.php +++ b/src/block/inventory/LoomInventory.php @@ -25,7 +25,6 @@ namespace pocketmine\block\inventory; use pocketmine\inventory\SimpleInventory; use pocketmine\inventory\TemporaryInventory; -use pocketmine\player\Player; use pocketmine\world\Position; final class LoomInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{ From c3ec9c09480bbc48d417f1731b263b24827abc81 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 9 Nov 2021 01:46:50 +0000 Subject: [PATCH 354/710] Effect default duration is once again NOT hardcoded, like PM3 I have no fucking idea why I hardcoded this to begin with. Not one of my better ideas ... --- src/entity/effect/Effect.php | 4 +++- src/entity/effect/InstantEffect.php | 7 +++++-- src/entity/effect/PoisonEffect.php | 4 ++-- src/entity/effect/VanillaEffects.php | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/entity/effect/Effect.php b/src/entity/effect/Effect.php index b5c385c6f..3d1bd4c7c 100644 --- a/src/entity/effect/Effect.php +++ b/src/entity/effect/Effect.php @@ -38,12 +38,14 @@ class Effect{ * @param Translatable|string $name Translation key used for effect name * @param Color $color Color of bubbles given by this effect * @param bool $bad Whether the effect is harmful + * @param int $defaultDuration * @param bool $hasBubbles Whether the effect has potion bubbles. Some do not (e.g. Instant Damage has its own particles instead of bubbles) */ public function __construct( protected Translatable|string $name, protected Color $color, protected bool $bad = false, + private int $defaultDuration = 600, protected bool $hasBubbles = true ){} @@ -73,7 +75,7 @@ class Effect{ * Returns the default duration (in ticks) this effect will apply for if a duration is not specified. */ public function getDefaultDuration() : int{ - return 600; + return $this->defaultDuration; } /** diff --git a/src/entity/effect/InstantEffect.php b/src/entity/effect/InstantEffect.php index 653925918..ac5852e2f 100644 --- a/src/entity/effect/InstantEffect.php +++ b/src/entity/effect/InstantEffect.php @@ -23,10 +23,13 @@ declare(strict_types=1); namespace pocketmine\entity\effect; +use pocketmine\color\Color; +use pocketmine\lang\Translatable; + abstract class InstantEffect extends Effect{ - public function getDefaultDuration() : int{ - return 1; + public function __construct(Translatable|string $name, Color $color, bool $bad = false, bool $hasBubbles = true){ + parent::__construct($name, $color, $bad, 1, $hasBubbles); } public function canTick(EffectInstance $instance) : bool{ diff --git a/src/entity/effect/PoisonEffect.php b/src/entity/effect/PoisonEffect.php index 99dffb3af..e3b1618b5 100644 --- a/src/entity/effect/PoisonEffect.php +++ b/src/entity/effect/PoisonEffect.php @@ -34,8 +34,8 @@ class PoisonEffect extends Effect{ /** @var bool */ private $fatal; - public function __construct(Translatable|string $name, Color $color, bool $isBad = false, bool $hasBubbles = true, bool $fatal = false){ - parent::__construct($name, $color, $isBad, $hasBubbles); + public function __construct(Translatable|string $name, Color $color, bool $isBad = false, int $defaultDuration = 600, bool $hasBubbles = true, bool $fatal = false){ + parent::__construct($name, $color, $isBad, $defaultDuration, $hasBubbles); $this->fatal = $fatal; } diff --git a/src/entity/effect/VanillaEffects.php b/src/entity/effect/VanillaEffects.php index 50bddc941..d382a9f60 100644 --- a/src/entity/effect/VanillaEffects.php +++ b/src/entity/effect/VanillaEffects.php @@ -68,7 +68,7 @@ final class VanillaEffects{ //TODO: bad_omen self::register("blindness", new Effect(KnownTranslationFactory::potion_blindness(), new Color(0x1f, 0x1f, 0x23), true)); self::register("conduit_power", new Effect(KnownTranslationFactory::potion_conduitPower(), new Color(0x1d, 0xc2, 0xd1))); - self::register("fatal_poison", new PoisonEffect(KnownTranslationFactory::potion_poison(), new Color(0x4e, 0x93, 0x31), true, true, true)); + self::register("fatal_poison", new PoisonEffect(KnownTranslationFactory::potion_poison(), new Color(0x4e, 0x93, 0x31), true, 600, true, true)); self::register("fire_resistance", new Effect(KnownTranslationFactory::potion_fireResistance(), new Color(0xe4, 0x9a, 0x3a))); self::register("haste", new Effect(KnownTranslationFactory::potion_digSpeed(), new Color(0xd9, 0xc0, 0x43))); self::register("health_boost", new HealthBoostEffect(KnownTranslationFactory::potion_healthBoost(), new Color(0xf8, 0x7d, 0x23))); @@ -84,7 +84,7 @@ final class VanillaEffects{ self::register("poison", new PoisonEffect(KnownTranslationFactory::potion_poison(), new Color(0x4e, 0x93, 0x31), true)); self::register("regeneration", new RegenerationEffect(KnownTranslationFactory::potion_regeneration(), new Color(0xcd, 0x5c, 0xab))); self::register("resistance", new Effect(KnownTranslationFactory::potion_resistance(), new Color(0x99, 0x45, 0x3a))); - self::register("saturation", new SaturationEffect(KnownTranslationFactory::potion_saturation(), new Color(0xf8, 0x24, 0x23), false)); + self::register("saturation", new SaturationEffect(KnownTranslationFactory::potion_saturation(), new Color(0xf8, 0x24, 0x23))); //TODO: slow_falling self::register("slowness", new SlownessEffect(KnownTranslationFactory::potion_moveSlowdown(), new Color(0x5a, 0x6c, 0x81), true)); self::register("speed", new SpeedEffect(KnownTranslationFactory::potion_moveSpeed(), new Color(0x7c, 0xaf, 0xc6))); From 635a9143de62e69c6811ef4bc9cb65933b166cd7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 9 Nov 2021 16:50:42 +0000 Subject: [PATCH 355/710] Release 4.0.0-BETA12 --- changelogs/4.0.md | 69 +++++++++++++++++++++++++++++++++++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 9e9faad62..a3f4e6720 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1634,3 +1634,72 @@ Released 6th November 2021. ### Gameplay - Chunks are now sent in proper circles. This improves the experience when flying quickly parallel to X or Z axis, since now more chunks in front of the player will load sooner. - Added support for emotes. + +# 4.0.0-BETA12 +Released 9th November 2021. + +## General +- Introduced support for connecting via IPv6. + - PHP binary used must now always be built with IPv6 support, even if IPv6 is disabled. This is because RakNet may still send link-local IPv6 loopback addresses in connection packets even when only using IPv4. + - The default port for IPv6 is `19133` (similar to Bedrock Dedicated Server). + - Port `19133` is used by default so that Minecraft Bedrock can detect IPv6 servers on LAN. + - GS4 Query is supported on both IPv4 and IPv6 according to `server.properties` settings. + - The following `server.properties` settings are influential: + - `enable-ipv6`: `on` by default. Disabling this completely disables IPv6 support. + - `server-ipv6`: `::` by default (equivalent to "any IP", like `0.0.0.0` for IPv4). Most users shouldn't need to change this setting, and it doesn't appear in `server.properties` by default. + - `server-portv6`: `19133` by default. You may run both IPv4 and IPv6 on the same port. +- Various internal changes have been made to prepare for negative Y axis support (upcoming 1.18). + +## Fixes +- Fixed resource packs not applying. +- Fixed inventory windows being unopenable after dying with inventory windows open. +- Fixed plugins being able to alter other plugins' permission defaults by redeclaring them in the `plugin.yml`. + +## API +### Block +- `VanillaBlocks::fromString()` has been removed. +- Added `CraftingTableInventory`. This exclusively represents a crafting table's 3x3 crafting grid. + +### Crafting +- `CraftingGrid` is now abstract. +- Removed `CraftingGrid->getHolder()`. +- The constructor of `CraftingGrid` no longer accepts a `Player` parameter. + +### Entity +#### Effect +- `Effect->__construct()` once again accepts an `int $defaultDuration` parameter. +- Removed `VanillaEffects::fromString()`. +- Added `StringToEffectParser` + - Supports custom aliases! + - This is used by `/effect` to provide name support. + +### Event +- `InventoryOpenEvent` is now fired when a player opens a crafting table's UI. +- `InventoryCloseEvent` is now fired when a player closes a crafting table's UI. +- `PlayerDropItemEvent` will now prevent the drops from force-closing of the following inventories: + - anvil + - enchanting table + - loom + +### Inventory +- Added `TemporaryInventory`. This should be implemented by any inventory whose contents should be evacuated when closing. +- Added `PlayerCraftingInventory`. This exclusively represents the player's own 2x2 crafting grid. + +### Item +- Removed `VanillaItems::fromString()` + - Obsoleted by the far superior, much more dynamic, and plugin-customizable `StringToItemParser`. + - `StringToItemParser` allows mapping strings to closure callbacks, allowing you to create aliases for `/give` for any item, including custom ones. + +#### Enchantment +- Removed `VanillaEnchantments::fromString()`. +- Added `StringToEnchantmentParser` + - Supports custom aliases! + - This is used by `/enchant` to provide name support. + +### Player +- Removed `Player->setCraftingGrid()`. To open a 3x3 crafting grid to a player, use `setCurrentWindow(new CraftingTableInventory)`. + +### Server +- Added the following API methods: + - `Server->getIpV6()` + - `Server->getPortV6()` \ No newline at end of file diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 5216a6650..1e7d35d7f 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,7 +30,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA12"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From 73592349cd29d91b03c2703107db859115a92e2d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 9 Nov 2021 16:50:46 +0000 Subject: [PATCH 356/710] 4.0.0-BETA13 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 1e7d35d7f..ee4366762 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,8 +29,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA12"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA13"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From 49a8eff11ea85494b6e830ad03d9c197facb05ed Mon Sep 17 00:00:00 2001 From: Dylan T Date: Thu, 11 Nov 2021 14:29:56 +0000 Subject: [PATCH 357/710] BUILDING: submodules are no longer required submodules are useful (e.g. devtools, build/php) but they are not required to build a server phar. --- BUILDING.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 155896a93..d6e97e05c 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -14,13 +14,12 @@ Because PocketMine-MP requires several non-standard PHP extensions and configura If you use a custom binary, you'll need to replace `composer` usages in this guide with `path/to/your/php path/to/your/composer.phar`. ## Setting up environment -1. `git clone --recursive https://github.com/pmmp/PocketMine-MP.git` +1. `git clone https://github.com/pmmp/PocketMine-MP.git` 2. `composer install` ## Checking out a different branch to build 1. `git checkout ` -2. `git submodule update --init` -3. Re-run `composer install` to synchronize dependencies. +2. Re-run `composer install` to synchronize dependencies. ## Optimizing for release builds 1. Add the flags `--no-dev --classmap-authoritative` to your `composer install` command. This will reduce build size and improve autoloading speed. From 3276047497b5be206b7288c3668b5f8f53813fae Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 12 Nov 2021 00:13:22 +0000 Subject: [PATCH 358/710] Updated composer dependencies --- composer.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index b8a2d17d2..1316f2f84 100644 --- a/composer.lock +++ b/composer.lock @@ -275,16 +275,16 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "5.1.0+bedrock-1.17.40", + "version": "5.1.2+bedrock-1.17.40", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "5abbe5bc21d8a9152d46c26578bf5257526612f9" + "reference": "5f600ce446f357391968c8ce92e3be989aa1dc9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/5abbe5bc21d8a9152d46c26578bf5257526612f9", - "reference": "5abbe5bc21d8a9152d46c26578bf5257526612f9", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/5f600ce446f357391968c8ce92e3be989aa1dc9e", + "reference": "5f600ce446f357391968c8ce92e3be989aa1dc9e", "shasum": "" }, "require": { @@ -316,9 +316,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/5.1.0+bedrock-1.17.40" + "source": "https://github.com/pmmp/BedrockProtocol/tree/5.1.2+bedrock-1.17.40" }, - "time": "2021-11-08T16:26:25+00:00" + "time": "2021-11-10T13:53:03+00:00" }, { "name": "pocketmine/binaryutils", @@ -2916,16 +2916,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", "shasum": "" }, "require": { @@ -2974,14 +2974,14 @@ } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" }, "funding": [ { @@ -2989,7 +2989,7 @@ "type": "github" } ], - "time": "2020-09-28T05:24:23+00:00" + "time": "2021-11-11T14:18:36+00:00" }, { "name": "sebastian/global-state", From e4754ab029c6acc9c82fe18fef0b08f9a161ae71 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 12 Nov 2021 00:16:53 +0000 Subject: [PATCH 359/710] PluginBase: Improved error messages for commands containing illegal characters --- composer.json | 2 +- composer.lock | 14 +++++++------- src/lang/KnownTranslationFactory.php | 6 ++++-- src/plugin/PluginBase.php | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index 9e9f75a66..e9eaa1009 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", "pocketmine/errorhandler": "^0.3.0", - "pocketmine/locale-data": "^1.1.4", + "pocketmine/locale-data": "^2.0.16", "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", "pocketmine/math": "^0.4.0", diff --git a/composer.lock b/composer.lock index 1316f2f84..d112e624c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4f8e023ae390414fb40b77857c16ebee", + "content-hash": "7787453a7902c21ea0d15aee34b12019", "packages": [ { "name": "adhocore/json-comment", @@ -533,16 +533,16 @@ }, { "name": "pocketmine/locale-data", - "version": "1.1.6", + "version": "2.0.16", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "216b49b87e20332f0b39d1717e1e2012a40074cc" + "reference": "8bd74825ac685446f67ea20999ce756a2acd5a30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/216b49b87e20332f0b39d1717e1e2012a40074cc", - "reference": "216b49b87e20332f0b39d1717e1e2012a40074cc", + "url": "https://api.github.com/repos/pmmp/Language/zipball/8bd74825ac685446f67ea20999ce756a2acd5a30", + "reference": "8bd74825ac685446f67ea20999ce756a2acd5a30", "shasum": "" }, "type": "library", @@ -550,9 +550,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/1.1.6" + "source": "https://github.com/pmmp/Language/tree/2.0.16" }, - "time": "2021-11-07T14:30:46+00:00" + "time": "2021-11-12T00:10:09+00:00" }, { "name": "pocketmine/log", diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 7d36320c2..35418d18c 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1666,10 +1666,11 @@ final class KnownTranslationFactory{ ]); } - public static function pocketmine_plugin_aliasError(Translatable|string $param0, Translatable|string $param1) : Translatable{ + public static function pocketmine_plugin_aliasError(Translatable|string $param0, Translatable|string $param1, Translatable|string $param2) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_ALIASERROR, [ 0 => $param0, 1 => $param1, + 2 => $param2, ]); } @@ -1689,10 +1690,11 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_CIRCULARDEPENDENCY, []); } - public static function pocketmine_plugin_commandError(Translatable|string $param0, Translatable|string $param1) : Translatable{ + public static function pocketmine_plugin_commandError(Translatable|string $param0, Translatable|string $param1, Translatable|string $param2) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_COMMANDERROR, [ 0 => $param0, 1 => $param1, + 2 => $param2, ]); } diff --git a/src/plugin/PluginBase.php b/src/plugin/PluginBase.php index db29c40da..7af6c3492 100644 --- a/src/plugin/PluginBase.php +++ b/src/plugin/PluginBase.php @@ -164,7 +164,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{ foreach($this->getDescription()->getCommands() as $key => $data){ if(strpos($key, ":") !== false){ - $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_commandError($key, $this->getDescription()->getFullName()))); + $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_commandError($key, $this->getDescription()->getFullName(), ":"))); continue; } @@ -180,7 +180,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{ $aliasList = []; foreach($data->getAliases() as $alias){ if(strpos($alias, ":") !== false){ - $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_aliasError($alias, $this->getDescription()->getFullName()))); + $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_aliasError($alias, $this->getDescription()->getFullName(), ":"))); continue; } $aliasList[] = $alias; From dc8243f88b36455d74b8180864d5a4a0097a4e90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Nov 2021 00:24:23 +0000 Subject: [PATCH 360/710] Bump phpstan/phpstan from 1.1.1 to 1.1.2 (#4564) Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.1.1 to 1.1.2. - [Release notes](https://github.com/phpstan/phpstan/releases) - [Commits](https://github.com/phpstan/phpstan/compare/1.1.1...1.1.2) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 8d686c5d4..59d271997 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "pocketmine/spl": "^0.4.0" }, "require-dev": { - "phpstan/phpstan": "1.1.1", + "phpstan/phpstan": "1.1.2", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index 77ca56a58..95940e6cf 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5a6a10488d889d0f844cce59e6c34809", + "content-hash": "f9c189426c25530b13815cd5cec091cc", "packages": [ { "name": "adhocore/json-comment", @@ -1011,16 +1011,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.1.1", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "cb317029197236c571c1b9305b8dd12850d8d85c" + "reference": "bcea0ae85868a89d5789c75f012c93129f842934" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cb317029197236c571c1b9305b8dd12850d8d85c", - "reference": "cb317029197236c571c1b9305b8dd12850d8d85c", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/bcea0ae85868a89d5789c75f012c93129f842934", + "reference": "bcea0ae85868a89d5789c75f012c93129f842934", "shasum": "" }, "require": { @@ -1051,7 +1051,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.1.1" + "source": "https://github.com/phpstan/phpstan/tree/1.1.2" }, "funding": [ { @@ -1071,7 +1071,7 @@ "type": "tidelift" } ], - "time": "2021-11-06T22:46:47+00:00" + "time": "2021-11-09T12:41:09+00:00" }, { "name": "phpstan/phpstan-phpunit", From ada469bc454c0e5ce8e18813e88f19d2c1cf8162 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Fri, 12 Nov 2021 01:35:39 +0000 Subject: [PATCH 361/710] README: do not show beta releases on badge [ci skip] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d1787e38..802f9c1dc 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@

CI - GitHub tag (latest semver) + GitHub release (latest SemVer) Docker image version (latest semver) Discord

From 399824c31c0986459bac3cbb828c04a7a75a5519 Mon Sep 17 00:00:00 2001 From: Covered123 <58715544+JavierLeon9966@users.noreply.github.com> Date: Sun, 14 Nov 2021 11:15:36 -0300 Subject: [PATCH 362/710] Add correct drop for Podzol (#4573) --- src/block/Podzol.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/block/Podzol.php b/src/block/Podzol.php index 8da535c54..0eeba12c8 100644 --- a/src/block/Podzol.php +++ b/src/block/Podzol.php @@ -23,6 +23,13 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\item\Item; + class Podzol extends Opaque{ + public function getDropsForCompatibleTool(Item $item) : array{ + return [ + VanillaBlocks::DIRT()->asItem() + ]; + } } From d4a382d56837a6cc5cd6f8de9dc9fa632ea6648f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AD=E3=82=89=E3=81=B2=E3=81=8B=E3=81=A0?= Date: Mon, 15 Nov 2021 00:40:20 +0900 Subject: [PATCH 363/710] Fix position of setworldspawn command (#4574) * The world spawn position is no longer rounded * Remove round() since the position is always int --- src/command/defaults/SetWorldSpawnCommand.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/command/defaults/SetWorldSpawnCommand.php b/src/command/defaults/SetWorldSpawnCommand.php index 9bd37db98..1257e388f 100644 --- a/src/command/defaults/SetWorldSpawnCommand.php +++ b/src/command/defaults/SetWorldSpawnCommand.php @@ -32,7 +32,6 @@ use pocketmine\permission\DefaultPermissionNames; use pocketmine\player\Player; use pocketmine\utils\TextFormat; use function count; -use function round; class SetWorldSpawnCommand extends VanillaCommand{ @@ -54,7 +53,7 @@ class SetWorldSpawnCommand extends VanillaCommand{ if($sender instanceof Player){ $location = $sender->getPosition(); $world = $location->getWorld(); - $pos = $location->asVector3()->round(); + $pos = $location->asVector3()->floor(); }else{ $sender->sendMessage(TextFormat::RED . "You can only perform this command as a player"); @@ -69,7 +68,7 @@ class SetWorldSpawnCommand extends VanillaCommand{ $world->setSpawnLocation($pos); - Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_setworldspawn_success((string) round($pos->x, 2), (string) round($pos->y, 2), (string) round($pos->z, 2))); + Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_setworldspawn_success((string) $pos->x, (string) $pos->y, (string) $pos->z)); return true; } From 639867a64027b3cf7a8c30183c9f203b484de4e5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 14 Nov 2021 15:51:41 +0000 Subject: [PATCH 364/710] Added missing aliases for wooden items --- src/item/StringToItemParser.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index 0d92ec428..f79f05939 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -214,6 +214,7 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("dark_oak_sign", fn() => VanillaBlocks::DARK_OAK_SIGN()); $result->registerBlock("dark_oak_slab", fn() => VanillaBlocks::DARK_OAK_SLAB()); $result->registerBlock("dark_oak_stairs", fn() => VanillaBlocks::DARK_OAK_STAIRS()); + $result->registerBlock("dark_oak_standing_sign", fn() => VanillaBlocks::DARK_OAK_SIGN()); $result->registerBlock("dark_oak_trapdoor", fn() => VanillaBlocks::DARK_OAK_TRAPDOOR()); $result->registerBlock("dark_oak_wall_sign", fn() => VanillaBlocks::DARK_OAK_WALL_SIGN()); $result->registerBlock("dark_oak_wood", fn() => VanillaBlocks::DARK_OAK_WOOD()); @@ -609,6 +610,8 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("jungle_trapdoor", fn() => VanillaBlocks::JUNGLE_TRAPDOOR()); $result->registerBlock("jungle_wall_sign", fn() => VanillaBlocks::JUNGLE_WALL_SIGN()); $result->registerBlock("jungle_wood", fn() => VanillaBlocks::JUNGLE_WOOD()); + $result->registerBlock("jungle_wood_stairs", fn() => VanillaBlocks::JUNGLE_STAIRS()); + $result->registerBlock("jungle_wooden_stairs", fn() => VanillaBlocks::JUNGLE_STAIRS()); $result->registerBlock("lab_table", fn() => VanillaBlocks::LAB_TABLE()); $result->registerBlock("ladder", fn() => VanillaBlocks::LADDER()); $result->registerBlock("lantern", fn() => VanillaBlocks::LANTERN()); @@ -695,6 +698,7 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("oak_sign", fn() => VanillaBlocks::OAK_SIGN()); $result->registerBlock("oak_slab", fn() => VanillaBlocks::OAK_SLAB()); $result->registerBlock("oak_stairs", fn() => VanillaBlocks::OAK_STAIRS()); + $result->registerBlock("oak_standing_sign", fn() => VanillaBlocks::OAK_SIGN()); $result->registerBlock("oak_trapdoor", fn() => VanillaBlocks::OAK_TRAPDOOR()); $result->registerBlock("oak_wall_sign", fn() => VanillaBlocks::OAK_WALL_SIGN()); $result->registerBlock("oak_wood", fn() => VanillaBlocks::OAK_WOOD()); From 3dd03075cbed0a22ac862b3ee21f5eac6419f352 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 14 Nov 2021 15:52:50 +0000 Subject: [PATCH 365/710] StringToItemParser: added some quality-of-life aliases --- src/item/StringToItemParser.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index f79f05939..df0b8944f 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -158,6 +158,7 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("chemical_heat", fn() => VanillaBlocks::CHEMICAL_HEAT()); $result->registerBlock("chemistry_table", fn() => VanillaBlocks::COMPOUND_CREATOR()); $result->registerBlock("chest", fn() => VanillaBlocks::CHEST()); + $result->registerBlock("chipped_anvil", fn() => VanillaBlocks::ANVIL()->setDamage(1)); $result->registerBlock("chiseled_quartz", fn() => VanillaBlocks::CHISELED_QUARTZ()); $result->registerBlock("chiseled_red_sandstone", fn() => VanillaBlocks::CHISELED_RED_SANDSTONE()); $result->registerBlock("chiseled_sandstone", fn() => VanillaBlocks::CHISELED_SANDSTONE()); @@ -165,6 +166,7 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("clay_block", fn() => VanillaBlocks::CLAY()); $result->registerBlock("coal_block", fn() => VanillaBlocks::COAL()); $result->registerBlock("coal_ore", fn() => VanillaBlocks::COAL_ORE()); + $result->registerBlock("coarse_dirt", fn() => VanillaBlocks::DIRT()->setCoarse(true)); $result->registerBlock("cobble", fn() => VanillaBlocks::COBBLESTONE()); $result->registerBlock("cobble_stairs", fn() => VanillaBlocks::COBBLESTONE_STAIRS()); $result->registerBlock("cobble_wall", fn() => VanillaBlocks::COBBLESTONE_WALL()); @@ -200,6 +202,7 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("cut_sandstone", fn() => VanillaBlocks::CUT_SANDSTONE()); $result->registerBlock("cut_sandstone_slab", fn() => VanillaBlocks::CUT_SANDSTONE_SLAB()); $result->registerBlock("cyan_glazed_terracotta", fn() => VanillaBlocks::CYAN_GLAZED_TERRACOTTA()); + $result->registerBlock("damaged_anvil", fn() => VanillaBlocks::ANVIL()->setDamage(2)); $result->registerBlock("dandelion", fn() => VanillaBlocks::DANDELION()); $result->registerBlock("dark_oak_button", fn() => VanillaBlocks::DARK_OAK_BUTTON()); $result->registerBlock("dark_oak_door", fn() => VanillaBlocks::DARK_OAK_DOOR()); From 2f408708f011319366ac5606740c2bf4f69eb90f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 14 Nov 2021 16:27:47 +0000 Subject: [PATCH 366/710] Explosion: fixed blocks with tiles not using said tiles for drop info closes #4571 --- src/world/Explosion.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/world/Explosion.php b/src/world/Explosion.php index 86d9eeb80..4fc1a1fb0 100644 --- a/src/world/Explosion.php +++ b/src/world/Explosion.php @@ -134,8 +134,7 @@ class Explosion{ $blastForce -= ($blastResistance / 5 + 0.3) * $this->stepLen; if($blastForce > 0){ if(!isset($this->affectedBlocks[World::blockHash($vBlockX, $vBlockY, $vBlockZ)])){ - $_block = $blockFactory->fromFullBlock($state); - $_block->position($this->world, $vBlockX, $vBlockY, $vBlockZ); + $_block = $this->world->getBlockAt($vBlockX, $vBlockY, $vBlockZ, true, false); foreach($_block->getAffectedBlocks() as $_affectedBlock){ $_affectedBlockPos = $_affectedBlock->getPosition(); $this->affectedBlocks[World::blockHash($_affectedBlockPos->x, $_affectedBlockPos->y, $_affectedBlockPos->z)] = $_affectedBlock; From 65247b7248bdee0f26a620cdcb06400ce839d980 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 14 Nov 2021 16:41:57 +0000 Subject: [PATCH 367/710] changelog: add notes about ender inventory closes #4569 --- changelogs/4.0.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index a3f4e6720..5dccaed82 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -313,6 +313,10 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` ### Entity #### General - `Entity` no longer extends from `Location`. `Entity->getLocation()` and `Entity->getPosition()` should be used instead. +- Ender inventory has been refactored. It's now split into two parts: + - `EnderChestInventory` is a temporary gateway "inventory" that acts as a proxy to the player's ender inventory. It has a `Position` for holder. This is discarded when the player closes the inventory window. + - `PlayerEnderInventory` is the storage part. This is stored in `Human` and does not contain any block info. + - To open the player's ender inventory, use `Player->setCurrentWindow(new EnderChestInventory($blockPos, $player->getEnderInventory()))`. - The following public fields have been removed: - `Entity->chunk`: Entities no longer know which chunk they are in (the `World` now manages this instead). - `Entity->height`: moved to `EntitySizeInfo`; use `Entity->size` instead @@ -351,6 +355,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Human->getMaxFood()` -> `HungerManager->getMaxFood()` - `Human->addFood()` -> `HungerManager->addFood()` - `Human->isHungry()` -> `HungerManager->isHungry()` + - `Human->getEnderChestInventory()` -> `Human->getEnderInventory()` - `Human->getSaturation()` -> `HungerManager->getSaturation()` - `Human->setSaturation()` -> `HungerManager->setSaturation()` - `Human->addSaturation()` -> `HungerManager->addSaturation()` @@ -564,6 +569,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `CallbackInventoryChangeListener` - `CreativeInventory`: contains the creative functionality previously embedded in `pocketmine\item\Item`, see Item changes for details - `InventoryChangeListener`: allows listening (but not interfering with) events in an inventory. + - `PlayerEnderInventory`: represents the pure storage part of the player's ender inventory, without any block information - `transaction\CreateItemAction` - `transaction\DestroyItemAction` - The following classes have been renamed / moved: @@ -588,6 +594,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - The following API methods have been removed: - `BaseInventory->getDefaultSize()` - `BaseInventory->setSize()` + - `EnderChestInventory->setHolderPosition()` - `Inventory->close()` - `Inventory->dropContents()` - `Inventory->getName()` From f2d5455c5e512939478baf83c7ca7807f56509bf Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 14 Nov 2021 16:42:35 +0000 Subject: [PATCH 368/710] changelog: mention that armor right-click equipping is now supported [ci skip] closes #4570 --- changelogs/4.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 5dccaed82..12fa5c9a6 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1283,6 +1283,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - Implemented offhand inventory. - Block-picking is now supported in survival mode. - Block picking behaviour now matches vanilla (no longer overwrites held item, jumps to existing item where possible). +- Armor can now be equipped by right-clicking while holding it. # 4.0.0-BETA2 Released 10th September 2021. From 4cad552909e50b565af731d0a49201a2a41cef2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AD=E3=82=89=E3=81=B2=E3=81=8B=E3=81=A0?= Date: Mon, 15 Nov 2021 05:07:37 +0900 Subject: [PATCH 369/710] Allow input of relative coordinates to setworldspawn command (#4575) --- src/command/defaults/SetWorldSpawnCommand.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/command/defaults/SetWorldSpawnCommand.php b/src/command/defaults/SetWorldSpawnCommand.php index 1257e388f..96582a349 100644 --- a/src/command/defaults/SetWorldSpawnCommand.php +++ b/src/command/defaults/SetWorldSpawnCommand.php @@ -31,6 +31,7 @@ use pocketmine\math\Vector3; use pocketmine\permission\DefaultPermissionNames; use pocketmine\player\Player; use pocketmine\utils\TextFormat; +use pocketmine\world\World; use function count; class SetWorldSpawnCommand extends VanillaCommand{ @@ -60,8 +61,18 @@ class SetWorldSpawnCommand extends VanillaCommand{ return true; } }elseif(count($args) === 3){ - $world = $sender->getServer()->getWorldManager()->getDefaultWorld(); - $pos = new Vector3($this->getInteger($sender, $args[0]), $this->getInteger($sender, $args[1]), $this->getInteger($sender, $args[2])); + if($sender instanceof Player){ + $base = $sender->getPosition(); + $world = $base->getWorld(); + }else{ + $base = new Vector3(0.0, 0.0, 0.0); + $world = $sender->getServer()->getWorldManager()->getDefaultWorld(); + } + $pos = (new Vector3( + $this->getRelativeDouble($base->x, $sender, $args[0]), + $this->getRelativeDouble($base->y, $sender, $args[1], World::Y_MIN, World::Y_MAX), + $this->getRelativeDouble($base->z, $sender, $args[2]), + ))->floor(); }else{ throw new InvalidCommandSyntaxException(); } From 269231c2283375b7a1794a0d03c1e1b05b9dcf4a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 15 Nov 2021 22:52:05 +0000 Subject: [PATCH 370/710] Ban foreach(arrayWithStringKeys as k => v) this is not as good as phpstan/phpstan-src#769 (e.g. array_key_first()/array_key_last() aren't covered by this, nor is array_rand()) but it does eliminate the most infuriating cases where this usually crops up. --- build/generate-known-translation-apis.php | 5 +- build/make-release.php | 3 +- phpstan.neon.dist | 1 + src/MemoryManager.php | 2 +- src/Server.php | 2 +- src/crash/CrashDump.php | 2 +- src/network/mcpe/convert/ItemTranslator.php | 3 +- src/network/query/QueryInfo.php | 2 +- src/permission/PermissibleInternal.php | 8 +- src/permission/PermissionParser.php | 3 +- src/plugin/PluginBase.php | 3 +- src/plugin/PluginLoadabilityChecker.php | 2 +- src/plugin/PluginManager.php | 10 +-- src/stats/SendUsageTask.php | 4 +- src/utils/Config.php | 6 +- src/utils/Filesystem.php | 3 +- src/utils/StringToTParser.php | 2 +- src/utils/Utils.php | 16 ++++ src/wizard/SetupWizard.php | 3 +- src/world/format/io/WorldProviderManager.php | 3 +- src/world/generator/GeneratorManager.php | 2 +- .../rules/UnsafeForeachArrayOfStringRule.php | 90 +++++++++++++++++++ tools/generate-permission-doc.php | 3 +- tools/simulate-chunk-selector.php | 5 +- 24 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php diff --git a/build/generate-known-translation-apis.php b/build/generate-known-translation-apis.php index b2703b513..feee9b183 100644 --- a/build/generate-known-translation-apis.php +++ b/build/generate-known-translation-apis.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\build\generate_known_translation_apis; use pocketmine\lang\Translatable; +use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; use function array_map; use function count; @@ -100,7 +101,7 @@ final class KnownTranslationKeys{ HEADER; ksort($languageDefinitions, SORT_STRING); - foreach($languageDefinitions as $k => $_){ + foreach(Utils::stringifyKeys($languageDefinitions) as $k => $_){ echo "\tpublic const "; echo constantify($k); echo " = \"" . $k . "\";\n"; @@ -135,7 +136,7 @@ HEADER; $parameterRegex = '/{%(.+?)}/'; $translationContainerClass = (new \ReflectionClass(Translatable::class))->getShortName(); - foreach($languageDefinitions as $key => $value){ + foreach(Utils::stringifyKeys($languageDefinitions) as $key => $value){ $parameters = []; if(preg_match_all($parameterRegex, $value, $matches) > 0){ foreach($matches[1] as $parameterName){ diff --git a/build/make-release.php b/build/make-release.php index 90961c392..e3a3dad81 100644 --- a/build/make-release.php +++ b/build/make-release.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\build\make_release; +use pocketmine\utils\Utils; use pocketmine\utils\VersionString; use pocketmine\VersionInfo; use function array_keys; @@ -76,7 +77,7 @@ const ACCEPTED_OPTS = [ function main() : void{ $filteredOpts = []; - foreach(getopt("", ["current:", "next:", "channel:", "help"]) as $optName => $optValue){ + foreach(Utils::stringifyKeys(getopt("", ["current:", "next:", "channel:", "help"])) as $optName => $optValue){ if($optName === "help"){ fwrite(STDOUT, "Options:\n"); diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 9da6fe352..6fec9cfa9 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -13,6 +13,7 @@ includes: rules: - pocketmine\phpstan\rules\DisallowEnumComparisonRule + - pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule # - pocketmine\phpstan\rules\ThreadedSupportedTypesRule parameters: diff --git a/src/MemoryManager.php b/src/MemoryManager.php index f45647969..9c2642b26 100644 --- a/src/MemoryManager.php +++ b/src/MemoryManager.php @@ -368,7 +368,7 @@ class MemoryManager{ '_SESSION' => true ]; - foreach($GLOBALS as $varName => $value){ + foreach(Utils::stringifyKeys($GLOBALS) as $varName => $value){ if(isset($ignoredGlobals[$varName])){ continue; } diff --git a/src/Server.php b/src/Server.php index b384c2957..628c9a311 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1201,7 +1201,7 @@ class Server{ * Unsubscribes from all broadcast channels. */ public function unsubscribeFromAllBroadcastChannels(CommandSender $subscriber) : void{ - foreach($this->broadcastSubscribers as $channelId => $recipients){ + foreach(Utils::stringifyKeys($this->broadcastSubscribers) as $channelId => $recipients){ $this->unsubscribeFromBroadcastChannel($channelId, $subscriber); } } diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php index 1d595402e..2719e317c 100644 --- a/src/crash/CrashDump.php +++ b/src/crash/CrashDump.php @@ -350,7 +350,7 @@ class CrashDump{ $this->addLine("Zend version: " . zend_version()); $this->addLine("OS: " . PHP_OS . ", " . Utils::getOS()); $this->addLine("Composer libraries: "); - foreach($composerLibraries as $library => $libraryVersion){ + foreach(Utils::stringifyKeys($composerLibraries) as $library => $libraryVersion){ $this->addLine("- $library $libraryVersion"); } } diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index bffa6cb18..dd1dc9cd2 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -27,6 +27,7 @@ use pocketmine\data\bedrock\LegacyItemIdToStringIdMap; use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; +use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; use function array_key_exists; use function file_get_contents; @@ -92,7 +93,7 @@ final class ItemTranslator{ } $simpleMappings[$newId] = $intId; } - foreach($legacyStringToIntMap->getStringToLegacyMap() as $stringId => $intId){ + foreach(Utils::stringifyKeys($legacyStringToIntMap->getStringToLegacyMap()) as $stringId => $intId){ if(isset($simpleMappings[$stringId])){ throw new \UnexpectedValueException("Old ID $stringId collides with new ID"); } diff --git a/src/network/query/QueryInfo.php b/src/network/query/QueryInfo.php index b6cb199ca..559f9a653 100644 --- a/src/network/query/QueryInfo.php +++ b/src/network/query/QueryInfo.php @@ -233,7 +233,7 @@ final class QueryInfo{ $query .= $key . "\x00" . $value . "\x00"; } - foreach($this->extraData as $key => $value){ + foreach(Utils::stringifyKeys($this->extraData) as $key => $value){ $query .= $key . "\x00" . $value . "\x00"; } diff --git a/src/permission/PermissibleInternal.php b/src/permission/PermissibleInternal.php index 0d14d7943..14cb0ba1a 100644 --- a/src/permission/PermissibleInternal.php +++ b/src/permission/PermissibleInternal.php @@ -27,6 +27,7 @@ use pocketmine\plugin\Plugin; use pocketmine\plugin\PluginException; use pocketmine\timings\Timings; use pocketmine\utils\ObjectSet; +use pocketmine\utils\Utils; use function count; use function spl_object_id; @@ -143,7 +144,7 @@ class PermissibleInternal implements Permissible{ $oldPermissions = $this->permissions; $this->permissions = []; - foreach($this->rootPermissions as $name => $isGranted){ + foreach(Utils::stringifyKeys($this->rootPermissions) as $name => $isGranted){ $perm = $permManager->getPermission($name); if($perm === null){ throw new \LogicException("Unregistered root permission $name"); @@ -187,11 +188,12 @@ class PermissibleInternal implements Permissible{ } /** - * @param bool[] $children + * @param bool[] $children + * @phpstan-param array $children */ private function calculateChildPermissions(array $children, bool $invert, ?PermissionAttachment $attachment, ?PermissionAttachmentInfo $parent) : void{ $permManager = PermissionManager::getInstance(); - foreach($children as $name => $v){ + foreach(Utils::stringifyKeys($children) as $name => $v){ $perm = $permManager->getPermission($name); $value = ($v xor $invert); $this->permissions[$name] = new PermissionAttachmentInfo($name, $attachment, $value, $parent); diff --git a/src/permission/PermissionParser.php b/src/permission/PermissionParser.php index c7733a49c..8aab762cf 100644 --- a/src/permission/PermissionParser.php +++ b/src/permission/PermissionParser.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\permission; +use pocketmine\utils\Utils; use function is_bool; use function strtolower; @@ -83,7 +84,7 @@ class PermissionParser{ */ public static function loadPermissions(array $data, string $default = self::DEFAULT_FALSE) : array{ $result = []; - foreach($data as $name => $entry){ + foreach(Utils::stringifyKeys($data) as $name => $entry){ $desc = null; if(isset($entry["default"])){ $default = PermissionParser::defaultFromString($entry["default"]); diff --git a/src/plugin/PluginBase.php b/src/plugin/PluginBase.php index 7af6c3492..32b30794e 100644 --- a/src/plugin/PluginBase.php +++ b/src/plugin/PluginBase.php @@ -32,6 +32,7 @@ use pocketmine\scheduler\TaskScheduler; use pocketmine\Server; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Config; +use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; use function count; use function dirname; @@ -162,7 +163,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{ private function registerYamlCommands() : void{ $pluginCmds = []; - foreach($this->getDescription()->getCommands() as $key => $data){ + foreach(Utils::stringifyKeys($this->getDescription()->getCommands()) as $key => $data){ if(strpos($key, ":") !== false){ $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_commandError($key, $this->getDescription()->getFullName(), ":"))); continue; diff --git a/src/plugin/PluginLoadabilityChecker.php b/src/plugin/PluginLoadabilityChecker.php index 9d3ca0387..a293f33c0 100644 --- a/src/plugin/PluginLoadabilityChecker.php +++ b/src/plugin/PluginLoadabilityChecker.php @@ -76,7 +76,7 @@ final class PluginLoadabilityChecker{ } } - foreach($description->getRequiredExtensions() as $extensionName => $versionConstrs){ + foreach(Utils::stringifyKeys($description->getRequiredExtensions()) as $extensionName => $versionConstrs){ $gotVersion = phpversion($extensionName); if($gotVersion === false){ return KnownTranslationFactory::pocketmine_plugin_extensionNotLoaded($extensionName); diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 46986946c..de8413097 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -181,7 +181,7 @@ class PluginManager{ } $opRoot = $permManager->getPermission(DefaultPermissions::ROOT_OPERATOR); $everyoneRoot = $permManager->getPermission(DefaultPermissions::ROOT_USER); - foreach($description->getPermissions() as $default => $perms){ + foreach(Utils::stringifyKeys($description->getPermissions()) as $default => $perms){ foreach($perms as $perm){ $permManager->addPermission($perm); switch($default){ @@ -345,7 +345,7 @@ class PluginManager{ while(count($triage->plugins) > 0){ $loadedThisLoop = 0; - foreach($triage->plugins as $name => $entry){ + foreach(Utils::stringifyKeys($triage->plugins) as $name => $entry){ $this->checkDepsForTriage($name, "hard", $triage->dependencies, $loadedPlugins, $triage); $this->checkDepsForTriage($name, "soft", $triage->softDependencies, $loadedPlugins, $triage); @@ -377,7 +377,7 @@ class PluginManager{ //No plugins loaded :( //check for skippable soft dependencies first, in case the dependents could resolve hard dependencies - foreach($triage->plugins as $name => $file){ + foreach(Utils::stringifyKeys($triage->plugins) as $name => $file){ if(isset($triage->softDependencies[$name]) && !isset($triage->dependencies[$name])){ foreach($triage->softDependencies[$name] as $k => $dependency){ if($this->getPlugin($dependency) === null && !array_key_exists($dependency, $triage->plugins)){ @@ -392,7 +392,7 @@ class PluginManager{ } } - foreach($triage->plugins as $name => $file){ + foreach(Utils::stringifyKeys($triage->plugins) as $name => $file){ if(isset($triage->dependencies[$name])){ $unknownDependencies = []; @@ -415,7 +415,7 @@ class PluginManager{ } } - foreach($triage->plugins as $name => $file){ + foreach(Utils::stringifyKeys($triage->plugins) as $name => $file){ $this->server->getLogger()->critical($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError($name, KnownTranslationFactory::pocketmine_plugin_circularDependency()))); } break; diff --git a/src/stats/SendUsageTask.php b/src/stats/SendUsageTask.php index d108ca94a..9440ae779 100644 --- a/src/stats/SendUsageTask.php +++ b/src/stats/SendUsageTask.php @@ -123,9 +123,7 @@ class SendUsageTask extends AsyncTask{ ]; //This anonymizes the user ids so they cannot be reversed to the original - foreach($playerList as $k => $v){ - $playerList[$k] = md5($v); - } + $playerList = array_map('md5', $playerList); $players = array_map(function(Player $p) : string{ return md5($p->getUniqueId()->getBytes()); }, $server->getOnlinePlayers()); diff --git a/src/utils/Config.php b/src/utils/Config.php index 562d614f8..1a5125496 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -425,7 +425,7 @@ class Config{ public function set($k, $v = true) : void{ $this->config[$k] = $v; $this->changed = true; - foreach($this->nestedCache as $nestedKey => $nvalue){ + foreach(Utils::stringifyKeys($this->nestedCache) as $nestedKey => $nvalue){ if(substr($nestedKey, 0, strlen($k) + 1) === ($k . ".")){ unset($this->nestedCache[$nestedKey]); } @@ -487,7 +487,7 @@ class Config{ */ private function fillDefaults(array $default, &$data) : int{ $changed = 0; - foreach($default as $k => $v){ + foreach(Utils::stringifyKeys($default) as $k => $v){ if(is_array($v)){ if(!isset($data[$k]) or !is_array($data[$k])){ $data[$k] = []; @@ -536,7 +536,7 @@ class Config{ */ public static function writeProperties(array $config) : string{ $content = "#Properties Config file\r\n#" . date("D M j H:i:s T Y") . "\r\n"; - foreach($config as $k => $v){ + foreach(Utils::stringifyKeys($config) as $k => $v){ if(is_bool($v)){ $v = $v ? "on" : "off"; } diff --git a/src/utils/Filesystem.php b/src/utils/Filesystem.php index 9a89976e6..2d107af6e 100644 --- a/src/utils/Filesystem.php +++ b/src/utils/Filesystem.php @@ -163,7 +163,8 @@ final class Filesystem{ $result = str_replace([DIRECTORY_SEPARATOR, ".php", "phar://"], ["/", "", ""], $path); //remove relative paths - foreach(self::$cleanedPaths as $cleanPath => $replacement){ + //this should probably never have integer keys, but it's safer than making PHPStan ignore it + foreach(Utils::stringifyKeys(self::$cleanedPaths) as $cleanPath => $replacement){ $cleanPath = rtrim(str_replace([DIRECTORY_SEPARATOR, "phar://"], ["/", ""], $cleanPath), "/"); if(strpos($result, $cleanPath) === 0){ $result = ltrim(str_replace($cleanPath, $replacement, $result), "/"); diff --git a/src/utils/StringToTParser.php b/src/utils/StringToTParser.php index 598b3768d..a15204ba4 100644 --- a/src/utils/StringToTParser.php +++ b/src/utils/StringToTParser.php @@ -75,7 +75,7 @@ abstract class StringToTParser{ return strtolower(str_replace([" ", "minecraft:"], ["_", ""], trim($input))); } - /** @return string[] */ + /** @return string[]|int[] */ public function getKnownAliases() : array{ return array_keys($this->callbackMap); } diff --git a/src/utils/Utils.php b/src/utils/Utils.php index b0e81ca28..6f9500125 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -571,6 +571,22 @@ final class Utils{ } } + /** + * Generator which forces array keys to string during iteration. + * This is necessary because PHP has an anti-feature where it casts numeric string keys to integers, leading to + * various crashes. + * + * @phpstan-template TKeyType of string + * @phpstan-template TValueType + * @phpstan-param array $array + * @phpstan-return \Generator + */ + public static function stringifyKeys(array $array) : \Generator{ + foreach($array as $key => $value){ // @phpstan-ignore-line - this is where we fix the stupid bullshit with array keys :) + yield (string) $key => $value; + } + } + public static function checkUTF8(string $string) : void{ if(!mb_check_encoding($string, 'UTF-8')){ throw new \InvalidArgumentException("Text must be valid UTF-8"); diff --git a/src/wizard/SetupWizard.php b/src/wizard/SetupWizard.php index bb1b8de26..6dfb3b690 100644 --- a/src/wizard/SetupWizard.php +++ b/src/wizard/SetupWizard.php @@ -35,6 +35,7 @@ use pocketmine\player\GameMode; use pocketmine\utils\Config; use pocketmine\utils\Internet; use pocketmine\utils\InternetException; +use pocketmine\utils\Utils; use pocketmine\VersionInfo; use Webmozart\PathUtil\Path; use function fgets; @@ -69,7 +70,7 @@ class SetupWizard{ } $this->message("Please select a language"); - foreach($langs as $short => $native){ + foreach(Utils::stringifyKeys($langs) as $short => $native){ $this->writeLine(" $native => $short"); } diff --git a/src/world/format/io/WorldProviderManager.php b/src/world/format/io/WorldProviderManager.php index 001f92913..64dad0816 100644 --- a/src/world/format/io/WorldProviderManager.php +++ b/src/world/format/io/WorldProviderManager.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\world\format\io; +use pocketmine\utils\Utils; use pocketmine\world\format\io\leveldb\LevelDB; use pocketmine\world\format\io\region\Anvil; use pocketmine\world\format\io\region\McRegion; @@ -77,7 +78,7 @@ final class WorldProviderManager{ */ public function getMatchingProviders(string $path) : array{ $result = []; - foreach($this->providers as $alias => $providerEntry){ + foreach(Utils::stringifyKeys($this->providers) as $alias => $providerEntry){ if($providerEntry->isValid($path)){ $result[$alias] = $providerEntry; } diff --git a/src/world/generator/GeneratorManager.php b/src/world/generator/GeneratorManager.php index 11fd02f3b..0e29cc68b 100644 --- a/src/world/generator/GeneratorManager.php +++ b/src/world/generator/GeneratorManager.php @@ -105,7 +105,7 @@ final class GeneratorManager{ */ public function getGeneratorName(string $class) : string{ Utils::testValidInstance($class, Generator::class); - foreach($this->list as $name => $c){ + foreach(Utils::stringifyKeys($this->list) as $name => $c){ if($c->getGeneratorClass() === $class){ return $name; } diff --git a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php b/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php new file mode 100644 index 000000000..639a5b469 --- /dev/null +++ b/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php @@ -0,0 +1,90 @@ + + */ +final class UnsafeForeachArrayOfStringRule implements Rule{ + + public function getNodeType() : string{ + return Foreach_::class; + } + + public function processNode(Node $node, Scope $scope) : array{ + /** @var Foreach_ $node */ + if($node->keyVar === null){ + return []; + } + $iterableType = $scope->getType($node->expr); + + if($iterableType->isArray()->no()){ + return []; + } + if($iterableType->isIterableAtLeastOnce()->no()){ + return []; + } + + $hasCastableKeyTypes = false; + $expectsIntKeyTypes = false; + TypeTraverser::map($iterableType->getIterableKeyType(), function(Type $type, callable $traverse) use (&$hasCastableKeyTypes, &$expectsIntKeyTypes) : Type{ + if($type instanceof IntegerType){ + $expectsIntKeyTypes = true; + return $type; + } + if(!$type instanceof StringType){ + return $traverse($type); + } + if($type->isNumericString()->no() || $type instanceof ClassStringType){ + //class-string cannot be numeric, even if PHPStan thinks they can be + return $type; + } + $hasCastableKeyTypes = true; + return $type; + }); + if($hasCastableKeyTypes && !$expectsIntKeyTypes){ + return [ + RuleErrorBuilder::message(sprintf( + "Unsafe foreach on array with key type %s (they might be casted to int).", + $iterableType->getIterableKeyType()->describe(VerbosityLevel::value()) + ))->tip("Use Utils::foreachWithStringKeys() for a safe Generator-based iterator.")->build() + ]; + } + return []; + } + +} \ No newline at end of file diff --git a/tools/generate-permission-doc.php b/tools/generate-permission-doc.php index 57fd04626..944d2aae3 100644 --- a/tools/generate-permission-doc.php +++ b/tools/generate-permission-doc.php @@ -26,6 +26,7 @@ namespace pocketmine\generate_permission_doc; use pocketmine\permission\DefaultPermissions; use pocketmine\permission\PermissionManager; use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Utils; use pocketmine\VersionInfo; use Webmozart\PathUtil\Path; use function count; @@ -90,7 +91,7 @@ foreach($permissions as $permission){ fwrite($doc, "|:-----|:----:|\n"); $children = $permission->getChildren(); ksort($children, SORT_STRING); - foreach($children as $childName => $isGranted){ + foreach(Utils::stringifyKeys($children) as $childName => $isGranted){ fwrite($doc, "| `$childName` | " . ($isGranted ? "Granted" : "Denied") . " |\n"); } fwrite($doc, "\n"); diff --git a/tools/simulate-chunk-selector.php b/tools/simulate-chunk-selector.php index b4af186e2..b30355f7c 100644 --- a/tools/simulate-chunk-selector.php +++ b/tools/simulate-chunk-selector.php @@ -6,6 +6,7 @@ namespace pocketmine\tools\simulate_chunk_selector; use pocketmine\player\ChunkSelector; use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Utils; use pocketmine\world\format\Chunk; use pocketmine\world\World; use Webmozart\PathUtil\Path; @@ -115,7 +116,7 @@ if(count(getopt("", ["help"])) !== 0){ exit(0); } -foreach(getopt("", ["radius:", "baseX:", "baseZ:", "scale:", "chunksPerStep:"]) as $name => $value){ +foreach(Utils::stringifyKeys(getopt("", ["radius:", "baseX:", "baseZ:", "scale:", "chunksPerStep:"])) as $name => $value){ if(!is_string($value) || (string) ((int) $value) !== $value){ fwrite(STDERR, "Value for --$name must be an integer\n"); exit(1); @@ -136,7 +137,7 @@ if($radius === null){ } $outputDirectory = null; -foreach(getopt("", ["output:"]) as $name => $value){ +foreach(Utils::stringifyKeys(getopt("", ["output:"])) as $name => $value){ assert($name === "output"); if(!is_string($value)){ fwrite(STDERR, "Value for --$name must be a string\n"); From 4599913034787143da4d32b3d76fa05ea066fe36 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 18 Nov 2021 00:58:20 +0000 Subject: [PATCH 371/710] Separate crashdump rendering from crashdump data collection this allows this code to be reused for reproducing crashdumps based on the original data. --- src/crash/CrashDump.php | 91 +++++++--------------------- src/crash/CrashDumpRenderer.php | 103 ++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 70 deletions(-) create mode 100644 src/crash/CrashDumpRenderer.php diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php index 2719e317c..f1072e354 100644 --- a/src/crash/CrashDump.php +++ b/src/crash/CrashDump.php @@ -42,9 +42,7 @@ use function file; use function file_exists; use function file_get_contents; use function fopen; -use function fwrite; use function get_loaded_extensions; -use function implode; use function is_dir; use function is_resource; use function json_encode; @@ -69,7 +67,6 @@ use function zend_version; use function zlib_encode; use const FILE_IGNORE_NEW_LINES; use const JSON_UNESCAPED_SLASHES; -use const PHP_EOL; use const PHP_OS; use const PHP_VERSION; use const SORT_STRING; @@ -84,14 +81,12 @@ class CrashDump{ */ private const FORMAT_VERSION = 4; - private const PLUGIN_INVOLVEMENT_NONE = "none"; - private const PLUGIN_INVOLVEMENT_DIRECT = "direct"; - private const PLUGIN_INVOLVEMENT_INDIRECT = "indirect"; + public const PLUGIN_INVOLVEMENT_NONE = "none"; + public const PLUGIN_INVOLVEMENT_DIRECT = "direct"; + public const PLUGIN_INVOLVEMENT_INDIRECT = "indirect"; /** @var Server */ private $server; - /** @var resource */ - private $fp; /** @var float */ private $time; private CrashDumpData $data; @@ -112,26 +107,27 @@ class CrashDump{ mkdir($crashPath); } $this->path = Path::join($crashPath, date("D_M_j-H.i.s-T_Y", (int) $this->time) . ".log"); - $fp = @fopen($this->path, "wb"); - if(!is_resource($fp)){ - throw new \RuntimeException("Could not create Crash Dump"); - } - $this->fp = $fp; + $this->data = new CrashDumpData(); $this->data->format_version = self::FORMAT_VERSION; $this->data->time = $this->time; $this->data->uptime = $this->time - $this->server->getStartTime(); - $this->addLine($this->server->getName() . " Crash Dump " . date("D M j H:i:s T Y", (int) $this->time)); - $this->addLine(); + $this->baseCrash(); $this->generalData(); $this->pluginsData(); $this->extraData(); - $this->encodeData(); + $fp = @fopen($this->path, "wb"); + if(!is_resource($fp)){ + throw new \RuntimeException("Could not create Crash Dump"); + } + $writer = new CrashDumpRenderer($fp, $this->data); + $writer->renderHumanReadable(); + $this->encodeData($writer); - fclose($this->fp); + fclose($fp); } public function getPath() : string{ @@ -146,11 +142,11 @@ class CrashDump{ return $this->data; } - private function encodeData() : void{ - $this->addLine(); - $this->addLine("----------------------REPORT THE DATA BELOW THIS LINE-----------------------"); - $this->addLine(); - $this->addLine("===BEGIN CRASH DUMP==="); + private function encodeData(CrashDumpRenderer $renderer) : void{ + $renderer->addLine(); + $renderer->addLine("----------------------REPORT THE DATA BELOW THIS LINE-----------------------"); + $renderer->addLine(); + $renderer->addLine("===BEGIN CRASH DUMP==="); $json = json_encode($this->data, JSON_UNESCAPED_SLASHES); if($json === false){ throw new \RuntimeException("Failed to encode crashdump JSON: " . json_last_error_msg()); @@ -159,16 +155,14 @@ class CrashDump{ if($zlibEncoded === false) throw new AssumptionFailedError("ZLIB compression failed"); $this->encodedData = $zlibEncoded; foreach(str_split(base64_encode($this->encodedData), 76) as $line){ - $this->addLine($line); + $renderer->addLine($line); } - $this->addLine("===END CRASH DUMP==="); + $renderer->addLine("===END CRASH DUMP==="); } private function pluginsData() : void{ if($this->pluginManager !== null){ $plugins = $this->pluginManager->getPlugins(); - $this->addLine(); - $this->addLine("Loaded plugins:"); ksort($plugins, SORT_STRING); foreach($plugins as $p){ $d = $p->getDescription(); @@ -184,7 +178,6 @@ class CrashDump{ load: mb_strtoupper($d->getOrder()->name()), website: $d->getWebsite() ); - $this->addLine($d->getName() . " " . $d->getVersion() . " by " . implode(", ", $d->getAuthors()) . " for API(s) " . implode(", ", $d->getCompatibleApis())); } } } @@ -250,10 +243,6 @@ class CrashDump{ $this->data->error = $error; unset($this->data->error["fullFile"]); unset($this->data->error["trace"]); - $this->addLine("Error: " . $error["message"]); - $this->addLine("File: " . $error["file"]); - $this->addLine("Line: " . $error["line"]); - $this->addLine("Type: " . $error["type"]); $this->data->plugin_involvement = self::PLUGIN_INVOLVEMENT_NONE; if(!$this->determinePluginFromFile($error["fullFile"], true)){ //fatal errors won't leave any stack trace @@ -267,36 +256,24 @@ class CrashDump{ } } - $this->addLine(); - $this->addLine("Code:"); - if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-code", true) and file_exists($error["fullFile"])){ $file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES); if($file !== false){ for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){ - $this->addLine("[" . ($l + 1) . "] " . $file[$l]); $this->data->code[$l + 1] = $file[$l]; } } } - $this->addLine(); - $this->addLine("Backtrace:"); - foreach(($this->data->trace = Utils::printableTrace($error["trace"])) as $line){ - $this->addLine($line); - } - $this->addLine(); + $this->data->trace = Utils::printableTrace($error["trace"]); } private function determinePluginFromFile(string $filePath, bool $crashFrame) : bool{ $frameCleanPath = Filesystem::cleanPath($filePath); if(strpos($frameCleanPath, Filesystem::CLEAN_PATH_SRC_PREFIX) !== 0){ - $this->addLine(); if($crashFrame){ - $this->addLine("THIS CRASH WAS CAUSED BY A PLUGIN"); $this->data->plugin_involvement = self::PLUGIN_INVOLVEMENT_DIRECT; }else{ - $this->addLine("A PLUGIN WAS INVOLVED IN THIS CRASH"); $this->data->plugin_involvement = self::PLUGIN_INVOLVEMENT_INDIRECT; } @@ -308,7 +285,6 @@ class CrashDump{ $filePath = Filesystem::cleanPath($file->getValue($plugin)); if(strpos($frameCleanPath, $filePath) === 0){ $this->data->plugin = $plugin->getName(); - $this->addLine("BAD PLUGIN: " . $plugin->getDescription()->getFullName()); break; } } @@ -319,7 +295,6 @@ class CrashDump{ } private function generalData() : void{ - $version = VersionInfo::VERSION(); $composerLibraries = []; foreach(InstalledVersions::getInstalledPackages() as $package){ $composerLibraries[$package] = sprintf( @@ -343,29 +318,5 @@ class CrashDump{ os: Utils::getOS(), composer_libraries: $composerLibraries, ); - $this->addLine($this->server->getName() . " version: " . $version->getFullVersion(true) . " [Protocol " . ProtocolInfo::CURRENT_PROTOCOL . "]"); - $this->addLine("Git commit: " . VersionInfo::GIT_HASH()); - $this->addLine("uname -a: " . php_uname("a")); - $this->addLine("PHP Version: " . phpversion()); - $this->addLine("Zend version: " . zend_version()); - $this->addLine("OS: " . PHP_OS . ", " . Utils::getOS()); - $this->addLine("Composer libraries: "); - foreach(Utils::stringifyKeys($composerLibraries) as $library => $libraryVersion){ - $this->addLine("- $library $libraryVersion"); - } - } - - /** - * @param string $line - */ - public function addLine($line = "") : void{ - fwrite($this->fp, $line . PHP_EOL); - } - - /** - * @param string $str - */ - public function add($str) : void{ - fwrite($this->fp, $str); } } diff --git a/src/crash/CrashDumpRenderer.php b/src/crash/CrashDumpRenderer.php new file mode 100644 index 000000000..68945229d --- /dev/null +++ b/src/crash/CrashDumpRenderer.php @@ -0,0 +1,103 @@ +addLine($this->data->general->name . " Crash Dump " . date("D M j H:i:s T Y", (int) $this->data->time)); + $this->addLine(); + + $this->addLine("Error: " . $this->data->error["message"]); + $this->addLine("File: " . $this->data->error["file"]); + $this->addLine("Line: " . $this->data->error["line"]); + $this->addLine("Type: " . $this->data->error["type"]); + + if($this->data->plugin_involvement !== CrashDump::PLUGIN_INVOLVEMENT_NONE){ + $this->addLine(); + $this->addLine(match($this->data->plugin_involvement){ + CrashDump::PLUGIN_INVOLVEMENT_DIRECT => "THIS CRASH WAS CAUSED BY A PLUGIN", + CrashDump::PLUGIN_INVOLVEMENT_INDIRECT => "A PLUGIN WAS INVOLVED IN THIS CRASH", + default => "Unknown plugin involvement!" + }); + } + if($this->data->plugin !== ""){ + $this->addLine("BAD PLUGIN: " . $this->data->plugin); + } + + $this->addLine(); + $this->addLine("Code:"); + + foreach($this->data->code as $lineNumber => $line){ + $this->addLine("[$lineNumber] $line"); + } + + $this->addLine(); + $this->addLine("Backtrace:"); + foreach($this->data->trace as $line){ + $this->addLine($line); + } + $this->addLine(); + + $version = new VersionString($this->data->general->base_version, $this->data->general->is_dev, $this->data->general->build); + + $this->addLine($this->data->general->name . " version: " . $version->getFullVersion(true) . " [Protocol " . $this->data->general->protocol . "]"); + $this->addLine("Git commit: " . $this->data->general->git); + $this->addLine("uname -a: " . $this->data->general->uname); + $this->addLine("PHP Version: " . $this->data->general->php); + $this->addLine("Zend version: " . $this->data->general->zend); + $this->addLine("OS: " . $this->data->general->php_os . ", " . $this->data->general->os); + $this->addLine("Composer libraries: "); + foreach(Utils::stringifyKeys($this->data->general->composer_libraries) as $library => $libraryVersion){ + $this->addLine("- $library $libraryVersion"); + } + + if(count($this->data->plugins) > 0){ + $this->addLine(); + $this->addLine("Loaded plugins:"); + foreach($this->data->plugins as $p){ + $this->addLine($p->name . " " . $p->version . " by " . implode(", ", $p->authors) . " for API(s) " . implode(", ", $p->api)); + } + } + } + + public function addLine(string $line = "") : void{ + fwrite($this->fp, $line . PHP_EOL); + } +} \ No newline at end of file From 7210db25b0abe86ae24de4fe098a7c0ee42c44be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Nov 2021 14:42:01 +0000 Subject: [PATCH 372/710] Bump phpstan/phpstan from 1.1.2 to 1.2.0 (#4583) Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.1.2 to 1.2.0. - [Release notes](https://github.com/phpstan/phpstan/releases) - [Changelog](https://github.com/phpstan/phpstan/blob/master/CHANGELOG.md) - [Commits](https://github.com/phpstan/phpstan/compare/1.1.2...1.2.0) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- composer.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 59d271997..400c32846 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "pocketmine/spl": "^0.4.0" }, "require-dev": { - "phpstan/phpstan": "1.1.2", + "phpstan/phpstan": "1.2.0", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index 95940e6cf..99c0f5755 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f9c189426c25530b13815cd5cec091cc", + "content-hash": "f13c4ed7311b99ac07dca31d2f77ad1d", "packages": [ { "name": "adhocore/json-comment", @@ -1011,16 +1011,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.1.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "bcea0ae85868a89d5789c75f012c93129f842934" + "reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/bcea0ae85868a89d5789c75f012c93129f842934", - "reference": "bcea0ae85868a89d5789c75f012c93129f842934", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cbe085f9fdead5b6d62e4c022ca52dc9427a10ee", + "reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee", "shasum": "" }, "require": { @@ -1036,7 +1036,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.2-dev" } }, "autoload": { @@ -1051,7 +1051,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.1.2" + "source": "https://github.com/phpstan/phpstan/tree/1.2.0" }, "funding": [ { @@ -1071,7 +1071,7 @@ "type": "tidelift" } ], - "time": "2021-11-09T12:41:09+00:00" + "time": "2021-11-18T14:09:01+00:00" }, { "name": "phpstan/phpstan-phpunit", From b4b954cc5fb92c7270ce207b5bc127ae2de837e9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 19 Nov 2021 21:38:43 +0000 Subject: [PATCH 373/710] build/generate-registry-annotations: accommodate code with CRLF --- build/generate-registry-annotations.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/generate-registry-annotations.php b/build/generate-registry-annotations.php index f7dce3c50..11e15a3c6 100644 --- a/build/generate-registry-annotations.php +++ b/build/generate-registry-annotations.php @@ -91,7 +91,7 @@ foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], throw new \RuntimeException("Failed to get contents of $file"); } - if(preg_match("/^namespace (.+);$/m", $contents, $matches) !== 1 || preg_match('/^((final|abstract)\s+)?class /m', $contents) !== 1){ + if(preg_match("/(*ANYCRLF)^namespace (.+);$/m", $contents, $matches) !== 1 || preg_match('/(*ANYCRLF)^((final|abstract)\s+)?class /m', $contents) !== 1){ continue; } $shortClassName = basename($file, ".php"); @@ -101,7 +101,7 @@ foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], } $reflect = new \ReflectionClass($className); $docComment = $reflect->getDocComment(); - if($docComment === false || preg_match("/^\s*\*\s*@generate-registry-docblock$/m", $docComment) !== 1){ + if($docComment === false || preg_match("/(*ANYCRLF)^\s*\*\s*@generate-registry-docblock$/m", $docComment) !== 1){ continue; } echo "Found registry in $file\n"; From b34e6f53ebe3ed265f88cadfa2f5900f9fd69d2d Mon Sep 17 00:00:00 2001 From: Rush2929 <76860328+Rush2929@users.noreply.github.com> Date: Sat, 20 Nov 2021 08:21:10 +0900 Subject: [PATCH 374/710] Changed visibility of Projectile->move to Protected. (#4585) --- src/entity/projectile/Projectile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entity/projectile/Projectile.php b/src/entity/projectile/Projectile.php index a549b0d7a..cf700b052 100644 --- a/src/entity/projectile/Projectile.php +++ b/src/entity/projectile/Projectile.php @@ -166,7 +166,7 @@ abstract class Projectile extends Entity{ return $this->blockHit === null and parent::hasMovementUpdate(); } - public function move(float $dx, float $dy, float $dz) : void{ + protected function move(float $dx, float $dy, float $dz) : void{ $this->blocksAround = null; Timings::$entityMove->startTiming(); From db135788b959242227b2f0f7fce774a38dc45edb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 20 Nov 2021 18:19:27 +0000 Subject: [PATCH 375/710] Updated transient dependencies --- composer.lock | 53 ++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/composer.lock b/composer.lock index 99c0f5755..dd293362e 100644 --- a/composer.lock +++ b/composer.lock @@ -484,6 +484,7 @@ "issues": "https://github.com/pmmp/SPL/issues", "source": "https://github.com/pmmp/SPL/tree/0.4.2" }, + "abandoned": true, "time": "2021-01-15T15:15:23+00:00" } ], @@ -617,16 +618,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.0", + "version": "v4.13.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "50953a2691a922aa1769461637869a0a2faa3f53" + "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/50953a2691a922aa1769461637869a0a2faa3f53", - "reference": "50953a2691a922aa1769461637869a0a2faa3f53", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd", + "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd", "shasum": "" }, "require": { @@ -667,9 +668,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1" }, - "time": "2021-09-20T12:20:58+00:00" + "time": "2021-11-03T20:52:16+00:00" }, { "name": "phar-io/manifest", @@ -1130,21 +1131,21 @@ }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.0.0", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "7f50eb112f37fda2ef956813d3f1e9b1e69d7940" + "reference": "e12d55f74a8cca18c6e684c6450767e055ba7717" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/7f50eb112f37fda2ef956813d3f1e9b1e69d7940", - "reference": "7f50eb112f37fda2ef956813d3f1e9b1e69d7940", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/e12d55f74a8cca18c6e684c6450767e055ba7717", + "reference": "e12d55f74a8cca18c6e684c6450767e055ba7717", "shasum": "" }, "require": { "php": "^7.1 || ^8.0", - "phpstan/phpstan": "^1.0" + "phpstan/phpstan": "^1.2.0" }, "require-dev": { "nikic/php-parser": "^4.13.0", @@ -1175,22 +1176,22 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.0.0" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.1.0" }, - "time": "2021-10-11T06:57:58+00:00" + "time": "2021-11-18T09:30:29+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.8", + "version": "9.2.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e" + "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", - "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", + "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", "shasum": "" }, "require": { @@ -1246,7 +1247,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.8" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9" }, "funding": [ { @@ -1254,7 +1255,7 @@ "type": "github" } ], - "time": "2021-10-30T08:01:38+00:00" + "time": "2021-11-19T15:21:02+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2029,16 +2030,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", "shasum": "" }, "require": { @@ -2087,14 +2088,14 @@ } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" }, "funding": [ { @@ -2102,7 +2103,7 @@ "type": "github" } ], - "time": "2020-09-28T05:24:23+00:00" + "time": "2021-11-11T14:18:36+00:00" }, { "name": "sebastian/global-state", From 3683884b9c58674e027bc0745c23c3d0976b5cc3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 20 Nov 2021 18:27:43 +0000 Subject: [PATCH 376/710] Updated build/php submodule to pmmp/php-build-scripts@7a2ab5b92218a5cd8e77f05ece0c5edce8f1863d --- build/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/php b/build/php index 365356dec..7a2ab5b92 160000 --- a/build/php +++ b/build/php @@ -1 +1 @@ -Subproject commit 365356dec1d184b858907d1208fe84d824b6541e +Subproject commit 7a2ab5b92218a5cd8e77f05ece0c5edce8f1863d From 7b4ef293bdc89188566e754b973d966bb0df3657 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 21 Nov 2021 20:49:00 +0000 Subject: [PATCH 377/710] NetworkBinaryStream: fixed incorrect field types for StructureSettings --- src/pocketmine/network/mcpe/NetworkBinaryStream.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php index 9fa3506c1..bbe80e72e 100644 --- a/src/pocketmine/network/mcpe/NetworkBinaryStream.php +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -786,8 +786,8 @@ class NetworkBinaryStream extends BinaryStream{ $result->lastTouchedByPlayerID = $this->getEntityUniqueId(); $result->rotation = $this->getByte(); $result->mirror = $this->getByte(); - $result->integrityValue = $this->getFloat(); - $result->integritySeed = $this->getInt(); + $result->integrityValue = $this->getLFloat(); + $result->integritySeed = $this->getLInt(); $result->pivot = $this->getVector3(); return $result; @@ -805,8 +805,8 @@ class NetworkBinaryStream extends BinaryStream{ $this->putEntityUniqueId($structureSettings->lastTouchedByPlayerID); $this->putByte($structureSettings->rotation); $this->putByte($structureSettings->mirror); - $this->putFloat($structureSettings->integrityValue); - $this->putInt($structureSettings->integritySeed); + $this->putLFloat($structureSettings->integrityValue); + $this->putLInt($structureSettings->integritySeed); $this->putVector3($structureSettings->pivot); } From fc7d297f60574965e858da2b8dc301ff6f5581fe Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 21 Nov 2021 20:51:35 +0000 Subject: [PATCH 378/710] Added missing fields of StructureSettings --- src/pocketmine/network/mcpe/NetworkBinaryStream.php | 4 ++++ .../network/mcpe/protocol/types/StructureSettings.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php index bbe80e72e..d07644f5f 100644 --- a/src/pocketmine/network/mcpe/NetworkBinaryStream.php +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -786,6 +786,8 @@ class NetworkBinaryStream extends BinaryStream{ $result->lastTouchedByPlayerID = $this->getEntityUniqueId(); $result->rotation = $this->getByte(); $result->mirror = $this->getByte(); + $result->animationMode = $this->getByte(); + $result->animationSeconds = $this->getLFloat(); $result->integrityValue = $this->getLFloat(); $result->integritySeed = $this->getLInt(); $result->pivot = $this->getVector3(); @@ -805,6 +807,8 @@ class NetworkBinaryStream extends BinaryStream{ $this->putEntityUniqueId($structureSettings->lastTouchedByPlayerID); $this->putByte($structureSettings->rotation); $this->putByte($structureSettings->mirror); + $this->putByte($structureSettings->animationMode); + $this->putLFloat($structureSettings->animationSeconds); $this->putLFloat($structureSettings->integrityValue); $this->putLInt($structureSettings->integritySeed); $this->putVector3($structureSettings->pivot); diff --git a/src/pocketmine/network/mcpe/protocol/types/StructureSettings.php b/src/pocketmine/network/mcpe/protocol/types/StructureSettings.php index 8e49bf64d..ea60dc99e 100644 --- a/src/pocketmine/network/mcpe/protocol/types/StructureSettings.php +++ b/src/pocketmine/network/mcpe/protocol/types/StructureSettings.php @@ -50,6 +50,10 @@ class StructureSettings{ public $rotation; /** @var int */ public $mirror; + /** @var int */ + public $animationMode; + /** @var float */ + public $animationSeconds; /** @var float */ public $integrityValue; /** @var int */ From ed8b4950a35c5d0d57eb3415bc7f78f0fc98f54f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 21 Nov 2021 21:10:58 +0000 Subject: [PATCH 379/710] Updated BedrockProtocol --- composer.json | 2 +- composer.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 0406c5643..4c71c4e13 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "fgrosse/phpasn1": "^2.3", "netresearch/jsonmapper": "^4.0", "pocketmine/bedrock-data": "^1.4.0+bedrock-1.17.40", - "pocketmine/bedrock-protocol": "^5.0.0+bedrock-1.17.40", + "pocketmine/bedrock-protocol": "^6.0.0+bedrock-1.17.40", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "^0.2.0", diff --git a/composer.lock b/composer.lock index e688bbe20..b078ca317 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "eb459041db634d88bee7d4202e096178", + "content-hash": "fb545e4c8e17b0b07e8e20986b64e5a6", "packages": [ { "name": "adhocore/json-comment", @@ -275,16 +275,16 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "5.1.2+bedrock-1.17.40", + "version": "6.0.0+bedrock-1.17.40", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "5f600ce446f357391968c8ce92e3be989aa1dc9e" + "reference": "906bafec4fc41f548749ce01d120902b25c1bbfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/5f600ce446f357391968c8ce92e3be989aa1dc9e", - "reference": "5f600ce446f357391968c8ce92e3be989aa1dc9e", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/906bafec4fc41f548749ce01d120902b25c1bbfe", + "reference": "906bafec4fc41f548749ce01d120902b25c1bbfe", "shasum": "" }, "require": { @@ -298,7 +298,7 @@ "ramsey/uuid": "^4.1" }, "require-dev": { - "phpstan/phpstan": "1.1.1", + "phpstan/phpstan": "1.2.0", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.5" @@ -316,9 +316,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/5.1.2+bedrock-1.17.40" + "source": "https://github.com/pmmp/BedrockProtocol/tree/6.0.0+bedrock-1.17.40" }, - "time": "2021-11-10T13:53:03+00:00" + "time": "2021-11-21T20:56:18+00:00" }, { "name": "pocketmine/binaryutils", From 37622e02b865e447298645adc943030518df98da Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 21 Nov 2021 21:11:39 +0000 Subject: [PATCH 380/710] Updated translations --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index b078ca317..969ab365b 100644 --- a/composer.lock +++ b/composer.lock @@ -533,16 +533,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.0.16", + "version": "2.0.17", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "8bd74825ac685446f67ea20999ce756a2acd5a30" + "reference": "30e4a64d5674bac556c4e2b9842b19a981471ac4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/8bd74825ac685446f67ea20999ce756a2acd5a30", - "reference": "8bd74825ac685446f67ea20999ce756a2acd5a30", + "url": "https://api.github.com/repos/pmmp/Language/zipball/30e4a64d5674bac556c4e2b9842b19a981471ac4", + "reference": "30e4a64d5674bac556c4e2b9842b19a981471ac4", "shasum": "" }, "type": "library", @@ -550,9 +550,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.0.16" + "source": "https://github.com/pmmp/Language/tree/2.0.17" }, - "time": "2021-11-12T00:10:09+00:00" + "time": "2021-11-12T00:59:39+00:00" }, { "name": "pocketmine/log", From cbe0f44c4f7bc3715acbf148f981bd93111c4c8f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 22 Nov 2021 14:58:45 +0000 Subject: [PATCH 381/710] ConsoleReaderChildProcess: Commit suicide in more cases this makes it slightly less annoying to get rid of as an orphan process, though it still won't immediately die. --- src/console/ConsoleReader.php | 27 ++++++---------------- src/console/ConsoleReaderChildProcess.php | 16 ++++++++++--- src/console/ConsoleReaderException.php | 28 +++++++++++++++++++++++ 3 files changed, 48 insertions(+), 23 deletions(-) create mode 100644 src/console/ConsoleReaderException.php diff --git a/src/console/ConsoleReader.php b/src/console/ConsoleReader.php index 9da61cb6d..c34be83c3 100644 --- a/src/console/ConsoleReader.php +++ b/src/console/ConsoleReader.php @@ -23,50 +23,37 @@ declare(strict_types=1); namespace pocketmine\console; +use pocketmine\utils\AssumptionFailedError; use function fclose; -use function fgets; use function fopen; -use function is_resource; use function stream_select; use function trim; -use function usleep; final class ConsoleReader{ /** @var resource */ private $stdin; public function __construct(){ - $this->initStdin(); - } - - private function initStdin() : void{ - if(is_resource($this->stdin)){ - fclose($this->stdin); - } - - $this->stdin = fopen("php://stdin", "r"); + $stdin = fopen("php://stdin", "r"); + if($stdin === false) throw new AssumptionFailedError("Opening stdin should never fail"); + $this->stdin = $stdin; } /** * Reads a line from the console and adds it to the buffer. This method may block the thread. + * @throws ConsoleReaderException */ public function readLine() : ?string{ - if(!is_resource($this->stdin)){ - $this->initStdin(); - } - $r = [$this->stdin]; $w = $e = null; if(($count = stream_select($r, $w, $e, 0, 200000)) === 0){ //nothing changed in 200000 microseconds return null; }elseif($count === false){ //stream error - $this->initStdin(); + throw new ConsoleReaderException("Unexpected EOF on select()"); } if(($raw = fgets($this->stdin)) === false){ //broken pipe or EOF - $this->initStdin(); - usleep(200000); //prevent CPU waste if it's end of pipe - return null; //loop back round + throw new ConsoleReaderException("Unexpected EOF on fgets()"); } $line = trim($raw); diff --git a/src/console/ConsoleReaderChildProcess.php b/src/console/ConsoleReaderChildProcess.php index 3879ecdff..6f4a74258 100644 --- a/src/console/ConsoleReaderChildProcess.php +++ b/src/console/ConsoleReaderChildProcess.php @@ -45,8 +45,18 @@ if($socket === false){ } $consoleReader = new ConsoleReader(); while(!feof($socket)){ - $line = $consoleReader->readLine(); - if($line !== null){ - fwrite($socket, $line . "\n"); + try{ + $line = $consoleReader->readLine(); + }catch(ConsoleReaderException $e){ + //Encountered unexpected EOF. This might be because the user did something stupid, or because the parent process + //has died. In either case, commit suicide. If the parent process is still alive, it will start a new console + //reader. + break; + } + if(@fwrite($socket, ($line ?? "") . "\n") === false){ + //Always send even if there's no line, to check if the parent is alive + //If the parent process was terminated forcibly, it won't close the connection properly, so feof() will return + //false even though the connection is actually broken. However, fwrite() will fail. + break; } } diff --git a/src/console/ConsoleReaderException.php b/src/console/ConsoleReaderException.php new file mode 100644 index 000000000..bf9e8fc67 --- /dev/null +++ b/src/console/ConsoleReaderException.php @@ -0,0 +1,28 @@ + Date: Mon, 22 Nov 2021 15:37:33 +0000 Subject: [PATCH 382/710] fixed spam --- src/console/ConsoleReaderThread.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/console/ConsoleReaderThread.php b/src/console/ConsoleReaderThread.php index dbf3770d3..fb9dc85bb 100644 --- a/src/console/ConsoleReaderThread.php +++ b/src/console/ConsoleReaderThread.php @@ -116,6 +116,9 @@ final class ConsoleReaderThread extends Thread{ $command = preg_replace("#\\x1b\\x5b([^\\x1b]*\\x7e|[\\x40-\\x50])#", "", trim($command)) ?? throw new AssumptionFailedError("This regex is assumed to be valid"); $command = preg_replace('/[[:cntrl:]]/', '', $command) ?? throw new AssumptionFailedError("This regex is assumed to be valid"); + if($command === ""){ + continue; + } $buffer[] = $command; if($notifier !== null){ $notifier->wakeupSleeper(); From 2bb97d8904497f84c0e5ae40f347a67d7f8471b0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 22 Nov 2021 15:40:47 +0000 Subject: [PATCH 383/710] Be quiet CS --- src/console/ConsoleReader.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/console/ConsoleReader.php b/src/console/ConsoleReader.php index c34be83c3..bd1fef4f5 100644 --- a/src/console/ConsoleReader.php +++ b/src/console/ConsoleReader.php @@ -25,6 +25,7 @@ namespace pocketmine\console; use pocketmine\utils\AssumptionFailedError; use function fclose; +use function fgets; use function fopen; use function stream_select; use function trim; From c37c261c0f5b0df545f99db7219f8c270d4024a6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 22 Nov 2021 22:19:40 +0000 Subject: [PATCH 384/710] Separate crashdump file generation from crashdump data collection this allows CrashDump to be used just to generate data, which will come in useful for non-crash error reporting in the future (e.g. packet decoding errors). --- src/Server.php | 29 ++++++++++++++++++++++++++++- src/crash/CrashDump.php | 38 ++++---------------------------------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/Server.php b/src/Server.php index 628c9a311..4ab8b8dcb 100644 --- a/src/Server.php +++ b/src/Server.php @@ -35,6 +35,7 @@ use pocketmine\console\ConsoleReaderThread; use pocketmine\crafting\CraftingManager; use pocketmine\crafting\CraftingManagerFromDataHelper; use pocketmine\crash\CrashDump; +use pocketmine\crash\CrashDumpRenderer; use pocketmine\data\java\GameModeIdMap; use pocketmine\entity\EntityDataHelper; use pocketmine\entity\Location; @@ -121,13 +122,18 @@ use function base64_encode; use function cli_set_process_title; use function copy; use function count; +use function date; +use function fclose; use function file_exists; use function file_get_contents; use function file_put_contents; use function filemtime; +use function fopen; use function get_class; use function ini_set; use function is_array; +use function is_dir; +use function is_resource; use function is_string; use function json_decode; use function max; @@ -1505,6 +1511,25 @@ class Server{ $this->crashDump(); } + private function writeCrashDumpFile(CrashDump $dump) : string{ + $crashFolder = Path::join($this->getDataPath(), "crashdumps"); + if(!is_dir($crashFolder)){ + mkdir($crashFolder); + } + $crashDumpPath = Path::join($crashFolder, date("D_M_j-H.i.s-T_Y", (int) $dump->getData()->time) . ".log"); + + $fp = @fopen($crashDumpPath, "wb"); + if(!is_resource($fp)){ + throw new \RuntimeException("Unable to open new file to generate crashdump"); + } + $writer = new CrashDumpRenderer($fp, $dump->getData()); + $writer->renderHumanReadable(); + $dump->encodeData($writer); + + fclose($fp); + return $crashDumpPath; + } + public function crashDump() : void{ while(@ob_end_flush()){} if(!$this->isRunning){ @@ -1521,7 +1546,9 @@ class Server{ $this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_create())); $dump = new CrashDump($this, $this->pluginManager ?? null); - $this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($dump->getPath()))); + $crashDumpPath = $this->writeCrashDumpFile($dump); + + $this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath))); if($this->configGroup->getPropertyBool("auto-report.enabled", true)){ $report = true; diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php index f1072e354..76cb0fef3 100644 --- a/src/crash/CrashDump.php +++ b/src/crash/CrashDump.php @@ -35,23 +35,17 @@ use pocketmine\utils\Utils; use pocketmine\VersionInfo; use Webmozart\PathUtil\Path; use function base64_encode; -use function date; use function error_get_last; -use function fclose; use function file; use function file_exists; use function file_get_contents; -use function fopen; use function get_loaded_extensions; -use function is_dir; -use function is_resource; use function json_encode; use function json_last_error_msg; use function ksort; use function max; use function mb_strtoupper; use function microtime; -use function mkdir; use function ob_end_clean; use function ob_get_contents; use function ob_start; @@ -87,51 +81,27 @@ class CrashDump{ /** @var Server */ private $server; - /** @var float */ - private $time; private CrashDumpData $data; /** @var string */ private $encodedData; - /** @var string */ - private $path; private ?PluginManager $pluginManager; public function __construct(Server $server, ?PluginManager $pluginManager){ - $this->time = microtime(true); + $now = microtime(true); $this->server = $server; $this->pluginManager = $pluginManager; - $crashPath = Path::join($this->server->getDataPath(), "crashdumps"); - if(!is_dir($crashPath)){ - mkdir($crashPath); - } - $this->path = Path::join($crashPath, date("D_M_j-H.i.s-T_Y", (int) $this->time) . ".log"); - $this->data = new CrashDumpData(); $this->data->format_version = self::FORMAT_VERSION; - $this->data->time = $this->time; - $this->data->uptime = $this->time - $this->server->getStartTime(); + $this->data->time = $now; + $this->data->uptime = $now - $this->server->getStartTime(); $this->baseCrash(); $this->generalData(); $this->pluginsData(); $this->extraData(); - - $fp = @fopen($this->path, "wb"); - if(!is_resource($fp)){ - throw new \RuntimeException("Could not create Crash Dump"); - } - $writer = new CrashDumpRenderer($fp, $this->data); - $writer->renderHumanReadable(); - $this->encodeData($writer); - - fclose($fp); - } - - public function getPath() : string{ - return $this->path; } public function getEncodedData() : string{ @@ -142,7 +112,7 @@ class CrashDump{ return $this->data; } - private function encodeData(CrashDumpRenderer $renderer) : void{ + public function encodeData(CrashDumpRenderer $renderer) : void{ $renderer->addLine(); $renderer->addLine("----------------------REPORT THE DATA BELOW THIS LINE-----------------------"); $renderer->addLine(); From 020cd7b966ceb89c47f210ef2f240e8e28746de2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 22 Nov 2021 22:31:07 +0000 Subject: [PATCH 385/710] CrashDump: fixed encodedData being uninitialized before getEncodedData() is called --- src/crash/CrashDump.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php index 76cb0fef3..8407e70ce 100644 --- a/src/crash/CrashDump.php +++ b/src/crash/CrashDump.php @@ -64,6 +64,7 @@ use const JSON_UNESCAPED_SLASHES; use const PHP_OS; use const PHP_VERSION; use const SORT_STRING; +use const ZLIB_ENCODING_DEFLATE; class CrashDump{ @@ -102,6 +103,14 @@ class CrashDump{ $this->pluginsData(); $this->extraData(); + + $json = json_encode($this->data, JSON_UNESCAPED_SLASHES); + if($json === false){ + throw new \RuntimeException("Failed to encode crashdump JSON: " . json_last_error_msg()); + } + $zlibEncoded = zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9); + if($zlibEncoded === false) throw new AssumptionFailedError("ZLIB compression failed"); + $this->encodedData = $zlibEncoded; } public function getEncodedData() : string{ @@ -117,13 +126,6 @@ class CrashDump{ $renderer->addLine("----------------------REPORT THE DATA BELOW THIS LINE-----------------------"); $renderer->addLine(); $renderer->addLine("===BEGIN CRASH DUMP==="); - $json = json_encode($this->data, JSON_UNESCAPED_SLASHES); - if($json === false){ - throw new \RuntimeException("Failed to encode crashdump JSON: " . json_last_error_msg()); - } - $zlibEncoded = zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9); - if($zlibEncoded === false) throw new AssumptionFailedError("ZLIB compression failed"); - $this->encodedData = $zlibEncoded; foreach(str_split(base64_encode($this->encodedData), 76) as $line){ $renderer->addLine($line); } From fb0eebc0dcbf61e2254645460d58b7c13b0d938c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 23 Nov 2021 01:39:35 +0000 Subject: [PATCH 386/710] RegionWorldProvider: Show a more specific message on missing required ByteArrayTags --- src/world/format/io/region/RegionWorldProvider.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/world/format/io/region/RegionWorldProvider.php b/src/world/format/io/region/RegionWorldProvider.php index 3ac9132f6..df28c3ffe 100644 --- a/src/world/format/io/region/RegionWorldProvider.php +++ b/src/world/format/io/region/RegionWorldProvider.php @@ -173,6 +173,9 @@ abstract class RegionWorldProvider extends BaseWorldProvider{ protected static function readFixedSizeByteArray(CompoundTag $chunk, string $tagName, int $length) : string{ $tag = $chunk->getTag($tagName); if(!($tag instanceof ByteArrayTag)){ + if($tag === null){ + throw new CorruptedChunkException("'$tagName' key is missing from chunk NBT"); + } throw new CorruptedChunkException("Expected TAG_ByteArray for '$tagName'"); } $data = $tag->getValue(); From d8f0fd0a7ef710930401ba056b7ae8be463d5cfb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 23 Nov 2021 01:49:48 +0000 Subject: [PATCH 387/710] McRegion: skip chunks with TerrainGenerated=false legacy PM used to save even ungenerated chunks, and omitted some tags when doing so which we expect to always be present. --- src/world/format/io/region/LegacyAnvilChunkTrait.php | 2 +- src/world/format/io/region/McRegion.php | 11 ++++++++++- src/world/format/io/region/RegionWorldProvider.php | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/world/format/io/region/LegacyAnvilChunkTrait.php b/src/world/format/io/region/LegacyAnvilChunkTrait.php index 8970a2fb3..7debb29ba 100644 --- a/src/world/format/io/region/LegacyAnvilChunkTrait.php +++ b/src/world/format/io/region/LegacyAnvilChunkTrait.php @@ -51,7 +51,7 @@ trait LegacyAnvilChunkTrait{ /** * @throws CorruptedChunkException */ - protected function deserializeChunk(string $data) : ChunkData{ + protected function deserializeChunk(string $data) : ?ChunkData{ $decompressed = @zlib_decode($data); if($decompressed === false){ throw new CorruptedChunkException("Failed to decompress chunk NBT"); diff --git a/src/world/format/io/region/McRegion.php b/src/world/format/io/region/McRegion.php index 3367a2f81..bf1597364 100644 --- a/src/world/format/io/region/McRegion.php +++ b/src/world/format/io/region/McRegion.php @@ -29,6 +29,7 @@ use pocketmine\data\bedrock\BiomeIds; use pocketmine\nbt\BigEndianNbtSerializer; use pocketmine\nbt\NbtDataException; use pocketmine\nbt\tag\ByteArrayTag; +use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntArrayTag; use pocketmine\nbt\tag\ListTag; @@ -45,7 +46,7 @@ class McRegion extends RegionWorldProvider{ /** * @throws CorruptedChunkException */ - protected function deserializeChunk(string $data) : ChunkData{ + protected function deserializeChunk(string $data) : ?ChunkData{ $decompressed = @zlib_decode($data); if($decompressed === false){ throw new CorruptedChunkException("Failed to decompress chunk NBT"); @@ -61,6 +62,14 @@ class McRegion extends RegionWorldProvider{ throw new CorruptedChunkException("'Level' key is missing from chunk NBT"); } + $legacyGeneratedTag = $chunk->getTag("TerrainGenerated"); + if($legacyGeneratedTag instanceof ByteTag && $legacyGeneratedTag->getValue() === 0){ + //In legacy PM before 3.0, PM used to save MCRegion chunks even when they weren't generated. In these cases + //(we'll see them in old worlds), some of the tags which we expect to always be present, will be missing. + //If TerrainGenerated (PM-specific tag from the olden days) is false, toss the chunk data and don't bother + //trying to read it. + return null; + } $subChunks = []; $fullIds = self::readFixedSizeByteArray($chunk, "Blocks", 32768); $fullData = self::readFixedSizeByteArray($chunk, "Data", 16384); diff --git a/src/world/format/io/region/RegionWorldProvider.php b/src/world/format/io/region/RegionWorldProvider.php index df28c3ffe..1fe62912c 100644 --- a/src/world/format/io/region/RegionWorldProvider.php +++ b/src/world/format/io/region/RegionWorldProvider.php @@ -146,7 +146,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{ /** * @throws CorruptedChunkException */ - abstract protected function deserializeChunk(string $data) : ChunkData; + abstract protected function deserializeChunk(string $data) : ?ChunkData; /** * @return CompoundTag[] From eb0cf52d81dfa799f0598cbdbc821114d6c56b5c Mon Sep 17 00:00:00 2001 From: Covered123 <58715544+JavierLeon9966@users.noreply.github.com> Date: Tue, 23 Nov 2021 14:09:33 -0300 Subject: [PATCH 388/710] Remove useless code (#4590) --- src/network/mcpe/convert/ItemTranslator.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index dd1dc9cd2..4aa82f32b 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -74,10 +74,6 @@ final class ItemTranslator{ throw new AssumptionFailedError("Invalid item table format"); } - $legacyStringToIntMapRaw = file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'item_id_map.json')); - if($legacyStringToIntMapRaw === false){ - throw new AssumptionFailedError("Missing required resource file"); - } $legacyStringToIntMap = LegacyItemIdToStringIdMap::getInstance(); /** @phpstan-var array $simpleMappings */ From 5c7125f190ad00c3eddbb65b3bc4dd29d6d56ab2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 23 Nov 2021 17:39:20 +0000 Subject: [PATCH 389/710] Improved error handling for loading broken entity / tile data --- src/block/tile/TileFactory.php | 31 +++++++++-------- src/data/SavedDataLoadingException.php | 28 ++++++++++++++++ src/entity/EntityDataHelper.php | 15 ++++++--- src/entity/EntityFactory.php | 46 ++++++++++++++------------ src/entity/Human.php | 5 +-- src/item/Item.php | 5 ++- src/world/World.php | 6 ++-- 7 files changed, 92 insertions(+), 44 deletions(-) create mode 100644 src/data/SavedDataLoadingException.php diff --git a/src/block/tile/TileFactory.php b/src/block/tile/TileFactory.php index 9c51050fe..f8a6db746 100644 --- a/src/block/tile/TileFactory.php +++ b/src/block/tile/TileFactory.php @@ -23,8 +23,9 @@ declare(strict_types=1); namespace pocketmine\block\tile; +use pocketmine\data\SavedDataLoadingException; use pocketmine\math\Vector3; -use pocketmine\nbt\NbtDataException; +use pocketmine\nbt\NbtException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\utils\SingletonTrait; use pocketmine\utils\Utils; @@ -112,21 +113,25 @@ final class TileFactory{ /** * @internal - * @throws NbtDataException + * @throws SavedDataLoadingException */ public function createFromData(World $world, CompoundTag $nbt) : ?Tile{ - $type = $nbt->getString(Tile::TAG_ID, ""); - if(!isset($this->knownTiles[$type])){ - return null; + try{ + $type = $nbt->getString(Tile::TAG_ID, ""); + if(!isset($this->knownTiles[$type])){ + return null; + } + $class = $this->knownTiles[$type]; + assert(is_a($class, Tile::class, true)); + /** + * @var Tile $tile + * @see Tile::__construct() + */ + $tile = new $class($world, new Vector3($nbt->getInt(Tile::TAG_X), $nbt->getInt(Tile::TAG_Y), $nbt->getInt(Tile::TAG_Z))); + $tile->readSaveData($nbt); + }catch(NbtException $e){ + throw new SavedDataLoadingException($e->getMessage(), 0, $e); } - $class = $this->knownTiles[$type]; - assert(is_a($class, Tile::class, true)); - /** - * @var Tile $tile - * @see Tile::__construct() - */ - $tile = new $class($world, new Vector3($nbt->getInt(Tile::TAG_X), $nbt->getInt(Tile::TAG_Y), $nbt->getInt(Tile::TAG_Z))); - $tile->readSaveData($nbt); return $tile; } diff --git a/src/data/SavedDataLoadingException.php b/src/data/SavedDataLoadingException.php new file mode 100644 index 000000000..fcc72c7ab --- /dev/null +++ b/src/data/SavedDataLoadingException.php @@ -0,0 +1,28 @@ +getTag("Rotation"); if(!($yawPitch instanceof ListTag) or $yawPitch->getTagType() !== NBT::TAG_Float){ - throw new \UnexpectedValueException("'Rotation' should be a List"); + throw new SavedDataLoadingException("'Rotation' should be a List"); } /** @var FloatTag[] $values */ $values = $yawPitch->getValue(); if(count($values) !== 2){ - throw new \UnexpectedValueException("Expected exactly 2 entries for 'Rotation'"); + throw new SavedDataLoadingException("Expected exactly 2 entries for 'Rotation'"); } return Location::fromObject($pos, $world, $values[0]->getValue(), $values[1]->getValue()); } + /** + * @throws SavedDataLoadingException + */ public static function parseVec3(CompoundTag $nbt, string $tagName, bool $optional) : Vector3{ $pos = $nbt->getTag($tagName); if($pos === null and $optional){ return new Vector3(0, 0, 0); } if(!($pos instanceof ListTag) or ($pos->getTagType() !== NBT::TAG_Double && $pos->getTagType() !== NBT::TAG_Float)){ - throw new \UnexpectedValueException("'$tagName' should be a List or List"); + throw new SavedDataLoadingException("'$tagName' should be a List or List"); } /** @var DoubleTag[]|FloatTag[] $values */ $values = $pos->getValue(); if(count($values) !== 3){ - throw new \UnexpectedValueException("Expected exactly 3 entries in '$tagName' tag"); + throw new SavedDataLoadingException("Expected exactly 3 entries in '$tagName' tag"); } return new Vector3($values[0]->getValue(), $values[1]->getValue(), $values[2]->getValue()); } diff --git a/src/entity/EntityFactory.php b/src/entity/EntityFactory.php index 809d32341..0010f0ace 100644 --- a/src/entity/EntityFactory.php +++ b/src/entity/EntityFactory.php @@ -30,6 +30,7 @@ use pocketmine\block\BlockFactory; use pocketmine\data\bedrock\EntityLegacyIds; use pocketmine\data\bedrock\PotionTypeIdMap; use pocketmine\data\bedrock\PotionTypeIds; +use pocketmine\data\SavedDataLoadingException; use pocketmine\entity\object\ExperienceOrb; use pocketmine\entity\object\FallingBlock; use pocketmine\entity\object\ItemEntity; @@ -45,7 +46,7 @@ use pocketmine\entity\projectile\SplashPotion; use pocketmine\item\Item; use pocketmine\math\Facing; use pocketmine\math\Vector3; -use pocketmine\nbt\NbtDataException; +use pocketmine\nbt\NbtException; use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; @@ -113,12 +114,12 @@ final class EntityFactory{ $this->register(ItemEntity::class, function(World $world, CompoundTag $nbt) : ItemEntity{ $itemTag = $nbt->getCompoundTag("Item"); if($itemTag === null){ - throw new \UnexpectedValueException("Expected \"Item\" NBT tag not found"); + throw new SavedDataLoadingException("Expected \"Item\" NBT tag not found"); } $item = Item::nbtDeserialize($itemTag); if($item->isNull()){ - throw new \UnexpectedValueException("Item is invalid"); + throw new SavedDataLoadingException("Item is invalid"); } return new ItemEntity(EntityDataHelper::parseLocation($nbt, $world), $item, $nbt); }, ['Item', 'minecraft:item'], EntityLegacyIds::ITEM); @@ -126,7 +127,7 @@ final class EntityFactory{ $this->register(Painting::class, function(World $world, CompoundTag $nbt) : Painting{ $motive = PaintingMotive::getMotiveByName($nbt->getString("Motive")); if($motive === null){ - throw new \UnexpectedValueException("Unknown painting motive"); + throw new SavedDataLoadingException("Unknown painting motive"); } $blockIn = new Vector3($nbt->getInt("TileX"), $nbt->getInt("TileY"), $nbt->getInt("TileZ")); if(($directionTag = $nbt->getTag("Direction")) instanceof ByteTag){ @@ -134,7 +135,7 @@ final class EntityFactory{ }elseif(($facingTag = $nbt->getTag("Facing")) instanceof ByteTag){ $facing = Painting::DATA_TO_FACING[$facingTag->getValue()] ?? Facing::NORTH; }else{ - throw new \UnexpectedValueException("Missing facing info"); + throw new SavedDataLoadingException("Missing facing info"); } return new Painting(EntityDataHelper::parseLocation($nbt, $world), $blockIn, $facing, $motive, $nbt); @@ -151,7 +152,7 @@ final class EntityFactory{ $this->register(SplashPotion::class, function(World $world, CompoundTag $nbt) : SplashPotion{ $potionType = PotionTypeIdMap::getInstance()->fromId($nbt->getShort("PotionId", PotionTypeIds::WATER)); if($potionType === null){ - throw new \UnexpectedValueException("No such potion type"); + throw new SavedDataLoadingException("No such potion type"); } return new SplashPotion(EntityDataHelper::parseLocation($nbt, $world), null, $potionType, $nbt); }, ['ThrownPotion', 'minecraft:potion', 'thrownpotion'], EntityLegacyIds::SPLASH_POTION); @@ -222,25 +223,28 @@ final class EntityFactory{ /** * Creates an entity from data stored on a chunk. * - * @throws \RuntimeException - * @throws NbtDataException + * @throws SavedDataLoadingException * @internal */ public function createFromData(World $world, CompoundTag $nbt) : ?Entity{ - $saveId = $nbt->getTag("id") ?? $nbt->getTag("identifier"); - $func = null; - if($saveId instanceof StringTag){ - $func = $this->creationFuncs[$saveId->getValue()] ?? null; - }elseif($saveId instanceof IntTag){ //legacy MCPE format - $func = $this->creationFuncs[$saveId->getValue() & 0xff] ?? null; - } - if($func === null){ - return null; - } - /** @var Entity $entity */ - $entity = $func($world, $nbt); + try{ + $saveId = $nbt->getTag("id") ?? $nbt->getTag("identifier"); + $func = null; + if($saveId instanceof StringTag){ + $func = $this->creationFuncs[$saveId->getValue()] ?? null; + }elseif($saveId instanceof IntTag){ //legacy MCPE format + $func = $this->creationFuncs[$saveId->getValue() & 0xff] ?? null; + } + if($func === null){ + return null; + } + /** @var Entity $entity */ + $entity = $func($world, $nbt); - return $entity; + return $entity; + }catch(NbtException $e){ + throw new SavedDataLoadingException($e->getMessage(), 0, $e); + } } public function injectSaveId(string $class, CompoundTag $saveData) : void{ diff --git a/src/entity/Human.php b/src/entity/Human.php index c77de5005..c82cee7f8 100644 --- a/src/entity/Human.php +++ b/src/entity/Human.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\entity; +use pocketmine\data\SavedDataLoadingException; use pocketmine\entity\animation\TotemUseAnimation; use pocketmine\entity\effect\EffectInstance; use pocketmine\entity\effect\VanillaEffects; @@ -104,12 +105,12 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ /** * @throws InvalidSkinException - * @throws \UnexpectedValueException + * @throws SavedDataLoadingException */ public static function parseSkinNBT(CompoundTag $nbt) : Skin{ $skinTag = $nbt->getCompoundTag("Skin"); if($skinTag === null){ - throw new \UnexpectedValueException("Missing skin data"); + throw new SavedDataLoadingException("Missing skin data"); } return new Skin( //this throws if the skin is invalid $skinTag->getString("Name"), diff --git a/src/item/Item.php b/src/item/Item.php index f37015ba9..bceb92142 100644 --- a/src/item/Item.php +++ b/src/item/Item.php @@ -31,6 +31,7 @@ use pocketmine\block\BlockBreakInfo; use pocketmine\block\BlockToolType; use pocketmine\block\VanillaBlocks; use pocketmine\data\bedrock\EnchantmentIdMap; +use pocketmine\data\SavedDataLoadingException; use pocketmine\entity\Entity; use pocketmine\item\enchantment\EnchantmentInstance; use pocketmine\math\Vector3; @@ -671,6 +672,8 @@ class Item implements \JsonSerializable{ /** * Deserializes an Item from an NBT CompoundTag + * @throws NbtException + * @throws SavedDataLoadingException */ public static function nbtDeserialize(CompoundTag $tag) : Item{ if($tag->getTag("id") === null or $tag->getTag("Count") === null){ @@ -692,7 +695,7 @@ class Item implements \JsonSerializable{ } $item->setCount($count); }else{ - throw new \InvalidArgumentException("Item CompoundTag ID must be an instance of StringTag or ShortTag, " . get_class($idTag) . " given"); + throw new SavedDataLoadingException("Item CompoundTag ID must be an instance of StringTag or ShortTag, " . get_class($idTag) . " given"); } $itemNBT = $tag->getCompoundTag("tag"); diff --git a/src/world/World.php b/src/world/World.php index dcd27805c..9549980eb 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -36,6 +36,7 @@ use pocketmine\block\tile\TileFactory; use pocketmine\block\UnknownBlock; use pocketmine\block\VanillaBlocks; use pocketmine\data\bedrock\BiomeIds; +use pocketmine\data\SavedDataLoadingException; use pocketmine\entity\Entity; use pocketmine\entity\EntityFactory; use pocketmine\entity\Location; @@ -57,7 +58,6 @@ use pocketmine\item\LegacyStringToItemParser; use pocketmine\lang\KnownTranslationFactory; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector3; -use pocketmine\nbt\NbtDataException; use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; @@ -2472,7 +2472,7 @@ class World implements ChunkManager{ foreach($chunkData->getEntityNBT() as $k => $nbt){ try{ $entity = $entityFactory->createFromData($this, $nbt); - }catch(NbtDataException $e){ + }catch(SavedDataLoadingException $e){ $logger->error("Bad entity data at list position $k: " . $e->getMessage()); $logger->logException($e); continue; @@ -2500,7 +2500,7 @@ class World implements ChunkManager{ foreach($chunkData->getTileNBT() as $k => $nbt){ try{ $tile = $tileFactory->createFromData($this, $nbt); - }catch(NbtDataException $e){ + }catch(SavedDataLoadingException $e){ $logger->error("Bad tile entity data at list position $k: " . $e->getMessage()); $logger->logException($e); continue; From b784a04e08392bef51cd87d2d4eff736c2d25f22 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 24 Nov 2021 16:38:37 +0000 Subject: [PATCH 390/710] Utils: fixed parseDocComment() ignoring tags containing hyphens --- src/utils/Utils.php | 2 +- tests/phpunit/utils/UtilsTest.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/utils/Utils.php b/src/utils/Utils.php index 6f9500125..d761f772f 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -506,7 +506,7 @@ final class Utils{ if($rawDocComment === false){ //usually empty doc comment, but this is safer and statically analysable return []; } - preg_match_all('/(*ANYCRLF)^[\t ]*(?:\* )?@([a-zA-Z]+)(?:[\t ]+(.+?))?[\t ]*$/m', $rawDocComment, $matches); + preg_match_all('/(*ANYCRLF)^[\t ]*(?:\* )?@([a-zA-Z\-]+)(?:[\t ]+(.+?))?[\t ]*$/m', $rawDocComment, $matches); return array_combine($matches[1], $matches[2]); } diff --git a/tests/phpunit/utils/UtilsTest.php b/tests/phpunit/utils/UtilsTest.php index 80fe84a45..7a8448815 100644 --- a/tests/phpunit/utils/UtilsTest.php +++ b/tests/phpunit/utils/UtilsTest.php @@ -90,6 +90,12 @@ class UtilsTest extends TestCase{ self::assertCount(0, $tags); } + public function testParseDocCommentWithTagsContainingHyphens() : void{ + $tags = Utils::parseDocComment("/** @phpstan-return list */"); + self::assertArrayHasKey("phpstan-return", $tags); + self::assertEquals("list", $tags["phpstan-return"]); + } + public function testNamespacedNiceClosureName() : void{ //be careful with this test. The closure has to be declared on the same line as the assertion. self::assertSame('closure@' . Filesystem::cleanPath(__FILE__) . '#L' . __LINE__, Utils::getNiceClosureName(function() : void{})); From 726c5652f7ae26bde54f6e59b33888a391fa298e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 24 Nov 2021 17:07:34 +0000 Subject: [PATCH 391/710] ScriptPluginLoader: fixed reading @tags from non-docblock lines preceding the first docblock --- src/pocketmine/plugin/ScriptPluginLoader.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/plugin/ScriptPluginLoader.php b/src/pocketmine/plugin/ScriptPluginLoader.php index ea9d4c22d..5f8b083bf 100644 --- a/src/pocketmine/plugin/ScriptPluginLoader.php +++ b/src/pocketmine/plugin/ScriptPluginLoader.php @@ -64,8 +64,12 @@ class ScriptPluginLoader implements PluginLoader{ $insideHeader = false; foreach($content as $line){ - if(!$insideHeader and strpos($line, "/**") !== false){ - $insideHeader = true; + if(!$insideHeader){ + if(strpos($line, "/**") !== false){ + $insideHeader = true; + }else{ + continue; + } } if(preg_match("/^[ \t]+\\*[ \t]+@([a-zA-Z]+)([ \t]+(.*))?$/", $line, $matches) > 0){ @@ -79,7 +83,7 @@ class ScriptPluginLoader implements PluginLoader{ $data[$key] = $content; } - if($insideHeader and strpos($line, "*/") !== false){ + if(strpos($line, "*/") !== false){ break; } } From 472ffb28ff9e934833aadf84d3ed0693a631a3b7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 24 Nov 2021 17:22:49 +0000 Subject: [PATCH 392/710] ScriptPluginLoader: use parseDocComment() instead of reinventing the wheel --- src/pocketmine/plugin/ScriptPluginLoader.php | 24 ++++++++------------ tests/phpstan/configs/phpstan-bugs.neon | 5 ++++ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/pocketmine/plugin/ScriptPluginLoader.php b/src/pocketmine/plugin/ScriptPluginLoader.php index 5f8b083bf..f446be72c 100644 --- a/src/pocketmine/plugin/ScriptPluginLoader.php +++ b/src/pocketmine/plugin/ScriptPluginLoader.php @@ -23,13 +23,14 @@ declare(strict_types=1); namespace pocketmine\plugin; +use pocketmine\utils\Utils; +use function count; use function file; +use function implode; use function is_file; -use function preg_match; use function strlen; use function strpos; use function substr; -use function trim; use const FILE_IGNORE_NEW_LINES; use const FILE_SKIP_EMPTY_LINES; @@ -60,9 +61,9 @@ class ScriptPluginLoader implements PluginLoader{ return null; } - $data = []; - $insideHeader = false; + + $docCommentLines = []; foreach($content as $line){ if(!$insideHeader){ if(strpos($line, "/**") !== false){ @@ -72,22 +73,15 @@ class ScriptPluginLoader implements PluginLoader{ } } - if(preg_match("/^[ \t]+\\*[ \t]+@([a-zA-Z]+)([ \t]+(.*))?$/", $line, $matches) > 0){ - $key = $matches[1]; - $content = trim($matches[3] ?? ""); - - if($key === "notscript"){ - return null; - } - - $data[$key] = $content; - } + $docCommentLines[] = $line; if(strpos($line, "*/") !== false){ break; } } - if($insideHeader){ + + $data = Utils::parseDocComment(implode("\n", $docCommentLines)); + if(count($data) !== 0){ return new PluginDescription($data); } diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index fdc5a57df..cc4842e75 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -80,6 +80,11 @@ parameters: count: 1 path: ../../../src/pocketmine/network/mcpe/protocol/DataPacket.php + - + message: "#^Parameter \\#1 \\$yamlString of class pocketmine\\\\plugin\\\\PluginDescription constructor expects array\\|string, array\\ given\\.$#" + count: 1 + path: ../../../src/pocketmine/plugin/ScriptPluginLoader.php + - message: "#^Dead catch \\- ReflectionException is never thrown in the try block\\.$#" count: 2 From ad56392d959e9d4eefb1cdae4bc659eac7ae2e1f Mon Sep 17 00:00:00 2001 From: Colin Date: Wed, 24 Nov 2021 22:42:51 +0100 Subject: [PATCH 393/710] Skull: fixed calculation of collision boxes (#4591) --- src/block/Skull.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/block/Skull.php b/src/block/Skull.php index 6ee2e77f4..47476abce 100644 --- a/src/block/Skull.php +++ b/src/block/Skull.php @@ -124,8 +124,14 @@ class Skull extends Flowable{ * @return AxisAlignedBB[] */ protected function recalculateCollisionBoxes() : array{ - //TODO: different bounds depending on attached face - return [AxisAlignedBB::one()->contract(0.25, 0, 0.25)->trim(Facing::UP, 0.5)]; + $collisionBox = AxisAlignedBB::one()->contract(0.25, 0, 0.25)->trim(Facing::UP, 0.5); + return match($this->facing){ + Facing::NORTH => [$collisionBox->offset(0, 0.25, 0.25)], + Facing::SOUTH => [$collisionBox->offset(0, 0.25, -0.25)], + Facing::WEST => [$collisionBox->offset(0.25, 0.25, 0)], + Facing::EAST => [$collisionBox->offset(-0.25, 0.25, 0)], + default => [$collisionBox] + }; } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ From adff561483f137468a22714e4cf054502990d3af Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 24 Nov 2021 23:40:54 +0000 Subject: [PATCH 394/710] phpstan: go nuclear on OPcache when using dynamic reflection (which is the default), any time static reflection comes into play, bad shit starts to happen because of FileReadTrapStreamWrapper. I attempted to fix these issues (phpstan/phpstan-src#801) and failed miserably. So, to save the hassle, it's time to just remove OPcache from the picture (which, unfortunately, also means that PHPStan will not benefit from JIT). --- tests/phpstan/bootstrap.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/phpstan/bootstrap.php b/tests/phpstan/bootstrap.php index 8073199f0..7e374a27f 100644 --- a/tests/phpstan/bootstrap.php +++ b/tests/phpstan/bootstrap.php @@ -33,3 +33,6 @@ define('pocketmine\GIT_COMMIT', str_repeat('00', 20)); define('pocketmine\PLUGIN_PATH', ''); define('pocketmine\START_TIME', microtime(true)); define('pocketmine\VERSION', '9.9.9'); + +//opcache breaks PHPStan when dynamic reflection is used - see https://github.com/phpstan/phpstan-src/pull/801#issuecomment-978431013 +ini_set('opcache.enable', 'off'); From fad96b77ceeae86a5b92ab7ba9cf37b5e80d8202 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 24 Nov 2021 23:49:56 +0000 Subject: [PATCH 395/710] stfu --- tests/phpstan/configs/phpstan-bugs.neon | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 8baae94f1..5b91ae748 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -40,6 +40,11 @@ parameters: count: 1 path: ../../../src/plugin/PluginManager.php + - + message: "#^Parameter \\#1 \\$yamlString of class pocketmine\\\\plugin\\\\PluginDescription constructor expects array\\|string, array\\ given\\.$#" + count: 1 + path: ../../../src/plugin/ScriptPluginLoader.php + - message: "#^Strict comparison using \\=\\=\\= between string and false will always evaluate to false\\.$#" count: 1 From bb7683158f8ac1cbe6930a27e5c9d3d9c8ef33d5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 24 Nov 2021 23:52:51 +0000 Subject: [PATCH 396/710] Remove dead ignoreErrors patterns --- tests/phpstan/configs/actual-problems.neon | 20 -------------------- tests/phpstan/configs/phpstan-bugs.neon | 10 ---------- 2 files changed, 30 deletions(-) diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index badcc3e0e..a9c45db8b 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -465,16 +465,6 @@ parameters: count: 1 path: ../../../src/command/SimpleCommandMap.php - - - message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#" - count: 1 - path: ../../../src/command/defaults/BanIpCommand.php - - - - message: "#^Only booleans are allowed in an if condition, int\\|false given\\.$#" - count: 1 - path: ../../../src/command/defaults/PardonIpCommand.php - - message: "#^Cannot call method addParticle\\(\\) on pocketmine\\\\world\\\\World\\|null\\.$#" count: 1 @@ -515,11 +505,6 @@ parameters: count: 1 path: ../../../src/command/defaults/TimingsCommand.php - - - message: "#^Property pocketmine\\\\console\\\\ConsoleReader\\:\\:\\$stdin \\(resource\\) does not accept resource\\|false\\.$#" - count: 1 - path: ../../../src/console/ConsoleReader.php - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" count: 1 @@ -1450,11 +1435,6 @@ parameters: count: 2 path: ../../../src/world/light/SkyLightUpdate.php - - - message: "#^Cannot call method getSubChunks\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" - count: 1 - path: ../../../src/world/light/SkyLightUpdate.php - - message: "#^Cannot call method setHeightMap\\(\\) on pocketmine\\\\world\\\\format\\\\Chunk\\|null\\.$#" count: 2 diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 5b91ae748..0d98c3677 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -5,11 +5,6 @@ parameters: count: 1 path: ../../../src/block/BaseBanner.php - - - message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#" - count: 2 - path: ../../../src/console/ConsoleReader.php - - message: "#^Method pocketmine\\\\crafting\\\\CraftingManager\\:\\:getDestructorCallbacks\\(\\) should return pocketmine\\\\utils\\\\ObjectSet\\ but returns pocketmine\\\\utils\\\\ObjectSet\\\\|pocketmine\\\\utils\\\\ObjectSet\\\\.$#" count: 1 @@ -20,11 +15,6 @@ parameters: count: 1 path: ../../../src/crafting/CraftingManager.php - - - message: "#^Property pocketmine\\\\crash\\\\CrashDumpData\\:\\:\\$extensions \\(array\\\\) does not accept array\\\\.$#" - count: 1 - path: ../../../src/crash/CrashDump.php - - message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#" count: 1 From c023c02b6cb93af684b999ffb8acb302b58e21d7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 24 Nov 2021 23:57:55 +0000 Subject: [PATCH 397/710] MemoryManager: Removed obsolete workaround for $GLOBALS not being defined on threads this was long since fixed, and everyone has since been forced to upgrade to pthreads 4.0.0, which definitely has the fix. --- phpstan.neon.dist | 1 - src/pocketmine/MemoryManager.php | 44 +++++++++++------------- tests/phpstan/configs/pthreads-bugs.neon | 7 ---- 3 files changed, 21 insertions(+), 31 deletions(-) delete mode 100644 tests/phpstan/configs/pthreads-bugs.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 6b559cd86..8ad20ab63 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -4,7 +4,6 @@ includes: - tests/phpstan/configs/php-bugs.neon - tests/phpstan/configs/phpstan-bugs.neon - tests/phpstan/configs/phpunit-wiring-tests.neon - - tests/phpstan/configs/pthreads-bugs.neon - tests/phpstan/configs/runtime-type-checks.neon - tests/phpstan/configs/spl-fixed-array-sucks.neon - vendor/phpstan/phpstan-phpunit/extension.neon diff --git a/src/pocketmine/MemoryManager.php b/src/pocketmine/MemoryManager.php index ec31d9181..e7b56fb5f 100644 --- a/src/pocketmine/MemoryManager.php +++ b/src/pocketmine/MemoryManager.php @@ -353,35 +353,33 @@ class MemoryManager{ file_put_contents($outputFolder . "/staticProperties.js", json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); $logger->info("[Dump] Wrote $staticCount static properties"); - if(isset($GLOBALS)){ //This might be null if we're on a different thread - $globalVariables = []; - $globalCount = 0; + $globalVariables = []; + $globalCount = 0; - $ignoredGlobals = [ - 'GLOBALS' => true, - '_SERVER' => true, - '_REQUEST' => true, - '_POST' => true, - '_GET' => true, - '_FILES' => true, - '_ENV' => true, - '_COOKIE' => true, - '_SESSION' => true - ]; + $ignoredGlobals = [ + 'GLOBALS' => true, + '_SERVER' => true, + '_REQUEST' => true, + '_POST' => true, + '_GET' => true, + '_FILES' => true, + '_ENV' => true, + '_COOKIE' => true, + '_SESSION' => true + ]; - foreach($GLOBALS as $varName => $value){ - if(isset($ignoredGlobals[$varName])){ - continue; - } - - $globalCount++; - $globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize); + foreach($GLOBALS as $varName => $value){ + if(isset($ignoredGlobals[$varName])){ + continue; } - file_put_contents($outputFolder . "/globalVariables.js", json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); - $logger->info("[Dump] Wrote $globalCount global variables"); + $globalCount++; + $globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize); } + file_put_contents($outputFolder . "/globalVariables.js", json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + $logger->info("[Dump] Wrote $globalCount global variables"); + $data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize); do{ diff --git a/tests/phpstan/configs/pthreads-bugs.neon b/tests/phpstan/configs/pthreads-bugs.neon deleted file mode 100644 index e9e5e535b..000000000 --- a/tests/phpstan/configs/pthreads-bugs.neon +++ /dev/null @@ -1,7 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Variable \\$GLOBALS in isset\\(\\) always exists and is not nullable\\.$#" - count: 1 - path: ../../../src/pocketmine/MemoryManager.php - From 9338d427429393f701f2b506178434cf46ed5023 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 25 Nov 2021 00:40:40 +0000 Subject: [PATCH 398/710] Release 4.0.0-BETA13 --- changelogs/4.0.md | 39 ++++++++++++++++++++++++++++++++++++++- src/VersionInfo.php | 2 +- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 12fa5c9a6..c7038c96c 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1710,4 +1710,41 @@ Released 9th November 2021. ### Server - Added the following API methods: - `Server->getIpV6()` - - `Server->getPortV6()` \ No newline at end of file + - `Server->getPortV6()` + +# 4.0.0-BETA13 +Released 25th November 2021. + +## General +- Improved error messages when a plugin command name or alias contains an illegal character. +- Fixed script plugins reading tags from non-docblocks before the actual docblock. +- Added a sanity check to `Human->setCurrentTotalXp()` to try and catch an elusive bug that's been appearing in the wild - please get in touch if you know how to reproduce it! +- Updated `BUILDING.md` to reflect the fact that submodules are no longer required to build or run the server. + +## Internals +- Crashdump rendering has been separated from crashdump data generation. This allows rendering crashdumps from existing JSON data. +- Direct iteration of arrays with string keys is now disallowed by a custom PHPStan rule. This is because numeric strings are casted to integers when used as array keys, which produces a variety of unexpected behaviour particularly for iteration. + - To iterate on arrays with string keys, `Utils::stringifyKeys()` must now be used. + +## Fixes +- Fixed various crashes involving bad entity data saved on disk (e.g. an item entity with invalid item would crash the server). +- Fixed various crashes involving arrays with numeric string keys. +- Fixed crash when players try to pickup XP while already having max XP. +- Fixed ungenerated chunks saved on disk by old versions of PocketMine-MP (before 3.0.0) being treated as corrupted during world conversion (they are now ignored instead). +- Fixed misleading corruption error message when saved chunks have missing NBT tags. + +## Gameplay +- Fixed `/setworldspawn` setting incorrect positions based on player position when in negative coordinates. +- `/setworldspawn` now accepts relative coordinates when used as a player. +- Added some extra aliases for `/give` and `/clear`: `chipped_anvil`, `coarse_dirt`, `damaged_anvil`, `dark_oak_standing_sign`, `jungle_wood_stairs`, `jungle_wooden_stairs` and `oak_standing_sign`. + - Some of these were added for quality-of-life, others were added just to be consistent. +- Fixed explosions dropping incorrect items when destroying blocks with tile data (e.g. banners, beds). +- Fixed the bounding box of skulls when mounted on a wall. +- Fixed podzol dropping itself when mined (instead of dirt). + +## API +### Entity +- `Projectile->move()` is now protected, like its parent. + +### Utils +- `Utils::parseDocComment()` now allows `-` in tag names. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index ee4366762..f4c221c3f 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -30,7 +30,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA13"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From 7dd5d0b59333417ba90967b1e0f8cb44e97386a2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 25 Nov 2021 00:40:43 +0000 Subject: [PATCH 399/710] 4.0.0-BETA14 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index f4c221c3f..b44c7856e 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -29,8 +29,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA13"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA14"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_NUMBER = 0; public const BUILD_CHANNEL = "beta"; From 5556861000563db6bd1108b6d782292ca3ef746f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 00:46:21 +0000 Subject: [PATCH 400/710] ItemFactory: move SweetBerries registration to the correct place --- src/item/ItemFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/item/ItemFactory.php b/src/item/ItemFactory.php index 0e1a710ce..95622b4e9 100644 --- a/src/item/ItemFactory.php +++ b/src/item/ItemFactory.php @@ -252,6 +252,7 @@ class ItemFactory{ $this->register(new Steak(new ItemIdentifier(ItemIds::STEAK, 0), "Steak")); $this->register(new Stick(new ItemIdentifier(ItemIds::STICK, 0), "Stick")); $this->register(new StringItem(new ItemIdentifier(ItemIds::STRING, 0), "String")); + $this->register(new SweetBerries(new ItemIdentifier(ItemIds::SWEET_BERRIES, 0), "Sweet Berries")); $this->register(new Totem(new ItemIdentifier(ItemIds::TOTEM, 0), "Totem of Undying")); $this->register(new WheatSeeds(new ItemIdentifier(ItemIds::WHEAT_SEEDS, 0), "Wheat Seeds")); $this->register(new WritableBook(new ItemIdentifier(ItemIds::WRITABLE_BOOK, 0), "Book & Quill")); @@ -327,7 +328,6 @@ class ItemFactory{ //TODO: minecraft:shield //TODO: minecraft:sparkler //TODO: minecraft:spawn_egg - $this->register(new SweetBerries(new ItemIdentifier(ItemIds::SWEET_BERRIES, 0), "Sweet Berries")); //TODO: minecraft:tnt_minecart //TODO: minecraft:trident //TODO: minecraft:turtle_helmet From 1bc7869f6e17d68785e33503a97128953b5fade0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 01:58:52 +0000 Subject: [PATCH 401/710] Added remapping for almost 4000 invalid blockstates when a block has sole ownership of an ID, the state bitmask can be ignored and we can just claim the whole metadata range for that single block. This fixes a large number of issues with unknown blocks on older worlds where world editors did not remove the metadata, although update blocks will currently still appear on initial chunk send due to lack of AOT conversion (TODO). --- src/block/BlockFactory.php | 664 +++++++++--------- .../block_factory_consistency_check.json | 2 +- 2 files changed, 338 insertions(+), 328 deletions(-) diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index 70077b71a..fd252f789 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -105,86 +105,86 @@ class BlockFactory{ $this->blastResistance = \SplFixedArray::fromArray(array_fill(0, 1024 << Block::INTERNAL_METADATA_BITS, 0.0)); $railBreakInfo = new BlockBreakInfo(0.7); - $this->register(new ActivatorRail(new BID(Ids::ACTIVATOR_RAIL, 0), "Activator Rail", $railBreakInfo)); - $this->register(new Air(new BID(Ids::AIR, 0), "Air", BlockBreakInfo::indestructible(-1.0))); - $this->register(new Anvil(new BID(Ids::ANVIL, 0), "Anvil", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0))); - $this->register(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new BlockBreakInfo(2.0 /* 1.0 in PC */, BlockToolType::AXE))); - $this->register(new BambooSapling(new BID(Ids::BAMBOO_SAPLING, 0), "Bamboo Sapling", BlockBreakInfo::instant())); + $this->registerAllMeta(new ActivatorRail(new BID(Ids::ACTIVATOR_RAIL, 0), "Activator Rail", $railBreakInfo)); + $this->registerAllMeta(new Air(new BID(Ids::AIR, 0), "Air", BlockBreakInfo::indestructible(-1.0))); + $this->registerAllMeta(new Anvil(new BID(Ids::ANVIL, 0), "Anvil", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0))); + $this->registerAllMeta(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new BlockBreakInfo(2.0 /* 1.0 in PC */, BlockToolType::AXE))); + $this->registerAllMeta(new BambooSapling(new BID(Ids::BAMBOO_SAPLING, 0), "Bamboo Sapling", BlockBreakInfo::instant())); $bannerBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE); - $this->register(new FloorBanner(new BID(Ids::STANDING_BANNER, 0, ItemIds::BANNER, TileBanner::class), "Banner", $bannerBreakInfo)); - $this->register(new WallBanner(new BID(Ids::WALL_BANNER, 0, ItemIds::BANNER, TileBanner::class), "Wall Banner", $bannerBreakInfo)); - $this->register(new Barrel(new BID(Ids::BARREL, 0, null, TileBarrel::class), "Barrel", new BlockBreakInfo(2.5, BlockToolType::AXE))); - $this->register(new Transparent(new BID(Ids::BARRIER, 0), "Barrier", BlockBreakInfo::indestructible())); - $this->register(new Beacon(new BID(Ids::BEACON, 0, null, TileBeacon::class), "Beacon", new BlockBreakInfo(3.0))); - $this->register(new Bed(new BID(Ids::BED_BLOCK, 0, ItemIds::BED, TileBed::class), "Bed Block", new BlockBreakInfo(0.2))); - $this->register(new Bedrock(new BID(Ids::BEDROCK, 0), "Bedrock", BlockBreakInfo::indestructible())); + $this->registerAllMeta(new FloorBanner(new BID(Ids::STANDING_BANNER, 0, ItemIds::BANNER, TileBanner::class), "Banner", $bannerBreakInfo)); + $this->registerAllMeta(new WallBanner(new BID(Ids::WALL_BANNER, 0, ItemIds::BANNER, TileBanner::class), "Wall Banner", $bannerBreakInfo)); + $this->registerAllMeta(new Barrel(new BID(Ids::BARREL, 0, null, TileBarrel::class), "Barrel", new BlockBreakInfo(2.5, BlockToolType::AXE))); + $this->registerAllMeta(new Transparent(new BID(Ids::BARRIER, 0), "Barrier", BlockBreakInfo::indestructible())); + $this->registerAllMeta(new Beacon(new BID(Ids::BEACON, 0, null, TileBeacon::class), "Beacon", new BlockBreakInfo(3.0))); + $this->registerAllMeta(new Bed(new BID(Ids::BED_BLOCK, 0, ItemIds::BED, TileBed::class), "Bed Block", new BlockBreakInfo(0.2))); + $this->registerAllMeta(new Bedrock(new BID(Ids::BEDROCK, 0), "Bedrock", BlockBreakInfo::indestructible())); - $this->register(new Beetroot(new BID(Ids::BEETROOT_BLOCK, 0), "Beetroot Block", BlockBreakInfo::instant())); - $this->register(new Bell(new BID(Ids::BELL, 0, null, TileBell::class), "Bell", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new BlueIce(new BID(Ids::BLUE_ICE, 0), "Blue Ice", new BlockBreakInfo(2.8, BlockToolType::PICKAXE))); - $this->register(new BoneBlock(new BID(Ids::BONE_BLOCK, 0), "Bone Block", new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new Bookshelf(new BID(Ids::BOOKSHELF, 0), "Bookshelf", new BlockBreakInfo(1.5, BlockToolType::AXE))); - $this->register(new BrewingStand(new BID(Ids::BREWING_STAND_BLOCK, 0, ItemIds::BREWING_STAND, TileBrewingStand::class), "Brewing Stand", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Beetroot(new BID(Ids::BEETROOT_BLOCK, 0), "Beetroot Block", BlockBreakInfo::instant())); + $this->registerAllMeta(new Bell(new BID(Ids::BELL, 0, null, TileBell::class), "Bell", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new BlueIce(new BID(Ids::BLUE_ICE, 0), "Blue Ice", new BlockBreakInfo(2.8, BlockToolType::PICKAXE))); + $this->registerAllMeta(new BoneBlock(new BID(Ids::BONE_BLOCK, 0), "Bone Block", new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Bookshelf(new BID(Ids::BOOKSHELF, 0), "Bookshelf", new BlockBreakInfo(1.5, BlockToolType::AXE))); + $this->registerAllMeta(new BrewingStand(new BID(Ids::BREWING_STAND_BLOCK, 0, ItemIds::BREWING_STAND, TileBrewingStand::class), "Brewing Stand", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); $bricksBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); - $this->register(new Stair(new BID(Ids::BRICK_STAIRS, 0), "Brick Stairs", $bricksBreakInfo)); - $this->register(new Opaque(new BID(Ids::BRICK_BLOCK, 0), "Bricks", $bricksBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::BRICK_STAIRS, 0), "Brick Stairs", $bricksBreakInfo)); + $this->registerAllMeta(new Opaque(new BID(Ids::BRICK_BLOCK, 0), "Bricks", $bricksBreakInfo)); - $this->register(new BrownMushroom(new BID(Ids::BROWN_MUSHROOM, 0), "Brown Mushroom", BlockBreakInfo::instant())); - $this->register(new Cactus(new BID(Ids::CACTUS, 0), "Cactus", new BlockBreakInfo(0.4))); - $this->register(new Cake(new BID(Ids::CAKE_BLOCK, 0, ItemIds::CAKE), "Cake", new BlockBreakInfo(0.5))); - $this->register(new Carrot(new BID(Ids::CARROTS, 0), "Carrot Block", BlockBreakInfo::instant())); + $this->registerAllMeta(new BrownMushroom(new BID(Ids::BROWN_MUSHROOM, 0), "Brown Mushroom", BlockBreakInfo::instant())); + $this->registerAllMeta(new Cactus(new BID(Ids::CACTUS, 0), "Cactus", new BlockBreakInfo(0.4))); + $this->registerAllMeta(new Cake(new BID(Ids::CAKE_BLOCK, 0, ItemIds::CAKE), "Cake", new BlockBreakInfo(0.5))); + $this->registerAllMeta(new Carrot(new BID(Ids::CARROTS, 0), "Carrot Block", BlockBreakInfo::instant())); $chestBreakInfo = new BlockBreakInfo(2.5, BlockToolType::AXE); - $this->register(new Chest(new BID(Ids::CHEST, 0, null, TileChest::class), "Chest", $chestBreakInfo)); - $this->register(new Clay(new BID(Ids::CLAY_BLOCK, 0), "Clay Block", new BlockBreakInfo(0.6, BlockToolType::SHOVEL))); - $this->register(new Coal(new BID(Ids::COAL_BLOCK, 0), "Coal Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0))); - $this->register(new CoalOre(new BID(Ids::COAL_ORE, 0), "Coal Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Chest(new BID(Ids::CHEST, 0, null, TileChest::class), "Chest", $chestBreakInfo)); + $this->registerAllMeta(new Clay(new BID(Ids::CLAY_BLOCK, 0), "Clay Block", new BlockBreakInfo(0.6, BlockToolType::SHOVEL))); + $this->registerAllMeta(new Coal(new BID(Ids::COAL_BLOCK, 0), "Coal Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0))); + $this->registerAllMeta(new CoalOre(new BID(Ids::COAL_ORE, 0), "Coal Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); $cobblestoneBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); - $this->register($cobblestone = new Opaque(new BID(Ids::COBBLESTONE, 0), "Cobblestone", $cobblestoneBreakInfo)); + $this->registerAllMeta($cobblestone = new Opaque(new BID(Ids::COBBLESTONE, 0), "Cobblestone", $cobblestoneBreakInfo)); $infestedStoneBreakInfo = new BlockBreakInfo(0.75); $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_COBBLESTONE), "Infested Cobblestone", $infestedStoneBreakInfo, $cobblestone)); - $this->register(new Opaque(new BID(Ids::MOSSY_COBBLESTONE, 0), "Mossy Cobblestone", $cobblestoneBreakInfo)); - $this->register(new Stair(new BID(Ids::COBBLESTONE_STAIRS, 0), "Cobblestone Stairs", $cobblestoneBreakInfo)); - $this->register(new Stair(new BID(Ids::MOSSY_COBBLESTONE_STAIRS, 0), "Mossy Cobblestone Stairs", $cobblestoneBreakInfo)); + $this->registerAllMeta(new Opaque(new BID(Ids::MOSSY_COBBLESTONE, 0), "Mossy Cobblestone", $cobblestoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::COBBLESTONE_STAIRS, 0), "Cobblestone Stairs", $cobblestoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::MOSSY_COBBLESTONE_STAIRS, 0), "Mossy Cobblestone Stairs", $cobblestoneBreakInfo)); - $this->register(new Cobweb(new BID(Ids::COBWEB, 0), "Cobweb", new BlockBreakInfo(4.0, BlockToolType::SWORD | BlockToolType::SHEARS, 1))); - $this->register(new CocoaBlock(new BID(Ids::COCOA, 0), "Cocoa Block", new BlockBreakInfo(0.2, BlockToolType::AXE, 0, 15.0))); - $this->register(new CoralBlock(new BID(Ids::CORAL_BLOCK, 0), "Coral Block", new BlockBreakInfo(7.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new CraftingTable(new BID(Ids::CRAFTING_TABLE, 0), "Crafting Table", new BlockBreakInfo(2.5, BlockToolType::AXE))); - $this->register(new DaylightSensor(new BIDFlattened(Ids::DAYLIGHT_DETECTOR, [Ids::DAYLIGHT_DETECTOR_INVERTED], 0, null, TileDaylightSensor::class), "Daylight Sensor", new BlockBreakInfo(0.2, BlockToolType::AXE))); - $this->register(new DeadBush(new BID(Ids::DEADBUSH, 0), "Dead Bush", BlockBreakInfo::instant(BlockToolType::SHEARS, 1))); - $this->register(new DetectorRail(new BID(Ids::DETECTOR_RAIL, 0), "Detector Rail", $railBreakInfo)); + $this->registerAllMeta(new Cobweb(new BID(Ids::COBWEB, 0), "Cobweb", new BlockBreakInfo(4.0, BlockToolType::SWORD | BlockToolType::SHEARS, 1))); + $this->registerAllMeta(new CocoaBlock(new BID(Ids::COCOA, 0), "Cocoa Block", new BlockBreakInfo(0.2, BlockToolType::AXE, 0, 15.0))); + $this->registerAllMeta(new CoralBlock(new BID(Ids::CORAL_BLOCK, 0), "Coral Block", new BlockBreakInfo(7.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new CraftingTable(new BID(Ids::CRAFTING_TABLE, 0), "Crafting Table", new BlockBreakInfo(2.5, BlockToolType::AXE))); + $this->registerAllMeta(new DaylightSensor(new BIDFlattened(Ids::DAYLIGHT_DETECTOR, [Ids::DAYLIGHT_DETECTOR_INVERTED], 0, null, TileDaylightSensor::class), "Daylight Sensor", new BlockBreakInfo(0.2, BlockToolType::AXE))); + $this->registerAllMeta(new DeadBush(new BID(Ids::DEADBUSH, 0), "Dead Bush", BlockBreakInfo::instant(BlockToolType::SHEARS, 1))); + $this->registerAllMeta(new DetectorRail(new BID(Ids::DETECTOR_RAIL, 0), "Detector Rail", $railBreakInfo)); - $this->register(new Opaque(new BID(Ids::DIAMOND_BLOCK, 0), "Diamond Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0))); - $this->register(new DiamondOre(new BID(Ids::DIAMOND_ORE, 0), "Diamond Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel()))); - $this->register(new Dirt(new BID(Ids::DIRT, 0), "Dirt", new BlockBreakInfo(0.5, BlockToolType::SHOVEL))); + $this->registerAllMeta(new Opaque(new BID(Ids::DIAMOND_BLOCK, 0), "Diamond Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0))); + $this->registerAllMeta(new DiamondOre(new BID(Ids::DIAMOND_ORE, 0), "Diamond Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel()))); + $this->registerAllMeta(new Dirt(new BID(Ids::DIRT, 0), "Dirt", new BlockBreakInfo(0.5, BlockToolType::SHOVEL))); $this->register(new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_SUNFLOWER), "Sunflower", BlockBreakInfo::instant())); $this->register(new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LILAC), "Lilac", BlockBreakInfo::instant())); $this->register(new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_ROSE_BUSH), "Rose Bush", BlockBreakInfo::instant())); $this->register(new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_PEONY), "Peony", BlockBreakInfo::instant())); $this->register(new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_TALLGRASS), "Double Tallgrass", BlockBreakInfo::instant(BlockToolType::SHEARS, 1))); $this->register(new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LARGE_FERN), "Large Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1))); - $this->register(new DragonEgg(new BID(Ids::DRAGON_EGG, 0), "Dragon Egg", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new DriedKelp(new BID(Ids::DRIED_KELP_BLOCK, 0), "Dried Kelp Block", new BlockBreakInfo(0.5, BlockToolType::NONE, 0, 12.5))); - $this->register(new Opaque(new BID(Ids::EMERALD_BLOCK, 0), "Emerald Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0))); - $this->register(new EmeraldOre(new BID(Ids::EMERALD_ORE, 0), "Emerald Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel()))); - $this->register(new EnchantingTable(new BID(Ids::ENCHANTING_TABLE, 0, null, TileEnchantingTable::class), "Enchanting Table", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0))); - $this->register(new EndPortalFrame(new BID(Ids::END_PORTAL_FRAME, 0), "End Portal Frame", BlockBreakInfo::indestructible())); - $this->register(new EndRod(new BID(Ids::END_ROD, 0), "End Rod", BlockBreakInfo::instant())); - $this->register(new Opaque(new BID(Ids::END_STONE, 0), "End Stone", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 45.0))); + $this->registerAllMeta(new DragonEgg(new BID(Ids::DRAGON_EGG, 0), "Dragon Egg", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new DriedKelp(new BID(Ids::DRIED_KELP_BLOCK, 0), "Dried Kelp Block", new BlockBreakInfo(0.5, BlockToolType::NONE, 0, 12.5))); + $this->registerAllMeta(new Opaque(new BID(Ids::EMERALD_BLOCK, 0), "Emerald Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0))); + $this->registerAllMeta(new EmeraldOre(new BID(Ids::EMERALD_ORE, 0), "Emerald Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel()))); + $this->registerAllMeta(new EnchantingTable(new BID(Ids::ENCHANTING_TABLE, 0, null, TileEnchantingTable::class), "Enchanting Table", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0))); + $this->registerAllMeta(new EndPortalFrame(new BID(Ids::END_PORTAL_FRAME, 0), "End Portal Frame", BlockBreakInfo::indestructible())); + $this->registerAllMeta(new EndRod(new BID(Ids::END_ROD, 0), "End Rod", BlockBreakInfo::instant())); + $this->registerAllMeta(new Opaque(new BID(Ids::END_STONE, 0), "End Stone", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 45.0))); $endBrickBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 4.0); - $this->register(new Opaque(new BID(Ids::END_BRICKS, 0), "End Stone Bricks", $endBrickBreakInfo)); - $this->register(new Stair(new BID(Ids::END_BRICK_STAIRS, 0), "End Stone Brick Stairs", $endBrickBreakInfo)); + $this->registerAllMeta(new Opaque(new BID(Ids::END_BRICKS, 0), "End Stone Bricks", $endBrickBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::END_BRICK_STAIRS, 0), "End Stone Brick Stairs", $endBrickBreakInfo)); - $this->register(new EnderChest(new BID(Ids::ENDER_CHEST, 0, null, TileEnderChest::class), "Ender Chest", new BlockBreakInfo(22.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 3000.0))); - $this->register(new Farmland(new BID(Ids::FARMLAND, 0), "Farmland", new BlockBreakInfo(0.6, BlockToolType::SHOVEL))); - $this->register(new Fire(new BID(Ids::FIRE, 0), "Fire Block", BlockBreakInfo::instant())); - $this->register(new FletchingTable(new BID(Ids::FLETCHING_TABLE, 0), "Fletching Table", new BlockBreakInfo(2.5, BlockToolType::AXE, 0, 2.5))); - $this->register(new Flower(new BID(Ids::DANDELION, 0), "Dandelion", BlockBreakInfo::instant())); + $this->registerAllMeta(new EnderChest(new BID(Ids::ENDER_CHEST, 0, null, TileEnderChest::class), "Ender Chest", new BlockBreakInfo(22.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 3000.0))); + $this->registerAllMeta(new Farmland(new BID(Ids::FARMLAND, 0), "Farmland", new BlockBreakInfo(0.6, BlockToolType::SHOVEL))); + $this->registerAllMeta(new Fire(new BID(Ids::FIRE, 0), "Fire Block", BlockBreakInfo::instant())); + $this->registerAllMeta(new FletchingTable(new BID(Ids::FLETCHING_TABLE, 0), "Fletching Table", new BlockBreakInfo(2.5, BlockToolType::AXE, 0, 2.5))); + $this->registerAllMeta(new Flower(new BID(Ids::DANDELION, 0), "Dandelion", BlockBreakInfo::instant())); $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ALLIUM), "Allium", BlockBreakInfo::instant())); $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_AZURE_BLUET), "Azure Bluet", BlockBreakInfo::instant())); $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_BLUE_ORCHID), "Blue Orchid", BlockBreakInfo::instant())); @@ -196,141 +196,133 @@ class BlockFactory{ $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_POPPY), "Poppy", BlockBreakInfo::instant())); $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_RED_TULIP), "Red Tulip", BlockBreakInfo::instant())); $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_WHITE_TULIP), "White Tulip", BlockBreakInfo::instant())); - - $flowerPot = new FlowerPot(new BID(Ids::FLOWER_POT_BLOCK, 0, ItemIds::FLOWER_POT, TileFlowerPot::class), "Flower Pot", BlockBreakInfo::instant()); - $this->register($flowerPot); - for($meta = 1; $meta < 16; ++$meta){ - $this->remap(Ids::FLOWER_POT_BLOCK, $meta, $flowerPot); - } - $this->register(new FrostedIce(new BID(Ids::FROSTED_ICE, 0), "Frosted Ice", new BlockBreakInfo(2.5, BlockToolType::PICKAXE))); - $this->register(new Furnace(new BIDFlattened(Ids::FURNACE, [Ids::LIT_FURNACE], 0, null, TileNormalFurnace::class), "Furnace", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new Furnace(new BIDFlattened(Ids::BLAST_FURNACE, [Ids::LIT_BLAST_FURNACE], 0, null, TileBlastFurnace::class), "Blast Furnace", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new Furnace(new BIDFlattened(Ids::SMOKER, [Ids::LIT_SMOKER], 0, null, TileSmoker::class), "Smoker", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new FlowerPot(new BID(Ids::FLOWER_POT_BLOCK, 0, ItemIds::FLOWER_POT, TileFlowerPot::class), "Flower Pot", BlockBreakInfo::instant())); + $this->registerAllMeta(new FrostedIce(new BID(Ids::FROSTED_ICE, 0), "Frosted Ice", new BlockBreakInfo(2.5, BlockToolType::PICKAXE))); + $this->registerAllMeta(new Furnace(new BIDFlattened(Ids::FURNACE, [Ids::LIT_FURNACE], 0, null, TileNormalFurnace::class), "Furnace", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Furnace(new BIDFlattened(Ids::BLAST_FURNACE, [Ids::LIT_BLAST_FURNACE], 0, null, TileBlastFurnace::class), "Blast Furnace", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Furnace(new BIDFlattened(Ids::SMOKER, [Ids::LIT_SMOKER], 0, null, TileSmoker::class), "Smoker", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); $glassBreakInfo = new BlockBreakInfo(0.3); - $this->register(new Glass(new BID(Ids::GLASS, 0), "Glass", $glassBreakInfo)); - $this->register(new GlassPane(new BID(Ids::GLASS_PANE, 0), "Glass Pane", $glassBreakInfo)); - $this->register(new GlowingObsidian(new BID(Ids::GLOWINGOBSIDIAN, 0), "Glowing Obsidian", new BlockBreakInfo(10.0, BlockToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 50.0))); - $this->register(new Glowstone(new BID(Ids::GLOWSTONE, 0), "Glowstone", new BlockBreakInfo(0.3, BlockToolType::PICKAXE))); - $this->register(new Opaque(new BID(Ids::GOLD_BLOCK, 0), "Gold Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0))); - $this->register(new Opaque(new BID(Ids::GOLD_ORE, 0), "Gold Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel()))); + $this->registerAllMeta(new Glass(new BID(Ids::GLASS, 0), "Glass", $glassBreakInfo)); + $this->registerAllMeta(new GlassPane(new BID(Ids::GLASS_PANE, 0), "Glass Pane", $glassBreakInfo)); + $this->registerAllMeta(new GlowingObsidian(new BID(Ids::GLOWINGOBSIDIAN, 0), "Glowing Obsidian", new BlockBreakInfo(10.0, BlockToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 50.0))); + $this->registerAllMeta(new Glowstone(new BID(Ids::GLOWSTONE, 0), "Glowstone", new BlockBreakInfo(0.3, BlockToolType::PICKAXE))); + $this->registerAllMeta(new Opaque(new BID(Ids::GOLD_BLOCK, 0), "Gold Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0))); + $this->registerAllMeta(new Opaque(new BID(Ids::GOLD_ORE, 0), "Gold Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel()))); $grassBreakInfo = new BlockBreakInfo(0.6, BlockToolType::SHOVEL); - $this->register(new Grass(new BID(Ids::GRASS, 0), "Grass", $grassBreakInfo)); - $this->register(new GrassPath(new BID(Ids::GRASS_PATH, 0), "Grass Path", $grassBreakInfo)); - $this->register(new Gravel(new BID(Ids::GRAVEL, 0), "Gravel", new BlockBreakInfo(0.6, BlockToolType::SHOVEL))); + $this->registerAllMeta(new Grass(new BID(Ids::GRASS, 0), "Grass", $grassBreakInfo)); + $this->registerAllMeta(new GrassPath(new BID(Ids::GRASS_PATH, 0), "Grass Path", $grassBreakInfo)); + $this->registerAllMeta(new Gravel(new BID(Ids::GRAVEL, 0), "Gravel", new BlockBreakInfo(0.6, BlockToolType::SHOVEL))); $hardenedClayBreakInfo = new BlockBreakInfo(1.25, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 21.0); - $this->register(new HardenedClay(new BID(Ids::HARDENED_CLAY, 0), "Hardened Clay", $hardenedClayBreakInfo)); + $this->registerAllMeta(new HardenedClay(new BID(Ids::HARDENED_CLAY, 0), "Hardened Clay", $hardenedClayBreakInfo)); $hardenedGlassBreakInfo = new BlockBreakInfo(10.0); - $this->register(new HardenedGlass(new BID(Ids::HARD_GLASS, 0), "Hardened Glass", $hardenedGlassBreakInfo)); - $this->register(new HardenedGlassPane(new BID(Ids::HARD_GLASS_PANE, 0), "Hardened Glass Pane", $hardenedGlassBreakInfo)); - $this->register(new HayBale(new BID(Ids::HAY_BALE, 0), "Hay Bale", new BlockBreakInfo(0.5))); - $this->register(new Hopper(new BID(Ids::HOPPER_BLOCK, 0, ItemIds::HOPPER, TileHopper::class), "Hopper", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 15.0))); - $this->register(new Ice(new BID(Ids::ICE, 0), "Ice", new BlockBreakInfo(0.5, BlockToolType::PICKAXE))); + $this->registerAllMeta(new HardenedGlass(new BID(Ids::HARD_GLASS, 0), "Hardened Glass", $hardenedGlassBreakInfo)); + $this->registerAllMeta(new HardenedGlassPane(new BID(Ids::HARD_GLASS_PANE, 0), "Hardened Glass Pane", $hardenedGlassBreakInfo)); + $this->registerAllMeta(new HayBale(new BID(Ids::HAY_BALE, 0), "Hay Bale", new BlockBreakInfo(0.5))); + $this->registerAllMeta(new Hopper(new BID(Ids::HOPPER_BLOCK, 0, ItemIds::HOPPER, TileHopper::class), "Hopper", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 15.0))); + $this->registerAllMeta(new Ice(new BID(Ids::ICE, 0), "Ice", new BlockBreakInfo(0.5, BlockToolType::PICKAXE))); $updateBlockBreakInfo = new BlockBreakInfo(1.0); - $this->register(new Opaque(new BID(Ids::INFO_UPDATE, 0), "update!", $updateBlockBreakInfo)); - $this->register(new Opaque(new BID(Ids::INFO_UPDATE2, 0), "ate!upd", $updateBlockBreakInfo)); - $this->register(new Transparent(new BID(Ids::INVISIBLEBEDROCK, 0), "Invisible Bedrock", BlockBreakInfo::indestructible())); + $this->registerAllMeta(new Opaque(new BID(Ids::INFO_UPDATE, 0), "update!", $updateBlockBreakInfo)); + $this->registerAllMeta(new Opaque(new BID(Ids::INFO_UPDATE2, 0), "ate!upd", $updateBlockBreakInfo)); + $this->registerAllMeta(new Transparent(new BID(Ids::INVISIBLEBEDROCK, 0), "Invisible Bedrock", BlockBreakInfo::indestructible())); $ironBreakInfo = new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel(), 30.0); - $this->register(new Opaque(new BID(Ids::IRON_BLOCK, 0), "Iron Block", $ironBreakInfo)); - $this->register(new Thin(new BID(Ids::IRON_BARS, 0), "Iron Bars", $ironBreakInfo)); + $this->registerAllMeta(new Opaque(new BID(Ids::IRON_BLOCK, 0), "Iron Block", $ironBreakInfo)); + $this->registerAllMeta(new Thin(new BID(Ids::IRON_BARS, 0), "Iron Bars", $ironBreakInfo)); $ironDoorBreakInfo = new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 25.0); - $this->register(new Door(new BID(Ids::IRON_DOOR_BLOCK, 0, ItemIds::IRON_DOOR), "Iron Door", $ironDoorBreakInfo)); - $this->register(new Trapdoor(new BID(Ids::IRON_TRAPDOOR, 0), "Iron Trapdoor", $ironDoorBreakInfo)); - $this->register(new Opaque(new BID(Ids::IRON_ORE, 0), "Iron Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel()))); - $this->register(new ItemFrame(new BID(Ids::FRAME_BLOCK, 0, ItemIds::FRAME, TileItemFrame::class), "Item Frame", new BlockBreakInfo(0.25))); - $this->register(new Jukebox(new BID(Ids::JUKEBOX, 0, ItemIds::JUKEBOX, TileJukebox::class), "Jukebox", new BlockBreakInfo(0.8, BlockToolType::AXE))); //TODO: in PC the hardness is 2.0, not 0.8, unsure if this is a MCPE bug or not - $this->register(new Ladder(new BID(Ids::LADDER, 0), "Ladder", new BlockBreakInfo(0.4, BlockToolType::AXE))); - $this->register(new Lantern(new BID(Ids::LANTERN, 0), "Lantern", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new Opaque(new BID(Ids::LAPIS_BLOCK, 0), "Lapis Lazuli Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel()))); - $this->register(new LapisOre(new BID(Ids::LAPIS_ORE, 0), "Lapis Lazuli Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel()))); - $this->register(new Lava(new BIDFlattened(Ids::FLOWING_LAVA, [Ids::STILL_LAVA], 0), "Lava", BlockBreakInfo::indestructible(500.0))); - $this->register(new Lever(new BID(Ids::LEVER, 0), "Lever", new BlockBreakInfo(0.5))); - $this->register(new Loom(new BID(Ids::LOOM, 0), "Loom", new BlockBreakInfo(2.5, BlockToolType::AXE))); - $this->register(new Magma(new BID(Ids::MAGMA, 0), "Magma Block", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new Melon(new BID(Ids::MELON_BLOCK, 0), "Melon Block", new BlockBreakInfo(1.0, BlockToolType::AXE))); - $this->register(new MelonStem(new BID(Ids::MELON_STEM, 0, ItemIds::MELON_SEEDS), "Melon Stem", BlockBreakInfo::instant())); - $this->register(new MonsterSpawner(new BID(Ids::MOB_SPAWNER, 0, null, TileMonsterSpawner::class), "Monster Spawner", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new Mycelium(new BID(Ids::MYCELIUM, 0), "Mycelium", new BlockBreakInfo(0.6, BlockToolType::SHOVEL))); + $this->registerAllMeta(new Door(new BID(Ids::IRON_DOOR_BLOCK, 0, ItemIds::IRON_DOOR), "Iron Door", $ironDoorBreakInfo)); + $this->registerAllMeta(new Trapdoor(new BID(Ids::IRON_TRAPDOOR, 0), "Iron Trapdoor", $ironDoorBreakInfo)); + $this->registerAllMeta(new Opaque(new BID(Ids::IRON_ORE, 0), "Iron Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel()))); + $this->registerAllMeta(new ItemFrame(new BID(Ids::FRAME_BLOCK, 0, ItemIds::FRAME, TileItemFrame::class), "Item Frame", new BlockBreakInfo(0.25))); + $this->registerAllMeta(new Jukebox(new BID(Ids::JUKEBOX, 0, ItemIds::JUKEBOX, TileJukebox::class), "Jukebox", new BlockBreakInfo(0.8, BlockToolType::AXE))); //TODO: in PC the hardness is 2.0, not 0.8, unsure if this is a MCPE bug or not + $this->registerAllMeta(new Ladder(new BID(Ids::LADDER, 0), "Ladder", new BlockBreakInfo(0.4, BlockToolType::AXE))); + $this->registerAllMeta(new Lantern(new BID(Ids::LANTERN, 0), "Lantern", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Opaque(new BID(Ids::LAPIS_BLOCK, 0), "Lapis Lazuli Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel()))); + $this->registerAllMeta(new LapisOre(new BID(Ids::LAPIS_ORE, 0), "Lapis Lazuli Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel()))); + $this->registerAllMeta(new Lava(new BIDFlattened(Ids::FLOWING_LAVA, [Ids::STILL_LAVA], 0), "Lava", BlockBreakInfo::indestructible(500.0))); + $this->registerAllMeta(new Lever(new BID(Ids::LEVER, 0), "Lever", new BlockBreakInfo(0.5))); + $this->registerAllMeta(new Loom(new BID(Ids::LOOM, 0), "Loom", new BlockBreakInfo(2.5, BlockToolType::AXE))); + $this->registerAllMeta(new Magma(new BID(Ids::MAGMA, 0), "Magma Block", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Melon(new BID(Ids::MELON_BLOCK, 0), "Melon Block", new BlockBreakInfo(1.0, BlockToolType::AXE))); + $this->registerAllMeta(new MelonStem(new BID(Ids::MELON_STEM, 0, ItemIds::MELON_SEEDS), "Melon Stem", BlockBreakInfo::instant())); + $this->registerAllMeta(new MonsterSpawner(new BID(Ids::MOB_SPAWNER, 0, null, TileMonsterSpawner::class), "Monster Spawner", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Mycelium(new BID(Ids::MYCELIUM, 0), "Mycelium", new BlockBreakInfo(0.6, BlockToolType::SHOVEL))); $netherBrickBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); - $this->register(new Opaque(new BID(Ids::NETHER_BRICK_BLOCK, 0), "Nether Bricks", $netherBrickBreakInfo)); - $this->register(new Opaque(new BID(Ids::RED_NETHER_BRICK, 0), "Red Nether Bricks", $netherBrickBreakInfo)); - $this->register(new Fence(new BID(Ids::NETHER_BRICK_FENCE, 0), "Nether Brick Fence", $netherBrickBreakInfo)); - $this->register(new Stair(new BID(Ids::NETHER_BRICK_STAIRS, 0), "Nether Brick Stairs", $netherBrickBreakInfo)); - $this->register(new Stair(new BID(Ids::RED_NETHER_BRICK_STAIRS, 0), "Red Nether Brick Stairs", $netherBrickBreakInfo)); - $this->register(new NetherPortal(new BID(Ids::PORTAL, 0), "Nether Portal", BlockBreakInfo::indestructible(0.0))); - $this->register(new NetherQuartzOre(new BID(Ids::NETHER_QUARTZ_ORE, 0), "Nether Quartz Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new NetherReactor(new BID(Ids::NETHERREACTOR, 0), "Nether Reactor Core", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BlockBreakInfo(1.0))); - $this->register(new NetherWartPlant(new BID(Ids::NETHER_WART_PLANT, 0, ItemIds::NETHER_WART), "Nether Wart", BlockBreakInfo::instant())); - $this->register(new Netherrack(new BID(Ids::NETHERRACK, 0), "Netherrack", new BlockBreakInfo(0.4, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new Note(new BID(Ids::NOTEBLOCK, 0, null, TileNote::class), "Note Block", new BlockBreakInfo(0.8, BlockToolType::AXE))); - $this->register(new Opaque(new BID(Ids::OBSIDIAN, 0), "Obsidian", new BlockBreakInfo(35.0 /* 50 in PC */, BlockToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 6000.0))); - $this->register(new PackedIce(new BID(Ids::PACKED_ICE, 0), "Packed Ice", new BlockBreakInfo(0.5, BlockToolType::PICKAXE))); - $this->register(new Podzol(new BID(Ids::PODZOL, 0), "Podzol", new BlockBreakInfo(0.5, BlockToolType::SHOVEL))); - $this->register(new Potato(new BID(Ids::POTATOES, 0), "Potato Block", BlockBreakInfo::instant())); - $this->register(new PoweredRail(new BID(Ids::GOLDEN_RAIL, Meta::RAIL_STRAIGHT_NORTH_SOUTH), "Powered Rail", $railBreakInfo)); + $this->registerAllMeta(new Opaque(new BID(Ids::NETHER_BRICK_BLOCK, 0), "Nether Bricks", $netherBrickBreakInfo)); + $this->registerAllMeta(new Opaque(new BID(Ids::RED_NETHER_BRICK, 0), "Red Nether Bricks", $netherBrickBreakInfo)); + $this->registerAllMeta(new Fence(new BID(Ids::NETHER_BRICK_FENCE, 0), "Nether Brick Fence", $netherBrickBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::NETHER_BRICK_STAIRS, 0), "Nether Brick Stairs", $netherBrickBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::RED_NETHER_BRICK_STAIRS, 0), "Red Nether Brick Stairs", $netherBrickBreakInfo)); + $this->registerAllMeta(new NetherPortal(new BID(Ids::PORTAL, 0), "Nether Portal", BlockBreakInfo::indestructible(0.0))); + $this->registerAllMeta(new NetherQuartzOre(new BID(Ids::NETHER_QUARTZ_ORE, 0), "Nether Quartz Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new NetherReactor(new BID(Ids::NETHERREACTOR, 0), "Nether Reactor Core", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BlockBreakInfo(1.0))); + $this->registerAllMeta(new NetherWartPlant(new BID(Ids::NETHER_WART_PLANT, 0, ItemIds::NETHER_WART), "Nether Wart", BlockBreakInfo::instant())); + $this->registerAllMeta(new Netherrack(new BID(Ids::NETHERRACK, 0), "Netherrack", new BlockBreakInfo(0.4, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Note(new BID(Ids::NOTEBLOCK, 0, null, TileNote::class), "Note Block", new BlockBreakInfo(0.8, BlockToolType::AXE))); + $this->registerAllMeta(new Opaque(new BID(Ids::OBSIDIAN, 0), "Obsidian", new BlockBreakInfo(35.0 /* 50 in PC */, BlockToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 6000.0))); + $this->registerAllMeta(new PackedIce(new BID(Ids::PACKED_ICE, 0), "Packed Ice", new BlockBreakInfo(0.5, BlockToolType::PICKAXE))); + $this->registerAllMeta(new Podzol(new BID(Ids::PODZOL, 0), "Podzol", new BlockBreakInfo(0.5, BlockToolType::SHOVEL))); + $this->registerAllMeta(new Potato(new BID(Ids::POTATOES, 0), "Potato Block", BlockBreakInfo::instant())); + $this->registerAllMeta(new PoweredRail(new BID(Ids::GOLDEN_RAIL, 0), "Powered Rail", $railBreakInfo)); $prismarineBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); $this->register(new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_BRICKS), "Prismarine Bricks", $prismarineBreakInfo)); - $this->register(new Stair(new BID(Ids::PRISMARINE_BRICKS_STAIRS, 0), "Prismarine Bricks Stairs", $prismarineBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::PRISMARINE_BRICKS_STAIRS, 0), "Prismarine Bricks Stairs", $prismarineBreakInfo)); $this->register(new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_DARK), "Dark Prismarine", $prismarineBreakInfo)); - $this->register(new Stair(new BID(Ids::DARK_PRISMARINE_STAIRS, 0), "Dark Prismarine Stairs", $prismarineBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::DARK_PRISMARINE_STAIRS, 0), "Dark Prismarine Stairs", $prismarineBreakInfo)); $this->register(new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_NORMAL), "Prismarine", $prismarineBreakInfo)); - $this->register(new Stair(new BID(Ids::PRISMARINE_STAIRS, 0), "Prismarine Stairs", $prismarineBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::PRISMARINE_STAIRS, 0), "Prismarine Stairs", $prismarineBreakInfo)); $pumpkinBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE); - $this->register($pumpkin = new Opaque(new BID(Ids::PUMPKIN, 0), "Pumpkin", $pumpkinBreakInfo)); - for($i = 1; $i <= 3; ++$i){ - $this->remap(Ids::PUMPKIN, $i, $pumpkin); - } - $this->register(new CarvedPumpkin(new BID(Ids::CARVED_PUMPKIN, 0), "Carved Pumpkin", $pumpkinBreakInfo)); - $this->register(new LitPumpkin(new BID(Ids::JACK_O_LANTERN, 0), "Jack o'Lantern", $pumpkinBreakInfo)); + $this->registerAllMeta($pumpkin = new Opaque(new BID(Ids::PUMPKIN, 0), "Pumpkin", $pumpkinBreakInfo)); + $this->registerAllMeta(new CarvedPumpkin(new BID(Ids::CARVED_PUMPKIN, 0), "Carved Pumpkin", $pumpkinBreakInfo)); + $this->registerAllMeta(new LitPumpkin(new BID(Ids::JACK_O_LANTERN, 0), "Jack o'Lantern", $pumpkinBreakInfo)); - $this->register(new PumpkinStem(new BID(Ids::PUMPKIN_STEM, 0, ItemIds::PUMPKIN_SEEDS), "Pumpkin Stem", BlockBreakInfo::instant())); + $this->registerAllMeta(new PumpkinStem(new BID(Ids::PUMPKIN_STEM, 0, ItemIds::PUMPKIN_SEEDS), "Pumpkin Stem", BlockBreakInfo::instant())); $purpurBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); $this->register(new Opaque(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_NORMAL), "Purpur Block", $purpurBreakInfo)); $this->register(new SimplePillar(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_PILLAR), "Purpur Pillar", $purpurBreakInfo)); - $this->register(new Stair(new BID(Ids::PURPUR_STAIRS, 0), "Purpur Stairs", $purpurBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::PURPUR_STAIRS, 0), "Purpur Stairs", $purpurBreakInfo)); $quartzBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()); $this->register(new Opaque(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_NORMAL), "Quartz Block", $quartzBreakInfo)); - $this->register(new Stair(new BID(Ids::QUARTZ_STAIRS, 0), "Quartz Stairs", $quartzBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::QUARTZ_STAIRS, 0), "Quartz Stairs", $quartzBreakInfo)); $this->register(new SimplePillar(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_CHISELED), "Chiseled Quartz Block", $quartzBreakInfo)); $this->register(new SimplePillar(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_PILLAR), "Quartz Pillar", $quartzBreakInfo)); $this->register(new Opaque(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_SMOOTH), "Smooth Quartz Block", $quartzBreakInfo)); //TODO: this has axis rotation in 1.9, unsure if a bug (https://bugs.mojang.com/browse/MCPE-39074) - $this->register(new Stair(new BID(Ids::SMOOTH_QUARTZ_STAIRS, 0), "Smooth Quartz Stairs", $quartzBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_QUARTZ_STAIRS, 0), "Smooth Quartz Stairs", $quartzBreakInfo)); - $this->register(new Rail(new BID(Ids::RAIL, 0), "Rail", $railBreakInfo)); - $this->register(new RedMushroom(new BID(Ids::RED_MUSHROOM, 0), "Red Mushroom", BlockBreakInfo::instant())); - $this->register(new Redstone(new BID(Ids::REDSTONE_BLOCK, 0), "Redstone Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0))); - $this->register(new RedstoneComparator(new BIDFlattened(Ids::UNPOWERED_COMPARATOR, [Ids::POWERED_COMPARATOR], 0, ItemIds::COMPARATOR, TileComparator::class), "Redstone Comparator", BlockBreakInfo::instant())); - $this->register(new RedstoneLamp(new BIDFlattened(Ids::REDSTONE_LAMP, [Ids::LIT_REDSTONE_LAMP], 0), "Redstone Lamp", new BlockBreakInfo(0.3))); - $this->register(new RedstoneOre(new BIDFlattened(Ids::REDSTONE_ORE, [Ids::LIT_REDSTONE_ORE], 0), "Redstone Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel()))); - $this->register(new RedstoneRepeater(new BIDFlattened(Ids::UNPOWERED_REPEATER, [Ids::POWERED_REPEATER], 0, ItemIds::REPEATER), "Redstone Repeater", BlockBreakInfo::instant())); - $this->register(new RedstoneTorch(new BIDFlattened(Ids::REDSTONE_TORCH, [Ids::UNLIT_REDSTONE_TORCH], 0), "Redstone Torch", BlockBreakInfo::instant())); - $this->register(new RedstoneWire(new BID(Ids::REDSTONE_WIRE, 0, ItemIds::REDSTONE), "Redstone", BlockBreakInfo::instant())); - $this->register(new Reserved6(new BID(Ids::RESERVED6, 0), "reserved6", BlockBreakInfo::instant())); + $this->registerAllMeta(new Rail(new BID(Ids::RAIL, 0), "Rail", $railBreakInfo)); + $this->registerAllMeta(new RedMushroom(new BID(Ids::RED_MUSHROOM, 0), "Red Mushroom", BlockBreakInfo::instant())); + $this->registerAllMeta(new Redstone(new BID(Ids::REDSTONE_BLOCK, 0), "Redstone Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0))); + $this->registerAllMeta(new RedstoneComparator(new BIDFlattened(Ids::UNPOWERED_COMPARATOR, [Ids::POWERED_COMPARATOR], 0, ItemIds::COMPARATOR, TileComparator::class), "Redstone Comparator", BlockBreakInfo::instant())); + $this->registerAllMeta(new RedstoneLamp(new BIDFlattened(Ids::REDSTONE_LAMP, [Ids::LIT_REDSTONE_LAMP], 0), "Redstone Lamp", new BlockBreakInfo(0.3))); + $this->registerAllMeta(new RedstoneOre(new BIDFlattened(Ids::REDSTONE_ORE, [Ids::LIT_REDSTONE_ORE], 0), "Redstone Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel()))); + $this->registerAllMeta(new RedstoneRepeater(new BIDFlattened(Ids::UNPOWERED_REPEATER, [Ids::POWERED_REPEATER], 0, ItemIds::REPEATER), "Redstone Repeater", BlockBreakInfo::instant())); + $this->registerAllMeta(new RedstoneTorch(new BIDFlattened(Ids::REDSTONE_TORCH, [Ids::UNLIT_REDSTONE_TORCH], 0), "Redstone Torch", BlockBreakInfo::instant())); + $this->registerAllMeta(new RedstoneWire(new BID(Ids::REDSTONE_WIRE, 0, ItemIds::REDSTONE), "Redstone", BlockBreakInfo::instant())); + $this->registerAllMeta(new Reserved6(new BID(Ids::RESERVED6, 0), "reserved6", BlockBreakInfo::instant())); $sandBreakInfo = new BlockBreakInfo(0.5, BlockToolType::SHOVEL); $this->register(new Sand(new BID(Ids::SAND, 0), "Sand", $sandBreakInfo)); $this->register(new Sand(new BID(Ids::SAND, 1), "Red Sand", $sandBreakInfo)); - $this->register(new SeaLantern(new BID(Ids::SEALANTERN, 0), "Sea Lantern", new BlockBreakInfo(0.3))); - $this->register(new SeaPickle(new BID(Ids::SEA_PICKLE, 0), "Sea Pickle", BlockBreakInfo::instant())); - $this->register(new Skull(new BID(Ids::MOB_HEAD_BLOCK, 0, ItemIds::SKULL, TileSkull::class), "Mob Head", new BlockBreakInfo(1.0))); - $this->register(new Slime(new BID(Ids::SLIME, 0), "Slime Block", BlockBreakInfo::instant())); - $this->register(new Snow(new BID(Ids::SNOW, 0), "Snow Block", new BlockBreakInfo(0.2, BlockToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new SnowLayer(new BID(Ids::SNOW_LAYER, 0), "Snow Layer", new BlockBreakInfo(0.1, BlockToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new SoulSand(new BID(Ids::SOUL_SAND, 0), "Soul Sand", new BlockBreakInfo(0.5, BlockToolType::SHOVEL))); - $this->register(new Sponge(new BID(Ids::SPONGE, 0), "Sponge", new BlockBreakInfo(0.6, BlockToolType::HOE))); + $this->registerAllMeta(new SeaLantern(new BID(Ids::SEALANTERN, 0), "Sea Lantern", new BlockBreakInfo(0.3))); + $this->registerAllMeta(new SeaPickle(new BID(Ids::SEA_PICKLE, 0), "Sea Pickle", BlockBreakInfo::instant())); + $this->registerAllMeta(new Skull(new BID(Ids::MOB_HEAD_BLOCK, 0, ItemIds::SKULL, TileSkull::class), "Mob Head", new BlockBreakInfo(1.0))); + $this->registerAllMeta(new Slime(new BID(Ids::SLIME, 0), "Slime Block", BlockBreakInfo::instant())); + $this->registerAllMeta(new Snow(new BID(Ids::SNOW, 0), "Snow Block", new BlockBreakInfo(0.2, BlockToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new SnowLayer(new BID(Ids::SNOW_LAYER, 0), "Snow Layer", new BlockBreakInfo(0.1, BlockToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new SoulSand(new BID(Ids::SOUL_SAND, 0), "Soul Sand", new BlockBreakInfo(0.5, BlockToolType::SHOVEL))); + $this->registerAllMeta(new Sponge(new BID(Ids::SPONGE, 0), "Sponge", new BlockBreakInfo(0.6, BlockToolType::HOE))); $shulkerBoxBreakInfo = new BlockBreakInfo(2, BlockToolType::PICKAXE); - $this->register(new ShulkerBox(new BID(Ids::UNDYED_SHULKER_BOX, 0, null, TileShulkerBox::class), "Shulker Box", $shulkerBoxBreakInfo)); + $this->registerAllMeta(new ShulkerBox(new BID(Ids::UNDYED_SHULKER_BOX, 0, null, TileShulkerBox::class), "Shulker Box", $shulkerBoxBreakInfo)); $stoneBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); $this->register($stone = new class(new BID(Ids::STONE, Meta::STONE_NORMAL), "Stone", $stoneBreakInfo) extends Opaque{ @@ -343,32 +335,32 @@ class BlockFactory{ } }); $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE), "Infested Stone", $infestedStoneBreakInfo, $stone)); - $this->register(new Stair(new BID(Ids::NORMAL_STONE_STAIRS, 0), "Stone Stairs", $stoneBreakInfo)); - $this->register(new Opaque(new BID(Ids::SMOOTH_STONE, 0), "Smooth Stone", $stoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::NORMAL_STONE_STAIRS, 0), "Stone Stairs", $stoneBreakInfo)); + $this->registerAllMeta(new Opaque(new BID(Ids::SMOOTH_STONE, 0), "Smooth Stone", $stoneBreakInfo)); $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_ANDESITE), "Andesite", $stoneBreakInfo)); - $this->register(new Stair(new BID(Ids::ANDESITE_STAIRS, 0), "Andesite Stairs", $stoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::ANDESITE_STAIRS, 0), "Andesite Stairs", $stoneBreakInfo)); $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_DIORITE), "Diorite", $stoneBreakInfo)); - $this->register(new Stair(new BID(Ids::DIORITE_STAIRS, 0), "Diorite Stairs", $stoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::DIORITE_STAIRS, 0), "Diorite Stairs", $stoneBreakInfo)); $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_GRANITE), "Granite", $stoneBreakInfo)); - $this->register(new Stair(new BID(Ids::GRANITE_STAIRS, 0), "Granite Stairs", $stoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::GRANITE_STAIRS, 0), "Granite Stairs", $stoneBreakInfo)); $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_POLISHED_ANDESITE), "Polished Andesite", $stoneBreakInfo)); - $this->register(new Stair(new BID(Ids::POLISHED_ANDESITE_STAIRS, 0), "Polished Andesite Stairs", $stoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::POLISHED_ANDESITE_STAIRS, 0), "Polished Andesite Stairs", $stoneBreakInfo)); $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_POLISHED_DIORITE), "Polished Diorite", $stoneBreakInfo)); - $this->register(new Stair(new BID(Ids::POLISHED_DIORITE_STAIRS, 0), "Polished Diorite Stairs", $stoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::POLISHED_DIORITE_STAIRS, 0), "Polished Diorite Stairs", $stoneBreakInfo)); $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_POLISHED_GRANITE), "Polished Granite", $stoneBreakInfo)); - $this->register(new Stair(new BID(Ids::POLISHED_GRANITE_STAIRS, 0), "Polished Granite Stairs", $stoneBreakInfo)); - $this->register(new Stair(new BID(Ids::STONE_BRICK_STAIRS, 0), "Stone Brick Stairs", $stoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::POLISHED_GRANITE_STAIRS, 0), "Polished Granite Stairs", $stoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::STONE_BRICK_STAIRS, 0), "Stone Brick Stairs", $stoneBreakInfo)); $this->register($chiseledStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CHISELED), "Chiseled Stone Bricks", $stoneBreakInfo)); $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK_CHISELED), "Infested Chiseled Stone Brick", $infestedStoneBreakInfo, $chiseledStoneBrick)); $this->register($crackedStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CRACKED), "Cracked Stone Bricks", $stoneBreakInfo)); $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK_CRACKED), "Infested Cracked Stone Brick", $infestedStoneBreakInfo, $crackedStoneBrick)); $this->register($mossyStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_MOSSY), "Mossy Stone Bricks", $stoneBreakInfo)); $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK_MOSSY), "Infested Mossy Stone Brick", $infestedStoneBreakInfo, $mossyStoneBrick)); - $this->register(new Stair(new BID(Ids::MOSSY_STONE_BRICK_STAIRS, 0), "Mossy Stone Brick Stairs", $stoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::MOSSY_STONE_BRICK_STAIRS, 0), "Mossy Stone Brick Stairs", $stoneBreakInfo)); $this->register($stoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_NORMAL), "Stone Bricks", $stoneBreakInfo)); $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK), "Infested Stone Brick", $infestedStoneBreakInfo, $stoneBrick)); - $this->register(new StoneButton(new BID(Ids::STONE_BUTTON, 0), "Stone Button", new BlockBreakInfo(0.5, BlockToolType::PICKAXE))); - $this->register(new StonePressurePlate(new BID(Ids::STONE_PRESSURE_PLATE, 0), "Stone Pressure Plate", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new StoneButton(new BID(Ids::STONE_BUTTON, 0), "Stone Button", new BlockBreakInfo(0.5, BlockToolType::PICKAXE))); + $this->registerAllMeta(new StonePressurePlate(new BID(Ids::STONE_PRESSURE_PLATE, 0), "Stone Pressure Plate", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); //TODO: in the future this won't be the same for all the types $stoneSlabBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); @@ -401,10 +393,10 @@ class BlockFactory{ $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_MOSSY_STONE_BRICK), "Mossy Stone Brick", $stoneSlabBreakInfo)); $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_SMOOTH_QUARTZ), "Smooth Quartz", $stoneSlabBreakInfo)); $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_STONE), "Stone", $stoneSlabBreakInfo)); - $this->register(new Opaque(new BID(Ids::STONECUTTER, 0), "Stonecutter", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BlockBreakInfo::instant())); - $this->register(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant())); - $this->register(new TNT(new BID(Ids::TNT, 0), "TNT", BlockBreakInfo::instant())); + $this->registerAllMeta(new Opaque(new BID(Ids::STONECUTTER, 0), "Stonecutter", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BlockBreakInfo::instant())); + $this->registerAllMeta(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant())); + $this->registerAllMeta(new TNT(new BID(Ids::TNT, 0), "TNT", BlockBreakInfo::instant())); $fern = new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_FERN), "Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)); $this->register($fern); @@ -415,19 +407,19 @@ class BlockFactory{ $this->register(new Torch(new BID(Ids::COLORED_TORCH_BP, 8), "Purple Torch", BlockBreakInfo::instant())); $this->register(new Torch(new BID(Ids::COLORED_TORCH_RG, 0), "Red Torch", BlockBreakInfo::instant())); $this->register(new Torch(new BID(Ids::COLORED_TORCH_RG, 8), "Green Torch", BlockBreakInfo::instant())); - $this->register(new Torch(new BID(Ids::TORCH, 0), "Torch", BlockBreakInfo::instant())); - $this->register(new TrappedChest(new BID(Ids::TRAPPED_CHEST, 0, null, TileChest::class), "Trapped Chest", $chestBreakInfo)); - $this->register(new Tripwire(new BID(Ids::TRIPWIRE, 0, ItemIds::STRING), "Tripwire", BlockBreakInfo::instant())); - $this->register(new TripwireHook(new BID(Ids::TRIPWIRE_HOOK, 0), "Tripwire Hook", BlockBreakInfo::instant())); - $this->register(new UnderwaterTorch(new BID(Ids::UNDERWATER_TORCH, 0), "Underwater Torch", BlockBreakInfo::instant())); - $this->register(new Vine(new BID(Ids::VINE, 0), "Vines", new BlockBreakInfo(0.2, BlockToolType::AXE))); - $this->register(new Water(new BIDFlattened(Ids::FLOWING_WATER, [Ids::STILL_WATER], 0), "Water", BlockBreakInfo::indestructible(500.0))); - $this->register(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", new BlockBreakInfo(0.6))); + $this->registerAllMeta(new Torch(new BID(Ids::TORCH, 0), "Torch", BlockBreakInfo::instant())); + $this->registerAllMeta(new TrappedChest(new BID(Ids::TRAPPED_CHEST, 0, null, TileChest::class), "Trapped Chest", $chestBreakInfo)); + $this->registerAllMeta(new Tripwire(new BID(Ids::TRIPWIRE, 0, ItemIds::STRING), "Tripwire", BlockBreakInfo::instant())); + $this->registerAllMeta(new TripwireHook(new BID(Ids::TRIPWIRE_HOOK, 0), "Tripwire Hook", BlockBreakInfo::instant())); + $this->registerAllMeta(new UnderwaterTorch(new BID(Ids::UNDERWATER_TORCH, 0), "Underwater Torch", BlockBreakInfo::instant())); + $this->registerAllMeta(new Vine(new BID(Ids::VINE, 0), "Vines", new BlockBreakInfo(0.2, BlockToolType::AXE))); + $this->registerAllMeta(new Water(new BIDFlattened(Ids::FLOWING_WATER, [Ids::STILL_WATER], 0), "Water", BlockBreakInfo::indestructible(500.0))); + $this->registerAllMeta(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", new BlockBreakInfo(0.6))); $weightedPressurePlateBreakInfo = new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()); - $this->register(new WeightedPressurePlateHeavy(new BID(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Heavy", $weightedPressurePlateBreakInfo)); - $this->register(new WeightedPressurePlateLight(new BID(Ids::LIGHT_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Light", $weightedPressurePlateBreakInfo)); - $this->register(new Wheat(new BID(Ids::WHEAT_BLOCK, 0), "Wheat Block", BlockBreakInfo::instant())); + $this->registerAllMeta(new WeightedPressurePlateHeavy(new BID(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Heavy", $weightedPressurePlateBreakInfo)); + $this->registerAllMeta(new WeightedPressurePlateLight(new BID(Ids::LIGHT_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Light", $weightedPressurePlateBreakInfo)); + $this->registerAllMeta(new Wheat(new BID(Ids::WHEAT_BLOCK, 0), "Wheat Block", BlockBreakInfo::instant())); $planksBreakInfo = new BlockBreakInfo(2.0, BlockToolType::AXE, 0, 15.0); $leavesBreakInfo = new BlockBreakInfo(0.2, BlockToolType::SHEARS); @@ -453,17 +445,17 @@ class BlockFactory{ $this->remap($magicNumber >= 4 ? Ids::LOG2 : Ids::LOG, ($magicNumber & 0x03) | 0b1100, $wood); $this->register(new Wood(new BID(Ids::WOOD, $magicNumber | BlockLegacyMetadata::WOOD_FLAG_STRIPPED), "Stripped $name Wood", $logBreakInfo, $treeType, true)); - $this->register(new Log(BlockLegacyIdHelper::getStrippedLogIdentifier($treeType), "Stripped " . $name . " Log", $logBreakInfo, $treeType, true)); - $this->register(new FenceGate(BlockLegacyIdHelper::getWoodenFenceIdentifier($treeType), $name . " Fence Gate", $planksBreakInfo)); - $this->register(new WoodenStairs(BlockLegacyIdHelper::getWoodenStairsIdentifier($treeType), $name . " Stairs", $planksBreakInfo)); - $this->register(new WoodenDoor(BlockLegacyIdHelper::getWoodenDoorIdentifier($treeType), $name . " Door", $woodenDoorBreakInfo)); + $this->registerAllMeta(new Log(BlockLegacyIdHelper::getStrippedLogIdentifier($treeType), "Stripped " . $name . " Log", $logBreakInfo, $treeType, true)); + $this->registerAllMeta(new FenceGate(BlockLegacyIdHelper::getWoodenFenceIdentifier($treeType), $name . " Fence Gate", $planksBreakInfo)); + $this->registerAllMeta(new WoodenStairs(BlockLegacyIdHelper::getWoodenStairsIdentifier($treeType), $name . " Stairs", $planksBreakInfo)); + $this->registerAllMeta(new WoodenDoor(BlockLegacyIdHelper::getWoodenDoorIdentifier($treeType), $name . " Door", $woodenDoorBreakInfo)); - $this->register(new WoodenButton(BlockLegacyIdHelper::getWoodenButtonIdentifier($treeType), $name . " Button", $woodenButtonBreakInfo)); - $this->register(new WoodenPressurePlate(BlockLegacyIdHelper::getWoodenPressurePlateIdentifier($treeType), $name . " Pressure Plate", $woodenPressurePlateBreakInfo)); - $this->register(new WoodenTrapdoor(BlockLegacyIdHelper::getWoodenTrapdoorIdentifier($treeType), $name . " Trapdoor", $woodenDoorBreakInfo)); + $this->registerAllMeta(new WoodenButton(BlockLegacyIdHelper::getWoodenButtonIdentifier($treeType), $name . " Button", $woodenButtonBreakInfo)); + $this->registerAllMeta(new WoodenPressurePlate(BlockLegacyIdHelper::getWoodenPressurePlateIdentifier($treeType), $name . " Pressure Plate", $woodenPressurePlateBreakInfo)); + $this->registerAllMeta(new WoodenTrapdoor(BlockLegacyIdHelper::getWoodenTrapdoorIdentifier($treeType), $name . " Trapdoor", $woodenDoorBreakInfo)); - $this->register(new FloorSign(BlockLegacyIdHelper::getWoodenFloorSignIdentifier($treeType), $name . " Sign", $signBreakInfo)); - $this->register(new WallSign(BlockLegacyIdHelper::getWoodenWallSignIdentifier($treeType), $name . " Wall Sign", $signBreakInfo)); + $this->registerAllMeta(new FloorSign(BlockLegacyIdHelper::getWoodenFloorSignIdentifier($treeType), $name . " Sign", $signBreakInfo)); + $this->registerAllMeta(new WallSign(BlockLegacyIdHelper::getWoodenWallSignIdentifier($treeType), $name . " Wall Sign", $signBreakInfo)); } static $sandstoneTypes = [ @@ -473,10 +465,10 @@ class BlockFactory{ Meta::SANDSTONE_SMOOTH => "Smooth " ]; $sandstoneBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()); - $this->register(new Stair(new BID(Ids::RED_SANDSTONE_STAIRS, 0), "Red Sandstone Stairs", $sandstoneBreakInfo)); - $this->register(new Stair(new BID(Ids::SMOOTH_RED_SANDSTONE_STAIRS, 0), "Smooth Red Sandstone Stairs", $sandstoneBreakInfo)); - $this->register(new Stair(new BID(Ids::SANDSTONE_STAIRS, 0), "Sandstone Stairs", $sandstoneBreakInfo)); - $this->register(new Stair(new BID(Ids::SMOOTH_SANDSTONE_STAIRS, 0), "Smooth Sandstone Stairs", $sandstoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::RED_SANDSTONE_STAIRS, 0), "Red Sandstone Stairs", $sandstoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_RED_SANDSTONE_STAIRS, 0), "Smooth Red Sandstone Stairs", $sandstoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::SANDSTONE_STAIRS, 0), "Sandstone Stairs", $sandstoneBreakInfo)); + $this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_SANDSTONE_STAIRS, 0), "Smooth Sandstone Stairs", $sandstoneBreakInfo)); foreach($sandstoneTypes as $variant => $prefix){ $this->register(new Opaque(new BID(Ids::SANDSTONE, $variant), $prefix . "Sandstone", $sandstoneBreakInfo)); $this->register(new Opaque(new BID(Ids::RED_SANDSTONE, $variant), $prefix . "Red Sandstone", $sandstoneBreakInfo)); @@ -487,18 +479,18 @@ class BlockFactory{ $coloredName = function(string $name) use($color) : string{ return $color->getDisplayName() . " " . $name; }; - $this->register(new GlazedTerracotta(BlockLegacyIdHelper::getGlazedTerracottaIdentifier($color), $coloredName("Glazed Terracotta"), $glazedTerracottaBreakInfo)); + $this->registerAllMeta(new GlazedTerracotta(BlockLegacyIdHelper::getGlazedTerracottaIdentifier($color), $coloredName("Glazed Terracotta"), $glazedTerracottaBreakInfo)); } - $this->register(new DyedShulkerBox(new BID(Ids::SHULKER_BOX, 0, null, TileShulkerBox::class), "Dyed Shulker Box", $shulkerBoxBreakInfo)); - $this->register(new StainedGlass(new BID(Ids::STAINED_GLASS, 0), "Stained Glass", $glassBreakInfo)); - $this->register(new StainedGlassPane(new BID(Ids::STAINED_GLASS_PANE, 0), "Stained Glass Pane", $glassBreakInfo)); - $this->register(new StainedHardenedClay(new BID(Ids::STAINED_CLAY, 0), "Stained Clay", $hardenedClayBreakInfo)); - $this->register(new StainedHardenedGlass(new BID(Ids::HARD_STAINED_GLASS, 0), "Stained Hardened Glass", $hardenedGlassBreakInfo)); - $this->register(new StainedHardenedGlassPane(new BID(Ids::HARD_STAINED_GLASS_PANE, 0), "Stained Hardened Glass Pane", $hardenedGlassBreakInfo)); - $this->register(new Carpet(new BID(Ids::CARPET, 0), "Carpet", new BlockBreakInfo(0.1))); - $this->register(new Concrete(new BID(Ids::CONCRETE, 0), "Concrete", new BlockBreakInfo(1.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->register(new ConcretePowder(new BID(Ids::CONCRETE_POWDER, 0), "Concrete Powder", new BlockBreakInfo(0.5, BlockToolType::SHOVEL))); - $this->register(new Wool(new BID(Ids::WOOL, 0), "Wool", new class(0.8, BlockToolType::SHEARS) extends BlockBreakInfo{ + $this->registerAllMeta(new DyedShulkerBox(new BID(Ids::SHULKER_BOX, 0, null, TileShulkerBox::class), "Dyed Shulker Box", $shulkerBoxBreakInfo)); + $this->registerAllMeta(new StainedGlass(new BID(Ids::STAINED_GLASS, 0), "Stained Glass", $glassBreakInfo)); + $this->registerAllMeta(new StainedGlassPane(new BID(Ids::STAINED_GLASS_PANE, 0), "Stained Glass Pane", $glassBreakInfo)); + $this->registerAllMeta(new StainedHardenedClay(new BID(Ids::STAINED_CLAY, 0), "Stained Clay", $hardenedClayBreakInfo)); + $this->registerAllMeta(new StainedHardenedGlass(new BID(Ids::HARD_STAINED_GLASS, 0), "Stained Hardened Glass", $hardenedGlassBreakInfo)); + $this->registerAllMeta(new StainedHardenedGlassPane(new BID(Ids::HARD_STAINED_GLASS_PANE, 0), "Stained Hardened Glass Pane", $hardenedGlassBreakInfo)); + $this->registerAllMeta(new Carpet(new BID(Ids::CARPET, 0), "Carpet", new BlockBreakInfo(0.1))); + $this->registerAllMeta(new Concrete(new BID(Ids::CONCRETE, 0), "Concrete", new BlockBreakInfo(1.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); + $this->registerAllMeta(new ConcretePowder(new BID(Ids::CONCRETE_POWDER, 0), "Concrete Powder", new BlockBreakInfo(0.5, BlockToolType::SHOVEL))); + $this->registerAllMeta(new Wool(new BID(Ids::WOOL, 0), "Wool", new class(0.8, BlockToolType::SHEARS) extends BlockBreakInfo{ public function getBreakTime(Item $item) : float{ $time = parent::getBreakTime($item); if($item->getBlockToolType() === BlockToolType::SHEARS){ @@ -534,21 +526,21 @@ class BlockFactory{ $this->register(new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_LAB_TABLE), "Lab Table", $chemistryTableBreakInfo)); $this->register(new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_MATERIAL_REDUCER), "Material Reducer", $chemistryTableBreakInfo)); - $this->register(new ChemicalHeat(new BID(Ids::CHEMICAL_HEAT, 0), "Heat Block", $chemistryTableBreakInfo)); + $this->registerAllMeta(new ChemicalHeat(new BID(Ids::CHEMICAL_HEAT, 0), "Heat Block", $chemistryTableBreakInfo)); $this->registerMushroomBlocks(); - $this->register(new Coral( + $this->registerAllMeta(new Coral( new BID(Ids::CORAL, 0), "Coral", BlockBreakInfo::instant(), )); - $this->register(new FloorCoralFan( + $this->registerAllMeta(new FloorCoralFan( new BlockIdentifierFlattened(Ids::CORAL_FAN, [Ids::CORAL_FAN_DEAD], 0, ItemIds::CORAL_FAN), "Coral Fan", BlockBreakInfo::instant(), )); - $this->register(new WallCoralFan( + $this->registerAllMeta(new WallCoralFan( new BlockIdentifierFlattened(Ids::CORAL_FAN_HANG, [Ids::CORAL_FAN_HANG2, Ids::CORAL_FAN_HANG3], 0, ItemIds::CORAL_FAN), "Wall Coral Fan", BlockBreakInfo::instant(), @@ -740,126 +732,144 @@ class BlockFactory{ private function registerElements() : void{ $instaBreak = BlockBreakInfo::instant(); - $this->register(new Opaque(new BID(Ids::ELEMENT_0, 0), "???", $instaBreak)); + $this->registerAllMeta(new Opaque(new BID(Ids::ELEMENT_0, 0), "???", $instaBreak)); - $this->register(new Element(new BID(Ids::ELEMENT_1, 0), "Hydrogen", $instaBreak, "h", 1, 5)); - $this->register(new Element(new BID(Ids::ELEMENT_2, 0), "Helium", $instaBreak, "he", 2, 7)); - $this->register(new Element(new BID(Ids::ELEMENT_3, 0), "Lithium", $instaBreak, "li", 3, 0)); - $this->register(new Element(new BID(Ids::ELEMENT_4, 0), "Beryllium", $instaBreak, "be", 4, 1)); - $this->register(new Element(new BID(Ids::ELEMENT_5, 0), "Boron", $instaBreak, "b", 5, 4)); - $this->register(new Element(new BID(Ids::ELEMENT_6, 0), "Carbon", $instaBreak, "c", 6, 5)); - $this->register(new Element(new BID(Ids::ELEMENT_7, 0), "Nitrogen", $instaBreak, "n", 7, 5)); - $this->register(new Element(new BID(Ids::ELEMENT_8, 0), "Oxygen", $instaBreak, "o", 8, 5)); - $this->register(new Element(new BID(Ids::ELEMENT_9, 0), "Fluorine", $instaBreak, "f", 9, 6)); - $this->register(new Element(new BID(Ids::ELEMENT_10, 0), "Neon", $instaBreak, "ne", 10, 7)); - $this->register(new Element(new BID(Ids::ELEMENT_11, 0), "Sodium", $instaBreak, "na", 11, 0)); - $this->register(new Element(new BID(Ids::ELEMENT_12, 0), "Magnesium", $instaBreak, "mg", 12, 1)); - $this->register(new Element(new BID(Ids::ELEMENT_13, 0), "Aluminum", $instaBreak, "al", 13, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_14, 0), "Silicon", $instaBreak, "si", 14, 4)); - $this->register(new Element(new BID(Ids::ELEMENT_15, 0), "Phosphorus", $instaBreak, "p", 15, 5)); - $this->register(new Element(new BID(Ids::ELEMENT_16, 0), "Sulfur", $instaBreak, "s", 16, 5)); - $this->register(new Element(new BID(Ids::ELEMENT_17, 0), "Chlorine", $instaBreak, "cl", 17, 6)); - $this->register(new Element(new BID(Ids::ELEMENT_18, 0), "Argon", $instaBreak, "ar", 18, 7)); - $this->register(new Element(new BID(Ids::ELEMENT_19, 0), "Potassium", $instaBreak, "k", 19, 0)); - $this->register(new Element(new BID(Ids::ELEMENT_20, 0), "Calcium", $instaBreak, "ca", 20, 1)); - $this->register(new Element(new BID(Ids::ELEMENT_21, 0), "Scandium", $instaBreak, "sc", 21, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_22, 0), "Titanium", $instaBreak, "ti", 22, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_23, 0), "Vanadium", $instaBreak, "v", 23, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_24, 0), "Chromium", $instaBreak, "cr", 24, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_25, 0), "Manganese", $instaBreak, "mn", 25, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_26, 0), "Iron", $instaBreak, "fe", 26, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_27, 0), "Cobalt", $instaBreak, "co", 27, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_28, 0), "Nickel", $instaBreak, "ni", 28, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_29, 0), "Copper", $instaBreak, "cu", 29, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_30, 0), "Zinc", $instaBreak, "zn", 30, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_31, 0), "Gallium", $instaBreak, "ga", 31, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_32, 0), "Germanium", $instaBreak, "ge", 32, 4)); - $this->register(new Element(new BID(Ids::ELEMENT_33, 0), "Arsenic", $instaBreak, "as", 33, 4)); - $this->register(new Element(new BID(Ids::ELEMENT_34, 0), "Selenium", $instaBreak, "se", 34, 5)); - $this->register(new Element(new BID(Ids::ELEMENT_35, 0), "Bromine", $instaBreak, "br", 35, 6)); - $this->register(new Element(new BID(Ids::ELEMENT_36, 0), "Krypton", $instaBreak, "kr", 36, 7)); - $this->register(new Element(new BID(Ids::ELEMENT_37, 0), "Rubidium", $instaBreak, "rb", 37, 0)); - $this->register(new Element(new BID(Ids::ELEMENT_38, 0), "Strontium", $instaBreak, "sr", 38, 1)); - $this->register(new Element(new BID(Ids::ELEMENT_39, 0), "Yttrium", $instaBreak, "y", 39, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_40, 0), "Zirconium", $instaBreak, "zr", 40, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_41, 0), "Niobium", $instaBreak, "nb", 41, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_42, 0), "Molybdenum", $instaBreak, "mo", 42, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_43, 0), "Technetium", $instaBreak, "tc", 43, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_44, 0), "Ruthenium", $instaBreak, "ru", 44, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_45, 0), "Rhodium", $instaBreak, "rh", 45, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_46, 0), "Palladium", $instaBreak, "pd", 46, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_47, 0), "Silver", $instaBreak, "ag", 47, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_48, 0), "Cadmium", $instaBreak, "cd", 48, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_49, 0), "Indium", $instaBreak, "in", 49, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_50, 0), "Tin", $instaBreak, "sn", 50, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_51, 0), "Antimony", $instaBreak, "sb", 51, 4)); - $this->register(new Element(new BID(Ids::ELEMENT_52, 0), "Tellurium", $instaBreak, "te", 52, 4)); - $this->register(new Element(new BID(Ids::ELEMENT_53, 0), "Iodine", $instaBreak, "i", 53, 6)); - $this->register(new Element(new BID(Ids::ELEMENT_54, 0), "Xenon", $instaBreak, "xe", 54, 7)); - $this->register(new Element(new BID(Ids::ELEMENT_55, 0), "Cesium", $instaBreak, "cs", 55, 0)); - $this->register(new Element(new BID(Ids::ELEMENT_56, 0), "Barium", $instaBreak, "ba", 56, 1)); - $this->register(new Element(new BID(Ids::ELEMENT_57, 0), "Lanthanum", $instaBreak, "la", 57, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_58, 0), "Cerium", $instaBreak, "ce", 58, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_59, 0), "Praseodymium", $instaBreak, "pr", 59, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_60, 0), "Neodymium", $instaBreak, "nd", 60, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_61, 0), "Promethium", $instaBreak, "pm", 61, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_62, 0), "Samarium", $instaBreak, "sm", 62, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_63, 0), "Europium", $instaBreak, "eu", 63, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_64, 0), "Gadolinium", $instaBreak, "gd", 64, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_65, 0), "Terbium", $instaBreak, "tb", 65, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_66, 0), "Dysprosium", $instaBreak, "dy", 66, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_67, 0), "Holmium", $instaBreak, "ho", 67, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_68, 0), "Erbium", $instaBreak, "er", 68, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_69, 0), "Thulium", $instaBreak, "tm", 69, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_70, 0), "Ytterbium", $instaBreak, "yb", 70, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_71, 0), "Lutetium", $instaBreak, "lu", 71, 8)); - $this->register(new Element(new BID(Ids::ELEMENT_72, 0), "Hafnium", $instaBreak, "hf", 72, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_73, 0), "Tantalum", $instaBreak, "ta", 73, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_74, 0), "Tungsten", $instaBreak, "w", 74, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_75, 0), "Rhenium", $instaBreak, "re", 75, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_76, 0), "Osmium", $instaBreak, "os", 76, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_77, 0), "Iridium", $instaBreak, "ir", 77, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_78, 0), "Platinum", $instaBreak, "pt", 78, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_79, 0), "Gold", $instaBreak, "au", 79, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_80, 0), "Mercury", $instaBreak, "hg", 80, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_81, 0), "Thallium", $instaBreak, "tl", 81, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_82, 0), "Lead", $instaBreak, "pb", 82, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_83, 0), "Bismuth", $instaBreak, "bi", 83, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_84, 0), "Polonium", $instaBreak, "po", 84, 4)); - $this->register(new Element(new BID(Ids::ELEMENT_85, 0), "Astatine", $instaBreak, "at", 85, 6)); - $this->register(new Element(new BID(Ids::ELEMENT_86, 0), "Radon", $instaBreak, "rn", 86, 7)); - $this->register(new Element(new BID(Ids::ELEMENT_87, 0), "Francium", $instaBreak, "fr", 87, 0)); - $this->register(new Element(new BID(Ids::ELEMENT_88, 0), "Radium", $instaBreak, "ra", 88, 1)); - $this->register(new Element(new BID(Ids::ELEMENT_89, 0), "Actinium", $instaBreak, "ac", 89, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_90, 0), "Thorium", $instaBreak, "th", 90, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_91, 0), "Protactinium", $instaBreak, "pa", 91, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_92, 0), "Uranium", $instaBreak, "u", 92, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_93, 0), "Neptunium", $instaBreak, "np", 93, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_94, 0), "Plutonium", $instaBreak, "pu", 94, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_95, 0), "Americium", $instaBreak, "am", 95, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_96, 0), "Curium", $instaBreak, "cm", 96, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_97, 0), "Berkelium", $instaBreak, "bk", 97, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_98, 0), "Californium", $instaBreak, "cf", 98, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_99, 0), "Einsteinium", $instaBreak, "es", 99, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_100, 0), "Fermium", $instaBreak, "fm", 100, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_101, 0), "Mendelevium", $instaBreak, "md", 101, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_102, 0), "Nobelium", $instaBreak, "no", 102, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_103, 0), "Lawrencium", $instaBreak, "lr", 103, 9)); - $this->register(new Element(new BID(Ids::ELEMENT_104, 0), "Rutherfordium", $instaBreak, "rf", 104, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_105, 0), "Dubnium", $instaBreak, "db", 105, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_106, 0), "Seaborgium", $instaBreak, "sg", 106, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_107, 0), "Bohrium", $instaBreak, "bh", 107, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_108, 0), "Hassium", $instaBreak, "hs", 108, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_109, 0), "Meitnerium", $instaBreak, "mt", 109, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_110, 0), "Darmstadtium", $instaBreak, "ds", 110, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_111, 0), "Roentgenium", $instaBreak, "rg", 111, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_112, 0), "Copernicium", $instaBreak, "cn", 112, 2)); - $this->register(new Element(new BID(Ids::ELEMENT_113, 0), "Nihonium", $instaBreak, "nh", 113, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_114, 0), "Flerovium", $instaBreak, "fl", 114, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_115, 0), "Moscovium", $instaBreak, "mc", 115, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_116, 0), "Livermorium", $instaBreak, "lv", 116, 3)); - $this->register(new Element(new BID(Ids::ELEMENT_117, 0), "Tennessine", $instaBreak, "ts", 117, 6)); - $this->register(new Element(new BID(Ids::ELEMENT_118, 0), "Oganesson", $instaBreak, "og", 118, 7)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_1, 0), "Hydrogen", $instaBreak, "h", 1, 5)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_2, 0), "Helium", $instaBreak, "he", 2, 7)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_3, 0), "Lithium", $instaBreak, "li", 3, 0)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_4, 0), "Beryllium", $instaBreak, "be", 4, 1)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_5, 0), "Boron", $instaBreak, "b", 5, 4)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_6, 0), "Carbon", $instaBreak, "c", 6, 5)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_7, 0), "Nitrogen", $instaBreak, "n", 7, 5)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_8, 0), "Oxygen", $instaBreak, "o", 8, 5)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_9, 0), "Fluorine", $instaBreak, "f", 9, 6)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_10, 0), "Neon", $instaBreak, "ne", 10, 7)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_11, 0), "Sodium", $instaBreak, "na", 11, 0)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_12, 0), "Magnesium", $instaBreak, "mg", 12, 1)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_13, 0), "Aluminum", $instaBreak, "al", 13, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_14, 0), "Silicon", $instaBreak, "si", 14, 4)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_15, 0), "Phosphorus", $instaBreak, "p", 15, 5)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_16, 0), "Sulfur", $instaBreak, "s", 16, 5)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_17, 0), "Chlorine", $instaBreak, "cl", 17, 6)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_18, 0), "Argon", $instaBreak, "ar", 18, 7)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_19, 0), "Potassium", $instaBreak, "k", 19, 0)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_20, 0), "Calcium", $instaBreak, "ca", 20, 1)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_21, 0), "Scandium", $instaBreak, "sc", 21, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_22, 0), "Titanium", $instaBreak, "ti", 22, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_23, 0), "Vanadium", $instaBreak, "v", 23, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_24, 0), "Chromium", $instaBreak, "cr", 24, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_25, 0), "Manganese", $instaBreak, "mn", 25, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_26, 0), "Iron", $instaBreak, "fe", 26, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_27, 0), "Cobalt", $instaBreak, "co", 27, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_28, 0), "Nickel", $instaBreak, "ni", 28, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_29, 0), "Copper", $instaBreak, "cu", 29, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_30, 0), "Zinc", $instaBreak, "zn", 30, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_31, 0), "Gallium", $instaBreak, "ga", 31, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_32, 0), "Germanium", $instaBreak, "ge", 32, 4)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_33, 0), "Arsenic", $instaBreak, "as", 33, 4)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_34, 0), "Selenium", $instaBreak, "se", 34, 5)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_35, 0), "Bromine", $instaBreak, "br", 35, 6)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_36, 0), "Krypton", $instaBreak, "kr", 36, 7)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_37, 0), "Rubidium", $instaBreak, "rb", 37, 0)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_38, 0), "Strontium", $instaBreak, "sr", 38, 1)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_39, 0), "Yttrium", $instaBreak, "y", 39, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_40, 0), "Zirconium", $instaBreak, "zr", 40, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_41, 0), "Niobium", $instaBreak, "nb", 41, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_42, 0), "Molybdenum", $instaBreak, "mo", 42, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_43, 0), "Technetium", $instaBreak, "tc", 43, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_44, 0), "Ruthenium", $instaBreak, "ru", 44, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_45, 0), "Rhodium", $instaBreak, "rh", 45, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_46, 0), "Palladium", $instaBreak, "pd", 46, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_47, 0), "Silver", $instaBreak, "ag", 47, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_48, 0), "Cadmium", $instaBreak, "cd", 48, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_49, 0), "Indium", $instaBreak, "in", 49, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_50, 0), "Tin", $instaBreak, "sn", 50, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_51, 0), "Antimony", $instaBreak, "sb", 51, 4)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_52, 0), "Tellurium", $instaBreak, "te", 52, 4)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_53, 0), "Iodine", $instaBreak, "i", 53, 6)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_54, 0), "Xenon", $instaBreak, "xe", 54, 7)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_55, 0), "Cesium", $instaBreak, "cs", 55, 0)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_56, 0), "Barium", $instaBreak, "ba", 56, 1)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_57, 0), "Lanthanum", $instaBreak, "la", 57, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_58, 0), "Cerium", $instaBreak, "ce", 58, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_59, 0), "Praseodymium", $instaBreak, "pr", 59, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_60, 0), "Neodymium", $instaBreak, "nd", 60, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_61, 0), "Promethium", $instaBreak, "pm", 61, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_62, 0), "Samarium", $instaBreak, "sm", 62, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_63, 0), "Europium", $instaBreak, "eu", 63, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_64, 0), "Gadolinium", $instaBreak, "gd", 64, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_65, 0), "Terbium", $instaBreak, "tb", 65, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_66, 0), "Dysprosium", $instaBreak, "dy", 66, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_67, 0), "Holmium", $instaBreak, "ho", 67, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_68, 0), "Erbium", $instaBreak, "er", 68, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_69, 0), "Thulium", $instaBreak, "tm", 69, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_70, 0), "Ytterbium", $instaBreak, "yb", 70, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_71, 0), "Lutetium", $instaBreak, "lu", 71, 8)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_72, 0), "Hafnium", $instaBreak, "hf", 72, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_73, 0), "Tantalum", $instaBreak, "ta", 73, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_74, 0), "Tungsten", $instaBreak, "w", 74, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_75, 0), "Rhenium", $instaBreak, "re", 75, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_76, 0), "Osmium", $instaBreak, "os", 76, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_77, 0), "Iridium", $instaBreak, "ir", 77, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_78, 0), "Platinum", $instaBreak, "pt", 78, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_79, 0), "Gold", $instaBreak, "au", 79, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_80, 0), "Mercury", $instaBreak, "hg", 80, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_81, 0), "Thallium", $instaBreak, "tl", 81, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_82, 0), "Lead", $instaBreak, "pb", 82, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_83, 0), "Bismuth", $instaBreak, "bi", 83, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_84, 0), "Polonium", $instaBreak, "po", 84, 4)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_85, 0), "Astatine", $instaBreak, "at", 85, 6)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_86, 0), "Radon", $instaBreak, "rn", 86, 7)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_87, 0), "Francium", $instaBreak, "fr", 87, 0)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_88, 0), "Radium", $instaBreak, "ra", 88, 1)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_89, 0), "Actinium", $instaBreak, "ac", 89, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_90, 0), "Thorium", $instaBreak, "th", 90, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_91, 0), "Protactinium", $instaBreak, "pa", 91, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_92, 0), "Uranium", $instaBreak, "u", 92, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_93, 0), "Neptunium", $instaBreak, "np", 93, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_94, 0), "Plutonium", $instaBreak, "pu", 94, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_95, 0), "Americium", $instaBreak, "am", 95, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_96, 0), "Curium", $instaBreak, "cm", 96, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_97, 0), "Berkelium", $instaBreak, "bk", 97, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_98, 0), "Californium", $instaBreak, "cf", 98, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_99, 0), "Einsteinium", $instaBreak, "es", 99, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_100, 0), "Fermium", $instaBreak, "fm", 100, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_101, 0), "Mendelevium", $instaBreak, "md", 101, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_102, 0), "Nobelium", $instaBreak, "no", 102, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_103, 0), "Lawrencium", $instaBreak, "lr", 103, 9)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_104, 0), "Rutherfordium", $instaBreak, "rf", 104, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_105, 0), "Dubnium", $instaBreak, "db", 105, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_106, 0), "Seaborgium", $instaBreak, "sg", 106, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_107, 0), "Bohrium", $instaBreak, "bh", 107, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_108, 0), "Hassium", $instaBreak, "hs", 108, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_109, 0), "Meitnerium", $instaBreak, "mt", 109, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_110, 0), "Darmstadtium", $instaBreak, "ds", 110, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_111, 0), "Roentgenium", $instaBreak, "rg", 111, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_112, 0), "Copernicium", $instaBreak, "cn", 112, 2)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_113, 0), "Nihonium", $instaBreak, "nh", 113, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_114, 0), "Flerovium", $instaBreak, "fl", 114, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_115, 0), "Moscovium", $instaBreak, "mc", 115, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_116, 0), "Livermorium", $instaBreak, "lv", 116, 3)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_117, 0), "Tennessine", $instaBreak, "ts", 117, 6)); + $this->registerAllMeta(new Element(new BID(Ids::ELEMENT_118, 0), "Oganesson", $instaBreak, "og", 118, 7)); + } + + /** + * Claims the whole metadata range (0-15) for all IDs associated with this block. Any unregistered states will be + * mapped to the default (provided) state. + * + * This should only be used when this block type has sole ownership of an ID. For IDs which contain multiple block + * types (variants), the regular register() method should be used instead. + */ + private function registerAllMeta(Block $block) : void{ + $this->register($block); + foreach($block->getIdInfo()->getAllBlockIds() as $id){ + for($meta = 0; $meta < 1 << Block::INTERNAL_METADATA_BITS; ++$meta){ + if(!$this->isRegistered($id, $meta)){ + $this->remap($id, $meta, $block); + } + } + } } private function registerSlabWithDoubleHighBitsRemapping(Slab $block) : void{ diff --git a/tests/phpunit/block/block_factory_consistency_check.json b/tests/phpunit/block/block_factory_consistency_check.json index 6df3cf098..c370eeaae 100644 --- a/tests/phpunit/block/block_factory_consistency_check.json +++ b/tests/phpunit/block/block_factory_consistency_check.json @@ -1 +1 @@ -{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7296":"Fletching Table","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"284":7472,"285":7473,"286":7474,"287":7475,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"496":498,"499":498,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"800":805,"806":805,"807":805,"864":866,"865":866,"870":866,"871":866,"976":978,"977":978,"982":978,"983":978,"992":978,"993":978,"998":978,"999":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1200":1221,"1206":1221,"1207":1221,"1216":1221,"1222":1221,"1223":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1377":1376,"1378":1376,"1379":1376,"1440":1441,"1443":1441,"1479":1472,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2493":2481,"2494":2482,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2604":7476,"2605":7477,"2732":2720,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3230":3218,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3334":3328,"3335":3328,"3468":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3824":3829,"3830":3829,"3831":3829,"3955":3952,"4163":4160,"4179":4176,"4195":4192,"4211":4208,"4227":4224,"4243":4240,"6181":6176,"6182":6176,"6183":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7504":7218,"7505":7218,"7510":7218,"7511":7218}} \ No newline at end of file +{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7296":"Fletching Table","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"33":32,"34":32,"35":32,"36":32,"37":32,"38":32,"39":32,"40":32,"41":32,"42":32,"43":32,"44":32,"45":32,"46":32,"47":32,"50":48,"51":48,"52":48,"53":48,"54":48,"55":48,"56":48,"57":48,"58":48,"59":48,"60":48,"61":48,"62":48,"63":48,"65":64,"66":64,"67":64,"68":64,"69":64,"70":64,"71":64,"72":64,"73":64,"74":64,"75":64,"76":64,"77":64,"78":64,"79":64,"114":112,"115":112,"116":112,"117":112,"118":112,"119":112,"120":112,"121":112,"122":112,"123":112,"124":112,"125":112,"126":112,"127":112,"209":208,"210":208,"211":208,"212":208,"213":208,"214":208,"215":208,"216":208,"217":208,"218":208,"219":208,"220":208,"221":208,"222":208,"223":208,"225":224,"226":224,"227":224,"228":224,"229":224,"230":224,"231":224,"232":224,"233":224,"234":224,"235":224,"236":224,"237":224,"238":224,"239":224,"241":240,"242":240,"243":240,"244":240,"245":240,"246":240,"247":240,"248":240,"249":240,"250":240,"251":240,"252":240,"253":240,"254":240,"255":240,"257":256,"258":256,"259":256,"260":256,"261":256,"262":256,"263":256,"264":256,"265":256,"266":256,"267":256,"268":256,"269":256,"270":256,"271":256,"284":7472,"285":7473,"286":7474,"287":7475,"306":304,"307":304,"308":304,"309":304,"310":304,"311":304,"312":304,"313":304,"314":304,"315":304,"316":304,"317":304,"318":304,"319":304,"321":320,"322":320,"323":320,"324":320,"325":320,"326":320,"327":320,"328":320,"329":320,"330":320,"331":320,"332":320,"333":320,"334":320,"335":320,"337":336,"338":336,"339":336,"340":336,"341":336,"342":336,"343":336,"344":336,"345":336,"346":336,"347":336,"348":336,"349":336,"350":336,"351":336,"353":352,"354":352,"355":352,"356":352,"357":352,"358":352,"359":352,"360":352,"361":352,"362":352,"363":352,"364":352,"365":352,"366":352,"367":352,"401":400,"402":400,"403":400,"404":400,"405":400,"406":400,"407":400,"408":400,"409":400,"410":400,"411":400,"412":400,"413":400,"414":400,"415":400,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"481":480,"482":480,"483":480,"484":480,"485":480,"486":480,"487":480,"488":480,"489":480,"490":480,"491":480,"492":480,"493":480,"494":480,"495":480,"496":498,"499":498,"513":512,"514":512,"515":512,"516":512,"517":512,"518":512,"519":512,"520":512,"521":512,"522":512,"523":512,"524":512,"525":512,"526":512,"527":512,"577":576,"578":576,"579":576,"580":576,"581":576,"582":576,"583":576,"584":576,"585":576,"586":576,"587":576,"588":576,"589":576,"590":576,"591":576,"593":592,"594":592,"595":592,"596":592,"597":592,"598":592,"599":592,"600":592,"601":592,"602":592,"603":592,"604":592,"605":592,"606":592,"607":592,"625":624,"626":624,"627":624,"628":624,"629":624,"630":624,"631":624,"632":624,"633":624,"634":624,"635":624,"636":624,"637":624,"638":624,"639":624,"641":640,"642":640,"643":640,"644":640,"645":640,"646":640,"647":640,"648":640,"649":640,"650":640,"651":640,"652":640,"653":640,"654":640,"655":640,"657":656,"658":656,"659":656,"660":656,"661":656,"662":656,"663":656,"664":656,"665":656,"666":656,"667":656,"668":656,"669":656,"670":656,"671":656,"673":672,"674":672,"675":672,"676":672,"677":672,"678":672,"679":672,"680":672,"681":672,"682":672,"683":672,"684":672,"685":672,"686":672,"687":672,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"721":720,"722":720,"723":720,"724":720,"725":720,"726":720,"727":720,"728":720,"729":720,"730":720,"731":720,"732":720,"733":720,"734":720,"735":720,"740":736,"741":736,"742":736,"743":736,"744":736,"745":736,"746":736,"747":736,"748":736,"749":736,"750":736,"751":736,"753":752,"754":752,"755":752,"756":752,"757":752,"758":752,"759":752,"760":752,"761":752,"762":752,"763":752,"764":752,"765":752,"766":752,"767":752,"769":768,"770":768,"771":768,"772":768,"773":768,"774":768,"775":768,"776":768,"777":768,"778":768,"779":768,"780":768,"781":768,"782":768,"783":768,"785":784,"786":784,"787":784,"788":784,"789":784,"790":784,"791":784,"792":784,"793":784,"794":784,"795":784,"796":784,"797":784,"798":784,"799":784,"800":805,"806":805,"807":805,"808":805,"809":805,"810":805,"811":805,"812":805,"813":805,"814":805,"815":805,"833":832,"834":832,"835":832,"836":832,"837":832,"838":832,"839":832,"840":832,"841":832,"842":832,"843":832,"844":832,"845":832,"846":832,"847":832,"856":851,"857":851,"858":851,"859":851,"860":851,"861":851,"862":851,"863":851,"864":866,"865":866,"870":866,"871":866,"872":866,"873":866,"874":866,"875":866,"876":866,"877":866,"878":866,"879":866,"897":896,"898":896,"899":896,"900":896,"901":896,"902":896,"903":896,"904":896,"905":896,"906":896,"907":896,"908":896,"909":896,"910":896,"911":896,"913":912,"914":912,"915":912,"916":912,"917":912,"918":912,"919":912,"920":912,"921":912,"922":912,"923":912,"924":912,"925":912,"926":912,"927":912,"929":928,"930":928,"931":928,"932":928,"933":928,"934":928,"935":928,"936":928,"937":928,"938":928,"939":928,"940":928,"941":928,"942":928,"943":928,"952":944,"953":944,"954":944,"955":944,"956":944,"957":944,"958":944,"959":944,"968":960,"969":960,"970":960,"971":960,"972":960,"973":960,"974":960,"975":960,"976":978,"977":978,"982":978,"983":978,"984":978,"985":978,"986":978,"987":978,"988":978,"989":978,"990":978,"991":978,"992":978,"993":978,"998":978,"999":978,"1000":978,"1001":978,"1002":978,"1003":978,"1004":978,"1005":978,"1006":978,"1007":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1048":1042,"1049":1042,"1050":1042,"1051":1042,"1052":1042,"1053":1042,"1054":1042,"1055":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1080":1075,"1081":1075,"1082":1075,"1083":1075,"1084":1075,"1085":1075,"1086":1075,"1087":1075,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1096":1090,"1097":1090,"1098":1090,"1099":1090,"1100":1090,"1101":1090,"1102":1090,"1103":1090,"1122":1120,"1123":1120,"1124":1120,"1125":1120,"1126":1120,"1127":1120,"1128":1120,"1129":1120,"1130":1120,"1131":1120,"1132":1120,"1133":1120,"1134":1120,"1135":1120,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1154":1152,"1155":1152,"1156":1152,"1157":1152,"1158":1152,"1159":1152,"1160":1152,"1161":1152,"1162":1152,"1163":1152,"1164":1152,"1165":1152,"1166":1152,"1167":1152,"1169":1168,"1170":1168,"1171":1168,"1172":1168,"1173":1168,"1174":1168,"1175":1168,"1176":1168,"1177":1168,"1178":1168,"1179":1168,"1180":1168,"1181":1168,"1182":1168,"1183":1168,"1185":1168,"1186":1168,"1187":1168,"1188":1168,"1189":1168,"1190":1168,"1191":1168,"1192":1168,"1193":1168,"1194":1168,"1195":1168,"1196":1168,"1197":1168,"1198":1168,"1199":1168,"1200":1221,"1206":1221,"1207":1221,"1208":1221,"1209":1221,"1210":1221,"1211":1221,"1212":1221,"1213":1221,"1214":1221,"1215":1221,"1216":1221,"1222":1221,"1223":1221,"1224":1221,"1225":1221,"1226":1221,"1227":1221,"1228":1221,"1229":1221,"1230":1221,"1231":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1256":1248,"1257":1248,"1258":1248,"1259":1248,"1260":1248,"1261":1248,"1262":1248,"1263":1248,"1265":1264,"1266":1264,"1267":1264,"1268":1264,"1269":1264,"1270":1264,"1271":1264,"1272":1264,"1273":1264,"1274":1264,"1275":1264,"1276":1264,"1277":1264,"1278":1264,"1279":1264,"1281":1280,"1282":1280,"1283":1280,"1284":1280,"1285":1280,"1286":1280,"1287":1280,"1288":1280,"1289":1280,"1290":1280,"1291":1280,"1292":1280,"1293":1280,"1294":1280,"1295":1280,"1313":1312,"1314":1312,"1315":1312,"1316":1312,"1317":1312,"1318":1312,"1319":1312,"1320":1312,"1321":1312,"1322":1312,"1323":1312,"1324":1312,"1325":1312,"1326":1312,"1327":1312,"1345":1344,"1346":1344,"1347":1344,"1348":1344,"1349":1344,"1350":1344,"1351":1344,"1352":1344,"1353":1344,"1354":1344,"1355":1344,"1356":1344,"1357":1344,"1358":1344,"1359":1344,"1377":1376,"1378":1376,"1379":1376,"1380":1376,"1381":1376,"1382":1376,"1383":1376,"1384":1376,"1385":1376,"1386":1376,"1387":1376,"1388":1376,"1389":1376,"1390":1376,"1391":1376,"1393":1392,"1394":1392,"1395":1392,"1396":1392,"1397":1392,"1398":1392,"1399":1392,"1400":1392,"1401":1392,"1402":1392,"1403":1392,"1404":1392,"1405":1392,"1406":1392,"1407":1392,"1409":1408,"1410":1408,"1411":1408,"1412":1408,"1413":1408,"1414":1408,"1415":1408,"1416":1408,"1417":1408,"1418":1408,"1419":1408,"1420":1408,"1421":1408,"1422":1408,"1423":1408,"1425":1424,"1426":1424,"1427":1424,"1428":1424,"1429":1424,"1430":1424,"1431":1424,"1432":1424,"1433":1424,"1434":1424,"1435":1424,"1436":1424,"1437":1424,"1438":1424,"1439":1424,"1440":1441,"1443":1441,"1444":1441,"1445":1441,"1446":1441,"1447":1441,"1448":1441,"1449":1441,"1450":1441,"1451":1441,"1452":1441,"1453":1441,"1454":1441,"1455":1441,"1460":1458,"1461":1458,"1462":1458,"1463":1458,"1464":1458,"1465":1458,"1466":1458,"1467":1458,"1468":1458,"1469":1458,"1470":1458,"1471":1458,"1479":1472,"1480":1472,"1481":1472,"1482":1472,"1483":1472,"1484":1472,"1485":1472,"1486":1472,"1487":1472,"1521":1520,"1522":1520,"1523":1520,"1524":1520,"1525":1520,"1526":1520,"1527":1520,"1528":1520,"1529":1520,"1530":1520,"1531":1520,"1532":1520,"1533":1520,"1534":1520,"1535":1520,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"1617":1616,"1618":1616,"1619":1616,"1620":1616,"1621":1616,"1622":1616,"1623":1616,"1624":1616,"1625":1616,"1626":1616,"1627":1616,"1628":1616,"1629":1616,"1630":1616,"1631":1616,"1633":1632,"1634":1632,"1635":1632,"1636":1632,"1637":1632,"1638":1632,"1639":1632,"1640":1632,"1641":1632,"1642":1632,"1643":1632,"1644":1632,"1645":1632,"1646":1632,"1647":1632,"1649":1648,"1650":1648,"1651":1648,"1652":1648,"1653":1648,"1654":1648,"1655":1648,"1656":1648,"1657":1648,"1658":1648,"1659":1648,"1660":1648,"1661":1648,"1662":1648,"1663":1648,"1672":1664,"1673":1664,"1674":1664,"1675":1664,"1676":1664,"1677":1664,"1678":1664,"1679":1664,"1688":1680,"1689":1680,"1690":1680,"1691":1680,"1692":1680,"1693":1680,"1694":1680,"1695":1680,"1736":1731,"1737":1731,"1738":1731,"1739":1731,"1740":1731,"1741":1731,"1742":1731,"1743":1731,"1752":1747,"1753":1747,"1754":1747,"1755":1747,"1756":1747,"1757":1747,"1758":1747,"1759":1747,"1761":1760,"1762":1760,"1763":1760,"1764":1760,"1765":1760,"1766":1760,"1767":1760,"1768":1760,"1769":1760,"1770":1760,"1771":1760,"1772":1760,"1773":1760,"1774":1760,"1775":1760,"1777":1776,"1778":1776,"1779":1776,"1780":1776,"1781":1776,"1782":1776,"1783":1776,"1784":1776,"1785":1776,"1786":1776,"1787":1776,"1788":1776,"1789":1776,"1790":1776,"1791":1776,"1793":1792,"1794":1792,"1795":1792,"1796":1792,"1797":1792,"1798":1792,"1799":1792,"1800":1792,"1801":1792,"1802":1792,"1803":1792,"1804":1792,"1805":1792,"1806":1792,"1807":1792,"1809":1808,"1810":1808,"1811":1808,"1812":1808,"1813":1808,"1814":1808,"1815":1808,"1816":1808,"1817":1808,"1818":1808,"1819":1808,"1820":1808,"1821":1808,"1822":1808,"1823":1808,"1832":1827,"1833":1827,"1834":1827,"1835":1827,"1836":1827,"1837":1827,"1838":1827,"1839":1827,"1844":1840,"1845":1840,"1846":1840,"1847":1840,"1848":1840,"1849":1840,"1850":1840,"1851":1840,"1852":1840,"1853":1840,"1854":1840,"1855":1840,"1857":1856,"1858":1856,"1859":1856,"1860":1856,"1861":1856,"1862":1856,"1863":1856,"1864":1856,"1865":1856,"1866":1856,"1867":1856,"1868":1856,"1869":1856,"1870":1856,"1871":1856,"1880":1872,"1881":1872,"1882":1872,"1883":1872,"1884":1872,"1885":1872,"1886":1872,"1887":1872,"1928":1922,"1929":1922,"1930":1922,"1931":1922,"1932":1922,"1933":1922,"1934":1922,"1935":1922,"1937":1936,"1938":1936,"1939":1936,"1940":1936,"1941":1936,"1942":1936,"1943":1936,"1944":1936,"1945":1936,"1946":1936,"1947":1936,"1948":1936,"1949":1936,"1950":1936,"1951":1936,"1953":1952,"1954":1952,"1955":1952,"1956":1952,"1957":1952,"1958":1952,"1959":1952,"1960":1952,"1961":1952,"1962":1952,"1963":1952,"1964":1952,"1965":1952,"1966":1952,"1967":1952,"1969":1968,"1970":1968,"1971":1968,"1972":1968,"1973":1968,"1974":1968,"1975":1968,"1976":1968,"1977":1968,"1978":1968,"1979":1968,"1980":1968,"1981":1968,"1982":1968,"1983":1968,"1985":1968,"1986":1968,"1987":1968,"1988":1968,"1989":1968,"1990":1968,"1991":1968,"1992":1968,"1993":1968,"1994":1968,"1995":1968,"1996":1968,"1997":1968,"1998":1968,"1999":1968,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2056":2051,"2057":2051,"2058":2051,"2059":2051,"2060":2051,"2061":2051,"2062":2051,"2063":2051,"2065":2064,"2066":2064,"2067":2064,"2068":2064,"2069":2064,"2070":2064,"2071":2064,"2072":2064,"2073":2064,"2074":2064,"2075":2064,"2076":2064,"2077":2064,"2078":2064,"2079":2064,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2088":2082,"2089":2082,"2090":2082,"2091":2082,"2092":2082,"2093":2082,"2094":2082,"2095":2082,"2129":2128,"2130":2128,"2131":2128,"2132":2128,"2133":2128,"2134":2128,"2135":2128,"2136":2128,"2137":2128,"2138":2128,"2139":2128,"2140":2128,"2141":2128,"2142":2128,"2143":2128,"2152":2147,"2153":2147,"2154":2147,"2155":2147,"2156":2147,"2157":2147,"2158":2147,"2159":2147,"2168":2163,"2169":2163,"2170":2163,"2171":2163,"2172":2163,"2173":2163,"2174":2163,"2175":2163,"2184":2179,"2185":2179,"2186":2179,"2187":2179,"2188":2179,"2189":2179,"2190":2179,"2191":2179,"2209":2208,"2210":2208,"2211":2208,"2212":2208,"2213":2208,"2214":2208,"2215":2208,"2216":2208,"2217":2208,"2218":2208,"2219":2208,"2220":2208,"2221":2208,"2222":2208,"2223":2208,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2264":2256,"2265":2256,"2266":2256,"2267":2256,"2268":2256,"2269":2256,"2270":2256,"2271":2256,"2280":2272,"2281":2272,"2282":2272,"2283":2272,"2284":2272,"2285":2272,"2286":2272,"2287":2272,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2344":2338,"2345":2338,"2346":2338,"2347":2338,"2348":2338,"2349":2338,"2350":2338,"2351":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2433":2432,"2434":2432,"2435":2432,"2436":2432,"2437":2432,"2438":2432,"2439":2432,"2440":2432,"2441":2432,"2442":2432,"2443":2432,"2444":2432,"2445":2432,"2446":2432,"2447":2432,"2449":2448,"2450":2448,"2451":2448,"2452":2448,"2453":2448,"2454":2448,"2455":2448,"2456":2448,"2457":2448,"2458":2448,"2459":2448,"2460":2448,"2461":2448,"2462":2448,"2463":2448,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2493":2481,"2494":2482,"2504":2499,"2505":2499,"2506":2499,"2507":2499,"2508":2499,"2509":2499,"2510":2499,"2511":2499,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2604":7476,"2605":7477,"2616":2611,"2617":2611,"2618":2611,"2619":2611,"2620":2611,"2621":2611,"2622":2611,"2623":2611,"2632":2627,"2633":2627,"2634":2627,"2635":2627,"2636":2627,"2637":2627,"2638":2627,"2639":2627,"2641":2640,"2642":2640,"2643":2640,"2644":2640,"2645":2640,"2646":2640,"2647":2640,"2648":2640,"2649":2640,"2650":2640,"2651":2640,"2652":2640,"2653":2640,"2654":2640,"2655":2640,"2705":2704,"2706":2704,"2707":2704,"2708":2704,"2709":2704,"2710":2704,"2711":2704,"2712":2704,"2713":2704,"2714":2704,"2715":2704,"2716":2704,"2717":2704,"2718":2704,"2719":2704,"2721":2720,"2722":2720,"2723":2720,"2725":2720,"2726":2720,"2727":2720,"2729":2720,"2730":2720,"2731":2720,"2732":2720,"2733":2720,"2734":2720,"2735":2720,"2753":2752,"2754":2752,"2755":2752,"2756":2752,"2757":2752,"2758":2752,"2759":2752,"2760":2752,"2761":2752,"2762":2752,"2763":2752,"2764":2752,"2765":2752,"2766":2752,"2767":2752,"2769":2768,"2770":2768,"2771":2768,"2772":2768,"2773":2768,"2774":2768,"2775":2768,"2776":2768,"2777":2768,"2778":2768,"2779":2768,"2780":2768,"2781":2768,"2782":2768,"2783":2768,"2785":2784,"2786":2784,"2787":2784,"2788":2784,"2789":2784,"2790":2784,"2791":2784,"2792":2784,"2793":2784,"2794":2784,"2795":2784,"2796":2784,"2797":2784,"2798":2784,"2799":2784,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2840":2834,"2841":2834,"2842":2834,"2843":2834,"2844":2834,"2845":2834,"2846":2834,"2847":2834,"2888":2883,"2889":2883,"2890":2883,"2891":2883,"2892":2883,"2893":2883,"2894":2883,"2895":2883,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3041":3040,"3042":3040,"3043":3040,"3044":3040,"3045":3040,"3046":3040,"3047":3040,"3048":3040,"3049":3040,"3050":3040,"3051":3040,"3052":3040,"3053":3040,"3054":3040,"3055":3040,"3073":3072,"3074":3072,"3075":3072,"3076":3072,"3077":3072,"3078":3072,"3079":3072,"3080":3072,"3081":3072,"3082":3072,"3083":3072,"3084":3072,"3085":3072,"3086":3072,"3087":3072,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3169":3168,"3170":3168,"3171":3168,"3172":3168,"3173":3168,"3174":3168,"3175":3168,"3176":3168,"3177":3168,"3178":3168,"3179":3168,"3180":3168,"3181":3168,"3182":3168,"3183":3168,"3192":3187,"3193":3187,"3194":3187,"3195":3187,"3196":3187,"3197":3187,"3198":3187,"3199":3187,"3230":3218,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3256":3251,"3257":3251,"3258":3251,"3259":3251,"3260":3251,"3261":3251,"3262":3251,"3263":3251,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3281":3280,"3282":3280,"3283":3280,"3284":3280,"3285":3280,"3286":3280,"3287":3280,"3288":3280,"3289":3280,"3290":3280,"3291":3280,"3292":3280,"3293":3280,"3294":3280,"3295":3280,"3297":3296,"3298":3296,"3299":3296,"3300":3296,"3301":3296,"3302":3296,"3303":3296,"3304":3296,"3305":3296,"3306":3296,"3307":3296,"3308":3296,"3309":3296,"3310":3296,"3311":3296,"3316":3312,"3317":3312,"3318":3312,"3319":3312,"3320":3312,"3321":3312,"3322":3312,"3323":3312,"3324":3312,"3325":3312,"3326":3312,"3327":3312,"3334":3328,"3335":3328,"3336":3328,"3337":3328,"3338":3328,"3339":3328,"3340":3328,"3341":3328,"3342":3328,"3343":3328,"3409":3408,"3410":3408,"3411":3408,"3412":3408,"3413":3408,"3414":3408,"3415":3408,"3416":3408,"3417":3408,"3418":3408,"3419":3408,"3420":3408,"3421":3408,"3422":3408,"3423":3408,"3425":3424,"3426":3424,"3427":3424,"3428":3424,"3429":3424,"3430":3424,"3431":3424,"3432":3424,"3433":3424,"3434":3424,"3435":3424,"3436":3424,"3437":3424,"3438":3424,"3439":3424,"3441":3440,"3442":3440,"3443":3440,"3444":3440,"3445":3440,"3446":3440,"3447":3440,"3448":3440,"3449":3440,"3450":3440,"3451":3440,"3452":3440,"3453":3440,"3454":3440,"3455":3440,"3457":3456,"3458":3456,"3459":3456,"3461":3456,"3462":3456,"3463":3456,"3465":3456,"3466":3456,"3467":3456,"3468":3456,"3469":3456,"3470":3456,"3471":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3512":3506,"3513":3506,"3514":3506,"3515":3506,"3516":3506,"3517":3506,"3518":3506,"3519":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3528":3522,"3529":3522,"3530":3522,"3531":3522,"3532":3522,"3533":3522,"3534":3522,"3535":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3544":3538,"3545":3538,"3546":3538,"3547":3538,"3548":3538,"3549":3538,"3550":3538,"3551":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3560":3554,"3561":3554,"3562":3554,"3563":3554,"3564":3554,"3565":3554,"3566":3554,"3567":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3576":3570,"3577":3570,"3578":3570,"3579":3570,"3580":3570,"3581":3570,"3582":3570,"3583":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3592":3586,"3593":3586,"3594":3586,"3595":3586,"3596":3586,"3597":3586,"3598":3586,"3599":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3608":3602,"3609":3602,"3610":3602,"3611":3602,"3612":3602,"3613":3602,"3614":3602,"3615":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3624":3618,"3625":3618,"3626":3618,"3627":3618,"3628":3618,"3629":3618,"3630":3618,"3631":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3640":3634,"3641":3634,"3642":3634,"3643":3634,"3644":3634,"3645":3634,"3646":3634,"3647":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3656":3650,"3657":3650,"3658":3650,"3659":3650,"3660":3650,"3661":3650,"3662":3650,"3663":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3672":3666,"3673":3666,"3674":3666,"3675":3666,"3676":3666,"3677":3666,"3678":3666,"3679":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3704":3698,"3705":3698,"3706":3698,"3707":3698,"3708":3698,"3709":3698,"3710":3698,"3711":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3720":3714,"3721":3714,"3722":3714,"3723":3714,"3724":3714,"3725":3714,"3726":3714,"3727":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3736":3730,"3737":3730,"3738":3730,"3739":3730,"3740":3730,"3741":3730,"3742":3730,"3743":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3752":3746,"3753":3746,"3754":3746,"3755":3746,"3756":3746,"3757":3746,"3758":3746,"3759":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3768":3762,"3769":3762,"3770":3762,"3771":3762,"3772":3762,"3773":3762,"3774":3762,"3775":3762,"3824":3829,"3830":3829,"3831":3829,"3832":3829,"3833":3829,"3834":3829,"3835":3829,"3836":3829,"3837":3829,"3838":3829,"3839":3829,"3889":3888,"3890":3888,"3891":3888,"3892":3888,"3893":3888,"3894":3888,"3895":3888,"3896":3888,"3897":3888,"3898":3888,"3899":3888,"3900":3888,"3901":3888,"3902":3888,"3903":3888,"3912":3904,"3913":3904,"3914":3904,"3915":3904,"3916":3904,"3917":3904,"3918":3904,"3919":3904,"3921":3920,"3922":3920,"3923":3920,"3924":3920,"3925":3920,"3926":3920,"3927":3920,"3928":3920,"3929":3920,"3930":3920,"3931":3920,"3932":3920,"3933":3920,"3934":3920,"3935":3920,"3937":3936,"3938":3936,"3939":3936,"3940":3936,"3941":3936,"3942":3936,"3943":3936,"3944":3936,"3945":3936,"3946":3936,"3947":3936,"3948":3936,"3949":3936,"3950":3936,"3951":3936,"3955":3952,"3956":3952,"3957":3952,"3958":3952,"3959":3952,"3960":3952,"3961":3952,"3962":3952,"3963":3952,"3964":3952,"3965":3952,"3966":3952,"3967":3952,"3969":3968,"3970":3968,"3971":3968,"3972":3968,"3973":3968,"3974":3968,"3975":3968,"3976":3968,"3977":3968,"3978":3968,"3979":3968,"3980":3968,"3981":3968,"3982":3968,"3983":3968,"3985":3984,"3986":3984,"3987":3984,"3988":3984,"3989":3984,"3990":3984,"3991":3984,"3992":3984,"3993":3984,"3994":3984,"3995":3984,"3996":3984,"3997":3984,"3998":3984,"3999":3984,"4049":4048,"4050":4048,"4051":4048,"4052":4048,"4053":4048,"4054":4048,"4055":4048,"4056":4048,"4057":4048,"4058":4048,"4059":4048,"4060":4048,"4061":4048,"4062":4048,"4063":4048,"4081":4080,"4082":4080,"4083":4080,"4084":4080,"4085":4080,"4086":4080,"4087":4080,"4088":4080,"4089":4080,"4090":4080,"4091":4080,"4092":4080,"4093":4080,"4094":4080,"4095":4080,"4120":4115,"4121":4115,"4122":4115,"4123":4115,"4124":4115,"4125":4115,"4126":4115,"4127":4115,"4136":4131,"4137":4131,"4138":4131,"4139":4131,"4140":4131,"4141":4131,"4142":4131,"4143":4131,"4152":4147,"4153":4147,"4154":4147,"4155":4147,"4156":4147,"4157":4147,"4158":4147,"4159":4147,"4163":4160,"4164":4160,"4165":4160,"4166":4160,"4167":4160,"4168":4160,"4169":4160,"4170":4160,"4171":4160,"4172":4160,"4173":4160,"4174":4160,"4175":4160,"4179":4176,"4180":4176,"4181":4176,"4182":4176,"4183":4176,"4184":4176,"4185":4176,"4186":4176,"4187":4176,"4188":4176,"4189":4176,"4190":4176,"4191":4176,"4195":4192,"4196":4192,"4197":4192,"4198":4192,"4199":4192,"4200":4192,"4201":4192,"4202":4192,"4203":4192,"4204":4192,"4205":4192,"4206":4192,"4207":4192,"4211":4208,"4212":4208,"4213":4208,"4214":4208,"4215":4208,"4216":4208,"4217":4208,"4218":4208,"4219":4208,"4220":4208,"4221":4208,"4222":4208,"4223":4208,"4227":4224,"4228":4224,"4229":4224,"4230":4224,"4231":4224,"4232":4224,"4233":4224,"4234":4224,"4235":4224,"4236":4224,"4237":4224,"4238":4224,"4239":4224,"4243":4240,"4244":4240,"4245":4240,"4246":4240,"4247":4240,"4248":4240,"4249":4240,"4250":4240,"4251":4240,"4252":4240,"4253":4240,"4254":4240,"4255":4240,"4257":4256,"4258":4256,"4259":4256,"4260":4256,"4261":4256,"4262":4256,"4263":4256,"4264":4256,"4265":4256,"4266":4256,"4267":4256,"4268":4256,"4269":4256,"4270":4256,"4271":4256,"4273":4272,"4274":4272,"4275":4272,"4276":4272,"4277":4272,"4278":4272,"4279":4272,"4280":4272,"4281":4272,"4282":4272,"4283":4272,"4284":4272,"4285":4272,"4286":4272,"4287":4272,"4289":4288,"4290":4288,"4291":4288,"4292":4288,"4293":4288,"4294":4288,"4295":4288,"4296":4288,"4297":4288,"4298":4288,"4299":4288,"4300":4288,"4301":4288,"4302":4288,"4303":4288,"4305":4304,"4306":4304,"4307":4304,"4308":4304,"4309":4304,"4310":4304,"4311":4304,"4312":4304,"4313":4304,"4314":4304,"4315":4304,"4316":4304,"4317":4304,"4318":4304,"4319":4304,"4321":4320,"4322":4320,"4323":4320,"4324":4320,"4325":4320,"4326":4320,"4327":4320,"4328":4320,"4329":4320,"4330":4320,"4331":4320,"4332":4320,"4333":4320,"4334":4320,"4335":4320,"4337":4336,"4338":4336,"4339":4336,"4340":4336,"4341":4336,"4342":4336,"4343":4336,"4344":4336,"4345":4336,"4346":4336,"4347":4336,"4348":4336,"4349":4336,"4350":4336,"4351":4336,"4353":4352,"4354":4352,"4355":4352,"4356":4352,"4357":4352,"4358":4352,"4359":4352,"4360":4352,"4361":4352,"4362":4352,"4363":4352,"4364":4352,"4365":4352,"4366":4352,"4367":4352,"4369":4368,"4370":4368,"4371":4368,"4372":4368,"4373":4368,"4374":4368,"4375":4368,"4376":4368,"4377":4368,"4378":4368,"4379":4368,"4380":4368,"4381":4368,"4382":4368,"4383":4368,"4385":4384,"4386":4384,"4387":4384,"4388":4384,"4389":4384,"4390":4384,"4391":4384,"4392":4384,"4393":4384,"4394":4384,"4395":4384,"4396":4384,"4397":4384,"4398":4384,"4399":4384,"4401":4400,"4402":4400,"4403":4400,"4404":4400,"4405":4400,"4406":4400,"4407":4400,"4408":4400,"4409":4400,"4410":4400,"4411":4400,"4412":4400,"4413":4400,"4414":4400,"4415":4400,"4417":4416,"4418":4416,"4419":4416,"4420":4416,"4421":4416,"4422":4416,"4423":4416,"4424":4416,"4425":4416,"4426":4416,"4427":4416,"4428":4416,"4429":4416,"4430":4416,"4431":4416,"4433":4432,"4434":4432,"4435":4432,"4436":4432,"4437":4432,"4438":4432,"4439":4432,"4440":4432,"4441":4432,"4442":4432,"4443":4432,"4444":4432,"4445":4432,"4446":4432,"4447":4432,"4449":4448,"4450":4448,"4451":4448,"4452":4448,"4453":4448,"4454":4448,"4455":4448,"4456":4448,"4457":4448,"4458":4448,"4459":4448,"4460":4448,"4461":4448,"4462":4448,"4463":4448,"4465":4464,"4466":4464,"4467":4464,"4468":4464,"4469":4464,"4470":4464,"4471":4464,"4472":4464,"4473":4464,"4474":4464,"4475":4464,"4476":4464,"4477":4464,"4478":4464,"4479":4464,"4481":4480,"4482":4480,"4483":4480,"4484":4480,"4485":4480,"4486":4480,"4487":4480,"4488":4480,"4489":4480,"4490":4480,"4491":4480,"4492":4480,"4493":4480,"4494":4480,"4495":4480,"4497":4496,"4498":4496,"4499":4496,"4500":4496,"4501":4496,"4502":4496,"4503":4496,"4504":4496,"4505":4496,"4506":4496,"4507":4496,"4508":4496,"4509":4496,"4510":4496,"4511":4496,"4513":4512,"4514":4512,"4515":4512,"4516":4512,"4517":4512,"4518":4512,"4519":4512,"4520":4512,"4521":4512,"4522":4512,"4523":4512,"4524":4512,"4525":4512,"4526":4512,"4527":4512,"4529":4528,"4530":4528,"4531":4528,"4532":4528,"4533":4528,"4534":4528,"4535":4528,"4536":4528,"4537":4528,"4538":4528,"4539":4528,"4540":4528,"4541":4528,"4542":4528,"4543":4528,"4545":4544,"4546":4544,"4547":4544,"4548":4544,"4549":4544,"4550":4544,"4551":4544,"4552":4544,"4553":4544,"4554":4544,"4555":4544,"4556":4544,"4557":4544,"4558":4544,"4559":4544,"4561":4560,"4562":4560,"4563":4560,"4564":4560,"4565":4560,"4566":4560,"4567":4560,"4568":4560,"4569":4560,"4570":4560,"4571":4560,"4572":4560,"4573":4560,"4574":4560,"4575":4560,"4577":4576,"4578":4576,"4579":4576,"4580":4576,"4581":4576,"4582":4576,"4583":4576,"4584":4576,"4585":4576,"4586":4576,"4587":4576,"4588":4576,"4589":4576,"4590":4576,"4591":4576,"4593":4592,"4594":4592,"4595":4592,"4596":4592,"4597":4592,"4598":4592,"4599":4592,"4600":4592,"4601":4592,"4602":4592,"4603":4592,"4604":4592,"4605":4592,"4606":4592,"4607":4592,"4609":4608,"4610":4608,"4611":4608,"4612":4608,"4613":4608,"4614":4608,"4615":4608,"4616":4608,"4617":4608,"4618":4608,"4619":4608,"4620":4608,"4621":4608,"4622":4608,"4623":4608,"4625":4624,"4626":4624,"4627":4624,"4628":4624,"4629":4624,"4630":4624,"4631":4624,"4632":4624,"4633":4624,"4634":4624,"4635":4624,"4636":4624,"4637":4624,"4638":4624,"4639":4624,"4641":4640,"4642":4640,"4643":4640,"4644":4640,"4645":4640,"4646":4640,"4647":4640,"4648":4640,"4649":4640,"4650":4640,"4651":4640,"4652":4640,"4653":4640,"4654":4640,"4655":4640,"4657":4656,"4658":4656,"4659":4656,"4660":4656,"4661":4656,"4662":4656,"4663":4656,"4664":4656,"4665":4656,"4666":4656,"4667":4656,"4668":4656,"4669":4656,"4670":4656,"4671":4656,"4673":4672,"4674":4672,"4675":4672,"4676":4672,"4677":4672,"4678":4672,"4679":4672,"4680":4672,"4681":4672,"4682":4672,"4683":4672,"4684":4672,"4685":4672,"4686":4672,"4687":4672,"4689":4688,"4690":4688,"4691":4688,"4692":4688,"4693":4688,"4694":4688,"4695":4688,"4696":4688,"4697":4688,"4698":4688,"4699":4688,"4700":4688,"4701":4688,"4702":4688,"4703":4688,"4705":4704,"4706":4704,"4707":4704,"4708":4704,"4709":4704,"4710":4704,"4711":4704,"4712":4704,"4713":4704,"4714":4704,"4715":4704,"4716":4704,"4717":4704,"4718":4704,"4719":4704,"4721":4720,"4722":4720,"4723":4720,"4724":4720,"4725":4720,"4726":4720,"4727":4720,"4728":4720,"4729":4720,"4730":4720,"4731":4720,"4732":4720,"4733":4720,"4734":4720,"4735":4720,"4737":4736,"4738":4736,"4739":4736,"4740":4736,"4741":4736,"4742":4736,"4743":4736,"4744":4736,"4745":4736,"4746":4736,"4747":4736,"4748":4736,"4749":4736,"4750":4736,"4751":4736,"4753":4752,"4754":4752,"4755":4752,"4756":4752,"4757":4752,"4758":4752,"4759":4752,"4760":4752,"4761":4752,"4762":4752,"4763":4752,"4764":4752,"4765":4752,"4766":4752,"4767":4752,"4769":4768,"4770":4768,"4771":4768,"4772":4768,"4773":4768,"4774":4768,"4775":4768,"4776":4768,"4777":4768,"4778":4768,"4779":4768,"4780":4768,"4781":4768,"4782":4768,"4783":4768,"4785":4784,"4786":4784,"4787":4784,"4788":4784,"4789":4784,"4790":4784,"4791":4784,"4792":4784,"4793":4784,"4794":4784,"4795":4784,"4796":4784,"4797":4784,"4798":4784,"4799":4784,"4801":4800,"4802":4800,"4803":4800,"4804":4800,"4805":4800,"4806":4800,"4807":4800,"4808":4800,"4809":4800,"4810":4800,"4811":4800,"4812":4800,"4813":4800,"4814":4800,"4815":4800,"4817":4816,"4818":4816,"4819":4816,"4820":4816,"4821":4816,"4822":4816,"4823":4816,"4824":4816,"4825":4816,"4826":4816,"4827":4816,"4828":4816,"4829":4816,"4830":4816,"4831":4816,"4833":4832,"4834":4832,"4835":4832,"4836":4832,"4837":4832,"4838":4832,"4839":4832,"4840":4832,"4841":4832,"4842":4832,"4843":4832,"4844":4832,"4845":4832,"4846":4832,"4847":4832,"4849":4848,"4850":4848,"4851":4848,"4852":4848,"4853":4848,"4854":4848,"4855":4848,"4856":4848,"4857":4848,"4858":4848,"4859":4848,"4860":4848,"4861":4848,"4862":4848,"4863":4848,"4865":4864,"4866":4864,"4867":4864,"4868":4864,"4869":4864,"4870":4864,"4871":4864,"4872":4864,"4873":4864,"4874":4864,"4875":4864,"4876":4864,"4877":4864,"4878":4864,"4879":4864,"4881":4880,"4882":4880,"4883":4880,"4884":4880,"4885":4880,"4886":4880,"4887":4880,"4888":4880,"4889":4880,"4890":4880,"4891":4880,"4892":4880,"4893":4880,"4894":4880,"4895":4880,"4897":4896,"4898":4896,"4899":4896,"4900":4896,"4901":4896,"4902":4896,"4903":4896,"4904":4896,"4905":4896,"4906":4896,"4907":4896,"4908":4896,"4909":4896,"4910":4896,"4911":4896,"4913":4912,"4914":4912,"4915":4912,"4916":4912,"4917":4912,"4918":4912,"4919":4912,"4920":4912,"4921":4912,"4922":4912,"4923":4912,"4924":4912,"4925":4912,"4926":4912,"4927":4912,"4929":4928,"4930":4928,"4931":4928,"4932":4928,"4933":4928,"4934":4928,"4935":4928,"4936":4928,"4937":4928,"4938":4928,"4939":4928,"4940":4928,"4941":4928,"4942":4928,"4943":4928,"4945":4944,"4946":4944,"4947":4944,"4948":4944,"4949":4944,"4950":4944,"4951":4944,"4952":4944,"4953":4944,"4954":4944,"4955":4944,"4956":4944,"4957":4944,"4958":4944,"4959":4944,"4961":4960,"4962":4960,"4963":4960,"4964":4960,"4965":4960,"4966":4960,"4967":4960,"4968":4960,"4969":4960,"4970":4960,"4971":4960,"4972":4960,"4973":4960,"4974":4960,"4975":4960,"4977":4976,"4978":4976,"4979":4976,"4980":4976,"4981":4976,"4982":4976,"4983":4976,"4984":4976,"4985":4976,"4986":4976,"4987":4976,"4988":4976,"4989":4976,"4990":4976,"4991":4976,"4993":4992,"4994":4992,"4995":4992,"4996":4992,"4997":4992,"4998":4992,"4999":4992,"5000":4992,"5001":4992,"5002":4992,"5003":4992,"5004":4992,"5005":4992,"5006":4992,"5007":4992,"5009":5008,"5010":5008,"5011":5008,"5012":5008,"5013":5008,"5014":5008,"5015":5008,"5016":5008,"5017":5008,"5018":5008,"5019":5008,"5020":5008,"5021":5008,"5022":5008,"5023":5008,"5025":5024,"5026":5024,"5027":5024,"5028":5024,"5029":5024,"5030":5024,"5031":5024,"5032":5024,"5033":5024,"5034":5024,"5035":5024,"5036":5024,"5037":5024,"5038":5024,"5039":5024,"5041":5040,"5042":5040,"5043":5040,"5044":5040,"5045":5040,"5046":5040,"5047":5040,"5048":5040,"5049":5040,"5050":5040,"5051":5040,"5052":5040,"5053":5040,"5054":5040,"5055":5040,"5057":5056,"5058":5056,"5059":5056,"5060":5056,"5061":5056,"5062":5056,"5063":5056,"5064":5056,"5065":5056,"5066":5056,"5067":5056,"5068":5056,"5069":5056,"5070":5056,"5071":5056,"5073":5072,"5074":5072,"5075":5072,"5076":5072,"5077":5072,"5078":5072,"5079":5072,"5080":5072,"5081":5072,"5082":5072,"5083":5072,"5084":5072,"5085":5072,"5086":5072,"5087":5072,"5089":5088,"5090":5088,"5091":5088,"5092":5088,"5093":5088,"5094":5088,"5095":5088,"5096":5088,"5097":5088,"5098":5088,"5099":5088,"5100":5088,"5101":5088,"5102":5088,"5103":5088,"5105":5104,"5106":5104,"5107":5104,"5108":5104,"5109":5104,"5110":5104,"5111":5104,"5112":5104,"5113":5104,"5114":5104,"5115":5104,"5116":5104,"5117":5104,"5118":5104,"5119":5104,"5121":5120,"5122":5120,"5123":5120,"5124":5120,"5125":5120,"5126":5120,"5127":5120,"5128":5120,"5129":5120,"5130":5120,"5131":5120,"5132":5120,"5133":5120,"5134":5120,"5135":5120,"5137":5136,"5138":5136,"5139":5136,"5140":5136,"5141":5136,"5142":5136,"5143":5136,"5144":5136,"5145":5136,"5146":5136,"5147":5136,"5148":5136,"5149":5136,"5150":5136,"5151":5136,"5153":5152,"5154":5152,"5155":5152,"5156":5152,"5157":5152,"5158":5152,"5159":5152,"5160":5152,"5161":5152,"5162":5152,"5163":5152,"5164":5152,"5165":5152,"5166":5152,"5167":5152,"5169":5168,"5170":5168,"5171":5168,"5172":5168,"5173":5168,"5174":5168,"5175":5168,"5176":5168,"5177":5168,"5178":5168,"5179":5168,"5180":5168,"5181":5168,"5182":5168,"5183":5168,"5185":5184,"5186":5184,"5187":5184,"5188":5184,"5189":5184,"5190":5184,"5191":5184,"5192":5184,"5193":5184,"5194":5184,"5195":5184,"5196":5184,"5197":5184,"5198":5184,"5199":5184,"5201":5200,"5202":5200,"5203":5200,"5204":5200,"5205":5200,"5206":5200,"5207":5200,"5208":5200,"5209":5200,"5210":5200,"5211":5200,"5212":5200,"5213":5200,"5214":5200,"5215":5200,"5217":5216,"5218":5216,"5219":5216,"5220":5216,"5221":5216,"5222":5216,"5223":5216,"5224":5216,"5225":5216,"5226":5216,"5227":5216,"5228":5216,"5229":5216,"5230":5216,"5231":5216,"5233":5232,"5234":5232,"5235":5232,"5236":5232,"5237":5232,"5238":5232,"5239":5232,"5240":5232,"5241":5232,"5242":5232,"5243":5232,"5244":5232,"5245":5232,"5246":5232,"5247":5232,"5249":5248,"5250":5248,"5251":5248,"5252":5248,"5253":5248,"5254":5248,"5255":5248,"5256":5248,"5257":5248,"5258":5248,"5259":5248,"5260":5248,"5261":5248,"5262":5248,"5263":5248,"5265":5264,"5266":5264,"5267":5264,"5268":5264,"5269":5264,"5270":5264,"5271":5264,"5272":5264,"5273":5264,"5274":5264,"5275":5264,"5276":5264,"5277":5264,"5278":5264,"5279":5264,"5281":5280,"5282":5280,"5283":5280,"5284":5280,"5285":5280,"5286":5280,"5287":5280,"5288":5280,"5289":5280,"5290":5280,"5291":5280,"5292":5280,"5293":5280,"5294":5280,"5295":5280,"5297":5296,"5298":5296,"5299":5296,"5300":5296,"5301":5296,"5302":5296,"5303":5296,"5304":5296,"5305":5296,"5306":5296,"5307":5296,"5308":5296,"5309":5296,"5310":5296,"5311":5296,"5313":5312,"5314":5312,"5315":5312,"5316":5312,"5317":5312,"5318":5312,"5319":5312,"5320":5312,"5321":5312,"5322":5312,"5323":5312,"5324":5312,"5325":5312,"5326":5312,"5327":5312,"5329":5328,"5330":5328,"5331":5328,"5332":5328,"5333":5328,"5334":5328,"5335":5328,"5336":5328,"5337":5328,"5338":5328,"5339":5328,"5340":5328,"5341":5328,"5342":5328,"5343":5328,"5345":5344,"5346":5344,"5347":5344,"5348":5344,"5349":5344,"5350":5344,"5351":5344,"5352":5344,"5353":5344,"5354":5344,"5355":5344,"5356":5344,"5357":5344,"5358":5344,"5359":5344,"5361":5360,"5362":5360,"5363":5360,"5364":5360,"5365":5360,"5366":5360,"5367":5360,"5368":5360,"5369":5360,"5370":5360,"5371":5360,"5372":5360,"5373":5360,"5374":5360,"5375":5360,"5377":5376,"5378":5376,"5379":5376,"5380":5376,"5381":5376,"5382":5376,"5383":5376,"5384":5376,"5385":5376,"5386":5376,"5387":5376,"5388":5376,"5389":5376,"5390":5376,"5391":5376,"5393":5392,"5394":5392,"5395":5392,"5396":5392,"5397":5392,"5398":5392,"5399":5392,"5400":5392,"5401":5392,"5402":5392,"5403":5392,"5404":5392,"5405":5392,"5406":5392,"5407":5392,"5409":5408,"5410":5408,"5411":5408,"5412":5408,"5413":5408,"5414":5408,"5415":5408,"5416":5408,"5417":5408,"5418":5408,"5419":5408,"5420":5408,"5421":5408,"5422":5408,"5423":5408,"5425":5424,"5426":5424,"5427":5424,"5428":5424,"5429":5424,"5430":5424,"5431":5424,"5432":5424,"5433":5424,"5434":5424,"5435":5424,"5436":5424,"5437":5424,"5438":5424,"5439":5424,"5441":5440,"5442":5440,"5443":5440,"5444":5440,"5445":5440,"5446":5440,"5447":5440,"5448":5440,"5449":5440,"5450":5440,"5451":5440,"5452":5440,"5453":5440,"5454":5440,"5455":5440,"5457":5456,"5458":5456,"5459":5456,"5460":5456,"5461":5456,"5462":5456,"5463":5456,"5464":5456,"5465":5456,"5466":5456,"5467":5456,"5468":5456,"5469":5456,"5470":5456,"5471":5456,"5473":5472,"5474":5472,"5475":5472,"5476":5472,"5477":5472,"5478":5472,"5479":5472,"5480":5472,"5481":5472,"5482":5472,"5483":5472,"5484":5472,"5485":5472,"5486":5472,"5487":5472,"5489":5488,"5490":5488,"5491":5488,"5492":5488,"5493":5488,"5494":5488,"5495":5488,"5496":5488,"5497":5488,"5498":5488,"5499":5488,"5500":5488,"5501":5488,"5502":5488,"5503":5488,"5505":5504,"5506":5504,"5507":5504,"5508":5504,"5509":5504,"5510":5504,"5511":5504,"5512":5504,"5513":5504,"5514":5504,"5515":5504,"5516":5504,"5517":5504,"5518":5504,"5519":5504,"5521":5520,"5522":5520,"5523":5520,"5524":5520,"5525":5520,"5526":5520,"5527":5520,"5528":5520,"5529":5520,"5530":5520,"5531":5520,"5532":5520,"5533":5520,"5534":5520,"5535":5520,"5537":5536,"5538":5536,"5539":5536,"5540":5536,"5541":5536,"5542":5536,"5543":5536,"5544":5536,"5545":5536,"5546":5536,"5547":5536,"5548":5536,"5549":5536,"5550":5536,"5551":5536,"5553":5552,"5554":5552,"5555":5552,"5556":5552,"5557":5552,"5558":5552,"5559":5552,"5560":5552,"5561":5552,"5562":5552,"5563":5552,"5564":5552,"5565":5552,"5566":5552,"5567":5552,"5569":5568,"5570":5568,"5571":5568,"5572":5568,"5573":5568,"5574":5568,"5575":5568,"5576":5568,"5577":5568,"5578":5568,"5579":5568,"5580":5568,"5581":5568,"5582":5568,"5583":5568,"5585":5584,"5586":5584,"5587":5584,"5588":5584,"5589":5584,"5590":5584,"5591":5584,"5592":5584,"5593":5584,"5594":5584,"5595":5584,"5596":5584,"5597":5584,"5598":5584,"5599":5584,"5601":5600,"5602":5600,"5603":5600,"5604":5600,"5605":5600,"5606":5600,"5607":5600,"5608":5600,"5609":5600,"5610":5600,"5611":5600,"5612":5600,"5613":5600,"5614":5600,"5615":5600,"5617":5616,"5618":5616,"5619":5616,"5620":5616,"5621":5616,"5622":5616,"5623":5616,"5624":5616,"5625":5616,"5626":5616,"5627":5616,"5628":5616,"5629":5616,"5630":5616,"5631":5616,"5633":5632,"5634":5632,"5635":5632,"5636":5632,"5637":5632,"5638":5632,"5639":5632,"5640":5632,"5641":5632,"5642":5632,"5643":5632,"5644":5632,"5645":5632,"5646":5632,"5647":5632,"5649":5648,"5650":5648,"5651":5648,"5652":5648,"5653":5648,"5654":5648,"5655":5648,"5656":5648,"5657":5648,"5658":5648,"5659":5648,"5660":5648,"5661":5648,"5662":5648,"5663":5648,"5665":5664,"5666":5664,"5667":5664,"5668":5664,"5669":5664,"5670":5664,"5671":5664,"5672":5664,"5673":5664,"5674":5664,"5675":5664,"5676":5664,"5677":5664,"5678":5664,"5679":5664,"5681":5680,"5682":5680,"5683":5680,"5684":5680,"5685":5680,"5686":5680,"5687":5680,"5688":5680,"5689":5680,"5690":5680,"5691":5680,"5692":5680,"5693":5680,"5694":5680,"5695":5680,"5697":5696,"5698":5696,"5699":5696,"5700":5696,"5701":5696,"5702":5696,"5703":5696,"5704":5696,"5705":5696,"5706":5696,"5707":5696,"5708":5696,"5709":5696,"5710":5696,"5711":5696,"5713":5712,"5714":5712,"5715":5712,"5716":5712,"5717":5712,"5718":5712,"5719":5712,"5720":5712,"5721":5712,"5722":5712,"5723":5712,"5724":5712,"5725":5712,"5726":5712,"5727":5712,"5729":5728,"5730":5728,"5731":5728,"5732":5728,"5733":5728,"5734":5728,"5735":5728,"5736":5728,"5737":5728,"5738":5728,"5739":5728,"5740":5728,"5741":5728,"5742":5728,"5743":5728,"5745":5744,"5746":5744,"5747":5744,"5748":5744,"5749":5744,"5750":5744,"5751":5744,"5752":5744,"5753":5744,"5754":5744,"5755":5744,"5756":5744,"5757":5744,"5758":5744,"5759":5744,"5761":5760,"5762":5760,"5763":5760,"5764":5760,"5765":5760,"5766":5760,"5767":5760,"5768":5760,"5769":5760,"5770":5760,"5771":5760,"5772":5760,"5773":5760,"5774":5760,"5775":5760,"5777":5776,"5778":5776,"5779":5776,"5780":5776,"5781":5776,"5782":5776,"5783":5776,"5784":5776,"5785":5776,"5786":5776,"5787":5776,"5788":5776,"5789":5776,"5790":5776,"5791":5776,"5793":5792,"5794":5792,"5795":5792,"5796":5792,"5797":5792,"5798":5792,"5799":5792,"5800":5792,"5801":5792,"5802":5792,"5803":5792,"5804":5792,"5805":5792,"5806":5792,"5807":5792,"5809":5808,"5810":5808,"5811":5808,"5812":5808,"5813":5808,"5814":5808,"5815":5808,"5816":5808,"5817":5808,"5818":5808,"5819":5808,"5820":5808,"5821":5808,"5822":5808,"5823":5808,"5825":5824,"5826":5824,"5827":5824,"5828":5824,"5829":5824,"5830":5824,"5831":5824,"5832":5824,"5833":5824,"5834":5824,"5835":5824,"5836":5824,"5837":5824,"5838":5824,"5839":5824,"5841":5840,"5842":5840,"5843":5840,"5844":5840,"5845":5840,"5846":5840,"5847":5840,"5848":5840,"5849":5840,"5850":5840,"5851":5840,"5852":5840,"5853":5840,"5854":5840,"5855":5840,"5857":5856,"5858":5856,"5859":5856,"5860":5856,"5861":5856,"5862":5856,"5863":5856,"5864":5856,"5865":5856,"5866":5856,"5867":5856,"5868":5856,"5869":5856,"5870":5856,"5871":5856,"5873":5872,"5874":5872,"5875":5872,"5876":5872,"5877":5872,"5878":5872,"5879":5872,"5880":5872,"5881":5872,"5882":5872,"5883":5872,"5884":5872,"5885":5872,"5886":5872,"5887":5872,"5889":5888,"5890":5888,"5891":5888,"5892":5888,"5893":5888,"5894":5888,"5895":5888,"5896":5888,"5897":5888,"5898":5888,"5899":5888,"5900":5888,"5901":5888,"5902":5888,"5903":5888,"5905":5904,"5906":5904,"5907":5904,"5908":5904,"5909":5904,"5910":5904,"5911":5904,"5912":5904,"5913":5904,"5914":5904,"5915":5904,"5916":5904,"5917":5904,"5918":5904,"5919":5904,"5921":5920,"5922":5920,"5923":5920,"5924":5920,"5925":5920,"5926":5920,"5927":5920,"5928":5920,"5929":5920,"5930":5920,"5931":5920,"5932":5920,"5933":5920,"5934":5920,"5935":5920,"5937":5936,"5938":5936,"5939":5936,"5940":5936,"5941":5936,"5942":5936,"5943":5936,"5944":5936,"5945":5936,"5946":5936,"5947":5936,"5948":5936,"5949":5936,"5950":5936,"5951":5936,"5953":5952,"5954":5952,"5955":5952,"5956":5952,"5957":5952,"5958":5952,"5959":5952,"5960":5952,"5961":5952,"5962":5952,"5963":5952,"5964":5952,"5965":5952,"5966":5952,"5967":5952,"5969":5968,"5970":5968,"5971":5968,"5972":5968,"5973":5968,"5974":5968,"5975":5968,"5976":5968,"5977":5968,"5978":5968,"5979":5968,"5980":5968,"5981":5968,"5982":5968,"5983":5968,"5985":5984,"5986":5984,"5987":5984,"5988":5984,"5989":5984,"5990":5984,"5991":5984,"5992":5984,"5993":5984,"5994":5984,"5995":5984,"5996":5984,"5997":5984,"5998":5984,"5999":5984,"6001":6000,"6002":6000,"6003":6000,"6004":6000,"6005":6000,"6006":6000,"6007":6000,"6008":6000,"6009":6000,"6010":6000,"6011":6000,"6012":6000,"6013":6000,"6014":6000,"6015":6000,"6017":6016,"6018":6016,"6019":6016,"6020":6016,"6021":6016,"6022":6016,"6023":6016,"6024":6016,"6025":6016,"6026":6016,"6027":6016,"6028":6016,"6029":6016,"6030":6016,"6031":6016,"6033":6032,"6034":6032,"6035":6032,"6036":6032,"6037":6032,"6038":6032,"6039":6032,"6040":6032,"6041":6032,"6042":6032,"6043":6032,"6044":6032,"6045":6032,"6046":6032,"6047":6032,"6049":6048,"6050":6048,"6051":6048,"6052":6048,"6053":6048,"6054":6048,"6055":6048,"6056":6048,"6057":6048,"6058":6048,"6059":6048,"6060":6048,"6061":6048,"6062":6048,"6063":6048,"6065":6064,"6066":6064,"6067":6064,"6068":6064,"6069":6064,"6070":6064,"6071":6064,"6072":6064,"6073":6064,"6074":6064,"6075":6064,"6076":6064,"6077":6064,"6078":6064,"6079":6064,"6081":6080,"6082":6080,"6083":6080,"6084":6080,"6085":6080,"6086":6080,"6087":6080,"6088":6080,"6089":6080,"6090":6080,"6091":6080,"6092":6080,"6093":6080,"6094":6080,"6095":6080,"6097":6096,"6098":6096,"6099":6096,"6100":6096,"6101":6096,"6102":6096,"6103":6096,"6104":6096,"6105":6096,"6106":6096,"6107":6096,"6108":6096,"6109":6096,"6110":6096,"6111":6096,"6113":6112,"6114":6112,"6115":6112,"6116":6112,"6117":6112,"6118":6112,"6119":6112,"6120":6112,"6121":6112,"6122":6112,"6123":6112,"6124":6112,"6125":6112,"6126":6112,"6127":6112,"6129":6128,"6130":6128,"6131":6128,"6132":6128,"6133":6128,"6134":6128,"6135":6128,"6136":6128,"6137":6128,"6138":6128,"6139":6128,"6140":6128,"6141":6128,"6142":6128,"6143":6128,"6145":6144,"6146":6144,"6147":6144,"6148":6144,"6149":6144,"6150":6144,"6151":6144,"6152":6144,"6153":6144,"6154":6144,"6155":6144,"6156":6144,"6157":6144,"6158":6144,"6159":6144,"6181":6176,"6182":6176,"6183":6176,"6184":6176,"6185":6176,"6186":6176,"6187":6176,"6188":6176,"6189":6176,"6190":6176,"6191":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6305":6304,"6306":6304,"6307":6304,"6308":6304,"6309":6304,"6310":6304,"6311":6304,"6312":6304,"6313":6304,"6314":6304,"6315":6304,"6316":6304,"6317":6304,"6318":6304,"6319":6304,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6482":6480,"6483":6480,"6484":6480,"6485":6480,"6486":6480,"6487":6480,"6488":6480,"6489":6480,"6490":6480,"6491":6480,"6492":6480,"6493":6480,"6494":6480,"6495":6480,"6498":6496,"6499":6496,"6500":6496,"6501":6496,"6502":6496,"6503":6496,"6504":6496,"6505":6496,"6506":6496,"6507":6496,"6508":6496,"6509":6496,"6510":6496,"6511":6496,"6514":6512,"6515":6512,"6516":6512,"6517":6512,"6518":6512,"6519":6512,"6520":6512,"6521":6512,"6522":6512,"6523":6512,"6524":6512,"6525":6512,"6526":6512,"6527":6512,"6530":6528,"6531":6528,"6532":6528,"6533":6528,"6534":6528,"6535":6528,"6536":6528,"6537":6528,"6538":6528,"6539":6528,"6540":6528,"6541":6528,"6542":6528,"6543":6528,"6546":6544,"6547":6544,"6548":6544,"6549":6544,"6550":6544,"6551":6544,"6552":6544,"6553":6544,"6554":6544,"6555":6544,"6556":6544,"6557":6544,"6558":6544,"6559":6544,"6564":6562,"6565":6562,"6566":6562,"6567":6562,"6568":6562,"6569":6562,"6570":6562,"6571":6562,"6572":6562,"6573":6562,"6574":6562,"6575":6562,"6584":6580,"6585":6580,"6586":6580,"6587":6580,"6588":6580,"6589":6580,"6590":6580,"6591":6580,"6657":6656,"6658":6656,"6659":6656,"6660":6656,"6661":6656,"6662":6656,"6663":6656,"6664":6656,"6665":6656,"6666":6656,"6667":6656,"6668":6656,"6669":6656,"6670":6656,"6671":6656,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6705":6704,"6706":6704,"6707":6704,"6708":6704,"6709":6704,"6710":6704,"6711":6704,"6713":6704,"6714":6704,"6715":6704,"6716":6704,"6717":6704,"6718":6704,"6719":6704,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6792":6787,"6793":6787,"6794":6787,"6795":6787,"6796":6787,"6797":6787,"6798":6787,"6799":6787,"6808":6803,"6809":6803,"6810":6803,"6811":6803,"6812":6803,"6813":6803,"6814":6803,"6815":6803,"6824":6819,"6825":6819,"6826":6819,"6827":6819,"6828":6819,"6829":6819,"6830":6819,"6831":6819,"6840":6835,"6841":6835,"6842":6835,"6843":6835,"6844":6835,"6845":6835,"6846":6835,"6847":6835,"6856":6851,"6857":6851,"6858":6851,"6859":6851,"6860":6851,"6861":6851,"6862":6851,"6863":6851,"6872":6867,"6873":6867,"6874":6867,"6875":6867,"6876":6867,"6877":6867,"6878":6867,"6879":6867,"6888":6883,"6889":6883,"6890":6883,"6891":6883,"6892":6883,"6893":6883,"6894":6883,"6895":6883,"6904":6899,"6905":6899,"6906":6899,"6907":6899,"6908":6899,"6909":6899,"6910":6899,"6911":6899,"6920":6915,"6921":6915,"6922":6915,"6923":6915,"6924":6915,"6925":6915,"6926":6915,"6927":6915,"6936":6931,"6937":6931,"6938":6931,"6939":6931,"6940":6931,"6941":6931,"6942":6931,"6943":6931,"6952":6947,"6953":6947,"6954":6947,"6955":6947,"6956":6947,"6957":6947,"6958":6947,"6959":6947,"6968":6963,"6969":6963,"6970":6963,"6971":6963,"6972":6963,"6973":6963,"6974":6963,"6975":6963,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7000":6994,"7001":6994,"7002":6994,"7003":6994,"7004":6994,"7005":6994,"7006":6994,"7007":6994,"7009":7008,"7010":7008,"7011":7008,"7012":7008,"7013":7008,"7014":7008,"7015":7008,"7016":7008,"7017":7008,"7018":7008,"7019":7008,"7020":7008,"7021":7008,"7022":7008,"7023":7008,"7032":7027,"7033":7027,"7034":7027,"7035":7027,"7036":7027,"7037":7027,"7038":7027,"7039":7027,"7048":7043,"7049":7043,"7050":7043,"7051":7043,"7052":7043,"7053":7043,"7054":7043,"7055":7043,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7080":7074,"7081":7074,"7082":7074,"7083":7074,"7084":7074,"7085":7074,"7086":7074,"7087":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7112":7106,"7113":7106,"7114":7106,"7115":7106,"7116":7106,"7117":7106,"7118":7106,"7119":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7144":7138,"7145":7138,"7146":7138,"7147":7138,"7148":7138,"7149":7138,"7150":7138,"7151":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7176":7170,"7177":7170,"7178":7170,"7179":7170,"7180":7170,"7181":7170,"7182":7170,"7183":7170,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7224":7218,"7225":7218,"7226":7218,"7227":7218,"7228":7218,"7229":7218,"7230":7218,"7231":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7256":7250,"7257":7250,"7258":7250,"7259":7250,"7260":7250,"7261":7250,"7262":7250,"7263":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7272":7250,"7273":7250,"7274":7250,"7275":7250,"7276":7250,"7277":7250,"7278":7250,"7279":7250,"7297":7296,"7298":7296,"7299":7296,"7300":7296,"7301":7296,"7302":7296,"7303":7296,"7304":7296,"7305":7296,"7306":7296,"7307":7296,"7308":7296,"7309":7296,"7310":7296,"7311":7296,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7348":7346,"7349":7346,"7350":7346,"7351":7346,"7352":7346,"7353":7346,"7354":7346,"7355":7346,"7356":7346,"7357":7346,"7358":7346,"7359":7346,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7400":7392,"7401":7392,"7402":7392,"7403":7392,"7404":7392,"7405":7392,"7406":7392,"7407":7392,"7410":7408,"7411":7408,"7412":7408,"7413":7408,"7414":7408,"7415":7408,"7416":7408,"7417":7408,"7418":7408,"7419":7408,"7420":7408,"7421":7408,"7422":7408,"7423":7408,"7504":7218,"7505":7218,"7510":7218,"7511":7218,"7512":7218,"7513":7218,"7514":7218,"7515":7218,"7516":7218,"7517":7218,"7518":7218,"7519":7218}} \ No newline at end of file From 7e0f6c02a1f67b8ab4ef8dc96923f182e5441df0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 21:59:39 +0000 Subject: [PATCH 402/710] Updated build/php submodule to pmmp/php-build-scripts@a59722c6764ce82e91a1ec2a9aa158e060022bed --- build/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/php b/build/php index 7a2ab5b92..a59722c67 160000 --- a/build/php +++ b/build/php @@ -1 +1 @@ -Subproject commit 7a2ab5b92218a5cd8e77f05ece0c5edce8f1863d +Subproject commit a59722c6764ce82e91a1ec2a9aa158e060022bed From f2540a72ad89d393ef4587ae446ebb952fa5a672 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 22:10:46 +0000 Subject: [PATCH 403/710] Backport improved make-release.php from PM4 --- build/make-release.php | 83 +++++++++++++++++++++++----------- src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/build/make-release.php b/build/make-release.php index ec6bc2f01..441e74ce2 100644 --- a/build/make-release.php +++ b/build/make-release.php @@ -24,64 +24,95 @@ declare(strict_types=1); namespace pocketmine\build\make_release; use pocketmine\utils\VersionString; -use function count; +use function array_keys; +use function array_map; use function dirname; use function fgets; use function file_get_contents; use function file_put_contents; use function fwrite; +use function getopt; +use function is_string; +use function max; use function preg_replace; use function sleep; use function sprintf; +use function str_pad; +use function strlen; use function system; use const pocketmine\BASE_VERSION; +use const pocketmine\BUILD_CHANNEL; use const STDERR; use const STDIN; +use const STDOUT; +use const STR_PAD_LEFT; require_once dirname(__DIR__) . '/vendor/autoload.php'; function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev, string $channel) : void{ $versionInfo = file_get_contents($versionInfoPath); $versionInfo = preg_replace( - $pattern = '/^const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m', - 'const BASE_VERSION = "' . $newVersion . '";', + $pattern = '/^([\t ]*public )?const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m', + '$1const BASE_VERSION = "' . $newVersion . '";', $versionInfo ); $versionInfo = preg_replace( - '/^const IS_DEVELOPMENT_BUILD = (?:true|false);$/m', - 'const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false') . ';', + '/^([\t ]*public )?const IS_DEVELOPMENT_BUILD = (?:true|false);$/m', + '$1const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false') . ';', $versionInfo ); $versionInfo = preg_replace( - '/^const BUILD_CHANNEL = ".*";$/m', - 'const BUILD_CHANNEL = "' . $channel . '";', + '/^([\t ]*public )?const BUILD_CHANNEL = ".*";$/m', + '$1const BUILD_CHANNEL = "' . $channel . '";', $versionInfo ); file_put_contents($versionInfoPath, $versionInfo); } -/** - * @param string[] $argv - * @phpstan-param list $argv - */ -function main(array $argv) : void{ - if(count($argv) < 2){ - fwrite(STDERR, "Arguments: [release version]\n"); - exit(1); +const ACCEPTED_OPTS = [ + "current" => "Version to insert and tag", + "next" => "Version to put in the file after tagging", + "channel" => "Release channel to post this build into" +]; + +function main() : void{ + $filteredOpts = []; + foreach(getopt("", ["current:", "next:", "channel:", "help"]) as $optName => $optValue){ + if($optName === "help"){ + fwrite(STDOUT, "Options:\n"); + + $maxLength = max(array_map(fn(string $str) => strlen($str), array_keys(ACCEPTED_OPTS))); + foreach(ACCEPTED_OPTS as $acceptedName => $description){ + fwrite(STDOUT, str_pad("--$acceptedName", $maxLength + 4, " ", STR_PAD_LEFT) . ": $description\n"); + } + exit(0); + } + if(!is_string($optValue)){ + fwrite(STDERR, "--$optName expects exactly 1 value\n"); + exit(1); + } + $filteredOpts[$optName] = $optValue; } - if(isset($argv[2])){ - $currentVer = new VersionString($argv[2]); + + if(isset($filteredOpts["current"])){ + $currentVer = new VersionString($filteredOpts["current"]); }else{ $currentVer = new VersionString(BASE_VERSION); } - $nextVer = new VersionString(sprintf( - "%u.%u.%u", - $currentVer->getMajor(), - $currentVer->getMinor(), - $currentVer->getPatch() + 1 - )); + if(isset($filteredOpts["next"])){ + $nextVer = new VersionString($filteredOpts["next"]); + }else{ + $nextVer = new VersionString(sprintf( + "%u.%u.%u", + $currentVer->getMajor(), + $currentVer->getMinor(), + $currentVer->getPatch() + 1 + )); + } + $channel = $filteredOpts["channel"] ?? BUILD_CHANNEL; echo "About to tag version $currentVer. Next version will be $nextVer.\n"; + echo "$currentVer will be published on release channel \"$channel\".\n"; echo "please add appropriate notes to the changelog and press enter..."; fgets(STDIN); system('git add "' . dirname(__DIR__) . '/changelogs"'); @@ -91,10 +122,10 @@ function main(array $argv) : void{ exit(1); } $versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php'; - replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $argv[1]); + replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel); system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"'); system('git tag ' . $currentVer->getBaseVersion()); - replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, ""); + replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel); system('git add "' . $versionInfoPath . '"'); system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"'); echo "pushing changes in 5 seconds\n"; @@ -102,4 +133,4 @@ function main(array $argv) : void{ system('git push origin HEAD ' . $currentVer->getBaseVersion()); } -main($argv); +main(); diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 05b503d48..bc4e06c15 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -36,4 +36,4 @@ const NAME = "PocketMine-MP"; const BASE_VERSION = "3.25.5"; const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; -const BUILD_CHANNEL = ""; +const BUILD_CHANNEL = "stable"; From 71b813d4f968748d7a64c6f1781a27a699142b5d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 22:27:58 +0000 Subject: [PATCH 404/710] Define pocketmine\BUILD_NUMBER from phar metadata this way we don't have to patch the code (no idea why we were doing that anyway). --- .github/workflows/draft-release.yml | 9 +++++---- build/generate-build-info-json.php | 6 +++--- build/server-phar.php | 10 ++++++++-- src/pocketmine/PocketMine.php | 11 ++++++++--- src/pocketmine/VersionInfo.php | 1 - tests/phpstan/bootstrap.php | 1 + 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index 37b743422..b70a2757f 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -35,11 +35,12 @@ jobs: - name: Install Composer dependencies run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs - - name: Patch VersionInfo + - name: Calculate build number + id: build-number run: | BUILD_NUMBER=2000+$GITHUB_RUN_NUMBER #to stay above jenkins echo "Build number: $BUILD_NUMBER" - sed -i "s/const BUILD_NUMBER = 0/const BUILD_NUMBER = ${BUILD_NUMBER}/" src/pocketmine/VersionInfo.php + echo ::set-output name=BUILD_NUMBER::$BUILD_NUMBER - name: Minify BedrockData JSON files run: php src/pocketmine/resources/vanilla/.minify_json.php @@ -68,7 +69,7 @@ jobs: done - name: Build PocketMine-MP.phar - run: php -dphar.readonly=0 build/server-phar.php --git ${{ github.sha }} + run: php -dphar.readonly=0 build/server-phar.php --git ${{ github.sha }} --build ${{ steps.build-number.outputs.BUILD_NUMBER }} - name: Get PocketMine-MP release version id: get-pm-version @@ -79,7 +80,7 @@ jobs: echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\BASE_VERSION);') - name: Generate build info - run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} > build_info.json + run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} > build_info.json - name: Upload release artifacts uses: actions/upload-artifact@v2 diff --git a/build/generate-build-info-json.php b/build/generate-build-info-json.php index 57828c372..b1ca16fca 100644 --- a/build/generate-build-info-json.php +++ b/build/generate-build-info-json.php @@ -23,15 +23,15 @@ declare(strict_types=1); require dirname(__DIR__) . '/vendor/autoload.php'; -if(count($argv) !== 4){ - fwrite(STDERR, "required args: "); +if(count($argv) !== 5){ + fwrite(STDERR, "required args: "); exit(1); } echo json_encode([ "php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION), "base_version" => \pocketmine\BASE_VERSION, - "build" => \pocketmine\BUILD_NUMBER, + "build" => (int) $argv[4], "is_dev" => \pocketmine\IS_DEVELOPMENT_BUILD, "channel" => \pocketmine\BUILD_CHANNEL, "git_commit" => $argv[1], diff --git a/build/server-phar.php b/build/server-phar.php index ed9200d35..462ff879c 100644 --- a/build/server-phar.php +++ b/build/server-phar.php @@ -134,13 +134,18 @@ function main() : void{ exit(1); } - $opts = getopt("", ["out:", "git:"]); + $opts = getopt("", ["out:", "git:", "build:"]); if(isset($opts["git"])){ $gitHash = $opts["git"]; }else{ $gitHash = Git::getRepositoryStatePretty(dirname(__DIR__)); echo "Git hash detected as $gitHash" . PHP_EOL; } + if(isset($opts["build"])){ + $build = (int) $opts["build"]; + }else{ + $build = 0; + } foreach(buildPhar( $opts["out"] ?? getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar", dirname(__DIR__) . DIRECTORY_SEPARATOR, @@ -149,7 +154,8 @@ function main() : void{ 'vendor' ], [ - 'git' => $gitHash + 'git' => $gitHash, + 'build' => $build ], <<<'STUB' getFullVersion(true)); - $gitHash = str_repeat("00", 20); + $buildNumber = 0; if(\Phar::running(true) === ""){ $gitHash = Git::getRepositoryStatePretty(\pocketmine\PATH); @@ -225,9 +223,16 @@ JIT_WARNING if(isset($meta["git"])){ $gitHash = $meta["git"]; } + if(isset($meta["build"]) && is_int($meta["build"])){ + $buildNumber = $meta["build"]; + } } define('pocketmine\GIT_COMMIT', $gitHash); + define('pocketmine\BUILD_NUMBER', $buildNumber); + + $version = new VersionString(\pocketmine\BASE_VERSION, \pocketmine\IS_DEVELOPMENT_BUILD, \pocketmine\BUILD_NUMBER); + define('pocketmine\VERSION', $version->getFullVersion(true)); $composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp'); if($composerGitHash !== null){ diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index bc4e06c15..7c6ecba82 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -35,5 +35,4 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.25.5"; const IS_DEVELOPMENT_BUILD = true; -const BUILD_NUMBER = 0; const BUILD_CHANNEL = "stable"; diff --git a/tests/phpstan/bootstrap.php b/tests/phpstan/bootstrap.php index 7e374a27f..2969d503c 100644 --- a/tests/phpstan/bootstrap.php +++ b/tests/phpstan/bootstrap.php @@ -30,6 +30,7 @@ if(!defined('LEVELDB_ZLIB_RAW_COMPRESSION')){ define('pocketmine\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__, 2) . '/vendor/autoload.php'); define('pocketmine\DATA', ''); define('pocketmine\GIT_COMMIT', str_repeat('00', 20)); +define('pocketmine\BUILD_NUMBER', 0); define('pocketmine\PLUGIN_PATH', ''); define('pocketmine\START_TIME', microtime(true)); define('pocketmine\VERSION', '9.9.9'); From 52a891ba7378f606bfb402b2b1cf6ac331355ed9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 22:32:25 +0000 Subject: [PATCH 405/710] shut --- tests/phpstan/configs/actual-problems.neon | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 8b5c5b192..59203a8d5 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -495,6 +495,11 @@ parameters: count: 2 path: ../../../src/pocketmine/PocketMine.php + - + message: "#^Cannot access offset 'build' on mixed\\.$#" + count: 3 + path: ../../../src/pocketmine/PocketMine.php + - message: "#^Cannot access offset 'git' on mixed\\.$#" count: 2 From 1bb6ac4fb676417ee0cede26ff0e90733c7b572d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 23:20:40 +0000 Subject: [PATCH 406/710] Release 3.25.5 --- changelogs/3.25.md | 5 +++++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/changelogs/3.25.md b/changelogs/3.25.md index 2520f5952..de3d613e5 100644 --- a/changelogs/3.25.md +++ b/changelogs/3.25.md @@ -28,3 +28,8 @@ Plugin developers should **only** update their required API to this version if y # 3.25.4 - Fixed a long-standing issue with `Player->removeWindow()` breaking inventory UIs on the client. + +# 3.25.5 +- Protocol: Fixed incorrect encoding in `StructureSettings` +- Fixed reading tags from non-docblock comments in script plugins. +- Build number is now defined in phar metadata instead of being patched into the source code directly. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 7c6ecba82..8f27e6f53 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,5 +34,5 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.25.5"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_CHANNEL = "stable"; From 32f619ac490659d58059dd7b6371fd84d1b23ffa Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 23:20:48 +0000 Subject: [PATCH 407/710] 3.25.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 8f27e6f53..26c0a5b3c 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.25.5"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.25.6"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_CHANNEL = "stable"; From 7ace24caaba029f128a6eb5d1d78742c3e103ec6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 23:36:19 +0000 Subject: [PATCH 408/710] Fixed borked build number this was a problem before the recent clean-up; the only reason it just decided to show now is because 2000+25 is valid PHP code, so PHP saved our asses. --- .github/workflows/draft-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index b70a2757f..1c8f3eb57 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -38,7 +38,7 @@ jobs: - name: Calculate build number id: build-number run: | - BUILD_NUMBER=2000+$GITHUB_RUN_NUMBER #to stay above jenkins + BUILD_NUMBER=$((2000+$GITHUB_RUN_NUMBER)) #to stay above jenkins echo "Build number: $BUILD_NUMBER" echo ::set-output name=BUILD_NUMBER::$BUILD_NUMBER From f95142f6b677180dd1b8d44b4bb49880329472ab Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 23:37:46 +0000 Subject: [PATCH 409/710] Release 3.25.6 --- changelogs/3.25.md | 3 +++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/changelogs/3.25.md b/changelogs/3.25.md index de3d613e5..4c3ab2978 100644 --- a/changelogs/3.25.md +++ b/changelogs/3.25.md @@ -33,3 +33,6 @@ Plugin developers should **only** update their required API to this version if y - Protocol: Fixed incorrect encoding in `StructureSettings` - Fixed reading tags from non-docblock comments in script plugins. - Build number is now defined in phar metadata instead of being patched into the source code directly. + +# 3.25.6 +- Fixed borked build number in release build of 3.25.5. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 26c0a5b3c..ee7e6d004 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,5 +34,5 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.25.6"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_CHANNEL = "stable"; From c19174a1744d2f9e7fb31d9959e789077545829b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 26 Nov 2021 23:37:47 +0000 Subject: [PATCH 410/710] 3.25.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 ee7e6d004..c2cf65738 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.25.6"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.25.7"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_CHANNEL = "stable"; From e5149756a8de7175594cea4dca072397c11b9751 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Nov 2021 00:06:09 +0000 Subject: [PATCH 411/710] WorldTimings: fixed merge error introduced by 3bf87378ef24eec8845bb048a6916f188d9b1220 --- src/world/WorldTimings.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/world/WorldTimings.php b/src/world/WorldTimings.php index 2ace79317..ac060e9a3 100644 --- a/src/world/WorldTimings.php +++ b/src/world/WorldTimings.php @@ -64,14 +64,14 @@ class WorldTimings{ $this->entityTick = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Tick Entities"); Timings::init(); //make sure the timers we want are available - $this->syncChunkSend = new TimingsHandler("** " . $name . "Player Send Chunks", Timings::$playerChunkSend); - $this->syncChunkSendPrepare = new TimingsHandler("** " . $name . "Player Send Chunk Prepare", Timings::$playerChunkSend); + $this->syncChunkSend = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Player Send Chunks", Timings::$playerChunkSend); + $this->syncChunkSendPrepare = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Player Send Chunk Prepare", Timings::$playerChunkSend); - $this->syncChunkLoad = new TimingsHandler("** " . $name . "Chunk Load", Timings::$worldLoad); - $this->syncChunkLoadData = new TimingsHandler("** " . $name . "Chunk Load - Data"); - $this->syncChunkLoadEntities = new TimingsHandler("** " . $name . "Chunk Load - Entities"); - $this->syncChunkLoadTileEntities = new TimingsHandler("** " . $name . "Chunk Load - TileEntities"); - $this->syncChunkSave = new TimingsHandler("** " . $name . "Chunk Save", Timings::$worldSave); + $this->syncChunkLoad = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load", Timings::$worldLoad); + $this->syncChunkLoadData = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Data"); + $this->syncChunkLoadEntities = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Entities"); + $this->syncChunkLoadTileEntities = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - TileEntities"); + $this->syncChunkSave = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Save", Timings::$worldSave); $this->doTick = new TimingsHandler($name . "World Tick"); } From 1f9400f9011546ab914090853069aaa76192a722 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Nov 2021 01:12:30 +0000 Subject: [PATCH 412/710] World: automatically remap invalid blockstates on chunk load this fixes a wide range of blocks with invalid blockstates becoming update! blocks on the client. The most common occurrence of this was air with nonzero metadata left behind by world editors which set blockIDs but not block metadata. This caused large ghost structures of update! blocks to appear from nowhere. The performance impact of this is very minimal (20 microseconds per chunk load in timings, compared to average 660 microseconds to load tiles). --- src/block/BlockFactory.php | 16 ++++++++++++++++ src/world/World.php | 21 +++++++++++++++++++++ src/world/WorldTimings.php | 2 ++ 3 files changed, 39 insertions(+) diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index fd252f789..38e26f6b7 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -75,6 +75,12 @@ class BlockFactory{ */ private $fullList; + /** + * @var \SplFixedArray|int[] + * @phpstan-var \SplFixedArray + */ + private \SplFixedArray $mappedStateIds; + /** * @var \SplFixedArray|int[] * @phpstan-var \SplFixedArray @@ -98,6 +104,7 @@ class BlockFactory{ public function __construct(){ $this->fullList = new \SplFixedArray(1024 << Block::INTERNAL_METADATA_BITS); + $this->mappedStateIds = new \SplFixedArray(1024 << Block::INTERNAL_METADATA_BITS); $this->light = \SplFixedArray::fromArray(array_fill(0, 1024 << Block::INTERNAL_METADATA_BITS, 0)); $this->lightFilter = \SplFixedArray::fromArray(array_fill(0, 1024 << Block::INTERNAL_METADATA_BITS, 1)); @@ -948,6 +955,7 @@ class BlockFactory{ private function fillStaticArrays(int $index, Block $block) : void{ $this->fullList[$index] = $block; + $this->mappedStateIds[$index] = $block->getFullId(); $this->light[$index] = $block->getLightLevel(); $this->lightFilter[$index] = min(15, $block->getLightFilter() + 1); //opacity plus 1 standard light filter $this->blocksDirectSkyLight[$index] = $block->blocksDirectSkyLight(); @@ -997,4 +1005,12 @@ class BlockFactory{ public function getAllKnownStates() : array{ return array_filter($this->fullList->toArray(), function(?Block $v) : bool{ return $v !== null; }); } + + /** + * Returns the ID of the state mapped to the given state ID. + * Used to correct invalid blockstates found in loaded chunks. + */ + public function getMappedStateId(int $fullState) : int{ + return $this->mappedStateIds[$fullState] ?? $fullState; + } } diff --git a/src/world/World.php b/src/world/World.php index 9549980eb..37236de22 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2466,6 +2466,27 @@ class World implements ChunkManager{ private function initChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void{ $logger = new \PrefixedLogger($this->logger, "Loading chunk $chunkX $chunkZ"); + + $this->timings->syncChunkLoadFixInvalidBlocks->startTiming(); + $blockFactory = BlockFactory::getInstance(); + $invalidBlocks = 0; + foreach($chunkData->getChunk()->getSubChunks() as $subChunk){ + foreach($subChunk->getBlockLayers() as $blockLayer){ + foreach($blockLayer->getPalette() as $blockStateId){ + $mappedStateId = $blockFactory->getMappedStateId($blockStateId); + if($mappedStateId !== $blockStateId){ + $blockLayer->replaceAll($blockStateId, $mappedStateId); + $invalidBlocks++; + } + } + } + } + if($invalidBlocks > 0){ + $logger->debug("Fixed $invalidBlocks invalid blockstates"); + $chunkData->getChunk()->setTerrainDirtyFlag(Chunk::DIRTY_FLAG_BLOCKS, true); + } + $this->timings->syncChunkLoadFixInvalidBlocks->stopTiming(); + if(count($chunkData->getEntityNBT()) !== 0){ $this->timings->syncChunkLoadEntities->startTiming(); $entityFactory = EntityFactory::getInstance(); diff --git a/src/world/WorldTimings.php b/src/world/WorldTimings.php index ac060e9a3..874a5f5fd 100644 --- a/src/world/WorldTimings.php +++ b/src/world/WorldTimings.php @@ -45,6 +45,7 @@ class WorldTimings{ public TimingsHandler $syncChunkLoad; public TimingsHandler $syncChunkLoadData; + public TimingsHandler $syncChunkLoadFixInvalidBlocks; public TimingsHandler $syncChunkLoadEntities; public TimingsHandler $syncChunkLoadTileEntities; public TimingsHandler $syncChunkSave; @@ -69,6 +70,7 @@ class WorldTimings{ $this->syncChunkLoad = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load", Timings::$worldLoad); $this->syncChunkLoadData = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Data"); + $this->syncChunkLoadFixInvalidBlocks = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Fix Invalid Blocks"); $this->syncChunkLoadEntities = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - Entities"); $this->syncChunkLoadTileEntities = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Load - TileEntities"); $this->syncChunkSave = new TimingsHandler(Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX . $name . "Chunk Save", Timings::$worldSave); From cc23e0b7a151cf6b3fda2836b717321f19003cb6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Nov 2021 03:52:32 +0000 Subject: [PATCH 413/710] Updated DevTools submodule to pmmp/DevTools@6af57741e67a928e2782cebe8dd422044d16dc04 --- tests/plugins/DevTools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plugins/DevTools b/tests/plugins/DevTools index db184c256..6af57741e 160000 --- a/tests/plugins/DevTools +++ b/tests/plugins/DevTools @@ -1 +1 @@ -Subproject commit db184c25636b1f984c6539fd4b1729b0b64b35d6 +Subproject commit 6af57741e67a928e2782cebe8dd422044d16dc04 From 95401937664e4dea59f1bdee63811258f2a794e9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Nov 2021 03:54:30 +0000 Subject: [PATCH 414/710] Fixed everything lighting on fire --- composer.json | 2 +- tests/travis.sh | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 4c71c4e13..b42e95a74 100644 --- a/composer.json +++ b/composer.json @@ -79,7 +79,7 @@ "sort-packages": true }, "scripts": { - "make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/DevTools/ConsoleScript.php --make tests/plugins/DevTools --out plugins/DevTools.phar", + "make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make tests/plugins/DevTools --out plugins/DevTools.phar", "make-server": [ "@composer install --no-dev --classmap-authoritative --ignore-platform-reqs", "@php -dphar.readonly=0 build/server-phar.php" diff --git a/tests/travis.sh b/tests/travis.sh index e16a28333..714e02425 100755 --- a/tests/travis.sh +++ b/tests/travis.sh @@ -19,9 +19,7 @@ rm PocketMine-MP.phar 2> /dev/null mkdir "$DATA_DIR" mkdir "$PLUGINS_DIR" -cd tests/plugins/DevTools -php -dphar.readonly=0 ./src/DevTools/ConsoleScript.php --make ./ --relative ./ --out "$PLUGINS_DIR/DevTools.phar" -cd ../../.. +composer make-devtools composer make-server if [ -f PocketMine-MP.phar ]; then From 932a88764c18967c2ba544562527707d3d7a1ab8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Nov 2021 04:07:25 +0000 Subject: [PATCH 415/710] composer commands suck --- tests/travis.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/travis.sh b/tests/travis.sh index 714e02425..094f65905 100755 --- a/tests/travis.sh +++ b/tests/travis.sh @@ -19,7 +19,9 @@ rm PocketMine-MP.phar 2> /dev/null mkdir "$DATA_DIR" mkdir "$PLUGINS_DIR" -composer make-devtools +cd tests/plugins/DevTools +php -dphar.readonly=0 ./src/ConsoleScript.php --make ./ --relative ./ --out "$PLUGINS_DIR/DevTools.phar" +cd ../../.. composer make-server if [ -f PocketMine-MP.phar ]; then From e2815eed60861564b678de5f6e43c16eb98f3da9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Nov 2021 20:07:58 +0000 Subject: [PATCH 416/710] BlockFactory: remap a bunch more invalid states --- src/block/BlockFactory.php | 239 +++++++++++------- .../block_factory_consistency_check.json | 2 +- 2 files changed, 146 insertions(+), 95 deletions(-) diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index 38e26f6b7..fd98293c5 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -151,8 +151,6 @@ class BlockFactory{ $cobblestoneBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); $this->registerAllMeta($cobblestone = new Opaque(new BID(Ids::COBBLESTONE, 0), "Cobblestone", $cobblestoneBreakInfo)); - $infestedStoneBreakInfo = new BlockBreakInfo(0.75); - $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_COBBLESTONE), "Infested Cobblestone", $infestedStoneBreakInfo, $cobblestone)); $this->registerAllMeta(new Opaque(new BID(Ids::MOSSY_COBBLESTONE, 0), "Mossy Cobblestone", $cobblestoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::COBBLESTONE_STAIRS, 0), "Cobblestone Stairs", $cobblestoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::MOSSY_COBBLESTONE_STAIRS, 0), "Mossy Cobblestone Stairs", $cobblestoneBreakInfo)); @@ -168,12 +166,14 @@ class BlockFactory{ $this->registerAllMeta(new Opaque(new BID(Ids::DIAMOND_BLOCK, 0), "Diamond Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0))); $this->registerAllMeta(new DiamondOre(new BID(Ids::DIAMOND_ORE, 0), "Diamond Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel()))); $this->registerAllMeta(new Dirt(new BID(Ids::DIRT, 0), "Dirt", new BlockBreakInfo(0.5, BlockToolType::SHOVEL))); - $this->register(new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_SUNFLOWER), "Sunflower", BlockBreakInfo::instant())); - $this->register(new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LILAC), "Lilac", BlockBreakInfo::instant())); - $this->register(new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_ROSE_BUSH), "Rose Bush", BlockBreakInfo::instant())); - $this->register(new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_PEONY), "Peony", BlockBreakInfo::instant())); - $this->register(new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_TALLGRASS), "Double Tallgrass", BlockBreakInfo::instant(BlockToolType::SHEARS, 1))); - $this->register(new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LARGE_FERN), "Large Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1))); + $this->registerAllMeta( + new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_SUNFLOWER), "Sunflower", BlockBreakInfo::instant()), + new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LILAC), "Lilac", BlockBreakInfo::instant()), + new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_ROSE_BUSH), "Rose Bush", BlockBreakInfo::instant()), + new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_PEONY), "Peony", BlockBreakInfo::instant()), + new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_TALLGRASS), "Double Tallgrass", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)), + new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LARGE_FERN), "Large Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)), + ); $this->registerAllMeta(new DragonEgg(new BID(Ids::DRAGON_EGG, 0), "Dragon Egg", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); $this->registerAllMeta(new DriedKelp(new BID(Ids::DRIED_KELP_BLOCK, 0), "Dried Kelp Block", new BlockBreakInfo(0.5, BlockToolType::NONE, 0, 12.5))); $this->registerAllMeta(new Opaque(new BID(Ids::EMERALD_BLOCK, 0), "Emerald Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0))); @@ -192,17 +192,19 @@ class BlockFactory{ $this->registerAllMeta(new Fire(new BID(Ids::FIRE, 0), "Fire Block", BlockBreakInfo::instant())); $this->registerAllMeta(new FletchingTable(new BID(Ids::FLETCHING_TABLE, 0), "Fletching Table", new BlockBreakInfo(2.5, BlockToolType::AXE, 0, 2.5))); $this->registerAllMeta(new Flower(new BID(Ids::DANDELION, 0), "Dandelion", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ALLIUM), "Allium", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_AZURE_BLUET), "Azure Bluet", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_BLUE_ORCHID), "Blue Orchid", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_CORNFLOWER), "Cornflower", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_LILY_OF_THE_VALLEY), "Lily of the Valley", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ORANGE_TULIP), "Orange Tulip", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_OXEYE_DAISY), "Oxeye Daisy", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_PINK_TULIP), "Pink Tulip", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_POPPY), "Poppy", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_RED_TULIP), "Red Tulip", BlockBreakInfo::instant())); - $this->register(new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_WHITE_TULIP), "White Tulip", BlockBreakInfo::instant())); + $this->registerAllMeta( + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_POPPY), "Poppy", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ALLIUM), "Allium", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_AZURE_BLUET), "Azure Bluet", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_BLUE_ORCHID), "Blue Orchid", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_CORNFLOWER), "Cornflower", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_LILY_OF_THE_VALLEY), "Lily of the Valley", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ORANGE_TULIP), "Orange Tulip", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_OXEYE_DAISY), "Oxeye Daisy", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_PINK_TULIP), "Pink Tulip", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_RED_TULIP), "Red Tulip", BlockBreakInfo::instant()), + new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_WHITE_TULIP), "White Tulip", BlockBreakInfo::instant()), + ); $this->registerAllMeta(new FlowerPot(new BID(Ids::FLOWER_POT_BLOCK, 0, ItemIds::FLOWER_POT, TileFlowerPot::class), "Flower Pot", BlockBreakInfo::instant())); $this->registerAllMeta(new FrostedIce(new BID(Ids::FROSTED_ICE, 0), "Frosted Ice", new BlockBreakInfo(2.5, BlockToolType::PICKAXE))); $this->registerAllMeta(new Furnace(new BIDFlattened(Ids::FURNACE, [Ids::LIT_FURNACE], 0, null, TileNormalFurnace::class), "Furnace", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); @@ -279,11 +281,13 @@ class BlockFactory{ $this->registerAllMeta(new PoweredRail(new BID(Ids::GOLDEN_RAIL, 0), "Powered Rail", $railBreakInfo)); $prismarineBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); - $this->register(new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_BRICKS), "Prismarine Bricks", $prismarineBreakInfo)); + $this->registerAllMeta( + new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_NORMAL), "Prismarine", $prismarineBreakInfo), + new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_DARK), "Dark Prismarine", $prismarineBreakInfo), + new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_BRICKS), "Prismarine Bricks", $prismarineBreakInfo) + ); $this->registerAllMeta(new Stair(new BID(Ids::PRISMARINE_BRICKS_STAIRS, 0), "Prismarine Bricks Stairs", $prismarineBreakInfo)); - $this->register(new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_DARK), "Dark Prismarine", $prismarineBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::DARK_PRISMARINE_STAIRS, 0), "Dark Prismarine Stairs", $prismarineBreakInfo)); - $this->register(new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_NORMAL), "Prismarine", $prismarineBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::PRISMARINE_STAIRS, 0), "Prismarine Stairs", $prismarineBreakInfo)); $pumpkinBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE); @@ -294,16 +298,20 @@ class BlockFactory{ $this->registerAllMeta(new PumpkinStem(new BID(Ids::PUMPKIN_STEM, 0, ItemIds::PUMPKIN_SEEDS), "Pumpkin Stem", BlockBreakInfo::instant())); $purpurBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); - $this->register(new Opaque(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_NORMAL), "Purpur Block", $purpurBreakInfo)); - $this->register(new SimplePillar(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_PILLAR), "Purpur Pillar", $purpurBreakInfo)); + $this->registerAllMeta( + new Opaque(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_NORMAL), "Purpur Block", $purpurBreakInfo), + new SimplePillar(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_PILLAR), "Purpur Pillar", $purpurBreakInfo) + ); $this->registerAllMeta(new Stair(new BID(Ids::PURPUR_STAIRS, 0), "Purpur Stairs", $purpurBreakInfo)); $quartzBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()); - $this->register(new Opaque(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_NORMAL), "Quartz Block", $quartzBreakInfo)); + $this->registerAllMeta( + new Opaque(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_NORMAL), "Quartz Block", $quartzBreakInfo), + new SimplePillar(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_CHISELED), "Chiseled Quartz Block", $quartzBreakInfo), + new SimplePillar(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_PILLAR), "Quartz Pillar", $quartzBreakInfo), + new Opaque(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_SMOOTH), "Smooth Quartz Block", $quartzBreakInfo) //TODO: we may need to account for the fact this previously incorrectly had axis + ); $this->registerAllMeta(new Stair(new BID(Ids::QUARTZ_STAIRS, 0), "Quartz Stairs", $quartzBreakInfo)); - $this->register(new SimplePillar(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_CHISELED), "Chiseled Quartz Block", $quartzBreakInfo)); - $this->register(new SimplePillar(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_PILLAR), "Quartz Pillar", $quartzBreakInfo)); - $this->register(new Opaque(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_SMOOTH), "Smooth Quartz Block", $quartzBreakInfo)); //TODO: this has axis rotation in 1.9, unsure if a bug (https://bugs.mojang.com/browse/MCPE-39074) $this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_QUARTZ_STAIRS, 0), "Smooth Quartz Stairs", $quartzBreakInfo)); $this->registerAllMeta(new Rail(new BID(Ids::RAIL, 0), "Rail", $railBreakInfo)); @@ -318,8 +326,10 @@ class BlockFactory{ $this->registerAllMeta(new Reserved6(new BID(Ids::RESERVED6, 0), "reserved6", BlockBreakInfo::instant())); $sandBreakInfo = new BlockBreakInfo(0.5, BlockToolType::SHOVEL); - $this->register(new Sand(new BID(Ids::SAND, 0), "Sand", $sandBreakInfo)); - $this->register(new Sand(new BID(Ids::SAND, 1), "Red Sand", $sandBreakInfo)); + $this->registerAllMeta( + new Sand(new BID(Ids::SAND, 0), "Sand", $sandBreakInfo), + new Sand(new BID(Ids::SAND, 1), "Red Sand", $sandBreakInfo) + ); $this->registerAllMeta(new SeaLantern(new BID(Ids::SEALANTERN, 0), "Sea Lantern", new BlockBreakInfo(0.3))); $this->registerAllMeta(new SeaPickle(new BID(Ids::SEA_PICKLE, 0), "Sea Pickle", BlockBreakInfo::instant())); $this->registerAllMeta(new Skull(new BID(Ids::MOB_HEAD_BLOCK, 0, ItemIds::SKULL, TileSkull::class), "Mob Head", new BlockBreakInfo(1.0))); @@ -332,40 +342,48 @@ class BlockFactory{ $this->registerAllMeta(new ShulkerBox(new BID(Ids::UNDYED_SHULKER_BOX, 0, null, TileShulkerBox::class), "Shulker Box", $shulkerBoxBreakInfo)); $stoneBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); - $this->register($stone = new class(new BID(Ids::STONE, Meta::STONE_NORMAL), "Stone", $stoneBreakInfo) extends Opaque{ - public function getDropsForCompatibleTool(Item $item) : array{ - return [VanillaBlocks::COBBLESTONE()->asItem()]; - } + $this->registerAllMeta( + $stone = new class(new BID(Ids::STONE, Meta::STONE_NORMAL), "Stone", $stoneBreakInfo) extends Opaque{ + public function getDropsForCompatibleTool(Item $item) : array{ + return [VanillaBlocks::COBBLESTONE()->asItem()]; + } - public function isAffectedBySilkTouch() : bool{ - return true; - } - }); - $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE), "Infested Stone", $infestedStoneBreakInfo, $stone)); + public function isAffectedBySilkTouch() : bool{ + return true; + } + }, + new Opaque(new BID(Ids::STONE, Meta::STONE_ANDESITE), "Andesite", $stoneBreakInfo), + new Opaque(new BID(Ids::STONE, Meta::STONE_DIORITE), "Diorite", $stoneBreakInfo), + new Opaque(new BID(Ids::STONE, Meta::STONE_GRANITE), "Granite", $stoneBreakInfo), + new Opaque(new BID(Ids::STONE, Meta::STONE_POLISHED_ANDESITE), "Polished Andesite", $stoneBreakInfo), + new Opaque(new BID(Ids::STONE, Meta::STONE_POLISHED_DIORITE), "Polished Diorite", $stoneBreakInfo), + new Opaque(new BID(Ids::STONE, Meta::STONE_POLISHED_GRANITE), "Polished Granite", $stoneBreakInfo) + ); + $this->registerAllMeta( + $stoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_NORMAL), "Stone Bricks", $stoneBreakInfo), + $mossyStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_MOSSY), "Mossy Stone Bricks", $stoneBreakInfo), + $crackedStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CRACKED), "Cracked Stone Bricks", $stoneBreakInfo), + $chiseledStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CHISELED), "Chiseled Stone Bricks", $stoneBreakInfo) + ); + $infestedStoneBreakInfo = new BlockBreakInfo(0.75); + $this->registerAllMeta( + new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE), "Infested Stone", $infestedStoneBreakInfo, $stone), + new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK), "Infested Stone Brick", $infestedStoneBreakInfo, $stoneBrick), + new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_COBBLESTONE), "Infested Cobblestone", $infestedStoneBreakInfo, $cobblestone), + new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK_MOSSY), "Infested Mossy Stone Brick", $infestedStoneBreakInfo, $mossyStoneBrick), + new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK_CRACKED), "Infested Cracked Stone Brick", $infestedStoneBreakInfo, $crackedStoneBrick), + new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK_CHISELED), "Infested Chiseled Stone Brick", $infestedStoneBreakInfo, $chiseledStoneBrick) + ); $this->registerAllMeta(new Stair(new BID(Ids::NORMAL_STONE_STAIRS, 0), "Stone Stairs", $stoneBreakInfo)); $this->registerAllMeta(new Opaque(new BID(Ids::SMOOTH_STONE, 0), "Smooth Stone", $stoneBreakInfo)); - $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_ANDESITE), "Andesite", $stoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::ANDESITE_STAIRS, 0), "Andesite Stairs", $stoneBreakInfo)); - $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_DIORITE), "Diorite", $stoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::DIORITE_STAIRS, 0), "Diorite Stairs", $stoneBreakInfo)); - $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_GRANITE), "Granite", $stoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::GRANITE_STAIRS, 0), "Granite Stairs", $stoneBreakInfo)); - $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_POLISHED_ANDESITE), "Polished Andesite", $stoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::POLISHED_ANDESITE_STAIRS, 0), "Polished Andesite Stairs", $stoneBreakInfo)); - $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_POLISHED_DIORITE), "Polished Diorite", $stoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::POLISHED_DIORITE_STAIRS, 0), "Polished Diorite Stairs", $stoneBreakInfo)); - $this->register(new Opaque(new BID(Ids::STONE, Meta::STONE_POLISHED_GRANITE), "Polished Granite", $stoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::POLISHED_GRANITE_STAIRS, 0), "Polished Granite Stairs", $stoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::STONE_BRICK_STAIRS, 0), "Stone Brick Stairs", $stoneBreakInfo)); - $this->register($chiseledStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CHISELED), "Chiseled Stone Bricks", $stoneBreakInfo)); - $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK_CHISELED), "Infested Chiseled Stone Brick", $infestedStoneBreakInfo, $chiseledStoneBrick)); - $this->register($crackedStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CRACKED), "Cracked Stone Bricks", $stoneBreakInfo)); - $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK_CRACKED), "Infested Cracked Stone Brick", $infestedStoneBreakInfo, $crackedStoneBrick)); - $this->register($mossyStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_MOSSY), "Mossy Stone Bricks", $stoneBreakInfo)); - $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK_MOSSY), "Infested Mossy Stone Brick", $infestedStoneBreakInfo, $mossyStoneBrick)); $this->registerAllMeta(new Stair(new BID(Ids::MOSSY_STONE_BRICK_STAIRS, 0), "Mossy Stone Brick Stairs", $stoneBreakInfo)); - $this->register($stoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_NORMAL), "Stone Bricks", $stoneBreakInfo)); - $this->register(new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK), "Infested Stone Brick", $infestedStoneBreakInfo, $stoneBrick)); $this->registerAllMeta(new StoneButton(new BID(Ids::STONE_BUTTON, 0), "Stone Button", new BlockBreakInfo(0.5, BlockToolType::PICKAXE))); $this->registerAllMeta(new StonePressurePlate(new BID(Ids::STONE_PRESSURE_PLATE, 0), "Stone Pressure Plate", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); @@ -404,16 +422,18 @@ class BlockFactory{ $this->registerAllMeta(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BlockBreakInfo::instant())); $this->registerAllMeta(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant())); $this->registerAllMeta(new TNT(new BID(Ids::TNT, 0), "TNT", BlockBreakInfo::instant())); - - $fern = new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_FERN), "Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)); - $this->register($fern); - $this->remap(Ids::TALLGRASS, 0, $fern); - $this->remap(Ids::TALLGRASS, 3, $fern); - $this->register(new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_NORMAL), "Tall Grass", BlockBreakInfo::instant(BlockToolType::SHEARS, 1))); - $this->register(new Torch(new BID(Ids::COLORED_TORCH_BP, 0), "Blue Torch", BlockBreakInfo::instant())); - $this->register(new Torch(new BID(Ids::COLORED_TORCH_BP, 8), "Purple Torch", BlockBreakInfo::instant())); - $this->register(new Torch(new BID(Ids::COLORED_TORCH_RG, 0), "Red Torch", BlockBreakInfo::instant())); - $this->register(new Torch(new BID(Ids::COLORED_TORCH_RG, 8), "Green Torch", BlockBreakInfo::instant())); + $this->registerAllMeta( + new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_FERN), "Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)), + new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_NORMAL), "Tall Grass", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)) + ); + $this->registerAllMeta( + new Torch(new BID(Ids::COLORED_TORCH_BP, 0), "Blue Torch", BlockBreakInfo::instant()), + new Torch(new BID(Ids::COLORED_TORCH_BP, 8), "Purple Torch", BlockBreakInfo::instant()) + ); + $this->registerAllMeta( + new Torch(new BID(Ids::COLORED_TORCH_RG, 0), "Red Torch", BlockBreakInfo::instant()), + new Torch(new BID(Ids::COLORED_TORCH_RG, 8), "Green Torch", BlockBreakInfo::instant()) + ); $this->registerAllMeta(new Torch(new BID(Ids::TORCH, 0), "Torch", BlockBreakInfo::instant())); $this->registerAllMeta(new TrappedChest(new BID(Ids::TRAPPED_CHEST, 0, null, TileChest::class), "Trapped Chest", $chestBreakInfo)); $this->registerAllMeta(new Tripwire(new BID(Ids::TRIPWIRE, 0, ItemIds::STRING), "Tripwire", BlockBreakInfo::instant())); @@ -435,22 +455,29 @@ class BlockFactory{ $woodenDoorBreakInfo = new BlockBreakInfo(3.0, BlockToolType::AXE, 0, 15.0); $woodenButtonBreakInfo = new BlockBreakInfo(0.5, BlockToolType::AXE); $woodenPressurePlateBreakInfo = new BlockBreakInfo(0.5, BlockToolType::AXE); + + $planks = []; + $saplings = []; + $fences = []; + $leaves = []; + $allSidedLogs = []; foreach(TreeType::getAll() as $treeType){ $magicNumber = $treeType->getMagicNumber(); $name = $treeType->getDisplayName(); - $this->register(new Planks(new BID(Ids::PLANKS, $magicNumber), $name . " Planks", $planksBreakInfo)); - $this->register(new Sapling(new BID(Ids::SAPLING, $magicNumber), $name . " Sapling", BlockBreakInfo::instant(), $treeType)); - $this->register(new WoodenFence(new BID(Ids::FENCE, $magicNumber), $name . " Fence", $planksBreakInfo)); + $planks[] = new Planks(new BID(Ids::PLANKS, $magicNumber), $name . " Planks", $planksBreakInfo); + $saplings[] = new Sapling(new BID(Ids::SAPLING, $magicNumber), $name . " Sapling", BlockBreakInfo::instant(), $treeType); + $fences[] = new WoodenFence(new BID(Ids::FENCE, $magicNumber), $name . " Fence", $planksBreakInfo); $this->registerSlabWithDoubleHighBitsRemapping(new WoodenSlab(new BIDFlattened(Ids::WOODEN_SLAB, [Ids::DOUBLE_WOODEN_SLAB], $magicNumber), $name, $planksBreakInfo)); //TODO: find a better way to deal with this split - $this->register(new Leaves(new BID($magicNumber >= 4 ? Ids::LEAVES2 : Ids::LEAVES, $magicNumber & 0x03), $name . " Leaves", $leavesBreakInfo, $treeType)); - $this->register(new Log(new BID($magicNumber >= 4 ? Ids::LOG2 : Ids::LOG, $magicNumber & 0x03), $name . " Log", $logBreakInfo, $treeType, false)); + $leaves[] = new Leaves(new BID($magicNumber >= 4 ? Ids::LEAVES2 : Ids::LEAVES, $magicNumber & 0x03), $name . " Leaves", $leavesBreakInfo, $treeType); + $this->register(new Log(new BID($magicNumber >= 4 ? Ids::LOG2 : Ids::LOG, $magicNumber & 0x03), $name . " Log", $logBreakInfo, $treeType, false)); $wood = new Wood(new BID(Ids::WOOD, $magicNumber), $name . " Wood", $logBreakInfo, $treeType, false); - $this->register($wood); $this->remap($magicNumber >= 4 ? Ids::LOG2 : Ids::LOG, ($magicNumber & 0x03) | 0b1100, $wood); - $this->register(new Wood(new BID(Ids::WOOD, $magicNumber | BlockLegacyMetadata::WOOD_FLAG_STRIPPED), "Stripped $name Wood", $logBreakInfo, $treeType, true)); + + $allSidedLogs[] = $wood; + $allSidedLogs[] = new Wood(new BID(Ids::WOOD, $magicNumber | BlockLegacyMetadata::WOOD_FLAG_STRIPPED), "Stripped $name Wood", $logBreakInfo, $treeType, true); $this->registerAllMeta(new Log(BlockLegacyIdHelper::getStrippedLogIdentifier($treeType), "Stripped " . $name . " Log", $logBreakInfo, $treeType, true)); $this->registerAllMeta(new FenceGate(BlockLegacyIdHelper::getWoodenFenceIdentifier($treeType), $name . " Fence Gate", $planksBreakInfo)); @@ -464,6 +491,11 @@ class BlockFactory{ $this->registerAllMeta(new FloorSign(BlockLegacyIdHelper::getWoodenFloorSignIdentifier($treeType), $name . " Sign", $signBreakInfo)); $this->registerAllMeta(new WallSign(BlockLegacyIdHelper::getWoodenWallSignIdentifier($treeType), $name . " Wall Sign", $signBreakInfo)); } + $this->registerAllMeta(...$planks); + $this->registerAllMeta(...$saplings); + $this->registerAllMeta(...$fences); + $this->registerAllMeta(...$leaves); + $this->registerAllMeta(...$allSidedLogs); static $sandstoneTypes = [ Meta::SANDSTONE_NORMAL => "", @@ -476,10 +508,14 @@ class BlockFactory{ $this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_RED_SANDSTONE_STAIRS, 0), "Smooth Red Sandstone Stairs", $sandstoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::SANDSTONE_STAIRS, 0), "Sandstone Stairs", $sandstoneBreakInfo)); $this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_SANDSTONE_STAIRS, 0), "Smooth Sandstone Stairs", $sandstoneBreakInfo)); + $sandstones = []; + $redSandstones = []; foreach($sandstoneTypes as $variant => $prefix){ - $this->register(new Opaque(new BID(Ids::SANDSTONE, $variant), $prefix . "Sandstone", $sandstoneBreakInfo)); - $this->register(new Opaque(new BID(Ids::RED_SANDSTONE, $variant), $prefix . "Red Sandstone", $sandstoneBreakInfo)); + $sandstones[] = new Opaque(new BID(Ids::SANDSTONE, $variant), $prefix . "Sandstone", $sandstoneBreakInfo); + $redSandstones[] = new Opaque(new BID(Ids::RED_SANDSTONE, $variant), $prefix . "Red Sandstone", $sandstoneBreakInfo); } + $this->registerAllMeta(...$sandstones); + $this->registerAllMeta(...$redSandstones); $glazedTerracottaBreakInfo = new BlockBreakInfo(1.4, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()); foreach(DyeColor::getAll() as $color){ @@ -510,28 +546,32 @@ class BlockFactory{ //TODO: in the future these won't all have the same hardness; they only do now because of the old metadata crap $wallBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_ANDESITE), "Andesite Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_BRICK), "Brick Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_DIORITE), "Diorite Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_END_STONE_BRICK), "End Stone Brick Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_GRANITE), "Granite Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_MOSSY_STONE_BRICK), "Mossy Stone Brick Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_MOSSY_COBBLESTONE), "Mossy Cobblestone Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_NETHER_BRICK), "Nether Brick Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_COBBLESTONE), "Cobblestone Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_PRISMARINE), "Prismarine Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_RED_NETHER_BRICK), "Red Nether Brick Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_RED_SANDSTONE), "Red Sandstone Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_SANDSTONE), "Sandstone Wall", $wallBreakInfo)); - $this->register(new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_STONE_BRICK), "Stone Brick Wall", $wallBreakInfo)); + $this->registerAllMeta( + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_COBBLESTONE), "Cobblestone Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_ANDESITE), "Andesite Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_BRICK), "Brick Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_DIORITE), "Diorite Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_END_STONE_BRICK), "End Stone Brick Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_GRANITE), "Granite Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_MOSSY_STONE_BRICK), "Mossy Stone Brick Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_MOSSY_COBBLESTONE), "Mossy Cobblestone Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_NETHER_BRICK), "Nether Brick Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_PRISMARINE), "Prismarine Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_RED_NETHER_BRICK), "Red Nether Brick Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_RED_SANDSTONE), "Red Sandstone Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_SANDSTONE), "Sandstone Wall", $wallBreakInfo), + new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_STONE_BRICK), "Stone Brick Wall", $wallBreakInfo), + ); $this->registerElements(); $chemistryTableBreakInfo = new BlockBreakInfo(2.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()); - $this->register(new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_COMPOUND_CREATOR), "Compound Creator", $chemistryTableBreakInfo)); - $this->register(new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_ELEMENT_CONSTRUCTOR), "Element Constructor", $chemistryTableBreakInfo)); - $this->register(new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_LAB_TABLE), "Lab Table", $chemistryTableBreakInfo)); - $this->register(new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_MATERIAL_REDUCER), "Material Reducer", $chemistryTableBreakInfo)); + $this->registerAllMeta( + new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_COMPOUND_CREATOR), "Compound Creator", $chemistryTableBreakInfo), + new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_ELEMENT_CONSTRUCTOR), "Element Constructor", $chemistryTableBreakInfo), + new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_LAB_TABLE), "Lab Table", $chemistryTableBreakInfo), + new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_MATERIAL_REDUCER), "Material Reducer", $chemistryTableBreakInfo) + ); $this->registerAllMeta(new ChemicalHeat(new BID(Ids::CHEMICAL_HEAT, 0), "Heat Block", $chemistryTableBreakInfo)); @@ -868,12 +908,23 @@ class BlockFactory{ * This should only be used when this block type has sole ownership of an ID. For IDs which contain multiple block * types (variants), the regular register() method should be used instead. */ - private function registerAllMeta(Block $block) : void{ - $this->register($block); - foreach($block->getIdInfo()->getAllBlockIds() as $id){ + private function registerAllMeta(Block $default, Block ...$additional) : void{ + $ids = []; + $this->register($default); + foreach($default->getIdInfo()->getAllBlockIds() as $id){ + $ids[$id] = $id; + } + foreach($additional as $block){ + $this->register($block); + foreach($block->getIdInfo()->getAllBlockIds() as $id){ + $ids[$id] = $id; + } + } + + foreach($ids as $id){ for($meta = 0; $meta < 1 << Block::INTERNAL_METADATA_BITS; ++$meta){ if(!$this->isRegistered($id, $meta)){ - $this->remap($id, $meta, $block); + $this->remap($id, $meta, $default); } } } diff --git a/tests/phpunit/block/block_factory_consistency_check.json b/tests/phpunit/block/block_factory_consistency_check.json index c370eeaae..932d526a4 100644 --- a/tests/phpunit/block/block_factory_consistency_check.json +++ b/tests/phpunit/block/block_factory_consistency_check.json @@ -1 +1 @@ -{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7296":"Fletching Table","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"33":32,"34":32,"35":32,"36":32,"37":32,"38":32,"39":32,"40":32,"41":32,"42":32,"43":32,"44":32,"45":32,"46":32,"47":32,"50":48,"51":48,"52":48,"53":48,"54":48,"55":48,"56":48,"57":48,"58":48,"59":48,"60":48,"61":48,"62":48,"63":48,"65":64,"66":64,"67":64,"68":64,"69":64,"70":64,"71":64,"72":64,"73":64,"74":64,"75":64,"76":64,"77":64,"78":64,"79":64,"114":112,"115":112,"116":112,"117":112,"118":112,"119":112,"120":112,"121":112,"122":112,"123":112,"124":112,"125":112,"126":112,"127":112,"209":208,"210":208,"211":208,"212":208,"213":208,"214":208,"215":208,"216":208,"217":208,"218":208,"219":208,"220":208,"221":208,"222":208,"223":208,"225":224,"226":224,"227":224,"228":224,"229":224,"230":224,"231":224,"232":224,"233":224,"234":224,"235":224,"236":224,"237":224,"238":224,"239":224,"241":240,"242":240,"243":240,"244":240,"245":240,"246":240,"247":240,"248":240,"249":240,"250":240,"251":240,"252":240,"253":240,"254":240,"255":240,"257":256,"258":256,"259":256,"260":256,"261":256,"262":256,"263":256,"264":256,"265":256,"266":256,"267":256,"268":256,"269":256,"270":256,"271":256,"284":7472,"285":7473,"286":7474,"287":7475,"306":304,"307":304,"308":304,"309":304,"310":304,"311":304,"312":304,"313":304,"314":304,"315":304,"316":304,"317":304,"318":304,"319":304,"321":320,"322":320,"323":320,"324":320,"325":320,"326":320,"327":320,"328":320,"329":320,"330":320,"331":320,"332":320,"333":320,"334":320,"335":320,"337":336,"338":336,"339":336,"340":336,"341":336,"342":336,"343":336,"344":336,"345":336,"346":336,"347":336,"348":336,"349":336,"350":336,"351":336,"353":352,"354":352,"355":352,"356":352,"357":352,"358":352,"359":352,"360":352,"361":352,"362":352,"363":352,"364":352,"365":352,"366":352,"367":352,"401":400,"402":400,"403":400,"404":400,"405":400,"406":400,"407":400,"408":400,"409":400,"410":400,"411":400,"412":400,"413":400,"414":400,"415":400,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"481":480,"482":480,"483":480,"484":480,"485":480,"486":480,"487":480,"488":480,"489":480,"490":480,"491":480,"492":480,"493":480,"494":480,"495":480,"496":498,"499":498,"513":512,"514":512,"515":512,"516":512,"517":512,"518":512,"519":512,"520":512,"521":512,"522":512,"523":512,"524":512,"525":512,"526":512,"527":512,"577":576,"578":576,"579":576,"580":576,"581":576,"582":576,"583":576,"584":576,"585":576,"586":576,"587":576,"588":576,"589":576,"590":576,"591":576,"593":592,"594":592,"595":592,"596":592,"597":592,"598":592,"599":592,"600":592,"601":592,"602":592,"603":592,"604":592,"605":592,"606":592,"607":592,"625":624,"626":624,"627":624,"628":624,"629":624,"630":624,"631":624,"632":624,"633":624,"634":624,"635":624,"636":624,"637":624,"638":624,"639":624,"641":640,"642":640,"643":640,"644":640,"645":640,"646":640,"647":640,"648":640,"649":640,"650":640,"651":640,"652":640,"653":640,"654":640,"655":640,"657":656,"658":656,"659":656,"660":656,"661":656,"662":656,"663":656,"664":656,"665":656,"666":656,"667":656,"668":656,"669":656,"670":656,"671":656,"673":672,"674":672,"675":672,"676":672,"677":672,"678":672,"679":672,"680":672,"681":672,"682":672,"683":672,"684":672,"685":672,"686":672,"687":672,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"721":720,"722":720,"723":720,"724":720,"725":720,"726":720,"727":720,"728":720,"729":720,"730":720,"731":720,"732":720,"733":720,"734":720,"735":720,"740":736,"741":736,"742":736,"743":736,"744":736,"745":736,"746":736,"747":736,"748":736,"749":736,"750":736,"751":736,"753":752,"754":752,"755":752,"756":752,"757":752,"758":752,"759":752,"760":752,"761":752,"762":752,"763":752,"764":752,"765":752,"766":752,"767":752,"769":768,"770":768,"771":768,"772":768,"773":768,"774":768,"775":768,"776":768,"777":768,"778":768,"779":768,"780":768,"781":768,"782":768,"783":768,"785":784,"786":784,"787":784,"788":784,"789":784,"790":784,"791":784,"792":784,"793":784,"794":784,"795":784,"796":784,"797":784,"798":784,"799":784,"800":805,"806":805,"807":805,"808":805,"809":805,"810":805,"811":805,"812":805,"813":805,"814":805,"815":805,"833":832,"834":832,"835":832,"836":832,"837":832,"838":832,"839":832,"840":832,"841":832,"842":832,"843":832,"844":832,"845":832,"846":832,"847":832,"856":851,"857":851,"858":851,"859":851,"860":851,"861":851,"862":851,"863":851,"864":866,"865":866,"870":866,"871":866,"872":866,"873":866,"874":866,"875":866,"876":866,"877":866,"878":866,"879":866,"897":896,"898":896,"899":896,"900":896,"901":896,"902":896,"903":896,"904":896,"905":896,"906":896,"907":896,"908":896,"909":896,"910":896,"911":896,"913":912,"914":912,"915":912,"916":912,"917":912,"918":912,"919":912,"920":912,"921":912,"922":912,"923":912,"924":912,"925":912,"926":912,"927":912,"929":928,"930":928,"931":928,"932":928,"933":928,"934":928,"935":928,"936":928,"937":928,"938":928,"939":928,"940":928,"941":928,"942":928,"943":928,"952":944,"953":944,"954":944,"955":944,"956":944,"957":944,"958":944,"959":944,"968":960,"969":960,"970":960,"971":960,"972":960,"973":960,"974":960,"975":960,"976":978,"977":978,"982":978,"983":978,"984":978,"985":978,"986":978,"987":978,"988":978,"989":978,"990":978,"991":978,"992":978,"993":978,"998":978,"999":978,"1000":978,"1001":978,"1002":978,"1003":978,"1004":978,"1005":978,"1006":978,"1007":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1048":1042,"1049":1042,"1050":1042,"1051":1042,"1052":1042,"1053":1042,"1054":1042,"1055":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1080":1075,"1081":1075,"1082":1075,"1083":1075,"1084":1075,"1085":1075,"1086":1075,"1087":1075,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1096":1090,"1097":1090,"1098":1090,"1099":1090,"1100":1090,"1101":1090,"1102":1090,"1103":1090,"1122":1120,"1123":1120,"1124":1120,"1125":1120,"1126":1120,"1127":1120,"1128":1120,"1129":1120,"1130":1120,"1131":1120,"1132":1120,"1133":1120,"1134":1120,"1135":1120,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1154":1152,"1155":1152,"1156":1152,"1157":1152,"1158":1152,"1159":1152,"1160":1152,"1161":1152,"1162":1152,"1163":1152,"1164":1152,"1165":1152,"1166":1152,"1167":1152,"1169":1168,"1170":1168,"1171":1168,"1172":1168,"1173":1168,"1174":1168,"1175":1168,"1176":1168,"1177":1168,"1178":1168,"1179":1168,"1180":1168,"1181":1168,"1182":1168,"1183":1168,"1185":1168,"1186":1168,"1187":1168,"1188":1168,"1189":1168,"1190":1168,"1191":1168,"1192":1168,"1193":1168,"1194":1168,"1195":1168,"1196":1168,"1197":1168,"1198":1168,"1199":1168,"1200":1221,"1206":1221,"1207":1221,"1208":1221,"1209":1221,"1210":1221,"1211":1221,"1212":1221,"1213":1221,"1214":1221,"1215":1221,"1216":1221,"1222":1221,"1223":1221,"1224":1221,"1225":1221,"1226":1221,"1227":1221,"1228":1221,"1229":1221,"1230":1221,"1231":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1256":1248,"1257":1248,"1258":1248,"1259":1248,"1260":1248,"1261":1248,"1262":1248,"1263":1248,"1265":1264,"1266":1264,"1267":1264,"1268":1264,"1269":1264,"1270":1264,"1271":1264,"1272":1264,"1273":1264,"1274":1264,"1275":1264,"1276":1264,"1277":1264,"1278":1264,"1279":1264,"1281":1280,"1282":1280,"1283":1280,"1284":1280,"1285":1280,"1286":1280,"1287":1280,"1288":1280,"1289":1280,"1290":1280,"1291":1280,"1292":1280,"1293":1280,"1294":1280,"1295":1280,"1313":1312,"1314":1312,"1315":1312,"1316":1312,"1317":1312,"1318":1312,"1319":1312,"1320":1312,"1321":1312,"1322":1312,"1323":1312,"1324":1312,"1325":1312,"1326":1312,"1327":1312,"1345":1344,"1346":1344,"1347":1344,"1348":1344,"1349":1344,"1350":1344,"1351":1344,"1352":1344,"1353":1344,"1354":1344,"1355":1344,"1356":1344,"1357":1344,"1358":1344,"1359":1344,"1377":1376,"1378":1376,"1379":1376,"1380":1376,"1381":1376,"1382":1376,"1383":1376,"1384":1376,"1385":1376,"1386":1376,"1387":1376,"1388":1376,"1389":1376,"1390":1376,"1391":1376,"1393":1392,"1394":1392,"1395":1392,"1396":1392,"1397":1392,"1398":1392,"1399":1392,"1400":1392,"1401":1392,"1402":1392,"1403":1392,"1404":1392,"1405":1392,"1406":1392,"1407":1392,"1409":1408,"1410":1408,"1411":1408,"1412":1408,"1413":1408,"1414":1408,"1415":1408,"1416":1408,"1417":1408,"1418":1408,"1419":1408,"1420":1408,"1421":1408,"1422":1408,"1423":1408,"1425":1424,"1426":1424,"1427":1424,"1428":1424,"1429":1424,"1430":1424,"1431":1424,"1432":1424,"1433":1424,"1434":1424,"1435":1424,"1436":1424,"1437":1424,"1438":1424,"1439":1424,"1440":1441,"1443":1441,"1444":1441,"1445":1441,"1446":1441,"1447":1441,"1448":1441,"1449":1441,"1450":1441,"1451":1441,"1452":1441,"1453":1441,"1454":1441,"1455":1441,"1460":1458,"1461":1458,"1462":1458,"1463":1458,"1464":1458,"1465":1458,"1466":1458,"1467":1458,"1468":1458,"1469":1458,"1470":1458,"1471":1458,"1479":1472,"1480":1472,"1481":1472,"1482":1472,"1483":1472,"1484":1472,"1485":1472,"1486":1472,"1487":1472,"1521":1520,"1522":1520,"1523":1520,"1524":1520,"1525":1520,"1526":1520,"1527":1520,"1528":1520,"1529":1520,"1530":1520,"1531":1520,"1532":1520,"1533":1520,"1534":1520,"1535":1520,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"1617":1616,"1618":1616,"1619":1616,"1620":1616,"1621":1616,"1622":1616,"1623":1616,"1624":1616,"1625":1616,"1626":1616,"1627":1616,"1628":1616,"1629":1616,"1630":1616,"1631":1616,"1633":1632,"1634":1632,"1635":1632,"1636":1632,"1637":1632,"1638":1632,"1639":1632,"1640":1632,"1641":1632,"1642":1632,"1643":1632,"1644":1632,"1645":1632,"1646":1632,"1647":1632,"1649":1648,"1650":1648,"1651":1648,"1652":1648,"1653":1648,"1654":1648,"1655":1648,"1656":1648,"1657":1648,"1658":1648,"1659":1648,"1660":1648,"1661":1648,"1662":1648,"1663":1648,"1672":1664,"1673":1664,"1674":1664,"1675":1664,"1676":1664,"1677":1664,"1678":1664,"1679":1664,"1688":1680,"1689":1680,"1690":1680,"1691":1680,"1692":1680,"1693":1680,"1694":1680,"1695":1680,"1736":1731,"1737":1731,"1738":1731,"1739":1731,"1740":1731,"1741":1731,"1742":1731,"1743":1731,"1752":1747,"1753":1747,"1754":1747,"1755":1747,"1756":1747,"1757":1747,"1758":1747,"1759":1747,"1761":1760,"1762":1760,"1763":1760,"1764":1760,"1765":1760,"1766":1760,"1767":1760,"1768":1760,"1769":1760,"1770":1760,"1771":1760,"1772":1760,"1773":1760,"1774":1760,"1775":1760,"1777":1776,"1778":1776,"1779":1776,"1780":1776,"1781":1776,"1782":1776,"1783":1776,"1784":1776,"1785":1776,"1786":1776,"1787":1776,"1788":1776,"1789":1776,"1790":1776,"1791":1776,"1793":1792,"1794":1792,"1795":1792,"1796":1792,"1797":1792,"1798":1792,"1799":1792,"1800":1792,"1801":1792,"1802":1792,"1803":1792,"1804":1792,"1805":1792,"1806":1792,"1807":1792,"1809":1808,"1810":1808,"1811":1808,"1812":1808,"1813":1808,"1814":1808,"1815":1808,"1816":1808,"1817":1808,"1818":1808,"1819":1808,"1820":1808,"1821":1808,"1822":1808,"1823":1808,"1832":1827,"1833":1827,"1834":1827,"1835":1827,"1836":1827,"1837":1827,"1838":1827,"1839":1827,"1844":1840,"1845":1840,"1846":1840,"1847":1840,"1848":1840,"1849":1840,"1850":1840,"1851":1840,"1852":1840,"1853":1840,"1854":1840,"1855":1840,"1857":1856,"1858":1856,"1859":1856,"1860":1856,"1861":1856,"1862":1856,"1863":1856,"1864":1856,"1865":1856,"1866":1856,"1867":1856,"1868":1856,"1869":1856,"1870":1856,"1871":1856,"1880":1872,"1881":1872,"1882":1872,"1883":1872,"1884":1872,"1885":1872,"1886":1872,"1887":1872,"1928":1922,"1929":1922,"1930":1922,"1931":1922,"1932":1922,"1933":1922,"1934":1922,"1935":1922,"1937":1936,"1938":1936,"1939":1936,"1940":1936,"1941":1936,"1942":1936,"1943":1936,"1944":1936,"1945":1936,"1946":1936,"1947":1936,"1948":1936,"1949":1936,"1950":1936,"1951":1936,"1953":1952,"1954":1952,"1955":1952,"1956":1952,"1957":1952,"1958":1952,"1959":1952,"1960":1952,"1961":1952,"1962":1952,"1963":1952,"1964":1952,"1965":1952,"1966":1952,"1967":1952,"1969":1968,"1970":1968,"1971":1968,"1972":1968,"1973":1968,"1974":1968,"1975":1968,"1976":1968,"1977":1968,"1978":1968,"1979":1968,"1980":1968,"1981":1968,"1982":1968,"1983":1968,"1985":1968,"1986":1968,"1987":1968,"1988":1968,"1989":1968,"1990":1968,"1991":1968,"1992":1968,"1993":1968,"1994":1968,"1995":1968,"1996":1968,"1997":1968,"1998":1968,"1999":1968,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2056":2051,"2057":2051,"2058":2051,"2059":2051,"2060":2051,"2061":2051,"2062":2051,"2063":2051,"2065":2064,"2066":2064,"2067":2064,"2068":2064,"2069":2064,"2070":2064,"2071":2064,"2072":2064,"2073":2064,"2074":2064,"2075":2064,"2076":2064,"2077":2064,"2078":2064,"2079":2064,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2088":2082,"2089":2082,"2090":2082,"2091":2082,"2092":2082,"2093":2082,"2094":2082,"2095":2082,"2129":2128,"2130":2128,"2131":2128,"2132":2128,"2133":2128,"2134":2128,"2135":2128,"2136":2128,"2137":2128,"2138":2128,"2139":2128,"2140":2128,"2141":2128,"2142":2128,"2143":2128,"2152":2147,"2153":2147,"2154":2147,"2155":2147,"2156":2147,"2157":2147,"2158":2147,"2159":2147,"2168":2163,"2169":2163,"2170":2163,"2171":2163,"2172":2163,"2173":2163,"2174":2163,"2175":2163,"2184":2179,"2185":2179,"2186":2179,"2187":2179,"2188":2179,"2189":2179,"2190":2179,"2191":2179,"2209":2208,"2210":2208,"2211":2208,"2212":2208,"2213":2208,"2214":2208,"2215":2208,"2216":2208,"2217":2208,"2218":2208,"2219":2208,"2220":2208,"2221":2208,"2222":2208,"2223":2208,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2264":2256,"2265":2256,"2266":2256,"2267":2256,"2268":2256,"2269":2256,"2270":2256,"2271":2256,"2280":2272,"2281":2272,"2282":2272,"2283":2272,"2284":2272,"2285":2272,"2286":2272,"2287":2272,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2344":2338,"2345":2338,"2346":2338,"2347":2338,"2348":2338,"2349":2338,"2350":2338,"2351":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2433":2432,"2434":2432,"2435":2432,"2436":2432,"2437":2432,"2438":2432,"2439":2432,"2440":2432,"2441":2432,"2442":2432,"2443":2432,"2444":2432,"2445":2432,"2446":2432,"2447":2432,"2449":2448,"2450":2448,"2451":2448,"2452":2448,"2453":2448,"2454":2448,"2455":2448,"2456":2448,"2457":2448,"2458":2448,"2459":2448,"2460":2448,"2461":2448,"2462":2448,"2463":2448,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2493":2481,"2494":2482,"2504":2499,"2505":2499,"2506":2499,"2507":2499,"2508":2499,"2509":2499,"2510":2499,"2511":2499,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2604":7476,"2605":7477,"2616":2611,"2617":2611,"2618":2611,"2619":2611,"2620":2611,"2621":2611,"2622":2611,"2623":2611,"2632":2627,"2633":2627,"2634":2627,"2635":2627,"2636":2627,"2637":2627,"2638":2627,"2639":2627,"2641":2640,"2642":2640,"2643":2640,"2644":2640,"2645":2640,"2646":2640,"2647":2640,"2648":2640,"2649":2640,"2650":2640,"2651":2640,"2652":2640,"2653":2640,"2654":2640,"2655":2640,"2705":2704,"2706":2704,"2707":2704,"2708":2704,"2709":2704,"2710":2704,"2711":2704,"2712":2704,"2713":2704,"2714":2704,"2715":2704,"2716":2704,"2717":2704,"2718":2704,"2719":2704,"2721":2720,"2722":2720,"2723":2720,"2725":2720,"2726":2720,"2727":2720,"2729":2720,"2730":2720,"2731":2720,"2732":2720,"2733":2720,"2734":2720,"2735":2720,"2753":2752,"2754":2752,"2755":2752,"2756":2752,"2757":2752,"2758":2752,"2759":2752,"2760":2752,"2761":2752,"2762":2752,"2763":2752,"2764":2752,"2765":2752,"2766":2752,"2767":2752,"2769":2768,"2770":2768,"2771":2768,"2772":2768,"2773":2768,"2774":2768,"2775":2768,"2776":2768,"2777":2768,"2778":2768,"2779":2768,"2780":2768,"2781":2768,"2782":2768,"2783":2768,"2785":2784,"2786":2784,"2787":2784,"2788":2784,"2789":2784,"2790":2784,"2791":2784,"2792":2784,"2793":2784,"2794":2784,"2795":2784,"2796":2784,"2797":2784,"2798":2784,"2799":2784,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2840":2834,"2841":2834,"2842":2834,"2843":2834,"2844":2834,"2845":2834,"2846":2834,"2847":2834,"2888":2883,"2889":2883,"2890":2883,"2891":2883,"2892":2883,"2893":2883,"2894":2883,"2895":2883,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3041":3040,"3042":3040,"3043":3040,"3044":3040,"3045":3040,"3046":3040,"3047":3040,"3048":3040,"3049":3040,"3050":3040,"3051":3040,"3052":3040,"3053":3040,"3054":3040,"3055":3040,"3073":3072,"3074":3072,"3075":3072,"3076":3072,"3077":3072,"3078":3072,"3079":3072,"3080":3072,"3081":3072,"3082":3072,"3083":3072,"3084":3072,"3085":3072,"3086":3072,"3087":3072,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3169":3168,"3170":3168,"3171":3168,"3172":3168,"3173":3168,"3174":3168,"3175":3168,"3176":3168,"3177":3168,"3178":3168,"3179":3168,"3180":3168,"3181":3168,"3182":3168,"3183":3168,"3192":3187,"3193":3187,"3194":3187,"3195":3187,"3196":3187,"3197":3187,"3198":3187,"3199":3187,"3230":3218,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3256":3251,"3257":3251,"3258":3251,"3259":3251,"3260":3251,"3261":3251,"3262":3251,"3263":3251,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3281":3280,"3282":3280,"3283":3280,"3284":3280,"3285":3280,"3286":3280,"3287":3280,"3288":3280,"3289":3280,"3290":3280,"3291":3280,"3292":3280,"3293":3280,"3294":3280,"3295":3280,"3297":3296,"3298":3296,"3299":3296,"3300":3296,"3301":3296,"3302":3296,"3303":3296,"3304":3296,"3305":3296,"3306":3296,"3307":3296,"3308":3296,"3309":3296,"3310":3296,"3311":3296,"3316":3312,"3317":3312,"3318":3312,"3319":3312,"3320":3312,"3321":3312,"3322":3312,"3323":3312,"3324":3312,"3325":3312,"3326":3312,"3327":3312,"3334":3328,"3335":3328,"3336":3328,"3337":3328,"3338":3328,"3339":3328,"3340":3328,"3341":3328,"3342":3328,"3343":3328,"3409":3408,"3410":3408,"3411":3408,"3412":3408,"3413":3408,"3414":3408,"3415":3408,"3416":3408,"3417":3408,"3418":3408,"3419":3408,"3420":3408,"3421":3408,"3422":3408,"3423":3408,"3425":3424,"3426":3424,"3427":3424,"3428":3424,"3429":3424,"3430":3424,"3431":3424,"3432":3424,"3433":3424,"3434":3424,"3435":3424,"3436":3424,"3437":3424,"3438":3424,"3439":3424,"3441":3440,"3442":3440,"3443":3440,"3444":3440,"3445":3440,"3446":3440,"3447":3440,"3448":3440,"3449":3440,"3450":3440,"3451":3440,"3452":3440,"3453":3440,"3454":3440,"3455":3440,"3457":3456,"3458":3456,"3459":3456,"3461":3456,"3462":3456,"3463":3456,"3465":3456,"3466":3456,"3467":3456,"3468":3456,"3469":3456,"3470":3456,"3471":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3512":3506,"3513":3506,"3514":3506,"3515":3506,"3516":3506,"3517":3506,"3518":3506,"3519":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3528":3522,"3529":3522,"3530":3522,"3531":3522,"3532":3522,"3533":3522,"3534":3522,"3535":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3544":3538,"3545":3538,"3546":3538,"3547":3538,"3548":3538,"3549":3538,"3550":3538,"3551":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3560":3554,"3561":3554,"3562":3554,"3563":3554,"3564":3554,"3565":3554,"3566":3554,"3567":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3576":3570,"3577":3570,"3578":3570,"3579":3570,"3580":3570,"3581":3570,"3582":3570,"3583":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3592":3586,"3593":3586,"3594":3586,"3595":3586,"3596":3586,"3597":3586,"3598":3586,"3599":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3608":3602,"3609":3602,"3610":3602,"3611":3602,"3612":3602,"3613":3602,"3614":3602,"3615":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3624":3618,"3625":3618,"3626":3618,"3627":3618,"3628":3618,"3629":3618,"3630":3618,"3631":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3640":3634,"3641":3634,"3642":3634,"3643":3634,"3644":3634,"3645":3634,"3646":3634,"3647":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3656":3650,"3657":3650,"3658":3650,"3659":3650,"3660":3650,"3661":3650,"3662":3650,"3663":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3672":3666,"3673":3666,"3674":3666,"3675":3666,"3676":3666,"3677":3666,"3678":3666,"3679":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3704":3698,"3705":3698,"3706":3698,"3707":3698,"3708":3698,"3709":3698,"3710":3698,"3711":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3720":3714,"3721":3714,"3722":3714,"3723":3714,"3724":3714,"3725":3714,"3726":3714,"3727":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3736":3730,"3737":3730,"3738":3730,"3739":3730,"3740":3730,"3741":3730,"3742":3730,"3743":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3752":3746,"3753":3746,"3754":3746,"3755":3746,"3756":3746,"3757":3746,"3758":3746,"3759":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3768":3762,"3769":3762,"3770":3762,"3771":3762,"3772":3762,"3773":3762,"3774":3762,"3775":3762,"3824":3829,"3830":3829,"3831":3829,"3832":3829,"3833":3829,"3834":3829,"3835":3829,"3836":3829,"3837":3829,"3838":3829,"3839":3829,"3889":3888,"3890":3888,"3891":3888,"3892":3888,"3893":3888,"3894":3888,"3895":3888,"3896":3888,"3897":3888,"3898":3888,"3899":3888,"3900":3888,"3901":3888,"3902":3888,"3903":3888,"3912":3904,"3913":3904,"3914":3904,"3915":3904,"3916":3904,"3917":3904,"3918":3904,"3919":3904,"3921":3920,"3922":3920,"3923":3920,"3924":3920,"3925":3920,"3926":3920,"3927":3920,"3928":3920,"3929":3920,"3930":3920,"3931":3920,"3932":3920,"3933":3920,"3934":3920,"3935":3920,"3937":3936,"3938":3936,"3939":3936,"3940":3936,"3941":3936,"3942":3936,"3943":3936,"3944":3936,"3945":3936,"3946":3936,"3947":3936,"3948":3936,"3949":3936,"3950":3936,"3951":3936,"3955":3952,"3956":3952,"3957":3952,"3958":3952,"3959":3952,"3960":3952,"3961":3952,"3962":3952,"3963":3952,"3964":3952,"3965":3952,"3966":3952,"3967":3952,"3969":3968,"3970":3968,"3971":3968,"3972":3968,"3973":3968,"3974":3968,"3975":3968,"3976":3968,"3977":3968,"3978":3968,"3979":3968,"3980":3968,"3981":3968,"3982":3968,"3983":3968,"3985":3984,"3986":3984,"3987":3984,"3988":3984,"3989":3984,"3990":3984,"3991":3984,"3992":3984,"3993":3984,"3994":3984,"3995":3984,"3996":3984,"3997":3984,"3998":3984,"3999":3984,"4049":4048,"4050":4048,"4051":4048,"4052":4048,"4053":4048,"4054":4048,"4055":4048,"4056":4048,"4057":4048,"4058":4048,"4059":4048,"4060":4048,"4061":4048,"4062":4048,"4063":4048,"4081":4080,"4082":4080,"4083":4080,"4084":4080,"4085":4080,"4086":4080,"4087":4080,"4088":4080,"4089":4080,"4090":4080,"4091":4080,"4092":4080,"4093":4080,"4094":4080,"4095":4080,"4120":4115,"4121":4115,"4122":4115,"4123":4115,"4124":4115,"4125":4115,"4126":4115,"4127":4115,"4136":4131,"4137":4131,"4138":4131,"4139":4131,"4140":4131,"4141":4131,"4142":4131,"4143":4131,"4152":4147,"4153":4147,"4154":4147,"4155":4147,"4156":4147,"4157":4147,"4158":4147,"4159":4147,"4163":4160,"4164":4160,"4165":4160,"4166":4160,"4167":4160,"4168":4160,"4169":4160,"4170":4160,"4171":4160,"4172":4160,"4173":4160,"4174":4160,"4175":4160,"4179":4176,"4180":4176,"4181":4176,"4182":4176,"4183":4176,"4184":4176,"4185":4176,"4186":4176,"4187":4176,"4188":4176,"4189":4176,"4190":4176,"4191":4176,"4195":4192,"4196":4192,"4197":4192,"4198":4192,"4199":4192,"4200":4192,"4201":4192,"4202":4192,"4203":4192,"4204":4192,"4205":4192,"4206":4192,"4207":4192,"4211":4208,"4212":4208,"4213":4208,"4214":4208,"4215":4208,"4216":4208,"4217":4208,"4218":4208,"4219":4208,"4220":4208,"4221":4208,"4222":4208,"4223":4208,"4227":4224,"4228":4224,"4229":4224,"4230":4224,"4231":4224,"4232":4224,"4233":4224,"4234":4224,"4235":4224,"4236":4224,"4237":4224,"4238":4224,"4239":4224,"4243":4240,"4244":4240,"4245":4240,"4246":4240,"4247":4240,"4248":4240,"4249":4240,"4250":4240,"4251":4240,"4252":4240,"4253":4240,"4254":4240,"4255":4240,"4257":4256,"4258":4256,"4259":4256,"4260":4256,"4261":4256,"4262":4256,"4263":4256,"4264":4256,"4265":4256,"4266":4256,"4267":4256,"4268":4256,"4269":4256,"4270":4256,"4271":4256,"4273":4272,"4274":4272,"4275":4272,"4276":4272,"4277":4272,"4278":4272,"4279":4272,"4280":4272,"4281":4272,"4282":4272,"4283":4272,"4284":4272,"4285":4272,"4286":4272,"4287":4272,"4289":4288,"4290":4288,"4291":4288,"4292":4288,"4293":4288,"4294":4288,"4295":4288,"4296":4288,"4297":4288,"4298":4288,"4299":4288,"4300":4288,"4301":4288,"4302":4288,"4303":4288,"4305":4304,"4306":4304,"4307":4304,"4308":4304,"4309":4304,"4310":4304,"4311":4304,"4312":4304,"4313":4304,"4314":4304,"4315":4304,"4316":4304,"4317":4304,"4318":4304,"4319":4304,"4321":4320,"4322":4320,"4323":4320,"4324":4320,"4325":4320,"4326":4320,"4327":4320,"4328":4320,"4329":4320,"4330":4320,"4331":4320,"4332":4320,"4333":4320,"4334":4320,"4335":4320,"4337":4336,"4338":4336,"4339":4336,"4340":4336,"4341":4336,"4342":4336,"4343":4336,"4344":4336,"4345":4336,"4346":4336,"4347":4336,"4348":4336,"4349":4336,"4350":4336,"4351":4336,"4353":4352,"4354":4352,"4355":4352,"4356":4352,"4357":4352,"4358":4352,"4359":4352,"4360":4352,"4361":4352,"4362":4352,"4363":4352,"4364":4352,"4365":4352,"4366":4352,"4367":4352,"4369":4368,"4370":4368,"4371":4368,"4372":4368,"4373":4368,"4374":4368,"4375":4368,"4376":4368,"4377":4368,"4378":4368,"4379":4368,"4380":4368,"4381":4368,"4382":4368,"4383":4368,"4385":4384,"4386":4384,"4387":4384,"4388":4384,"4389":4384,"4390":4384,"4391":4384,"4392":4384,"4393":4384,"4394":4384,"4395":4384,"4396":4384,"4397":4384,"4398":4384,"4399":4384,"4401":4400,"4402":4400,"4403":4400,"4404":4400,"4405":4400,"4406":4400,"4407":4400,"4408":4400,"4409":4400,"4410":4400,"4411":4400,"4412":4400,"4413":4400,"4414":4400,"4415":4400,"4417":4416,"4418":4416,"4419":4416,"4420":4416,"4421":4416,"4422":4416,"4423":4416,"4424":4416,"4425":4416,"4426":4416,"4427":4416,"4428":4416,"4429":4416,"4430":4416,"4431":4416,"4433":4432,"4434":4432,"4435":4432,"4436":4432,"4437":4432,"4438":4432,"4439":4432,"4440":4432,"4441":4432,"4442":4432,"4443":4432,"4444":4432,"4445":4432,"4446":4432,"4447":4432,"4449":4448,"4450":4448,"4451":4448,"4452":4448,"4453":4448,"4454":4448,"4455":4448,"4456":4448,"4457":4448,"4458":4448,"4459":4448,"4460":4448,"4461":4448,"4462":4448,"4463":4448,"4465":4464,"4466":4464,"4467":4464,"4468":4464,"4469":4464,"4470":4464,"4471":4464,"4472":4464,"4473":4464,"4474":4464,"4475":4464,"4476":4464,"4477":4464,"4478":4464,"4479":4464,"4481":4480,"4482":4480,"4483":4480,"4484":4480,"4485":4480,"4486":4480,"4487":4480,"4488":4480,"4489":4480,"4490":4480,"4491":4480,"4492":4480,"4493":4480,"4494":4480,"4495":4480,"4497":4496,"4498":4496,"4499":4496,"4500":4496,"4501":4496,"4502":4496,"4503":4496,"4504":4496,"4505":4496,"4506":4496,"4507":4496,"4508":4496,"4509":4496,"4510":4496,"4511":4496,"4513":4512,"4514":4512,"4515":4512,"4516":4512,"4517":4512,"4518":4512,"4519":4512,"4520":4512,"4521":4512,"4522":4512,"4523":4512,"4524":4512,"4525":4512,"4526":4512,"4527":4512,"4529":4528,"4530":4528,"4531":4528,"4532":4528,"4533":4528,"4534":4528,"4535":4528,"4536":4528,"4537":4528,"4538":4528,"4539":4528,"4540":4528,"4541":4528,"4542":4528,"4543":4528,"4545":4544,"4546":4544,"4547":4544,"4548":4544,"4549":4544,"4550":4544,"4551":4544,"4552":4544,"4553":4544,"4554":4544,"4555":4544,"4556":4544,"4557":4544,"4558":4544,"4559":4544,"4561":4560,"4562":4560,"4563":4560,"4564":4560,"4565":4560,"4566":4560,"4567":4560,"4568":4560,"4569":4560,"4570":4560,"4571":4560,"4572":4560,"4573":4560,"4574":4560,"4575":4560,"4577":4576,"4578":4576,"4579":4576,"4580":4576,"4581":4576,"4582":4576,"4583":4576,"4584":4576,"4585":4576,"4586":4576,"4587":4576,"4588":4576,"4589":4576,"4590":4576,"4591":4576,"4593":4592,"4594":4592,"4595":4592,"4596":4592,"4597":4592,"4598":4592,"4599":4592,"4600":4592,"4601":4592,"4602":4592,"4603":4592,"4604":4592,"4605":4592,"4606":4592,"4607":4592,"4609":4608,"4610":4608,"4611":4608,"4612":4608,"4613":4608,"4614":4608,"4615":4608,"4616":4608,"4617":4608,"4618":4608,"4619":4608,"4620":4608,"4621":4608,"4622":4608,"4623":4608,"4625":4624,"4626":4624,"4627":4624,"4628":4624,"4629":4624,"4630":4624,"4631":4624,"4632":4624,"4633":4624,"4634":4624,"4635":4624,"4636":4624,"4637":4624,"4638":4624,"4639":4624,"4641":4640,"4642":4640,"4643":4640,"4644":4640,"4645":4640,"4646":4640,"4647":4640,"4648":4640,"4649":4640,"4650":4640,"4651":4640,"4652":4640,"4653":4640,"4654":4640,"4655":4640,"4657":4656,"4658":4656,"4659":4656,"4660":4656,"4661":4656,"4662":4656,"4663":4656,"4664":4656,"4665":4656,"4666":4656,"4667":4656,"4668":4656,"4669":4656,"4670":4656,"4671":4656,"4673":4672,"4674":4672,"4675":4672,"4676":4672,"4677":4672,"4678":4672,"4679":4672,"4680":4672,"4681":4672,"4682":4672,"4683":4672,"4684":4672,"4685":4672,"4686":4672,"4687":4672,"4689":4688,"4690":4688,"4691":4688,"4692":4688,"4693":4688,"4694":4688,"4695":4688,"4696":4688,"4697":4688,"4698":4688,"4699":4688,"4700":4688,"4701":4688,"4702":4688,"4703":4688,"4705":4704,"4706":4704,"4707":4704,"4708":4704,"4709":4704,"4710":4704,"4711":4704,"4712":4704,"4713":4704,"4714":4704,"4715":4704,"4716":4704,"4717":4704,"4718":4704,"4719":4704,"4721":4720,"4722":4720,"4723":4720,"4724":4720,"4725":4720,"4726":4720,"4727":4720,"4728":4720,"4729":4720,"4730":4720,"4731":4720,"4732":4720,"4733":4720,"4734":4720,"4735":4720,"4737":4736,"4738":4736,"4739":4736,"4740":4736,"4741":4736,"4742":4736,"4743":4736,"4744":4736,"4745":4736,"4746":4736,"4747":4736,"4748":4736,"4749":4736,"4750":4736,"4751":4736,"4753":4752,"4754":4752,"4755":4752,"4756":4752,"4757":4752,"4758":4752,"4759":4752,"4760":4752,"4761":4752,"4762":4752,"4763":4752,"4764":4752,"4765":4752,"4766":4752,"4767":4752,"4769":4768,"4770":4768,"4771":4768,"4772":4768,"4773":4768,"4774":4768,"4775":4768,"4776":4768,"4777":4768,"4778":4768,"4779":4768,"4780":4768,"4781":4768,"4782":4768,"4783":4768,"4785":4784,"4786":4784,"4787":4784,"4788":4784,"4789":4784,"4790":4784,"4791":4784,"4792":4784,"4793":4784,"4794":4784,"4795":4784,"4796":4784,"4797":4784,"4798":4784,"4799":4784,"4801":4800,"4802":4800,"4803":4800,"4804":4800,"4805":4800,"4806":4800,"4807":4800,"4808":4800,"4809":4800,"4810":4800,"4811":4800,"4812":4800,"4813":4800,"4814":4800,"4815":4800,"4817":4816,"4818":4816,"4819":4816,"4820":4816,"4821":4816,"4822":4816,"4823":4816,"4824":4816,"4825":4816,"4826":4816,"4827":4816,"4828":4816,"4829":4816,"4830":4816,"4831":4816,"4833":4832,"4834":4832,"4835":4832,"4836":4832,"4837":4832,"4838":4832,"4839":4832,"4840":4832,"4841":4832,"4842":4832,"4843":4832,"4844":4832,"4845":4832,"4846":4832,"4847":4832,"4849":4848,"4850":4848,"4851":4848,"4852":4848,"4853":4848,"4854":4848,"4855":4848,"4856":4848,"4857":4848,"4858":4848,"4859":4848,"4860":4848,"4861":4848,"4862":4848,"4863":4848,"4865":4864,"4866":4864,"4867":4864,"4868":4864,"4869":4864,"4870":4864,"4871":4864,"4872":4864,"4873":4864,"4874":4864,"4875":4864,"4876":4864,"4877":4864,"4878":4864,"4879":4864,"4881":4880,"4882":4880,"4883":4880,"4884":4880,"4885":4880,"4886":4880,"4887":4880,"4888":4880,"4889":4880,"4890":4880,"4891":4880,"4892":4880,"4893":4880,"4894":4880,"4895":4880,"4897":4896,"4898":4896,"4899":4896,"4900":4896,"4901":4896,"4902":4896,"4903":4896,"4904":4896,"4905":4896,"4906":4896,"4907":4896,"4908":4896,"4909":4896,"4910":4896,"4911":4896,"4913":4912,"4914":4912,"4915":4912,"4916":4912,"4917":4912,"4918":4912,"4919":4912,"4920":4912,"4921":4912,"4922":4912,"4923":4912,"4924":4912,"4925":4912,"4926":4912,"4927":4912,"4929":4928,"4930":4928,"4931":4928,"4932":4928,"4933":4928,"4934":4928,"4935":4928,"4936":4928,"4937":4928,"4938":4928,"4939":4928,"4940":4928,"4941":4928,"4942":4928,"4943":4928,"4945":4944,"4946":4944,"4947":4944,"4948":4944,"4949":4944,"4950":4944,"4951":4944,"4952":4944,"4953":4944,"4954":4944,"4955":4944,"4956":4944,"4957":4944,"4958":4944,"4959":4944,"4961":4960,"4962":4960,"4963":4960,"4964":4960,"4965":4960,"4966":4960,"4967":4960,"4968":4960,"4969":4960,"4970":4960,"4971":4960,"4972":4960,"4973":4960,"4974":4960,"4975":4960,"4977":4976,"4978":4976,"4979":4976,"4980":4976,"4981":4976,"4982":4976,"4983":4976,"4984":4976,"4985":4976,"4986":4976,"4987":4976,"4988":4976,"4989":4976,"4990":4976,"4991":4976,"4993":4992,"4994":4992,"4995":4992,"4996":4992,"4997":4992,"4998":4992,"4999":4992,"5000":4992,"5001":4992,"5002":4992,"5003":4992,"5004":4992,"5005":4992,"5006":4992,"5007":4992,"5009":5008,"5010":5008,"5011":5008,"5012":5008,"5013":5008,"5014":5008,"5015":5008,"5016":5008,"5017":5008,"5018":5008,"5019":5008,"5020":5008,"5021":5008,"5022":5008,"5023":5008,"5025":5024,"5026":5024,"5027":5024,"5028":5024,"5029":5024,"5030":5024,"5031":5024,"5032":5024,"5033":5024,"5034":5024,"5035":5024,"5036":5024,"5037":5024,"5038":5024,"5039":5024,"5041":5040,"5042":5040,"5043":5040,"5044":5040,"5045":5040,"5046":5040,"5047":5040,"5048":5040,"5049":5040,"5050":5040,"5051":5040,"5052":5040,"5053":5040,"5054":5040,"5055":5040,"5057":5056,"5058":5056,"5059":5056,"5060":5056,"5061":5056,"5062":5056,"5063":5056,"5064":5056,"5065":5056,"5066":5056,"5067":5056,"5068":5056,"5069":5056,"5070":5056,"5071":5056,"5073":5072,"5074":5072,"5075":5072,"5076":5072,"5077":5072,"5078":5072,"5079":5072,"5080":5072,"5081":5072,"5082":5072,"5083":5072,"5084":5072,"5085":5072,"5086":5072,"5087":5072,"5089":5088,"5090":5088,"5091":5088,"5092":5088,"5093":5088,"5094":5088,"5095":5088,"5096":5088,"5097":5088,"5098":5088,"5099":5088,"5100":5088,"5101":5088,"5102":5088,"5103":5088,"5105":5104,"5106":5104,"5107":5104,"5108":5104,"5109":5104,"5110":5104,"5111":5104,"5112":5104,"5113":5104,"5114":5104,"5115":5104,"5116":5104,"5117":5104,"5118":5104,"5119":5104,"5121":5120,"5122":5120,"5123":5120,"5124":5120,"5125":5120,"5126":5120,"5127":5120,"5128":5120,"5129":5120,"5130":5120,"5131":5120,"5132":5120,"5133":5120,"5134":5120,"5135":5120,"5137":5136,"5138":5136,"5139":5136,"5140":5136,"5141":5136,"5142":5136,"5143":5136,"5144":5136,"5145":5136,"5146":5136,"5147":5136,"5148":5136,"5149":5136,"5150":5136,"5151":5136,"5153":5152,"5154":5152,"5155":5152,"5156":5152,"5157":5152,"5158":5152,"5159":5152,"5160":5152,"5161":5152,"5162":5152,"5163":5152,"5164":5152,"5165":5152,"5166":5152,"5167":5152,"5169":5168,"5170":5168,"5171":5168,"5172":5168,"5173":5168,"5174":5168,"5175":5168,"5176":5168,"5177":5168,"5178":5168,"5179":5168,"5180":5168,"5181":5168,"5182":5168,"5183":5168,"5185":5184,"5186":5184,"5187":5184,"5188":5184,"5189":5184,"5190":5184,"5191":5184,"5192":5184,"5193":5184,"5194":5184,"5195":5184,"5196":5184,"5197":5184,"5198":5184,"5199":5184,"5201":5200,"5202":5200,"5203":5200,"5204":5200,"5205":5200,"5206":5200,"5207":5200,"5208":5200,"5209":5200,"5210":5200,"5211":5200,"5212":5200,"5213":5200,"5214":5200,"5215":5200,"5217":5216,"5218":5216,"5219":5216,"5220":5216,"5221":5216,"5222":5216,"5223":5216,"5224":5216,"5225":5216,"5226":5216,"5227":5216,"5228":5216,"5229":5216,"5230":5216,"5231":5216,"5233":5232,"5234":5232,"5235":5232,"5236":5232,"5237":5232,"5238":5232,"5239":5232,"5240":5232,"5241":5232,"5242":5232,"5243":5232,"5244":5232,"5245":5232,"5246":5232,"5247":5232,"5249":5248,"5250":5248,"5251":5248,"5252":5248,"5253":5248,"5254":5248,"5255":5248,"5256":5248,"5257":5248,"5258":5248,"5259":5248,"5260":5248,"5261":5248,"5262":5248,"5263":5248,"5265":5264,"5266":5264,"5267":5264,"5268":5264,"5269":5264,"5270":5264,"5271":5264,"5272":5264,"5273":5264,"5274":5264,"5275":5264,"5276":5264,"5277":5264,"5278":5264,"5279":5264,"5281":5280,"5282":5280,"5283":5280,"5284":5280,"5285":5280,"5286":5280,"5287":5280,"5288":5280,"5289":5280,"5290":5280,"5291":5280,"5292":5280,"5293":5280,"5294":5280,"5295":5280,"5297":5296,"5298":5296,"5299":5296,"5300":5296,"5301":5296,"5302":5296,"5303":5296,"5304":5296,"5305":5296,"5306":5296,"5307":5296,"5308":5296,"5309":5296,"5310":5296,"5311":5296,"5313":5312,"5314":5312,"5315":5312,"5316":5312,"5317":5312,"5318":5312,"5319":5312,"5320":5312,"5321":5312,"5322":5312,"5323":5312,"5324":5312,"5325":5312,"5326":5312,"5327":5312,"5329":5328,"5330":5328,"5331":5328,"5332":5328,"5333":5328,"5334":5328,"5335":5328,"5336":5328,"5337":5328,"5338":5328,"5339":5328,"5340":5328,"5341":5328,"5342":5328,"5343":5328,"5345":5344,"5346":5344,"5347":5344,"5348":5344,"5349":5344,"5350":5344,"5351":5344,"5352":5344,"5353":5344,"5354":5344,"5355":5344,"5356":5344,"5357":5344,"5358":5344,"5359":5344,"5361":5360,"5362":5360,"5363":5360,"5364":5360,"5365":5360,"5366":5360,"5367":5360,"5368":5360,"5369":5360,"5370":5360,"5371":5360,"5372":5360,"5373":5360,"5374":5360,"5375":5360,"5377":5376,"5378":5376,"5379":5376,"5380":5376,"5381":5376,"5382":5376,"5383":5376,"5384":5376,"5385":5376,"5386":5376,"5387":5376,"5388":5376,"5389":5376,"5390":5376,"5391":5376,"5393":5392,"5394":5392,"5395":5392,"5396":5392,"5397":5392,"5398":5392,"5399":5392,"5400":5392,"5401":5392,"5402":5392,"5403":5392,"5404":5392,"5405":5392,"5406":5392,"5407":5392,"5409":5408,"5410":5408,"5411":5408,"5412":5408,"5413":5408,"5414":5408,"5415":5408,"5416":5408,"5417":5408,"5418":5408,"5419":5408,"5420":5408,"5421":5408,"5422":5408,"5423":5408,"5425":5424,"5426":5424,"5427":5424,"5428":5424,"5429":5424,"5430":5424,"5431":5424,"5432":5424,"5433":5424,"5434":5424,"5435":5424,"5436":5424,"5437":5424,"5438":5424,"5439":5424,"5441":5440,"5442":5440,"5443":5440,"5444":5440,"5445":5440,"5446":5440,"5447":5440,"5448":5440,"5449":5440,"5450":5440,"5451":5440,"5452":5440,"5453":5440,"5454":5440,"5455":5440,"5457":5456,"5458":5456,"5459":5456,"5460":5456,"5461":5456,"5462":5456,"5463":5456,"5464":5456,"5465":5456,"5466":5456,"5467":5456,"5468":5456,"5469":5456,"5470":5456,"5471":5456,"5473":5472,"5474":5472,"5475":5472,"5476":5472,"5477":5472,"5478":5472,"5479":5472,"5480":5472,"5481":5472,"5482":5472,"5483":5472,"5484":5472,"5485":5472,"5486":5472,"5487":5472,"5489":5488,"5490":5488,"5491":5488,"5492":5488,"5493":5488,"5494":5488,"5495":5488,"5496":5488,"5497":5488,"5498":5488,"5499":5488,"5500":5488,"5501":5488,"5502":5488,"5503":5488,"5505":5504,"5506":5504,"5507":5504,"5508":5504,"5509":5504,"5510":5504,"5511":5504,"5512":5504,"5513":5504,"5514":5504,"5515":5504,"5516":5504,"5517":5504,"5518":5504,"5519":5504,"5521":5520,"5522":5520,"5523":5520,"5524":5520,"5525":5520,"5526":5520,"5527":5520,"5528":5520,"5529":5520,"5530":5520,"5531":5520,"5532":5520,"5533":5520,"5534":5520,"5535":5520,"5537":5536,"5538":5536,"5539":5536,"5540":5536,"5541":5536,"5542":5536,"5543":5536,"5544":5536,"5545":5536,"5546":5536,"5547":5536,"5548":5536,"5549":5536,"5550":5536,"5551":5536,"5553":5552,"5554":5552,"5555":5552,"5556":5552,"5557":5552,"5558":5552,"5559":5552,"5560":5552,"5561":5552,"5562":5552,"5563":5552,"5564":5552,"5565":5552,"5566":5552,"5567":5552,"5569":5568,"5570":5568,"5571":5568,"5572":5568,"5573":5568,"5574":5568,"5575":5568,"5576":5568,"5577":5568,"5578":5568,"5579":5568,"5580":5568,"5581":5568,"5582":5568,"5583":5568,"5585":5584,"5586":5584,"5587":5584,"5588":5584,"5589":5584,"5590":5584,"5591":5584,"5592":5584,"5593":5584,"5594":5584,"5595":5584,"5596":5584,"5597":5584,"5598":5584,"5599":5584,"5601":5600,"5602":5600,"5603":5600,"5604":5600,"5605":5600,"5606":5600,"5607":5600,"5608":5600,"5609":5600,"5610":5600,"5611":5600,"5612":5600,"5613":5600,"5614":5600,"5615":5600,"5617":5616,"5618":5616,"5619":5616,"5620":5616,"5621":5616,"5622":5616,"5623":5616,"5624":5616,"5625":5616,"5626":5616,"5627":5616,"5628":5616,"5629":5616,"5630":5616,"5631":5616,"5633":5632,"5634":5632,"5635":5632,"5636":5632,"5637":5632,"5638":5632,"5639":5632,"5640":5632,"5641":5632,"5642":5632,"5643":5632,"5644":5632,"5645":5632,"5646":5632,"5647":5632,"5649":5648,"5650":5648,"5651":5648,"5652":5648,"5653":5648,"5654":5648,"5655":5648,"5656":5648,"5657":5648,"5658":5648,"5659":5648,"5660":5648,"5661":5648,"5662":5648,"5663":5648,"5665":5664,"5666":5664,"5667":5664,"5668":5664,"5669":5664,"5670":5664,"5671":5664,"5672":5664,"5673":5664,"5674":5664,"5675":5664,"5676":5664,"5677":5664,"5678":5664,"5679":5664,"5681":5680,"5682":5680,"5683":5680,"5684":5680,"5685":5680,"5686":5680,"5687":5680,"5688":5680,"5689":5680,"5690":5680,"5691":5680,"5692":5680,"5693":5680,"5694":5680,"5695":5680,"5697":5696,"5698":5696,"5699":5696,"5700":5696,"5701":5696,"5702":5696,"5703":5696,"5704":5696,"5705":5696,"5706":5696,"5707":5696,"5708":5696,"5709":5696,"5710":5696,"5711":5696,"5713":5712,"5714":5712,"5715":5712,"5716":5712,"5717":5712,"5718":5712,"5719":5712,"5720":5712,"5721":5712,"5722":5712,"5723":5712,"5724":5712,"5725":5712,"5726":5712,"5727":5712,"5729":5728,"5730":5728,"5731":5728,"5732":5728,"5733":5728,"5734":5728,"5735":5728,"5736":5728,"5737":5728,"5738":5728,"5739":5728,"5740":5728,"5741":5728,"5742":5728,"5743":5728,"5745":5744,"5746":5744,"5747":5744,"5748":5744,"5749":5744,"5750":5744,"5751":5744,"5752":5744,"5753":5744,"5754":5744,"5755":5744,"5756":5744,"5757":5744,"5758":5744,"5759":5744,"5761":5760,"5762":5760,"5763":5760,"5764":5760,"5765":5760,"5766":5760,"5767":5760,"5768":5760,"5769":5760,"5770":5760,"5771":5760,"5772":5760,"5773":5760,"5774":5760,"5775":5760,"5777":5776,"5778":5776,"5779":5776,"5780":5776,"5781":5776,"5782":5776,"5783":5776,"5784":5776,"5785":5776,"5786":5776,"5787":5776,"5788":5776,"5789":5776,"5790":5776,"5791":5776,"5793":5792,"5794":5792,"5795":5792,"5796":5792,"5797":5792,"5798":5792,"5799":5792,"5800":5792,"5801":5792,"5802":5792,"5803":5792,"5804":5792,"5805":5792,"5806":5792,"5807":5792,"5809":5808,"5810":5808,"5811":5808,"5812":5808,"5813":5808,"5814":5808,"5815":5808,"5816":5808,"5817":5808,"5818":5808,"5819":5808,"5820":5808,"5821":5808,"5822":5808,"5823":5808,"5825":5824,"5826":5824,"5827":5824,"5828":5824,"5829":5824,"5830":5824,"5831":5824,"5832":5824,"5833":5824,"5834":5824,"5835":5824,"5836":5824,"5837":5824,"5838":5824,"5839":5824,"5841":5840,"5842":5840,"5843":5840,"5844":5840,"5845":5840,"5846":5840,"5847":5840,"5848":5840,"5849":5840,"5850":5840,"5851":5840,"5852":5840,"5853":5840,"5854":5840,"5855":5840,"5857":5856,"5858":5856,"5859":5856,"5860":5856,"5861":5856,"5862":5856,"5863":5856,"5864":5856,"5865":5856,"5866":5856,"5867":5856,"5868":5856,"5869":5856,"5870":5856,"5871":5856,"5873":5872,"5874":5872,"5875":5872,"5876":5872,"5877":5872,"5878":5872,"5879":5872,"5880":5872,"5881":5872,"5882":5872,"5883":5872,"5884":5872,"5885":5872,"5886":5872,"5887":5872,"5889":5888,"5890":5888,"5891":5888,"5892":5888,"5893":5888,"5894":5888,"5895":5888,"5896":5888,"5897":5888,"5898":5888,"5899":5888,"5900":5888,"5901":5888,"5902":5888,"5903":5888,"5905":5904,"5906":5904,"5907":5904,"5908":5904,"5909":5904,"5910":5904,"5911":5904,"5912":5904,"5913":5904,"5914":5904,"5915":5904,"5916":5904,"5917":5904,"5918":5904,"5919":5904,"5921":5920,"5922":5920,"5923":5920,"5924":5920,"5925":5920,"5926":5920,"5927":5920,"5928":5920,"5929":5920,"5930":5920,"5931":5920,"5932":5920,"5933":5920,"5934":5920,"5935":5920,"5937":5936,"5938":5936,"5939":5936,"5940":5936,"5941":5936,"5942":5936,"5943":5936,"5944":5936,"5945":5936,"5946":5936,"5947":5936,"5948":5936,"5949":5936,"5950":5936,"5951":5936,"5953":5952,"5954":5952,"5955":5952,"5956":5952,"5957":5952,"5958":5952,"5959":5952,"5960":5952,"5961":5952,"5962":5952,"5963":5952,"5964":5952,"5965":5952,"5966":5952,"5967":5952,"5969":5968,"5970":5968,"5971":5968,"5972":5968,"5973":5968,"5974":5968,"5975":5968,"5976":5968,"5977":5968,"5978":5968,"5979":5968,"5980":5968,"5981":5968,"5982":5968,"5983":5968,"5985":5984,"5986":5984,"5987":5984,"5988":5984,"5989":5984,"5990":5984,"5991":5984,"5992":5984,"5993":5984,"5994":5984,"5995":5984,"5996":5984,"5997":5984,"5998":5984,"5999":5984,"6001":6000,"6002":6000,"6003":6000,"6004":6000,"6005":6000,"6006":6000,"6007":6000,"6008":6000,"6009":6000,"6010":6000,"6011":6000,"6012":6000,"6013":6000,"6014":6000,"6015":6000,"6017":6016,"6018":6016,"6019":6016,"6020":6016,"6021":6016,"6022":6016,"6023":6016,"6024":6016,"6025":6016,"6026":6016,"6027":6016,"6028":6016,"6029":6016,"6030":6016,"6031":6016,"6033":6032,"6034":6032,"6035":6032,"6036":6032,"6037":6032,"6038":6032,"6039":6032,"6040":6032,"6041":6032,"6042":6032,"6043":6032,"6044":6032,"6045":6032,"6046":6032,"6047":6032,"6049":6048,"6050":6048,"6051":6048,"6052":6048,"6053":6048,"6054":6048,"6055":6048,"6056":6048,"6057":6048,"6058":6048,"6059":6048,"6060":6048,"6061":6048,"6062":6048,"6063":6048,"6065":6064,"6066":6064,"6067":6064,"6068":6064,"6069":6064,"6070":6064,"6071":6064,"6072":6064,"6073":6064,"6074":6064,"6075":6064,"6076":6064,"6077":6064,"6078":6064,"6079":6064,"6081":6080,"6082":6080,"6083":6080,"6084":6080,"6085":6080,"6086":6080,"6087":6080,"6088":6080,"6089":6080,"6090":6080,"6091":6080,"6092":6080,"6093":6080,"6094":6080,"6095":6080,"6097":6096,"6098":6096,"6099":6096,"6100":6096,"6101":6096,"6102":6096,"6103":6096,"6104":6096,"6105":6096,"6106":6096,"6107":6096,"6108":6096,"6109":6096,"6110":6096,"6111":6096,"6113":6112,"6114":6112,"6115":6112,"6116":6112,"6117":6112,"6118":6112,"6119":6112,"6120":6112,"6121":6112,"6122":6112,"6123":6112,"6124":6112,"6125":6112,"6126":6112,"6127":6112,"6129":6128,"6130":6128,"6131":6128,"6132":6128,"6133":6128,"6134":6128,"6135":6128,"6136":6128,"6137":6128,"6138":6128,"6139":6128,"6140":6128,"6141":6128,"6142":6128,"6143":6128,"6145":6144,"6146":6144,"6147":6144,"6148":6144,"6149":6144,"6150":6144,"6151":6144,"6152":6144,"6153":6144,"6154":6144,"6155":6144,"6156":6144,"6157":6144,"6158":6144,"6159":6144,"6181":6176,"6182":6176,"6183":6176,"6184":6176,"6185":6176,"6186":6176,"6187":6176,"6188":6176,"6189":6176,"6190":6176,"6191":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6305":6304,"6306":6304,"6307":6304,"6308":6304,"6309":6304,"6310":6304,"6311":6304,"6312":6304,"6313":6304,"6314":6304,"6315":6304,"6316":6304,"6317":6304,"6318":6304,"6319":6304,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6482":6480,"6483":6480,"6484":6480,"6485":6480,"6486":6480,"6487":6480,"6488":6480,"6489":6480,"6490":6480,"6491":6480,"6492":6480,"6493":6480,"6494":6480,"6495":6480,"6498":6496,"6499":6496,"6500":6496,"6501":6496,"6502":6496,"6503":6496,"6504":6496,"6505":6496,"6506":6496,"6507":6496,"6508":6496,"6509":6496,"6510":6496,"6511":6496,"6514":6512,"6515":6512,"6516":6512,"6517":6512,"6518":6512,"6519":6512,"6520":6512,"6521":6512,"6522":6512,"6523":6512,"6524":6512,"6525":6512,"6526":6512,"6527":6512,"6530":6528,"6531":6528,"6532":6528,"6533":6528,"6534":6528,"6535":6528,"6536":6528,"6537":6528,"6538":6528,"6539":6528,"6540":6528,"6541":6528,"6542":6528,"6543":6528,"6546":6544,"6547":6544,"6548":6544,"6549":6544,"6550":6544,"6551":6544,"6552":6544,"6553":6544,"6554":6544,"6555":6544,"6556":6544,"6557":6544,"6558":6544,"6559":6544,"6564":6562,"6565":6562,"6566":6562,"6567":6562,"6568":6562,"6569":6562,"6570":6562,"6571":6562,"6572":6562,"6573":6562,"6574":6562,"6575":6562,"6584":6580,"6585":6580,"6586":6580,"6587":6580,"6588":6580,"6589":6580,"6590":6580,"6591":6580,"6657":6656,"6658":6656,"6659":6656,"6660":6656,"6661":6656,"6662":6656,"6663":6656,"6664":6656,"6665":6656,"6666":6656,"6667":6656,"6668":6656,"6669":6656,"6670":6656,"6671":6656,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6705":6704,"6706":6704,"6707":6704,"6708":6704,"6709":6704,"6710":6704,"6711":6704,"6713":6704,"6714":6704,"6715":6704,"6716":6704,"6717":6704,"6718":6704,"6719":6704,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6792":6787,"6793":6787,"6794":6787,"6795":6787,"6796":6787,"6797":6787,"6798":6787,"6799":6787,"6808":6803,"6809":6803,"6810":6803,"6811":6803,"6812":6803,"6813":6803,"6814":6803,"6815":6803,"6824":6819,"6825":6819,"6826":6819,"6827":6819,"6828":6819,"6829":6819,"6830":6819,"6831":6819,"6840":6835,"6841":6835,"6842":6835,"6843":6835,"6844":6835,"6845":6835,"6846":6835,"6847":6835,"6856":6851,"6857":6851,"6858":6851,"6859":6851,"6860":6851,"6861":6851,"6862":6851,"6863":6851,"6872":6867,"6873":6867,"6874":6867,"6875":6867,"6876":6867,"6877":6867,"6878":6867,"6879":6867,"6888":6883,"6889":6883,"6890":6883,"6891":6883,"6892":6883,"6893":6883,"6894":6883,"6895":6883,"6904":6899,"6905":6899,"6906":6899,"6907":6899,"6908":6899,"6909":6899,"6910":6899,"6911":6899,"6920":6915,"6921":6915,"6922":6915,"6923":6915,"6924":6915,"6925":6915,"6926":6915,"6927":6915,"6936":6931,"6937":6931,"6938":6931,"6939":6931,"6940":6931,"6941":6931,"6942":6931,"6943":6931,"6952":6947,"6953":6947,"6954":6947,"6955":6947,"6956":6947,"6957":6947,"6958":6947,"6959":6947,"6968":6963,"6969":6963,"6970":6963,"6971":6963,"6972":6963,"6973":6963,"6974":6963,"6975":6963,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7000":6994,"7001":6994,"7002":6994,"7003":6994,"7004":6994,"7005":6994,"7006":6994,"7007":6994,"7009":7008,"7010":7008,"7011":7008,"7012":7008,"7013":7008,"7014":7008,"7015":7008,"7016":7008,"7017":7008,"7018":7008,"7019":7008,"7020":7008,"7021":7008,"7022":7008,"7023":7008,"7032":7027,"7033":7027,"7034":7027,"7035":7027,"7036":7027,"7037":7027,"7038":7027,"7039":7027,"7048":7043,"7049":7043,"7050":7043,"7051":7043,"7052":7043,"7053":7043,"7054":7043,"7055":7043,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7080":7074,"7081":7074,"7082":7074,"7083":7074,"7084":7074,"7085":7074,"7086":7074,"7087":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7112":7106,"7113":7106,"7114":7106,"7115":7106,"7116":7106,"7117":7106,"7118":7106,"7119":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7144":7138,"7145":7138,"7146":7138,"7147":7138,"7148":7138,"7149":7138,"7150":7138,"7151":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7176":7170,"7177":7170,"7178":7170,"7179":7170,"7180":7170,"7181":7170,"7182":7170,"7183":7170,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7224":7218,"7225":7218,"7226":7218,"7227":7218,"7228":7218,"7229":7218,"7230":7218,"7231":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7256":7250,"7257":7250,"7258":7250,"7259":7250,"7260":7250,"7261":7250,"7262":7250,"7263":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7272":7250,"7273":7250,"7274":7250,"7275":7250,"7276":7250,"7277":7250,"7278":7250,"7279":7250,"7297":7296,"7298":7296,"7299":7296,"7300":7296,"7301":7296,"7302":7296,"7303":7296,"7304":7296,"7305":7296,"7306":7296,"7307":7296,"7308":7296,"7309":7296,"7310":7296,"7311":7296,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7348":7346,"7349":7346,"7350":7346,"7351":7346,"7352":7346,"7353":7346,"7354":7346,"7355":7346,"7356":7346,"7357":7346,"7358":7346,"7359":7346,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7400":7392,"7401":7392,"7402":7392,"7403":7392,"7404":7392,"7405":7392,"7406":7392,"7407":7392,"7410":7408,"7411":7408,"7412":7408,"7413":7408,"7414":7408,"7415":7408,"7416":7408,"7417":7408,"7418":7408,"7419":7408,"7420":7408,"7421":7408,"7422":7408,"7423":7408,"7504":7218,"7505":7218,"7510":7218,"7511":7218,"7512":7218,"7513":7218,"7514":7218,"7515":7218,"7516":7218,"7517":7218,"7518":7218,"7519":7218}} \ No newline at end of file +{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7296":"Fletching Table","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"23":16,"24":16,"25":16,"26":16,"27":16,"28":16,"29":16,"30":16,"31":16,"33":32,"34":32,"35":32,"36":32,"37":32,"38":32,"39":32,"40":32,"41":32,"42":32,"43":32,"44":32,"45":32,"46":32,"47":32,"50":48,"51":48,"52":48,"53":48,"54":48,"55":48,"56":48,"57":48,"58":48,"59":48,"60":48,"61":48,"62":48,"63":48,"65":64,"66":64,"67":64,"68":64,"69":64,"70":64,"71":64,"72":64,"73":64,"74":64,"75":64,"76":64,"77":64,"78":64,"79":64,"86":80,"87":80,"88":80,"89":80,"90":80,"91":80,"92":80,"93":80,"94":80,"95":80,"102":96,"103":96,"110":96,"111":96,"114":112,"115":112,"116":112,"117":112,"118":112,"119":112,"120":112,"121":112,"122":112,"123":112,"124":112,"125":112,"126":112,"127":112,"194":192,"195":192,"196":192,"197":192,"198":192,"199":192,"200":192,"201":192,"202":192,"203":192,"204":192,"205":192,"206":192,"207":192,"209":208,"210":208,"211":208,"212":208,"213":208,"214":208,"215":208,"216":208,"217":208,"218":208,"219":208,"220":208,"221":208,"222":208,"223":208,"225":224,"226":224,"227":224,"228":224,"229":224,"230":224,"231":224,"232":224,"233":224,"234":224,"235":224,"236":224,"237":224,"238":224,"239":224,"241":240,"242":240,"243":240,"244":240,"245":240,"246":240,"247":240,"248":240,"249":240,"250":240,"251":240,"252":240,"253":240,"254":240,"255":240,"257":256,"258":256,"259":256,"260":256,"261":256,"262":256,"263":256,"264":256,"265":256,"266":256,"267":256,"268":256,"269":256,"270":256,"271":256,"284":7472,"285":7473,"286":7474,"287":7475,"306":304,"307":304,"308":304,"309":304,"310":304,"311":304,"312":304,"313":304,"314":304,"315":304,"316":304,"317":304,"318":304,"319":304,"321":320,"322":320,"323":320,"324":320,"325":320,"326":320,"327":320,"328":320,"329":320,"330":320,"331":320,"332":320,"333":320,"334":320,"335":320,"337":336,"338":336,"339":336,"340":336,"341":336,"342":336,"343":336,"344":336,"345":336,"346":336,"347":336,"348":336,"349":336,"350":336,"351":336,"353":352,"354":352,"355":352,"356":352,"357":352,"358":352,"359":352,"360":352,"361":352,"362":352,"363":352,"364":352,"365":352,"366":352,"367":352,"388":384,"389":384,"390":384,"391":384,"392":384,"393":384,"394":384,"395":384,"396":384,"397":384,"398":384,"399":384,"401":400,"402":400,"403":400,"404":400,"405":400,"406":400,"407":400,"408":400,"409":400,"410":400,"411":400,"412":400,"413":400,"414":400,"415":400,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"481":480,"482":480,"483":480,"484":480,"485":480,"486":480,"487":480,"488":480,"489":480,"490":480,"491":480,"492":480,"493":480,"494":480,"495":480,"496":498,"499":498,"500":498,"501":498,"502":498,"503":498,"504":498,"505":498,"506":498,"507":498,"508":498,"509":498,"510":498,"511":498,"513":512,"514":512,"515":512,"516":512,"517":512,"518":512,"519":512,"520":512,"521":512,"522":512,"523":512,"524":512,"525":512,"526":512,"527":512,"577":576,"578":576,"579":576,"580":576,"581":576,"582":576,"583":576,"584":576,"585":576,"586":576,"587":576,"588":576,"589":576,"590":576,"591":576,"593":592,"594":592,"595":592,"596":592,"597":592,"598":592,"599":592,"600":592,"601":592,"602":592,"603":592,"604":592,"605":592,"606":592,"607":592,"619":608,"620":608,"621":608,"622":608,"623":608,"625":624,"626":624,"627":624,"628":624,"629":624,"630":624,"631":624,"632":624,"633":624,"634":624,"635":624,"636":624,"637":624,"638":624,"639":624,"641":640,"642":640,"643":640,"644":640,"645":640,"646":640,"647":640,"648":640,"649":640,"650":640,"651":640,"652":640,"653":640,"654":640,"655":640,"657":656,"658":656,"659":656,"660":656,"661":656,"662":656,"663":656,"664":656,"665":656,"666":656,"667":656,"668":656,"669":656,"670":656,"671":656,"673":672,"674":672,"675":672,"676":672,"677":672,"678":672,"679":672,"680":672,"681":672,"682":672,"683":672,"684":672,"685":672,"686":672,"687":672,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"721":720,"722":720,"723":720,"724":720,"725":720,"726":720,"727":720,"728":720,"729":720,"730":720,"731":720,"732":720,"733":720,"734":720,"735":720,"740":736,"741":736,"742":736,"743":736,"744":736,"745":736,"746":736,"747":736,"748":736,"749":736,"750":736,"751":736,"753":752,"754":752,"755":752,"756":752,"757":752,"758":752,"759":752,"760":752,"761":752,"762":752,"763":752,"764":752,"765":752,"766":752,"767":752,"769":768,"770":768,"771":768,"772":768,"773":768,"774":768,"775":768,"776":768,"777":768,"778":768,"779":768,"780":768,"781":768,"782":768,"783":768,"785":784,"786":784,"787":784,"788":784,"789":784,"790":784,"791":784,"792":784,"793":784,"794":784,"795":784,"796":784,"797":784,"798":784,"799":784,"800":805,"806":805,"807":805,"808":805,"809":805,"810":805,"811":805,"812":805,"813":805,"814":805,"815":805,"833":832,"834":832,"835":832,"836":832,"837":832,"838":832,"839":832,"840":832,"841":832,"842":832,"843":832,"844":832,"845":832,"846":832,"847":832,"856":851,"857":851,"858":851,"859":851,"860":851,"861":851,"862":851,"863":851,"864":866,"865":866,"870":866,"871":866,"872":866,"873":866,"874":866,"875":866,"876":866,"877":866,"878":866,"879":866,"897":896,"898":896,"899":896,"900":896,"901":896,"902":896,"903":896,"904":896,"905":896,"906":896,"907":896,"908":896,"909":896,"910":896,"911":896,"913":912,"914":912,"915":912,"916":912,"917":912,"918":912,"919":912,"920":912,"921":912,"922":912,"923":912,"924":912,"925":912,"926":912,"927":912,"929":928,"930":928,"931":928,"932":928,"933":928,"934":928,"935":928,"936":928,"937":928,"938":928,"939":928,"940":928,"941":928,"942":928,"943":928,"952":944,"953":944,"954":944,"955":944,"956":944,"957":944,"958":944,"959":944,"968":960,"969":960,"970":960,"971":960,"972":960,"973":960,"974":960,"975":960,"976":978,"977":978,"982":978,"983":978,"984":978,"985":978,"986":978,"987":978,"988":978,"989":978,"990":978,"991":978,"992":978,"993":978,"998":978,"999":978,"1000":978,"1001":978,"1002":978,"1003":978,"1004":978,"1005":978,"1006":978,"1007":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1048":1042,"1049":1042,"1050":1042,"1051":1042,"1052":1042,"1053":1042,"1054":1042,"1055":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1080":1075,"1081":1075,"1082":1075,"1083":1075,"1084":1075,"1085":1075,"1086":1075,"1087":1075,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1096":1090,"1097":1090,"1098":1090,"1099":1090,"1100":1090,"1101":1090,"1102":1090,"1103":1090,"1122":1120,"1123":1120,"1124":1120,"1125":1120,"1126":1120,"1127":1120,"1128":1120,"1129":1120,"1130":1120,"1131":1120,"1132":1120,"1133":1120,"1134":1120,"1135":1120,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1154":1152,"1155":1152,"1156":1152,"1157":1152,"1158":1152,"1159":1152,"1160":1152,"1161":1152,"1162":1152,"1163":1152,"1164":1152,"1165":1152,"1166":1152,"1167":1152,"1169":1168,"1170":1168,"1171":1168,"1172":1168,"1173":1168,"1174":1168,"1175":1168,"1176":1168,"1177":1168,"1178":1168,"1179":1168,"1180":1168,"1181":1168,"1182":1168,"1183":1168,"1185":1168,"1186":1168,"1187":1168,"1188":1168,"1189":1168,"1190":1168,"1191":1168,"1192":1168,"1193":1168,"1194":1168,"1195":1168,"1196":1168,"1197":1168,"1198":1168,"1199":1168,"1200":1221,"1206":1221,"1207":1221,"1208":1221,"1209":1221,"1210":1221,"1211":1221,"1212":1221,"1213":1221,"1214":1221,"1215":1221,"1216":1221,"1222":1221,"1223":1221,"1224":1221,"1225":1221,"1226":1221,"1227":1221,"1228":1221,"1229":1221,"1230":1221,"1231":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1256":1248,"1257":1248,"1258":1248,"1259":1248,"1260":1248,"1261":1248,"1262":1248,"1263":1248,"1265":1264,"1266":1264,"1267":1264,"1268":1264,"1269":1264,"1270":1264,"1271":1264,"1272":1264,"1273":1264,"1274":1264,"1275":1264,"1276":1264,"1277":1264,"1278":1264,"1279":1264,"1281":1280,"1282":1280,"1283":1280,"1284":1280,"1285":1280,"1286":1280,"1287":1280,"1288":1280,"1289":1280,"1290":1280,"1291":1280,"1292":1280,"1293":1280,"1294":1280,"1295":1280,"1313":1312,"1314":1312,"1315":1312,"1316":1312,"1317":1312,"1318":1312,"1319":1312,"1320":1312,"1321":1312,"1322":1312,"1323":1312,"1324":1312,"1325":1312,"1326":1312,"1327":1312,"1345":1344,"1346":1344,"1347":1344,"1348":1344,"1349":1344,"1350":1344,"1351":1344,"1352":1344,"1353":1344,"1354":1344,"1355":1344,"1356":1344,"1357":1344,"1358":1344,"1359":1344,"1366":1360,"1367":1360,"1368":1360,"1369":1360,"1370":1360,"1371":1360,"1372":1360,"1373":1360,"1374":1360,"1375":1360,"1377":1376,"1378":1376,"1379":1376,"1380":1376,"1381":1376,"1382":1376,"1383":1376,"1384":1376,"1385":1376,"1386":1376,"1387":1376,"1388":1376,"1389":1376,"1390":1376,"1391":1376,"1393":1392,"1394":1392,"1395":1392,"1396":1392,"1397":1392,"1398":1392,"1399":1392,"1400":1392,"1401":1392,"1402":1392,"1403":1392,"1404":1392,"1405":1392,"1406":1392,"1407":1392,"1409":1408,"1410":1408,"1411":1408,"1412":1408,"1413":1408,"1414":1408,"1415":1408,"1416":1408,"1417":1408,"1418":1408,"1419":1408,"1420":1408,"1421":1408,"1422":1408,"1423":1408,"1425":1424,"1426":1424,"1427":1424,"1428":1424,"1429":1424,"1430":1424,"1431":1424,"1432":1424,"1433":1424,"1434":1424,"1435":1424,"1436":1424,"1437":1424,"1438":1424,"1439":1424,"1440":1441,"1443":1441,"1444":1441,"1445":1441,"1446":1441,"1447":1441,"1448":1441,"1449":1441,"1450":1441,"1451":1441,"1452":1441,"1453":1441,"1454":1441,"1455":1441,"1460":1458,"1461":1458,"1462":1458,"1463":1458,"1464":1458,"1465":1458,"1466":1458,"1467":1458,"1468":1458,"1469":1458,"1470":1458,"1471":1458,"1479":1472,"1480":1472,"1481":1472,"1482":1472,"1483":1472,"1484":1472,"1485":1472,"1486":1472,"1487":1472,"1521":1520,"1522":1520,"1523":1520,"1524":1520,"1525":1520,"1526":1520,"1527":1520,"1528":1520,"1529":1520,"1530":1520,"1531":1520,"1532":1520,"1533":1520,"1534":1520,"1535":1520,"1558":1552,"1559":1552,"1560":1552,"1561":1552,"1562":1552,"1563":1552,"1564":1552,"1565":1552,"1566":1552,"1567":1552,"1572":1568,"1573":1568,"1574":1568,"1575":1568,"1576":1568,"1577":1568,"1578":1568,"1579":1568,"1580":1568,"1581":1568,"1582":1568,"1583":1568,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"1617":1616,"1618":1616,"1619":1616,"1620":1616,"1621":1616,"1622":1616,"1623":1616,"1624":1616,"1625":1616,"1626":1616,"1627":1616,"1628":1616,"1629":1616,"1630":1616,"1631":1616,"1633":1632,"1634":1632,"1635":1632,"1636":1632,"1637":1632,"1638":1632,"1639":1632,"1640":1632,"1641":1632,"1642":1632,"1643":1632,"1644":1632,"1645":1632,"1646":1632,"1647":1632,"1649":1648,"1650":1648,"1651":1648,"1652":1648,"1653":1648,"1654":1648,"1655":1648,"1656":1648,"1657":1648,"1658":1648,"1659":1648,"1660":1648,"1661":1648,"1662":1648,"1663":1648,"1672":1664,"1673":1664,"1674":1664,"1675":1664,"1676":1664,"1677":1664,"1678":1664,"1679":1664,"1688":1680,"1689":1680,"1690":1680,"1691":1680,"1692":1680,"1693":1680,"1694":1680,"1695":1680,"1736":1731,"1737":1731,"1738":1731,"1739":1731,"1740":1731,"1741":1731,"1742":1731,"1743":1731,"1752":1747,"1753":1747,"1754":1747,"1755":1747,"1756":1747,"1757":1747,"1758":1747,"1759":1747,"1761":1760,"1762":1760,"1763":1760,"1764":1760,"1765":1760,"1766":1760,"1767":1760,"1768":1760,"1769":1760,"1770":1760,"1771":1760,"1772":1760,"1773":1760,"1774":1760,"1775":1760,"1777":1776,"1778":1776,"1779":1776,"1780":1776,"1781":1776,"1782":1776,"1783":1776,"1784":1776,"1785":1776,"1786":1776,"1787":1776,"1788":1776,"1789":1776,"1790":1776,"1791":1776,"1793":1792,"1794":1792,"1795":1792,"1796":1792,"1797":1792,"1798":1792,"1799":1792,"1800":1792,"1801":1792,"1802":1792,"1803":1792,"1804":1792,"1805":1792,"1806":1792,"1807":1792,"1809":1808,"1810":1808,"1811":1808,"1812":1808,"1813":1808,"1814":1808,"1815":1808,"1816":1808,"1817":1808,"1818":1808,"1819":1808,"1820":1808,"1821":1808,"1822":1808,"1823":1808,"1832":1827,"1833":1827,"1834":1827,"1835":1827,"1836":1827,"1837":1827,"1838":1827,"1839":1827,"1844":1840,"1845":1840,"1846":1840,"1847":1840,"1848":1840,"1849":1840,"1850":1840,"1851":1840,"1852":1840,"1853":1840,"1854":1840,"1855":1840,"1857":1856,"1858":1856,"1859":1856,"1860":1856,"1861":1856,"1862":1856,"1863":1856,"1864":1856,"1865":1856,"1866":1856,"1867":1856,"1868":1856,"1869":1856,"1870":1856,"1871":1856,"1880":1872,"1881":1872,"1882":1872,"1883":1872,"1884":1872,"1885":1872,"1886":1872,"1887":1872,"1928":1922,"1929":1922,"1930":1922,"1931":1922,"1932":1922,"1933":1922,"1934":1922,"1935":1922,"1937":1936,"1938":1936,"1939":1936,"1940":1936,"1941":1936,"1942":1936,"1943":1936,"1944":1936,"1945":1936,"1946":1936,"1947":1936,"1948":1936,"1949":1936,"1950":1936,"1951":1936,"1953":1952,"1954":1952,"1955":1952,"1956":1952,"1957":1952,"1958":1952,"1959":1952,"1960":1952,"1961":1952,"1962":1952,"1963":1952,"1964":1952,"1965":1952,"1966":1952,"1967":1952,"1969":1968,"1970":1968,"1971":1968,"1972":1968,"1973":1968,"1974":1968,"1975":1968,"1976":1968,"1977":1968,"1978":1968,"1979":1968,"1980":1968,"1981":1968,"1982":1968,"1983":1968,"1985":1968,"1986":1968,"1987":1968,"1988":1968,"1989":1968,"1990":1968,"1991":1968,"1992":1968,"1993":1968,"1994":1968,"1995":1968,"1996":1968,"1997":1968,"1998":1968,"1999":1968,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2056":2051,"2057":2051,"2058":2051,"2059":2051,"2060":2051,"2061":2051,"2062":2051,"2063":2051,"2065":2064,"2066":2064,"2067":2064,"2068":2064,"2069":2064,"2070":2064,"2071":2064,"2072":2064,"2073":2064,"2074":2064,"2075":2064,"2076":2064,"2077":2064,"2078":2064,"2079":2064,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2088":2082,"2089":2082,"2090":2082,"2091":2082,"2092":2082,"2093":2082,"2094":2082,"2095":2082,"2129":2128,"2130":2128,"2131":2128,"2132":2128,"2133":2128,"2134":2128,"2135":2128,"2136":2128,"2137":2128,"2138":2128,"2139":2128,"2140":2128,"2141":2128,"2142":2128,"2143":2128,"2152":2147,"2153":2147,"2154":2147,"2155":2147,"2156":2147,"2157":2147,"2158":2147,"2159":2147,"2168":2163,"2169":2163,"2170":2163,"2171":2163,"2172":2163,"2173":2163,"2174":2163,"2175":2163,"2184":2179,"2185":2179,"2186":2179,"2187":2179,"2188":2179,"2189":2179,"2190":2179,"2191":2179,"2209":2208,"2210":2208,"2211":2208,"2212":2208,"2213":2208,"2214":2208,"2215":2208,"2216":2208,"2217":2208,"2218":2208,"2219":2208,"2220":2208,"2221":2208,"2222":2208,"2223":2208,"2238":2224,"2239":2224,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2264":2256,"2265":2256,"2266":2256,"2267":2256,"2268":2256,"2269":2256,"2270":2256,"2271":2256,"2280":2272,"2281":2272,"2282":2272,"2283":2272,"2284":2272,"2285":2272,"2286":2272,"2287":2272,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2344":2338,"2345":2338,"2346":2338,"2347":2338,"2348":2338,"2349":2338,"2350":2338,"2351":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2433":2432,"2434":2432,"2435":2432,"2436":2432,"2437":2432,"2438":2432,"2439":2432,"2440":2432,"2441":2432,"2442":2432,"2443":2432,"2444":2432,"2445":2432,"2446":2432,"2447":2432,"2449":2448,"2450":2448,"2451":2448,"2452":2448,"2453":2448,"2454":2448,"2455":2448,"2456":2448,"2457":2448,"2458":2448,"2459":2448,"2460":2448,"2461":2448,"2462":2448,"2463":2448,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2484":2480,"2487":2480,"2488":2480,"2491":2480,"2492":2480,"2493":2481,"2494":2482,"2495":2480,"2504":2499,"2505":2499,"2506":2499,"2507":2499,"2508":2499,"2509":2499,"2510":2499,"2511":2499,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2578":288,"2579":288,"2582":288,"2583":288,"2586":288,"2587":288,"2590":288,"2591":288,"2604":7476,"2605":7477,"2616":2611,"2617":2611,"2618":2611,"2619":2611,"2620":2611,"2621":2611,"2622":2611,"2623":2611,"2632":2627,"2633":2627,"2634":2627,"2635":2627,"2636":2627,"2637":2627,"2638":2627,"2639":2627,"2641":2640,"2642":2640,"2643":2640,"2644":2640,"2645":2640,"2646":2640,"2647":2640,"2648":2640,"2649":2640,"2650":2640,"2651":2640,"2652":2640,"2653":2640,"2654":2640,"2655":2640,"2691":2688,"2692":2688,"2693":2688,"2694":2688,"2695":2688,"2696":2688,"2697":2688,"2698":2688,"2699":2688,"2700":2688,"2701":2688,"2702":2688,"2703":2688,"2705":2704,"2706":2704,"2707":2704,"2708":2704,"2709":2704,"2710":2704,"2711":2704,"2712":2704,"2713":2704,"2714":2704,"2715":2704,"2716":2704,"2717":2704,"2718":2704,"2719":2704,"2721":2720,"2722":2720,"2723":2720,"2725":2720,"2726":2720,"2727":2720,"2729":2720,"2730":2720,"2731":2720,"2732":2720,"2733":2720,"2734":2720,"2735":2720,"2753":2752,"2754":2752,"2755":2752,"2756":2752,"2757":2752,"2758":2752,"2759":2752,"2760":2752,"2761":2752,"2762":2752,"2763":2752,"2764":2752,"2765":2752,"2766":2752,"2767":2752,"2769":2768,"2770":2768,"2771":2768,"2772":2768,"2773":2768,"2774":2768,"2775":2768,"2776":2768,"2777":2768,"2778":2768,"2779":2768,"2780":2768,"2781":2768,"2782":2768,"2783":2768,"2785":2784,"2786":2784,"2787":2784,"2788":2784,"2789":2784,"2790":2784,"2791":2784,"2792":2784,"2793":2784,"2794":2784,"2795":2784,"2796":2784,"2797":2784,"2798":2784,"2799":2784,"2806":2800,"2807":2800,"2814":2800,"2815":2800,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2840":2834,"2841":2834,"2842":2834,"2843":2834,"2844":2834,"2845":2834,"2846":2834,"2847":2834,"2868":2864,"2869":2864,"2870":2864,"2871":2864,"2872":2864,"2873":2864,"2874":2864,"2875":2864,"2876":2864,"2877":2864,"2878":2864,"2879":2864,"2888":2883,"2889":2883,"2890":2883,"2891":2883,"2892":2883,"2893":2883,"2894":2883,"2895":2883,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3041":3040,"3042":3040,"3043":3040,"3044":3040,"3045":3040,"3046":3040,"3047":3040,"3048":3040,"3049":3040,"3050":3040,"3051":3040,"3052":3040,"3053":3040,"3054":3040,"3055":3040,"3073":3072,"3074":3072,"3075":3072,"3076":3072,"3077":3072,"3078":3072,"3079":3072,"3080":3072,"3081":3072,"3082":3072,"3083":3072,"3084":3072,"3085":3072,"3086":3072,"3087":3072,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3169":3168,"3170":3168,"3171":3168,"3172":3168,"3173":3168,"3174":3168,"3175":3168,"3176":3168,"3177":3168,"3178":3168,"3179":3168,"3180":3168,"3181":3168,"3182":3168,"3183":3168,"3192":3187,"3193":3187,"3194":3187,"3195":3187,"3196":3187,"3197":3187,"3198":3187,"3199":3187,"3217":3216,"3219":3216,"3220":3216,"3221":3216,"3223":3216,"3224":3216,"3225":3216,"3227":3216,"3228":3216,"3229":3216,"3230":3218,"3231":3216,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3256":3251,"3257":3251,"3258":3251,"3259":3251,"3260":3251,"3261":3251,"3262":3251,"3263":3251,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3281":3280,"3282":3280,"3283":3280,"3284":3280,"3285":3280,"3286":3280,"3287":3280,"3288":3280,"3289":3280,"3290":3280,"3291":3280,"3292":3280,"3293":3280,"3294":3280,"3295":3280,"3297":3296,"3298":3296,"3299":3296,"3300":3296,"3301":3296,"3302":3296,"3303":3296,"3304":3296,"3305":3296,"3306":3296,"3307":3296,"3308":3296,"3309":3296,"3310":3296,"3311":3296,"3316":3312,"3317":3312,"3318":3312,"3319":3312,"3320":3312,"3321":3312,"3322":3312,"3323":3312,"3324":3312,"3325":3312,"3326":3312,"3327":3312,"3334":3328,"3335":3328,"3336":3328,"3337":3328,"3338":3328,"3339":3328,"3340":3328,"3341":3328,"3342":3328,"3343":3328,"3409":3408,"3410":3408,"3411":3408,"3412":3408,"3413":3408,"3414":3408,"3415":3408,"3416":3408,"3417":3408,"3418":3408,"3419":3408,"3420":3408,"3421":3408,"3422":3408,"3423":3408,"3425":3424,"3426":3424,"3427":3424,"3428":3424,"3429":3424,"3430":3424,"3431":3424,"3432":3424,"3433":3424,"3434":3424,"3435":3424,"3436":3424,"3437":3424,"3438":3424,"3439":3424,"3441":3440,"3442":3440,"3443":3440,"3444":3440,"3445":3440,"3446":3440,"3447":3440,"3448":3440,"3449":3440,"3450":3440,"3451":3440,"3452":3440,"3453":3440,"3454":3440,"3455":3440,"3457":3456,"3458":3456,"3459":3456,"3461":3456,"3462":3456,"3463":3456,"3465":3456,"3466":3456,"3467":3456,"3468":3456,"3469":3456,"3470":3456,"3471":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3512":3506,"3513":3506,"3514":3506,"3515":3506,"3516":3506,"3517":3506,"3518":3506,"3519":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3528":3522,"3529":3522,"3530":3522,"3531":3522,"3532":3522,"3533":3522,"3534":3522,"3535":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3544":3538,"3545":3538,"3546":3538,"3547":3538,"3548":3538,"3549":3538,"3550":3538,"3551":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3560":3554,"3561":3554,"3562":3554,"3563":3554,"3564":3554,"3565":3554,"3566":3554,"3567":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3576":3570,"3577":3570,"3578":3570,"3579":3570,"3580":3570,"3581":3570,"3582":3570,"3583":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3592":3586,"3593":3586,"3594":3586,"3595":3586,"3596":3586,"3597":3586,"3598":3586,"3599":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3608":3602,"3609":3602,"3610":3602,"3611":3602,"3612":3602,"3613":3602,"3614":3602,"3615":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3624":3618,"3625":3618,"3626":3618,"3627":3618,"3628":3618,"3629":3618,"3630":3618,"3631":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3640":3634,"3641":3634,"3642":3634,"3643":3634,"3644":3634,"3645":3634,"3646":3634,"3647":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3656":3650,"3657":3650,"3658":3650,"3659":3650,"3660":3650,"3661":3650,"3662":3650,"3663":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3672":3666,"3673":3666,"3674":3666,"3675":3666,"3676":3666,"3677":3666,"3678":3666,"3679":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3704":3698,"3705":3698,"3706":3698,"3707":3698,"3708":3698,"3709":3698,"3710":3698,"3711":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3720":3714,"3721":3714,"3722":3714,"3723":3714,"3724":3714,"3725":3714,"3726":3714,"3727":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3736":3730,"3737":3730,"3738":3730,"3739":3730,"3740":3730,"3741":3730,"3742":3730,"3743":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3752":3746,"3753":3746,"3754":3746,"3755":3746,"3756":3746,"3757":3746,"3758":3746,"3759":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3768":3762,"3769":3762,"3770":3762,"3771":3762,"3772":3762,"3773":3762,"3774":3762,"3775":3762,"3824":3829,"3830":3829,"3831":3829,"3832":3829,"3833":3829,"3834":3829,"3835":3829,"3836":3829,"3837":3829,"3838":3829,"3839":3829,"3889":3888,"3890":3888,"3891":3888,"3892":3888,"3893":3888,"3894":3888,"3895":3888,"3896":3888,"3897":3888,"3898":3888,"3899":3888,"3900":3888,"3901":3888,"3902":3888,"3903":3888,"3912":3904,"3913":3904,"3914":3904,"3915":3904,"3916":3904,"3917":3904,"3918":3904,"3919":3904,"3921":3920,"3922":3920,"3923":3920,"3924":3920,"3925":3920,"3926":3920,"3927":3920,"3928":3920,"3929":3920,"3930":3920,"3931":3920,"3932":3920,"3933":3920,"3934":3920,"3935":3920,"3937":3936,"3938":3936,"3939":3936,"3940":3936,"3941":3936,"3942":3936,"3943":3936,"3944":3936,"3945":3936,"3946":3936,"3947":3936,"3948":3936,"3949":3936,"3950":3936,"3951":3936,"3955":3952,"3956":3952,"3957":3952,"3958":3952,"3959":3952,"3960":3952,"3961":3952,"3962":3952,"3963":3952,"3964":3952,"3965":3952,"3966":3952,"3967":3952,"3969":3968,"3970":3968,"3971":3968,"3972":3968,"3973":3968,"3974":3968,"3975":3968,"3976":3968,"3977":3968,"3978":3968,"3979":3968,"3980":3968,"3981":3968,"3982":3968,"3983":3968,"3985":3984,"3986":3984,"3987":3984,"3988":3984,"3989":3984,"3990":3984,"3991":3984,"3992":3984,"3993":3984,"3994":3984,"3995":3984,"3996":3984,"3997":3984,"3998":3984,"3999":3984,"4049":4048,"4050":4048,"4051":4048,"4052":4048,"4053":4048,"4054":4048,"4055":4048,"4056":4048,"4057":4048,"4058":4048,"4059":4048,"4060":4048,"4061":4048,"4062":4048,"4063":4048,"4081":4080,"4082":4080,"4083":4080,"4084":4080,"4085":4080,"4086":4080,"4087":4080,"4088":4080,"4089":4080,"4090":4080,"4091":4080,"4092":4080,"4093":4080,"4094":4080,"4095":4080,"4120":4115,"4121":4115,"4122":4115,"4123":4115,"4124":4115,"4125":4115,"4126":4115,"4127":4115,"4136":4131,"4137":4131,"4138":4131,"4139":4131,"4140":4131,"4141":4131,"4142":4131,"4143":4131,"4152":4147,"4153":4147,"4154":4147,"4155":4147,"4156":4147,"4157":4147,"4158":4147,"4159":4147,"4163":4160,"4164":4160,"4165":4160,"4166":4160,"4167":4160,"4168":4160,"4169":4160,"4170":4160,"4171":4160,"4172":4160,"4173":4160,"4174":4160,"4175":4160,"4179":4176,"4180":4176,"4181":4176,"4182":4176,"4183":4176,"4184":4176,"4185":4176,"4186":4176,"4187":4176,"4188":4176,"4189":4176,"4190":4176,"4191":4176,"4195":4192,"4196":4192,"4197":4192,"4198":4192,"4199":4192,"4200":4192,"4201":4192,"4202":4192,"4203":4192,"4204":4192,"4205":4192,"4206":4192,"4207":4192,"4211":4208,"4212":4208,"4213":4208,"4214":4208,"4215":4208,"4216":4208,"4217":4208,"4218":4208,"4219":4208,"4220":4208,"4221":4208,"4222":4208,"4223":4208,"4227":4224,"4228":4224,"4229":4224,"4230":4224,"4231":4224,"4232":4224,"4233":4224,"4234":4224,"4235":4224,"4236":4224,"4237":4224,"4238":4224,"4239":4224,"4243":4240,"4244":4240,"4245":4240,"4246":4240,"4247":4240,"4248":4240,"4249":4240,"4250":4240,"4251":4240,"4252":4240,"4253":4240,"4254":4240,"4255":4240,"4257":4256,"4258":4256,"4259":4256,"4260":4256,"4261":4256,"4262":4256,"4263":4256,"4264":4256,"4265":4256,"4266":4256,"4267":4256,"4268":4256,"4269":4256,"4270":4256,"4271":4256,"4273":4272,"4274":4272,"4275":4272,"4276":4272,"4277":4272,"4278":4272,"4279":4272,"4280":4272,"4281":4272,"4282":4272,"4283":4272,"4284":4272,"4285":4272,"4286":4272,"4287":4272,"4289":4288,"4290":4288,"4291":4288,"4292":4288,"4293":4288,"4294":4288,"4295":4288,"4296":4288,"4297":4288,"4298":4288,"4299":4288,"4300":4288,"4301":4288,"4302":4288,"4303":4288,"4305":4304,"4306":4304,"4307":4304,"4308":4304,"4309":4304,"4310":4304,"4311":4304,"4312":4304,"4313":4304,"4314":4304,"4315":4304,"4316":4304,"4317":4304,"4318":4304,"4319":4304,"4321":4320,"4322":4320,"4323":4320,"4324":4320,"4325":4320,"4326":4320,"4327":4320,"4328":4320,"4329":4320,"4330":4320,"4331":4320,"4332":4320,"4333":4320,"4334":4320,"4335":4320,"4337":4336,"4338":4336,"4339":4336,"4340":4336,"4341":4336,"4342":4336,"4343":4336,"4344":4336,"4345":4336,"4346":4336,"4347":4336,"4348":4336,"4349":4336,"4350":4336,"4351":4336,"4353":4352,"4354":4352,"4355":4352,"4356":4352,"4357":4352,"4358":4352,"4359":4352,"4360":4352,"4361":4352,"4362":4352,"4363":4352,"4364":4352,"4365":4352,"4366":4352,"4367":4352,"4369":4368,"4370":4368,"4371":4368,"4372":4368,"4373":4368,"4374":4368,"4375":4368,"4376":4368,"4377":4368,"4378":4368,"4379":4368,"4380":4368,"4381":4368,"4382":4368,"4383":4368,"4385":4384,"4386":4384,"4387":4384,"4388":4384,"4389":4384,"4390":4384,"4391":4384,"4392":4384,"4393":4384,"4394":4384,"4395":4384,"4396":4384,"4397":4384,"4398":4384,"4399":4384,"4401":4400,"4402":4400,"4403":4400,"4404":4400,"4405":4400,"4406":4400,"4407":4400,"4408":4400,"4409":4400,"4410":4400,"4411":4400,"4412":4400,"4413":4400,"4414":4400,"4415":4400,"4417":4416,"4418":4416,"4419":4416,"4420":4416,"4421":4416,"4422":4416,"4423":4416,"4424":4416,"4425":4416,"4426":4416,"4427":4416,"4428":4416,"4429":4416,"4430":4416,"4431":4416,"4433":4432,"4434":4432,"4435":4432,"4436":4432,"4437":4432,"4438":4432,"4439":4432,"4440":4432,"4441":4432,"4442":4432,"4443":4432,"4444":4432,"4445":4432,"4446":4432,"4447":4432,"4449":4448,"4450":4448,"4451":4448,"4452":4448,"4453":4448,"4454":4448,"4455":4448,"4456":4448,"4457":4448,"4458":4448,"4459":4448,"4460":4448,"4461":4448,"4462":4448,"4463":4448,"4465":4464,"4466":4464,"4467":4464,"4468":4464,"4469":4464,"4470":4464,"4471":4464,"4472":4464,"4473":4464,"4474":4464,"4475":4464,"4476":4464,"4477":4464,"4478":4464,"4479":4464,"4481":4480,"4482":4480,"4483":4480,"4484":4480,"4485":4480,"4486":4480,"4487":4480,"4488":4480,"4489":4480,"4490":4480,"4491":4480,"4492":4480,"4493":4480,"4494":4480,"4495":4480,"4497":4496,"4498":4496,"4499":4496,"4500":4496,"4501":4496,"4502":4496,"4503":4496,"4504":4496,"4505":4496,"4506":4496,"4507":4496,"4508":4496,"4509":4496,"4510":4496,"4511":4496,"4513":4512,"4514":4512,"4515":4512,"4516":4512,"4517":4512,"4518":4512,"4519":4512,"4520":4512,"4521":4512,"4522":4512,"4523":4512,"4524":4512,"4525":4512,"4526":4512,"4527":4512,"4529":4528,"4530":4528,"4531":4528,"4532":4528,"4533":4528,"4534":4528,"4535":4528,"4536":4528,"4537":4528,"4538":4528,"4539":4528,"4540":4528,"4541":4528,"4542":4528,"4543":4528,"4545":4544,"4546":4544,"4547":4544,"4548":4544,"4549":4544,"4550":4544,"4551":4544,"4552":4544,"4553":4544,"4554":4544,"4555":4544,"4556":4544,"4557":4544,"4558":4544,"4559":4544,"4561":4560,"4562":4560,"4563":4560,"4564":4560,"4565":4560,"4566":4560,"4567":4560,"4568":4560,"4569":4560,"4570":4560,"4571":4560,"4572":4560,"4573":4560,"4574":4560,"4575":4560,"4577":4576,"4578":4576,"4579":4576,"4580":4576,"4581":4576,"4582":4576,"4583":4576,"4584":4576,"4585":4576,"4586":4576,"4587":4576,"4588":4576,"4589":4576,"4590":4576,"4591":4576,"4593":4592,"4594":4592,"4595":4592,"4596":4592,"4597":4592,"4598":4592,"4599":4592,"4600":4592,"4601":4592,"4602":4592,"4603":4592,"4604":4592,"4605":4592,"4606":4592,"4607":4592,"4609":4608,"4610":4608,"4611":4608,"4612":4608,"4613":4608,"4614":4608,"4615":4608,"4616":4608,"4617":4608,"4618":4608,"4619":4608,"4620":4608,"4621":4608,"4622":4608,"4623":4608,"4625":4624,"4626":4624,"4627":4624,"4628":4624,"4629":4624,"4630":4624,"4631":4624,"4632":4624,"4633":4624,"4634":4624,"4635":4624,"4636":4624,"4637":4624,"4638":4624,"4639":4624,"4641":4640,"4642":4640,"4643":4640,"4644":4640,"4645":4640,"4646":4640,"4647":4640,"4648":4640,"4649":4640,"4650":4640,"4651":4640,"4652":4640,"4653":4640,"4654":4640,"4655":4640,"4657":4656,"4658":4656,"4659":4656,"4660":4656,"4661":4656,"4662":4656,"4663":4656,"4664":4656,"4665":4656,"4666":4656,"4667":4656,"4668":4656,"4669":4656,"4670":4656,"4671":4656,"4673":4672,"4674":4672,"4675":4672,"4676":4672,"4677":4672,"4678":4672,"4679":4672,"4680":4672,"4681":4672,"4682":4672,"4683":4672,"4684":4672,"4685":4672,"4686":4672,"4687":4672,"4689":4688,"4690":4688,"4691":4688,"4692":4688,"4693":4688,"4694":4688,"4695":4688,"4696":4688,"4697":4688,"4698":4688,"4699":4688,"4700":4688,"4701":4688,"4702":4688,"4703":4688,"4705":4704,"4706":4704,"4707":4704,"4708":4704,"4709":4704,"4710":4704,"4711":4704,"4712":4704,"4713":4704,"4714":4704,"4715":4704,"4716":4704,"4717":4704,"4718":4704,"4719":4704,"4721":4720,"4722":4720,"4723":4720,"4724":4720,"4725":4720,"4726":4720,"4727":4720,"4728":4720,"4729":4720,"4730":4720,"4731":4720,"4732":4720,"4733":4720,"4734":4720,"4735":4720,"4737":4736,"4738":4736,"4739":4736,"4740":4736,"4741":4736,"4742":4736,"4743":4736,"4744":4736,"4745":4736,"4746":4736,"4747":4736,"4748":4736,"4749":4736,"4750":4736,"4751":4736,"4753":4752,"4754":4752,"4755":4752,"4756":4752,"4757":4752,"4758":4752,"4759":4752,"4760":4752,"4761":4752,"4762":4752,"4763":4752,"4764":4752,"4765":4752,"4766":4752,"4767":4752,"4769":4768,"4770":4768,"4771":4768,"4772":4768,"4773":4768,"4774":4768,"4775":4768,"4776":4768,"4777":4768,"4778":4768,"4779":4768,"4780":4768,"4781":4768,"4782":4768,"4783":4768,"4785":4784,"4786":4784,"4787":4784,"4788":4784,"4789":4784,"4790":4784,"4791":4784,"4792":4784,"4793":4784,"4794":4784,"4795":4784,"4796":4784,"4797":4784,"4798":4784,"4799":4784,"4801":4800,"4802":4800,"4803":4800,"4804":4800,"4805":4800,"4806":4800,"4807":4800,"4808":4800,"4809":4800,"4810":4800,"4811":4800,"4812":4800,"4813":4800,"4814":4800,"4815":4800,"4817":4816,"4818":4816,"4819":4816,"4820":4816,"4821":4816,"4822":4816,"4823":4816,"4824":4816,"4825":4816,"4826":4816,"4827":4816,"4828":4816,"4829":4816,"4830":4816,"4831":4816,"4833":4832,"4834":4832,"4835":4832,"4836":4832,"4837":4832,"4838":4832,"4839":4832,"4840":4832,"4841":4832,"4842":4832,"4843":4832,"4844":4832,"4845":4832,"4846":4832,"4847":4832,"4849":4848,"4850":4848,"4851":4848,"4852":4848,"4853":4848,"4854":4848,"4855":4848,"4856":4848,"4857":4848,"4858":4848,"4859":4848,"4860":4848,"4861":4848,"4862":4848,"4863":4848,"4865":4864,"4866":4864,"4867":4864,"4868":4864,"4869":4864,"4870":4864,"4871":4864,"4872":4864,"4873":4864,"4874":4864,"4875":4864,"4876":4864,"4877":4864,"4878":4864,"4879":4864,"4881":4880,"4882":4880,"4883":4880,"4884":4880,"4885":4880,"4886":4880,"4887":4880,"4888":4880,"4889":4880,"4890":4880,"4891":4880,"4892":4880,"4893":4880,"4894":4880,"4895":4880,"4897":4896,"4898":4896,"4899":4896,"4900":4896,"4901":4896,"4902":4896,"4903":4896,"4904":4896,"4905":4896,"4906":4896,"4907":4896,"4908":4896,"4909":4896,"4910":4896,"4911":4896,"4913":4912,"4914":4912,"4915":4912,"4916":4912,"4917":4912,"4918":4912,"4919":4912,"4920":4912,"4921":4912,"4922":4912,"4923":4912,"4924":4912,"4925":4912,"4926":4912,"4927":4912,"4929":4928,"4930":4928,"4931":4928,"4932":4928,"4933":4928,"4934":4928,"4935":4928,"4936":4928,"4937":4928,"4938":4928,"4939":4928,"4940":4928,"4941":4928,"4942":4928,"4943":4928,"4945":4944,"4946":4944,"4947":4944,"4948":4944,"4949":4944,"4950":4944,"4951":4944,"4952":4944,"4953":4944,"4954":4944,"4955":4944,"4956":4944,"4957":4944,"4958":4944,"4959":4944,"4961":4960,"4962":4960,"4963":4960,"4964":4960,"4965":4960,"4966":4960,"4967":4960,"4968":4960,"4969":4960,"4970":4960,"4971":4960,"4972":4960,"4973":4960,"4974":4960,"4975":4960,"4977":4976,"4978":4976,"4979":4976,"4980":4976,"4981":4976,"4982":4976,"4983":4976,"4984":4976,"4985":4976,"4986":4976,"4987":4976,"4988":4976,"4989":4976,"4990":4976,"4991":4976,"4993":4992,"4994":4992,"4995":4992,"4996":4992,"4997":4992,"4998":4992,"4999":4992,"5000":4992,"5001":4992,"5002":4992,"5003":4992,"5004":4992,"5005":4992,"5006":4992,"5007":4992,"5009":5008,"5010":5008,"5011":5008,"5012":5008,"5013":5008,"5014":5008,"5015":5008,"5016":5008,"5017":5008,"5018":5008,"5019":5008,"5020":5008,"5021":5008,"5022":5008,"5023":5008,"5025":5024,"5026":5024,"5027":5024,"5028":5024,"5029":5024,"5030":5024,"5031":5024,"5032":5024,"5033":5024,"5034":5024,"5035":5024,"5036":5024,"5037":5024,"5038":5024,"5039":5024,"5041":5040,"5042":5040,"5043":5040,"5044":5040,"5045":5040,"5046":5040,"5047":5040,"5048":5040,"5049":5040,"5050":5040,"5051":5040,"5052":5040,"5053":5040,"5054":5040,"5055":5040,"5057":5056,"5058":5056,"5059":5056,"5060":5056,"5061":5056,"5062":5056,"5063":5056,"5064":5056,"5065":5056,"5066":5056,"5067":5056,"5068":5056,"5069":5056,"5070":5056,"5071":5056,"5073":5072,"5074":5072,"5075":5072,"5076":5072,"5077":5072,"5078":5072,"5079":5072,"5080":5072,"5081":5072,"5082":5072,"5083":5072,"5084":5072,"5085":5072,"5086":5072,"5087":5072,"5089":5088,"5090":5088,"5091":5088,"5092":5088,"5093":5088,"5094":5088,"5095":5088,"5096":5088,"5097":5088,"5098":5088,"5099":5088,"5100":5088,"5101":5088,"5102":5088,"5103":5088,"5105":5104,"5106":5104,"5107":5104,"5108":5104,"5109":5104,"5110":5104,"5111":5104,"5112":5104,"5113":5104,"5114":5104,"5115":5104,"5116":5104,"5117":5104,"5118":5104,"5119":5104,"5121":5120,"5122":5120,"5123":5120,"5124":5120,"5125":5120,"5126":5120,"5127":5120,"5128":5120,"5129":5120,"5130":5120,"5131":5120,"5132":5120,"5133":5120,"5134":5120,"5135":5120,"5137":5136,"5138":5136,"5139":5136,"5140":5136,"5141":5136,"5142":5136,"5143":5136,"5144":5136,"5145":5136,"5146":5136,"5147":5136,"5148":5136,"5149":5136,"5150":5136,"5151":5136,"5153":5152,"5154":5152,"5155":5152,"5156":5152,"5157":5152,"5158":5152,"5159":5152,"5160":5152,"5161":5152,"5162":5152,"5163":5152,"5164":5152,"5165":5152,"5166":5152,"5167":5152,"5169":5168,"5170":5168,"5171":5168,"5172":5168,"5173":5168,"5174":5168,"5175":5168,"5176":5168,"5177":5168,"5178":5168,"5179":5168,"5180":5168,"5181":5168,"5182":5168,"5183":5168,"5185":5184,"5186":5184,"5187":5184,"5188":5184,"5189":5184,"5190":5184,"5191":5184,"5192":5184,"5193":5184,"5194":5184,"5195":5184,"5196":5184,"5197":5184,"5198":5184,"5199":5184,"5201":5200,"5202":5200,"5203":5200,"5204":5200,"5205":5200,"5206":5200,"5207":5200,"5208":5200,"5209":5200,"5210":5200,"5211":5200,"5212":5200,"5213":5200,"5214":5200,"5215":5200,"5217":5216,"5218":5216,"5219":5216,"5220":5216,"5221":5216,"5222":5216,"5223":5216,"5224":5216,"5225":5216,"5226":5216,"5227":5216,"5228":5216,"5229":5216,"5230":5216,"5231":5216,"5233":5232,"5234":5232,"5235":5232,"5236":5232,"5237":5232,"5238":5232,"5239":5232,"5240":5232,"5241":5232,"5242":5232,"5243":5232,"5244":5232,"5245":5232,"5246":5232,"5247":5232,"5249":5248,"5250":5248,"5251":5248,"5252":5248,"5253":5248,"5254":5248,"5255":5248,"5256":5248,"5257":5248,"5258":5248,"5259":5248,"5260":5248,"5261":5248,"5262":5248,"5263":5248,"5265":5264,"5266":5264,"5267":5264,"5268":5264,"5269":5264,"5270":5264,"5271":5264,"5272":5264,"5273":5264,"5274":5264,"5275":5264,"5276":5264,"5277":5264,"5278":5264,"5279":5264,"5281":5280,"5282":5280,"5283":5280,"5284":5280,"5285":5280,"5286":5280,"5287":5280,"5288":5280,"5289":5280,"5290":5280,"5291":5280,"5292":5280,"5293":5280,"5294":5280,"5295":5280,"5297":5296,"5298":5296,"5299":5296,"5300":5296,"5301":5296,"5302":5296,"5303":5296,"5304":5296,"5305":5296,"5306":5296,"5307":5296,"5308":5296,"5309":5296,"5310":5296,"5311":5296,"5313":5312,"5314":5312,"5315":5312,"5316":5312,"5317":5312,"5318":5312,"5319":5312,"5320":5312,"5321":5312,"5322":5312,"5323":5312,"5324":5312,"5325":5312,"5326":5312,"5327":5312,"5329":5328,"5330":5328,"5331":5328,"5332":5328,"5333":5328,"5334":5328,"5335":5328,"5336":5328,"5337":5328,"5338":5328,"5339":5328,"5340":5328,"5341":5328,"5342":5328,"5343":5328,"5345":5344,"5346":5344,"5347":5344,"5348":5344,"5349":5344,"5350":5344,"5351":5344,"5352":5344,"5353":5344,"5354":5344,"5355":5344,"5356":5344,"5357":5344,"5358":5344,"5359":5344,"5361":5360,"5362":5360,"5363":5360,"5364":5360,"5365":5360,"5366":5360,"5367":5360,"5368":5360,"5369":5360,"5370":5360,"5371":5360,"5372":5360,"5373":5360,"5374":5360,"5375":5360,"5377":5376,"5378":5376,"5379":5376,"5380":5376,"5381":5376,"5382":5376,"5383":5376,"5384":5376,"5385":5376,"5386":5376,"5387":5376,"5388":5376,"5389":5376,"5390":5376,"5391":5376,"5393":5392,"5394":5392,"5395":5392,"5396":5392,"5397":5392,"5398":5392,"5399":5392,"5400":5392,"5401":5392,"5402":5392,"5403":5392,"5404":5392,"5405":5392,"5406":5392,"5407":5392,"5409":5408,"5410":5408,"5411":5408,"5412":5408,"5413":5408,"5414":5408,"5415":5408,"5416":5408,"5417":5408,"5418":5408,"5419":5408,"5420":5408,"5421":5408,"5422":5408,"5423":5408,"5425":5424,"5426":5424,"5427":5424,"5428":5424,"5429":5424,"5430":5424,"5431":5424,"5432":5424,"5433":5424,"5434":5424,"5435":5424,"5436":5424,"5437":5424,"5438":5424,"5439":5424,"5441":5440,"5442":5440,"5443":5440,"5444":5440,"5445":5440,"5446":5440,"5447":5440,"5448":5440,"5449":5440,"5450":5440,"5451":5440,"5452":5440,"5453":5440,"5454":5440,"5455":5440,"5457":5456,"5458":5456,"5459":5456,"5460":5456,"5461":5456,"5462":5456,"5463":5456,"5464":5456,"5465":5456,"5466":5456,"5467":5456,"5468":5456,"5469":5456,"5470":5456,"5471":5456,"5473":5472,"5474":5472,"5475":5472,"5476":5472,"5477":5472,"5478":5472,"5479":5472,"5480":5472,"5481":5472,"5482":5472,"5483":5472,"5484":5472,"5485":5472,"5486":5472,"5487":5472,"5489":5488,"5490":5488,"5491":5488,"5492":5488,"5493":5488,"5494":5488,"5495":5488,"5496":5488,"5497":5488,"5498":5488,"5499":5488,"5500":5488,"5501":5488,"5502":5488,"5503":5488,"5505":5504,"5506":5504,"5507":5504,"5508":5504,"5509":5504,"5510":5504,"5511":5504,"5512":5504,"5513":5504,"5514":5504,"5515":5504,"5516":5504,"5517":5504,"5518":5504,"5519":5504,"5521":5520,"5522":5520,"5523":5520,"5524":5520,"5525":5520,"5526":5520,"5527":5520,"5528":5520,"5529":5520,"5530":5520,"5531":5520,"5532":5520,"5533":5520,"5534":5520,"5535":5520,"5537":5536,"5538":5536,"5539":5536,"5540":5536,"5541":5536,"5542":5536,"5543":5536,"5544":5536,"5545":5536,"5546":5536,"5547":5536,"5548":5536,"5549":5536,"5550":5536,"5551":5536,"5553":5552,"5554":5552,"5555":5552,"5556":5552,"5557":5552,"5558":5552,"5559":5552,"5560":5552,"5561":5552,"5562":5552,"5563":5552,"5564":5552,"5565":5552,"5566":5552,"5567":5552,"5569":5568,"5570":5568,"5571":5568,"5572":5568,"5573":5568,"5574":5568,"5575":5568,"5576":5568,"5577":5568,"5578":5568,"5579":5568,"5580":5568,"5581":5568,"5582":5568,"5583":5568,"5585":5584,"5586":5584,"5587":5584,"5588":5584,"5589":5584,"5590":5584,"5591":5584,"5592":5584,"5593":5584,"5594":5584,"5595":5584,"5596":5584,"5597":5584,"5598":5584,"5599":5584,"5601":5600,"5602":5600,"5603":5600,"5604":5600,"5605":5600,"5606":5600,"5607":5600,"5608":5600,"5609":5600,"5610":5600,"5611":5600,"5612":5600,"5613":5600,"5614":5600,"5615":5600,"5617":5616,"5618":5616,"5619":5616,"5620":5616,"5621":5616,"5622":5616,"5623":5616,"5624":5616,"5625":5616,"5626":5616,"5627":5616,"5628":5616,"5629":5616,"5630":5616,"5631":5616,"5633":5632,"5634":5632,"5635":5632,"5636":5632,"5637":5632,"5638":5632,"5639":5632,"5640":5632,"5641":5632,"5642":5632,"5643":5632,"5644":5632,"5645":5632,"5646":5632,"5647":5632,"5649":5648,"5650":5648,"5651":5648,"5652":5648,"5653":5648,"5654":5648,"5655":5648,"5656":5648,"5657":5648,"5658":5648,"5659":5648,"5660":5648,"5661":5648,"5662":5648,"5663":5648,"5665":5664,"5666":5664,"5667":5664,"5668":5664,"5669":5664,"5670":5664,"5671":5664,"5672":5664,"5673":5664,"5674":5664,"5675":5664,"5676":5664,"5677":5664,"5678":5664,"5679":5664,"5681":5680,"5682":5680,"5683":5680,"5684":5680,"5685":5680,"5686":5680,"5687":5680,"5688":5680,"5689":5680,"5690":5680,"5691":5680,"5692":5680,"5693":5680,"5694":5680,"5695":5680,"5697":5696,"5698":5696,"5699":5696,"5700":5696,"5701":5696,"5702":5696,"5703":5696,"5704":5696,"5705":5696,"5706":5696,"5707":5696,"5708":5696,"5709":5696,"5710":5696,"5711":5696,"5713":5712,"5714":5712,"5715":5712,"5716":5712,"5717":5712,"5718":5712,"5719":5712,"5720":5712,"5721":5712,"5722":5712,"5723":5712,"5724":5712,"5725":5712,"5726":5712,"5727":5712,"5729":5728,"5730":5728,"5731":5728,"5732":5728,"5733":5728,"5734":5728,"5735":5728,"5736":5728,"5737":5728,"5738":5728,"5739":5728,"5740":5728,"5741":5728,"5742":5728,"5743":5728,"5745":5744,"5746":5744,"5747":5744,"5748":5744,"5749":5744,"5750":5744,"5751":5744,"5752":5744,"5753":5744,"5754":5744,"5755":5744,"5756":5744,"5757":5744,"5758":5744,"5759":5744,"5761":5760,"5762":5760,"5763":5760,"5764":5760,"5765":5760,"5766":5760,"5767":5760,"5768":5760,"5769":5760,"5770":5760,"5771":5760,"5772":5760,"5773":5760,"5774":5760,"5775":5760,"5777":5776,"5778":5776,"5779":5776,"5780":5776,"5781":5776,"5782":5776,"5783":5776,"5784":5776,"5785":5776,"5786":5776,"5787":5776,"5788":5776,"5789":5776,"5790":5776,"5791":5776,"5793":5792,"5794":5792,"5795":5792,"5796":5792,"5797":5792,"5798":5792,"5799":5792,"5800":5792,"5801":5792,"5802":5792,"5803":5792,"5804":5792,"5805":5792,"5806":5792,"5807":5792,"5809":5808,"5810":5808,"5811":5808,"5812":5808,"5813":5808,"5814":5808,"5815":5808,"5816":5808,"5817":5808,"5818":5808,"5819":5808,"5820":5808,"5821":5808,"5822":5808,"5823":5808,"5825":5824,"5826":5824,"5827":5824,"5828":5824,"5829":5824,"5830":5824,"5831":5824,"5832":5824,"5833":5824,"5834":5824,"5835":5824,"5836":5824,"5837":5824,"5838":5824,"5839":5824,"5841":5840,"5842":5840,"5843":5840,"5844":5840,"5845":5840,"5846":5840,"5847":5840,"5848":5840,"5849":5840,"5850":5840,"5851":5840,"5852":5840,"5853":5840,"5854":5840,"5855":5840,"5857":5856,"5858":5856,"5859":5856,"5860":5856,"5861":5856,"5862":5856,"5863":5856,"5864":5856,"5865":5856,"5866":5856,"5867":5856,"5868":5856,"5869":5856,"5870":5856,"5871":5856,"5873":5872,"5874":5872,"5875":5872,"5876":5872,"5877":5872,"5878":5872,"5879":5872,"5880":5872,"5881":5872,"5882":5872,"5883":5872,"5884":5872,"5885":5872,"5886":5872,"5887":5872,"5889":5888,"5890":5888,"5891":5888,"5892":5888,"5893":5888,"5894":5888,"5895":5888,"5896":5888,"5897":5888,"5898":5888,"5899":5888,"5900":5888,"5901":5888,"5902":5888,"5903":5888,"5905":5904,"5906":5904,"5907":5904,"5908":5904,"5909":5904,"5910":5904,"5911":5904,"5912":5904,"5913":5904,"5914":5904,"5915":5904,"5916":5904,"5917":5904,"5918":5904,"5919":5904,"5921":5920,"5922":5920,"5923":5920,"5924":5920,"5925":5920,"5926":5920,"5927":5920,"5928":5920,"5929":5920,"5930":5920,"5931":5920,"5932":5920,"5933":5920,"5934":5920,"5935":5920,"5937":5936,"5938":5936,"5939":5936,"5940":5936,"5941":5936,"5942":5936,"5943":5936,"5944":5936,"5945":5936,"5946":5936,"5947":5936,"5948":5936,"5949":5936,"5950":5936,"5951":5936,"5953":5952,"5954":5952,"5955":5952,"5956":5952,"5957":5952,"5958":5952,"5959":5952,"5960":5952,"5961":5952,"5962":5952,"5963":5952,"5964":5952,"5965":5952,"5966":5952,"5967":5952,"5969":5968,"5970":5968,"5971":5968,"5972":5968,"5973":5968,"5974":5968,"5975":5968,"5976":5968,"5977":5968,"5978":5968,"5979":5968,"5980":5968,"5981":5968,"5982":5968,"5983":5968,"5985":5984,"5986":5984,"5987":5984,"5988":5984,"5989":5984,"5990":5984,"5991":5984,"5992":5984,"5993":5984,"5994":5984,"5995":5984,"5996":5984,"5997":5984,"5998":5984,"5999":5984,"6001":6000,"6002":6000,"6003":6000,"6004":6000,"6005":6000,"6006":6000,"6007":6000,"6008":6000,"6009":6000,"6010":6000,"6011":6000,"6012":6000,"6013":6000,"6014":6000,"6015":6000,"6017":6016,"6018":6016,"6019":6016,"6020":6016,"6021":6016,"6022":6016,"6023":6016,"6024":6016,"6025":6016,"6026":6016,"6027":6016,"6028":6016,"6029":6016,"6030":6016,"6031":6016,"6033":6032,"6034":6032,"6035":6032,"6036":6032,"6037":6032,"6038":6032,"6039":6032,"6040":6032,"6041":6032,"6042":6032,"6043":6032,"6044":6032,"6045":6032,"6046":6032,"6047":6032,"6049":6048,"6050":6048,"6051":6048,"6052":6048,"6053":6048,"6054":6048,"6055":6048,"6056":6048,"6057":6048,"6058":6048,"6059":6048,"6060":6048,"6061":6048,"6062":6048,"6063":6048,"6065":6064,"6066":6064,"6067":6064,"6068":6064,"6069":6064,"6070":6064,"6071":6064,"6072":6064,"6073":6064,"6074":6064,"6075":6064,"6076":6064,"6077":6064,"6078":6064,"6079":6064,"6081":6080,"6082":6080,"6083":6080,"6084":6080,"6085":6080,"6086":6080,"6087":6080,"6088":6080,"6089":6080,"6090":6080,"6091":6080,"6092":6080,"6093":6080,"6094":6080,"6095":6080,"6097":6096,"6098":6096,"6099":6096,"6100":6096,"6101":6096,"6102":6096,"6103":6096,"6104":6096,"6105":6096,"6106":6096,"6107":6096,"6108":6096,"6109":6096,"6110":6096,"6111":6096,"6113":6112,"6114":6112,"6115":6112,"6116":6112,"6117":6112,"6118":6112,"6119":6112,"6120":6112,"6121":6112,"6122":6112,"6123":6112,"6124":6112,"6125":6112,"6126":6112,"6127":6112,"6129":6128,"6130":6128,"6131":6128,"6132":6128,"6133":6128,"6134":6128,"6135":6128,"6136":6128,"6137":6128,"6138":6128,"6139":6128,"6140":6128,"6141":6128,"6142":6128,"6143":6128,"6145":6144,"6146":6144,"6147":6144,"6148":6144,"6149":6144,"6150":6144,"6151":6144,"6152":6144,"6153":6144,"6154":6144,"6155":6144,"6156":6144,"6157":6144,"6158":6144,"6159":6144,"6181":6176,"6182":6176,"6183":6176,"6184":6176,"6185":6176,"6186":6176,"6187":6176,"6188":6176,"6189":6176,"6190":6176,"6191":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6305":6304,"6306":6304,"6307":6304,"6308":6304,"6309":6304,"6310":6304,"6311":6304,"6312":6304,"6313":6304,"6314":6304,"6315":6304,"6316":6304,"6317":6304,"6318":6304,"6319":6304,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6482":6480,"6483":6480,"6484":6480,"6485":6480,"6486":6480,"6487":6480,"6488":6480,"6489":6480,"6490":6480,"6491":6480,"6492":6480,"6493":6480,"6494":6480,"6495":6480,"6498":6496,"6499":6496,"6500":6496,"6501":6496,"6502":6496,"6503":6496,"6504":6496,"6505":6496,"6506":6496,"6507":6496,"6508":6496,"6509":6496,"6510":6496,"6511":6496,"6514":6512,"6515":6512,"6516":6512,"6517":6512,"6518":6512,"6519":6512,"6520":6512,"6521":6512,"6522":6512,"6523":6512,"6524":6512,"6525":6512,"6526":6512,"6527":6512,"6530":6528,"6531":6528,"6532":6528,"6533":6528,"6534":6528,"6535":6528,"6536":6528,"6537":6528,"6538":6528,"6539":6528,"6540":6528,"6541":6528,"6542":6528,"6543":6528,"6546":6544,"6547":6544,"6548":6544,"6549":6544,"6550":6544,"6551":6544,"6552":6544,"6553":6544,"6554":6544,"6555":6544,"6556":6544,"6557":6544,"6558":6544,"6559":6544,"6564":6562,"6565":6562,"6566":6562,"6567":6562,"6568":6562,"6569":6562,"6570":6562,"6571":6562,"6572":6562,"6573":6562,"6574":6562,"6575":6562,"6584":6580,"6585":6580,"6586":6580,"6587":6580,"6588":6580,"6589":6580,"6590":6580,"6591":6580,"6657":6656,"6658":6656,"6659":6656,"6660":6656,"6661":6656,"6662":6656,"6663":6656,"6664":6656,"6665":6656,"6666":6656,"6667":6656,"6668":6656,"6669":6656,"6670":6656,"6671":6656,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6705":6704,"6706":6704,"6707":6704,"6708":6704,"6709":6704,"6710":6704,"6711":6704,"6713":6704,"6714":6704,"6715":6704,"6716":6704,"6717":6704,"6718":6704,"6719":6704,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6792":6787,"6793":6787,"6794":6787,"6795":6787,"6796":6787,"6797":6787,"6798":6787,"6799":6787,"6808":6803,"6809":6803,"6810":6803,"6811":6803,"6812":6803,"6813":6803,"6814":6803,"6815":6803,"6824":6819,"6825":6819,"6826":6819,"6827":6819,"6828":6819,"6829":6819,"6830":6819,"6831":6819,"6840":6835,"6841":6835,"6842":6835,"6843":6835,"6844":6835,"6845":6835,"6846":6835,"6847":6835,"6856":6851,"6857":6851,"6858":6851,"6859":6851,"6860":6851,"6861":6851,"6862":6851,"6863":6851,"6872":6867,"6873":6867,"6874":6867,"6875":6867,"6876":6867,"6877":6867,"6878":6867,"6879":6867,"6888":6883,"6889":6883,"6890":6883,"6891":6883,"6892":6883,"6893":6883,"6894":6883,"6895":6883,"6904":6899,"6905":6899,"6906":6899,"6907":6899,"6908":6899,"6909":6899,"6910":6899,"6911":6899,"6920":6915,"6921":6915,"6922":6915,"6923":6915,"6924":6915,"6925":6915,"6926":6915,"6927":6915,"6936":6931,"6937":6931,"6938":6931,"6939":6931,"6940":6931,"6941":6931,"6942":6931,"6943":6931,"6952":6947,"6953":6947,"6954":6947,"6955":6947,"6956":6947,"6957":6947,"6958":6947,"6959":6947,"6968":6963,"6969":6963,"6970":6963,"6971":6963,"6972":6963,"6973":6963,"6974":6963,"6975":6963,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7000":6994,"7001":6994,"7002":6994,"7003":6994,"7004":6994,"7005":6994,"7006":6994,"7007":6994,"7009":7008,"7010":7008,"7011":7008,"7012":7008,"7013":7008,"7014":7008,"7015":7008,"7016":7008,"7017":7008,"7018":7008,"7019":7008,"7020":7008,"7021":7008,"7022":7008,"7023":7008,"7032":7027,"7033":7027,"7034":7027,"7035":7027,"7036":7027,"7037":7027,"7038":7027,"7039":7027,"7048":7043,"7049":7043,"7050":7043,"7051":7043,"7052":7043,"7053":7043,"7054":7043,"7055":7043,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7080":7074,"7081":7074,"7082":7074,"7083":7074,"7084":7074,"7085":7074,"7086":7074,"7087":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7112":7106,"7113":7106,"7114":7106,"7115":7106,"7116":7106,"7117":7106,"7118":7106,"7119":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7144":7138,"7145":7138,"7146":7138,"7147":7138,"7148":7138,"7149":7138,"7150":7138,"7151":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7176":7170,"7177":7170,"7178":7170,"7179":7170,"7180":7170,"7181":7170,"7182":7170,"7183":7170,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7224":7218,"7225":7218,"7226":7218,"7227":7218,"7228":7218,"7229":7218,"7230":7218,"7231":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7256":7250,"7257":7250,"7258":7250,"7259":7250,"7260":7250,"7261":7250,"7262":7250,"7263":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7272":7250,"7273":7250,"7274":7250,"7275":7250,"7276":7250,"7277":7250,"7278":7250,"7279":7250,"7297":7296,"7298":7296,"7299":7296,"7300":7296,"7301":7296,"7302":7296,"7303":7296,"7304":7296,"7305":7296,"7306":7296,"7307":7296,"7308":7296,"7309":7296,"7310":7296,"7311":7296,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7348":7346,"7349":7346,"7350":7346,"7351":7346,"7352":7346,"7353":7346,"7354":7346,"7355":7346,"7356":7346,"7357":7346,"7358":7346,"7359":7346,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7400":7392,"7401":7392,"7402":7392,"7403":7392,"7404":7392,"7405":7392,"7406":7392,"7407":7392,"7410":7408,"7411":7408,"7412":7408,"7413":7408,"7414":7408,"7415":7408,"7416":7408,"7417":7408,"7418":7408,"7419":7408,"7420":7408,"7421":7408,"7422":7408,"7423":7408,"7478":7472,"7479":7472,"7486":7472,"7487":7472,"7504":7218,"7505":7218,"7510":7218,"7511":7218,"7512":7218,"7513":7218,"7514":7218,"7515":7218,"7516":7218,"7517":7218,"7518":7218,"7519":7218}} \ No newline at end of file From 52f0c4f3ed7f82e9bb04ad471432e61ab4725bee Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 27 Nov 2021 22:51:14 +0000 Subject: [PATCH 417/710] Removed dodgy test using invalid block metadata --- tests/phpunit/block/BlockTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/phpunit/block/BlockTest.php b/tests/phpunit/block/BlockTest.php index 1e7e470ae..8e101bc0f 100644 --- a/tests/phpunit/block/BlockTest.php +++ b/tests/phpunit/block/BlockTest.php @@ -107,7 +107,6 @@ class BlockTest extends TestCase{ public function blockGetProvider() : array{ return [ [BlockLegacyIds::STONE, 5], - [BlockLegacyIds::STONE, 15], [BlockLegacyIds::GOLD_BLOCK, 0], [BlockLegacyIds::WOODEN_PLANKS, 5], [BlockLegacyIds::SAND, 0], From 4a8ca603a1de9277c1ba91f3159a27791ea667ea Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 28 Nov 2021 18:53:34 +0000 Subject: [PATCH 418/710] Log a message when forceShutdown() is called for anything other than a graceful shutdown --- src/Server.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Server.php b/src/Server.php index 4ab8b8dcb..f10a6b689 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1413,6 +1413,9 @@ class Server{ echo "\x1b]0;\x07"; } + if($this->isRunning){ + $this->logger->emergency("Forcing server shutdown"); + } try{ if(!$this->isRunning()){ $this->sendUsage(SendUsageTask::TYPE_CLOSE); From 882df94bcbfc0b6111ebe2d9d5e717726ed590e0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 29 Nov 2021 23:45:10 +0000 Subject: [PATCH 419/710] ConsoleReaderThread: fixed zombie process leak --- src/console/ConsoleReaderThread.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/console/ConsoleReaderThread.php b/src/console/ConsoleReaderThread.php index fb9dc85bb..bdfccd80f 100644 --- a/src/console/ConsoleReaderThread.php +++ b/src/console/ConsoleReaderThread.php @@ -31,6 +31,7 @@ use function base64_encode; use function fgets; use function fopen; use function preg_replace; +use function proc_close; use function proc_open; use function proc_terminate; use function sprintf; @@ -130,6 +131,7 @@ final class ConsoleReaderThread extends Thread{ //gets stuck in a blocking fgets() read because stream_select() is a hunk of junk (hence the separate process in //the first place). proc_terminate($sub); + proc_close($sub); stream_socket_shutdown($client, STREAM_SHUT_RDWR); } From 6f8f460a6c84f057013c74db8c47782ae4923b42 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 00:27:52 +0000 Subject: [PATCH 420/710] Partially revert "ConsoleReaderChildProcess: Commit suicide in more cases" This reverts commit cbe0f44c4f7bc3715acbf148f981bd93111c4c8f. This achieves the same result as the reverted commit wrt. process in the same manner (writing a keepalive into the socket and checking if it failed to send). However, it does _not_ allow the process to die on reaching pipe EOF, since this can cause many spams of subprocesses when stdin is actually not a tty (e.g. in a Docker container). --- src/console/ConsoleReader.php | 25 ++++++++++++++------ src/console/ConsoleReaderChildProcess.php | 9 +------- src/console/ConsoleReaderException.php | 28 ----------------------- 3 files changed, 19 insertions(+), 43 deletions(-) delete mode 100644 src/console/ConsoleReaderException.php diff --git a/src/console/ConsoleReader.php b/src/console/ConsoleReader.php index bd1fef4f5..6d7545fde 100644 --- a/src/console/ConsoleReader.php +++ b/src/console/ConsoleReader.php @@ -23,38 +23,49 @@ declare(strict_types=1); namespace pocketmine\console; -use pocketmine\utils\AssumptionFailedError; use function fclose; use function fgets; use function fopen; +use function is_resource; use function stream_select; use function trim; +use function usleep; final class ConsoleReader{ /** @var resource */ private $stdin; public function __construct(){ - $stdin = fopen("php://stdin", "r"); - if($stdin === false) throw new AssumptionFailedError("Opening stdin should never fail"); - $this->stdin = $stdin; + $this->initStdin(); + } + + private function initStdin() : void{ + if(is_resource($this->stdin)){ + fclose($this->stdin); + } + + $this->stdin = fopen("php://stdin", "r"); } /** * Reads a line from the console and adds it to the buffer. This method may block the thread. - * @throws ConsoleReaderException */ public function readLine() : ?string{ + if(!is_resource($this->stdin)){ + $this->initStdin(); + } + $r = [$this->stdin]; $w = $e = null; if(($count = stream_select($r, $w, $e, 0, 200000)) === 0){ //nothing changed in 200000 microseconds return null; }elseif($count === false){ //stream error - throw new ConsoleReaderException("Unexpected EOF on select()"); + return null; } if(($raw = fgets($this->stdin)) === false){ //broken pipe or EOF - throw new ConsoleReaderException("Unexpected EOF on fgets()"); + usleep(200000); //prevent CPU waste if it's end of pipe + return null; //loop back round } $line = trim($raw); diff --git a/src/console/ConsoleReaderChildProcess.php b/src/console/ConsoleReaderChildProcess.php index 6f4a74258..509d0daca 100644 --- a/src/console/ConsoleReaderChildProcess.php +++ b/src/console/ConsoleReaderChildProcess.php @@ -45,14 +45,7 @@ if($socket === false){ } $consoleReader = new ConsoleReader(); while(!feof($socket)){ - try{ - $line = $consoleReader->readLine(); - }catch(ConsoleReaderException $e){ - //Encountered unexpected EOF. This might be because the user did something stupid, or because the parent process - //has died. In either case, commit suicide. If the parent process is still alive, it will start a new console - //reader. - break; - } + $line = $consoleReader->readLine(); if(@fwrite($socket, ($line ?? "") . "\n") === false){ //Always send even if there's no line, to check if the parent is alive //If the parent process was terminated forcibly, it won't close the connection properly, so feof() will return diff --git a/src/console/ConsoleReaderException.php b/src/console/ConsoleReaderException.php deleted file mode 100644 index bf9e8fc67..000000000 --- a/src/console/ConsoleReaderException.php +++ /dev/null @@ -1,28 +0,0 @@ - Date: Tue, 30 Nov 2021 00:36:38 +0000 Subject: [PATCH 421/710] Fixed PHPStan complaints --- src/console/ConsoleReader.php | 5 ++++- tests/phpstan/configs/actual-problems.neon | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/console/ConsoleReader.php b/src/console/ConsoleReader.php index 6d7545fde..77a3f4b6f 100644 --- a/src/console/ConsoleReader.php +++ b/src/console/ConsoleReader.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\console; +use pocketmine\utils\AssumptionFailedError; use function fclose; use function fgets; use function fopen; @@ -44,7 +45,9 @@ final class ConsoleReader{ fclose($this->stdin); } - $this->stdin = fopen("php://stdin", "r"); + $stdin = fopen("php://stdin", "r"); + if($stdin === false) throw new AssumptionFailedError("Opening stdin should never fail"); + $this->stdin = $stdin; } /** diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index a9c45db8b..52b727319 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -505,6 +505,11 @@ parameters: count: 1 path: ../../../src/command/defaults/TimingsCommand.php + - + message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#" + count: 2 + path: ../../../src/console/ConsoleReader.php + - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" count: 1 From 38325c8573ae46d7861eb5fe45459668d41dd00f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 01:14:21 +0000 Subject: [PATCH 422/710] Updated translations --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 969ab365b..3bb3c0e48 100644 --- a/composer.lock +++ b/composer.lock @@ -533,16 +533,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.0.17", + "version": "2.0.20", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "30e4a64d5674bac556c4e2b9842b19a981471ac4" + "reference": "a6e4eb22587e0014f6d658732cf633262723f8d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/30e4a64d5674bac556c4e2b9842b19a981471ac4", - "reference": "30e4a64d5674bac556c4e2b9842b19a981471ac4", + "url": "https://api.github.com/repos/pmmp/Language/zipball/a6e4eb22587e0014f6d658732cf633262723f8d3", + "reference": "a6e4eb22587e0014f6d658732cf633262723f8d3", "shasum": "" }, "type": "library", @@ -550,9 +550,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.0.17" + "source": "https://github.com/pmmp/Language/tree/2.0.20" }, - "time": "2021-11-12T00:59:39+00:00" + "time": "2021-11-25T20:56:12+00:00" }, { "name": "pocketmine/log", From ba295dc7dc63bc1b8350785bf8d0e44248e150b1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 01:16:28 +0000 Subject: [PATCH 423/710] Always use LF in .neon files --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index bec13fa0a..20ef6a046 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,6 +4,7 @@ *.sh text eol=lf *.txt text eol=lf *.properties text eol=lf +*.neon text eol=lf *.bat text eol=crlf *.cmd text eol=crlf *.ps1 text eol=crlf From 8079ae341a84f3df65e578b5b7166a4311ba4688 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 01:19:14 +0000 Subject: [PATCH 424/710] Updated build/php submodule to pmmp/php-build-scripts@bd329dba08242b6ecb99ef7fbf9a0031dcbbb3ff --- build/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/php b/build/php index a59722c67..bd329dba0 160000 --- a/build/php +++ b/build/php @@ -1 +1 @@ -Subproject commit a59722c6764ce82e91a1ec2a9aa158e060022bed +Subproject commit bd329dba08242b6ecb99ef7fbf9a0031dcbbb3ff From 6d62b06ce68c605a35c1af35da7a48431d929767 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 01:26:07 +0000 Subject: [PATCH 425/710] Release 4.0.0-BETA14 --- changelogs/4.0.md | 10 ++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index c7038c96c..27d27ac61 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1748,3 +1748,13 @@ Released 25th November 2021. ### Utils - `Utils::parseDocComment()` now allows `-` in tag names. + +# 4.0.0-BETA14 +Released 30th November 2021. + +## General +- The server will now log an EMERGENCY-level message when `forceShutdown()` is used for any other reason than a graceful shutdown. +- The server will now attempt to translate invalid blocks to valid equivalents when loading chunks. This fixes many issues with `update!` blocks appearing in worlds, particularly ghost structures (these would appear when world editors previously erased some blocks by setting their IDs but not metadata). + +## Fixes +- Fixed `ConsoleReaderThread` spawning many zombie processes when running a server inside a Docker container. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index fc0171e8a..ce5edfdd4 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA14"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "beta"; private function __construct(){ From d21a3d87506fe4a7758893b86703bbd241d37ae4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 01:26:07 +0000 Subject: [PATCH 426/710] 4.0.0-BETA15 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index ce5edfdd4..4699d4eb0 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA14"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA15"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "beta"; private function __construct(){ From 9931c1d50aad0397dab4f7da073436f53697d447 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 18:46:29 +0000 Subject: [PATCH 427/710] Protocol changes for 1.18.0 --- composer.json | 1 + composer.lock | 3 +- src/pocketmine/Player.php | 1 + src/pocketmine/PocketMine.php | 11 ++++ src/pocketmine/level/format/Chunk.php | 64 ++++++++++++++++++- .../level/format/io/ChunkRequestTask.php | 9 +-- .../network/mcpe/protocol/ProtocolInfo.php | 6 +- .../network/mcpe/protocol/StartGamePacket.php | 4 ++ .../network/mcpe/protocol/SubChunkPacket.php | 12 +++- src/pocketmine/resources/vanilla | 2 +- 10 files changed, 100 insertions(+), 13 deletions(-) diff --git a/composer.json b/composer.json index 400c32846..ab792210b 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "require": { "php": "^8.0", "php-64bit": "*", + "ext-chunkutils2": "^0.3.1", "ext-ctype": "*", "ext-curl": "*", "ext-date": "*", diff --git a/composer.lock b/composer.lock index dd293362e..e948d9abf 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f13c4ed7311b99ac07dca31d2f77ad1d", + "content-hash": "2d144524b177c9e7f699ba7366c16354", "packages": [ { "name": "adhocore/json-comment", @@ -2761,6 +2761,7 @@ "platform": { "php": "^8.0", "php-64bit": "*", + "ext-chunkutils2": "^0.3.1", "ext-ctype": "*", "ext-curl": "*", "ext-date": "*", diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index d1dbe7891..7721b4013 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -2279,6 +2279,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $pk->itemTable = ItemTypeDictionary::getInstance()->getEntries(); $pk->playerMovementSettings = new PlayerMovementSettings(PlayerMovementType::LEGACY, 0, false); $pk->serverSoftwareVersion = sprintf("%s %s", \pocketmine\NAME, \pocketmine\VERSION); + $pk->blockPaletteChecksum = 0; //we don't bother with this (0 skips verification) - the preimage is some dumb stringified NBT, not even actual NBT $this->dataPacket($pk); $this->sendDataPacket(new AvailableActorIdentifiersPacket()); diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index be7fa241e..2c6c1fdd8 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -74,6 +74,7 @@ namespace pocketmine { } $extensions = [ + "chunkutils2" => "PocketMine ChunkUtils v2", "curl" => "cURL", "ctype" => "ctype", "date" => "Date", @@ -115,6 +116,16 @@ namespace pocketmine { } } + $chunkutils2_version = phpversion("chunkutils2"); + $wantedVersionLock = "0.3"; + $wantedVersionMin = "$wantedVersionLock.0"; + if($chunkutils2_version !== false && ( + version_compare($chunkutils2_version, $wantedVersionMin) < 0 || + preg_match("/^" . preg_quote($wantedVersionLock, "/") . "\.\d+(?:-dev)?$/", $chunkutils2_version) === 0 //lock in at ^0.2, optionally at a patch release + )){ + $messages[] = "chunkutils2 ^$wantedVersionMin is required, while you have $chunkutils2_version."; + } + if(extension_loaded("pocketmine")){ $messages[] = "The native PocketMine extension is no longer supported."; } diff --git a/src/pocketmine/level/format/Chunk.php b/src/pocketmine/level/format/Chunk.php index a80b41f0f..2055862c6 100644 --- a/src/pocketmine/level/format/Chunk.php +++ b/src/pocketmine/level/format/Chunk.php @@ -28,6 +28,7 @@ namespace pocketmine\level\format; use pocketmine\block\BlockFactory; use pocketmine\entity\Entity; +use pocketmine\level\biome\Biome; use pocketmine\level\Level; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; @@ -35,13 +36,20 @@ use pocketmine\nbt\tag\StringTag; use pocketmine\Player; use pocketmine\tile\Spawnable; use pocketmine\tile\Tile; +use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Binary; use pocketmine\utils\BinaryStream; +use pocketmine\world\format\PalettedBlockArray; use function array_fill; use function array_filter; +use function array_flip; use function array_values; use function assert; use function chr; use function count; +use function file_get_contents; +use function is_array; +use function json_decode; use function ord; use function pack; use function str_repeat; @@ -841,10 +849,21 @@ class Chunk{ public function networkSerialize() : string{ $result = ""; $subChunkCount = $this->getSubChunkSendCount(); + + //TODO: HACK! fill in fake subchunks to make up for the new negative space client-side + for($y = 0; $y < 4; ++$y){ + $result .= chr(8); //subchunk version 8 + $result .= chr(0); //0 layers - client will treat this as all-air + } for($y = 0; $y < $subChunkCount; ++$y){ $result .= $this->subChunks[$y]->networkSerialize(); } - $result .= $this->biomeIds . chr(0); //border block array count + + //TODO: right now we don't support 3D natively, so we just 3Dify our 2D biomes so they fill the column + $encodedBiomePalette = $this->networkSerializeBiomesAsPalette(); + $result .= str_repeat($encodedBiomePalette, 25); + + $result .= chr(0); //border block array count //Border block entry format: 1 byte (4 bits X, 4 bits Z). These are however useless since they crash the regular client. foreach($this->tiles as $tile){ @@ -856,6 +875,49 @@ class Chunk{ return $result; } + private function networkSerializeBiomesAsPalette() : string{ + /** @var string[]|null $biomeIdMap */ + static $biomeIdMap = null; + if($biomeIdMap === null){ + $biomeIdMapRaw = file_get_contents(\pocketmine\RESOURCE_PATH . '/vanilla/biome_id_map.json'); + if($biomeIdMapRaw === false) throw new AssumptionFailedError(); + $biomeIdMapDecoded = json_decode($biomeIdMapRaw, true); + if(!is_array($biomeIdMapDecoded)) throw new AssumptionFailedError(); + $biomeIdMap = array_flip($biomeIdMapDecoded); + } + $biomePalette = new PalettedBlockArray($this->getBiomeId(0, 0)); + for($x = 0; $x < 16; ++$x){ + for($z = 0; $z < 16; ++$z){ + $biomeId = $this->getBiomeId($x, $z); + if(!isset($biomeIdMap[$biomeId])){ + //make sure we aren't sending bogus biomes - the 1.18.0 client crashes if we do this + $biomeId = Biome::OCEAN; + } + for($y = 0; $y < 16; ++$y){ + $biomePalette->set($x, $y, $z, $biomeId); + } + } + } + + $biomePaletteBitsPerBlock = $biomePalette->getBitsPerBlock(); + $encodedBiomePalette = + chr(($biomePaletteBitsPerBlock << 1) | 1) . //the last bit is non-persistence (like for blocks), though it has no effect on biomes since they always use integer IDs + $biomePalette->getWordArray(); + + //these LSHIFT by 1 uvarints are optimizations: the client expects zigzag varints here + //but since we know they are always unsigned, we can avoid the extra fcall overhead of + //zigzag and just shift directly. + $biomePaletteArray = $biomePalette->getPalette(); + if($biomePaletteBitsPerBlock !== 0){ + $encodedBiomePalette .= Binary::writeUnsignedVarInt(count($biomePaletteArray) << 1); + } + foreach($biomePaletteArray as $p){ + $encodedBiomePalette .= Binary::writeUnsignedVarInt($p << 1); + } + + return $encodedBiomePalette; + } + /** * Fast-serializes the chunk for passing between threads * TODO: tiles and entities diff --git a/src/pocketmine/level/format/io/ChunkRequestTask.php b/src/pocketmine/level/format/io/ChunkRequestTask.php index 945ae324a..9cf66ce2b 100644 --- a/src/pocketmine/level/format/io/ChunkRequestTask.php +++ b/src/pocketmine/level/format/io/ChunkRequestTask.php @@ -47,21 +47,18 @@ class ChunkRequestTask extends AsyncTask{ /** @var int */ protected $compressionLevel; - /** @var int */ - private $subChunkCount; - public function __construct(Level $level, int $chunkX, int $chunkZ, Chunk $chunk){ $this->levelId = $level->getId(); $this->compressionLevel = $level->getServer()->networkCompressionLevel; - $this->chunk = $chunk->networkSerialize(); + $this->chunk = $chunk->fastSerialize(); $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; - $this->subChunkCount = $chunk->getSubChunkSendCount(); } public function onRun(){ - $pk = LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $this->subChunkCount, $this->chunk); + $chunk = Chunk::fastDeserialize($this->chunk); + $pk = LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $chunk->getSubChunkSendCount() + 4, $chunk->networkSerialize()); $batch = new BatchPacket(); $batch->addPacket($pk); diff --git a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php index 94012727b..e43718e02 100644 --- a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php +++ b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php @@ -37,11 +37,11 @@ interface ProtocolInfo{ */ /** Actual Minecraft: PE protocol version */ - public const CURRENT_PROTOCOL = 471; + public const CURRENT_PROTOCOL = 475; /** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */ - public const MINECRAFT_VERSION = 'v1.17.40'; + public const MINECRAFT_VERSION = 'v1.18.0'; /** Version number sent to clients in ping responses. */ - public const MINECRAFT_VERSION_NETWORK = '1.17.40'; + public const MINECRAFT_VERSION_NETWORK = '1.18.0'; public const LOGIN_PACKET = 0x01; public const PLAY_STATUS_PACKET = 0x02; diff --git a/src/pocketmine/network/mcpe/protocol/StartGamePacket.php b/src/pocketmine/network/mcpe/protocol/StartGamePacket.php index df3de9e1e..d702732df 100644 --- a/src/pocketmine/network/mcpe/protocol/StartGamePacket.php +++ b/src/pocketmine/network/mcpe/protocol/StartGamePacket.php @@ -182,6 +182,8 @@ class StartGamePacket extends DataPacket{ /** @var string */ public $serverSoftwareVersion; + public int $blockPaletteChecksum; + protected function decodePayload(){ $this->entityUniqueId = $this->getEntityUniqueId(); $this->entityRuntimeId = $this->getEntityRuntimeId(); @@ -265,6 +267,7 @@ class StartGamePacket extends DataPacket{ $this->multiplayerCorrelationId = $this->getString(); $this->enableNewInventorySystem = $this->getBool(); $this->serverSoftwareVersion = $this->getString(); + $this->blockPaletteChecksum = $this->getLLong(); } protected function encodePayload(){ @@ -346,6 +349,7 @@ class StartGamePacket extends DataPacket{ $this->putString($this->multiplayerCorrelationId); $this->putBool($this->enableNewInventorySystem); $this->putString($this->serverSoftwareVersion); + $this->putLLong($this->blockPaletteChecksum); } public function handle(NetworkSession $session) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/SubChunkPacket.php b/src/pocketmine/network/mcpe/protocol/SubChunkPacket.php index 35d4be5f4..ade9163d4 100644 --- a/src/pocketmine/network/mcpe/protocol/SubChunkPacket.php +++ b/src/pocketmine/network/mcpe/protocol/SubChunkPacket.php @@ -39,8 +39,9 @@ class SubChunkPacket extends DataPacket{ private string $data; private int $requestResult; private ?SubChunkPacketHeightMapInfo $heightMapData = null; + private ?int $usedBlobHash = null; - public static function create(int $dimension, int $subChunkX, int $subChunkY, int $subChunkZ, string $data, int $requestResult, ?SubChunkPacketHeightMapInfo $heightMapData) : self{ + public static function create(int $dimension, int $subChunkX, int $subChunkY, int $subChunkZ, string $data, int $requestResult, ?SubChunkPacketHeightMapInfo $heightMapData, ?int $usedBlobHash) : self{ $result = new self; $result->dimension = $dimension; $result->subChunkX = $subChunkX; @@ -49,6 +50,7 @@ class SubChunkPacket extends DataPacket{ $result->data = $data; $result->requestResult = $requestResult; $result->heightMapData = $heightMapData; + $result->usedBlobHash = $usedBlobHash; return $result; } @@ -66,6 +68,8 @@ class SubChunkPacket extends DataPacket{ public function getHeightMapData() : ?SubChunkPacketHeightMapInfo{ return $this->heightMapData; } + public function getUsedBlobHash() : ?int{ return $this->usedBlobHash; } + protected function decodePayload() : void{ $this->dimension = $this->getVarInt(); $this->subChunkX = $this->getVarInt(); @@ -81,6 +85,7 @@ class SubChunkPacket extends DataPacket{ SubChunkPacketHeightMapType::ALL_TOO_LOW => SubChunkPacketHeightMapInfo::allTooLow(), default => throw new \UnexpectedValueException("Unknown heightmap data type $heightMapDataType") }; + $this->usedBlobHash = $this->getBool() ? $this->getLLong() : null; } protected function encodePayload() : void{ @@ -101,6 +106,11 @@ class SubChunkPacket extends DataPacket{ $this->putByte(SubChunkPacketHeightMapType::DATA); $heightMapData->write($this); } + $usedBlobHash = $this->usedBlobHash; + $this->putBool($usedBlobHash !== null); + if($usedBlobHash !== null){ + $this->putLLong($usedBlobHash); + } } public function handle(NetworkSession $handler) : bool{ diff --git a/src/pocketmine/resources/vanilla b/src/pocketmine/resources/vanilla index f29b7be8f..482c679aa 160000 --- a/src/pocketmine/resources/vanilla +++ b/src/pocketmine/resources/vanilla @@ -1 +1 @@ -Subproject commit f29b7be8fa3046d2ee4c6421485b97b3f5b07774 +Subproject commit 482c679aa5ed0b81c088c2b1ff0b8110a94c8a6c From 0aeac3af7d58132c1006a9087f780c36ecdb2b44 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 18:53:36 +0000 Subject: [PATCH 428/710] Release 3.26.0 --- changelogs/3.26.md | 11 +++++++++++ src/pocketmine/VersionInfo.php | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 changelogs/3.26.md diff --git a/changelogs/3.26.md b/changelogs/3.26.md new file mode 100644 index 000000000..9ee4332c0 --- /dev/null +++ b/changelogs/3.26.md @@ -0,0 +1,11 @@ +**For Minecraft: Bedrock Edition 1.18.0** + +### Note about API versions +Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps. +Plugin developers should **only** update their required API to this version if you need the changes in this build. + +**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do. + +# 3.26.0 +- Added support for Minecraft: Bedrock Edition 1.18.0. +- Removed compatibility with earlier versions. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index c2cf65738..b4d5ae9b6 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.25.7"; -const IS_DEVELOPMENT_BUILD = true; +const BASE_VERSION = "3.26.0"; +const IS_DEVELOPMENT_BUILD = false; const BUILD_CHANNEL = "stable"; From d5f81fe2614a63a26c961dde3998b8c868854bcf Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 18:53:36 +0000 Subject: [PATCH 429/710] 3.26.1 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 b4d5ae9b6..d044a9e13 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.26.0"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.26.1"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_CHANNEL = "stable"; From 8620e67d88d5ce6090e03307964bdbf39e712fd0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 19:16:38 +0000 Subject: [PATCH 430/710] Protocol changes for 1.18.0 --- composer.json | 4 +- composer.lock | 26 ++++----- src/data/bedrock/LegacyBiomeIdToStringMap.php | 35 ++++++++++++ src/network/mcpe/ChunkRequestTask.php | 2 +- .../mcpe/handler/PreSpawnPacketHandler.php | 1 + .../mcpe/serializer/ChunkSerializer.php | 54 ++++++++++++++++++- 6 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 src/data/bedrock/LegacyBiomeIdToStringMap.php diff --git a/composer.json b/composer.json index b42e95a74..5d6c1e4c6 100644 --- a/composer.json +++ b/composer.json @@ -34,8 +34,8 @@ "adhocore/json-comment": "^1.1", "fgrosse/phpasn1": "^2.3", "netresearch/jsonmapper": "^4.0", - "pocketmine/bedrock-data": "^1.4.0+bedrock-1.17.40", - "pocketmine/bedrock-protocol": "^6.0.0+bedrock-1.17.40", + "pocketmine/bedrock-data": "^1.5.0+bedrock-1.18.0", + "pocketmine/bedrock-protocol": "^7.0.0+bedrock-1.18.0", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "^0.2.0", diff --git a/composer.lock b/composer.lock index 3bb3c0e48..66f1c97df 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fb545e4c8e17b0b07e8e20986b64e5a6", + "content-hash": "4acde3df19f222385a36bf6c7b15f965", "packages": [ { "name": "adhocore/json-comment", @@ -249,16 +249,16 @@ }, { "name": "pocketmine/bedrock-data", - "version": "1.4.0+bedrock-1.17.40", + "version": "1.5.0+bedrock-1.18.0", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockData.git", - "reference": "f29b7be8fa3046d2ee4c6421485b97b3f5b07774" + "reference": "482c679aa5ed0b81c088c2b1ff0b8110a94c8a6c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/f29b7be8fa3046d2ee4c6421485b97b3f5b07774", - "reference": "f29b7be8fa3046d2ee4c6421485b97b3f5b07774", + "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/482c679aa5ed0b81c088c2b1ff0b8110a94c8a6c", + "reference": "482c679aa5ed0b81c088c2b1ff0b8110a94c8a6c", "shasum": "" }, "type": "library", @@ -269,22 +269,22 @@ "description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/BedrockData/issues", - "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.17.40" + "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.18.0" }, - "time": "2021-10-19T16:55:41+00:00" + "time": "2021-11-30T18:30:46+00:00" }, { "name": "pocketmine/bedrock-protocol", - "version": "6.0.0+bedrock-1.17.40", + "version": "7.0.0+bedrock-1.18.0", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "906bafec4fc41f548749ce01d120902b25c1bbfe" + "reference": "040a883a4abb8c9b93114d5278cb5fecc635da82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/906bafec4fc41f548749ce01d120902b25c1bbfe", - "reference": "906bafec4fc41f548749ce01d120902b25c1bbfe", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/040a883a4abb8c9b93114d5278cb5fecc635da82", + "reference": "040a883a4abb8c9b93114d5278cb5fecc635da82", "shasum": "" }, "require": { @@ -316,9 +316,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/6.0.0+bedrock-1.17.40" + "source": "https://github.com/pmmp/BedrockProtocol/tree/7.0.0+bedrock-1.18.0" }, - "time": "2021-11-21T20:56:18+00:00" + "time": "2021-11-30T19:02:41+00:00" }, { "name": "pocketmine/binaryutils", diff --git a/src/data/bedrock/LegacyBiomeIdToStringMap.php b/src/data/bedrock/LegacyBiomeIdToStringMap.php new file mode 100644 index 000000000..2ccdc6abd --- /dev/null +++ b/src/data/bedrock/LegacyBiomeIdToStringMap.php @@ -0,0 +1,35 @@ +chunk); - $subCount = ChunkSerializer::getSubChunkCount($chunk); + $subCount = ChunkSerializer::getSubChunkCount($chunk) + ChunkSerializer::LOWER_PADDING_SIZE; $encoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()); $payload = ChunkSerializer::serializeFullChunk($chunk, RuntimeBlockMapping::getInstance(), $encoderContext, $this->tiles); $this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::create($this->chunkX, $this->chunkZ, $subCount, null, $payload))->getBuffer())); diff --git a/src/network/mcpe/handler/PreSpawnPacketHandler.php b/src/network/mcpe/handler/PreSpawnPacketHandler.php index 6d2091065..dbad9ab6c 100644 --- a/src/network/mcpe/handler/PreSpawnPacketHandler.php +++ b/src/network/mcpe/handler/PreSpawnPacketHandler.php @@ -104,6 +104,7 @@ class PreSpawnPacketHandler extends PacketHandler{ false, sprintf("%s %s", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(true)), [], + 0, GlobalItemTypeDictionary::getInstance()->getDictionary()->getEntries() )); diff --git a/src/network/mcpe/serializer/ChunkSerializer.php b/src/network/mcpe/serializer/ChunkSerializer.php index af5336465..2d76f1291 100644 --- a/src/network/mcpe/serializer/ChunkSerializer.php +++ b/src/network/mcpe/serializer/ChunkSerializer.php @@ -24,6 +24,8 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\serializer; use pocketmine\block\tile\Spawnable; +use pocketmine\data\bedrock\BiomeIds; +use pocketmine\data\bedrock\LegacyBiomeIdToStringMap; use pocketmine\nbt\TreeRoot; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer; @@ -32,10 +34,14 @@ use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext; use pocketmine\utils\Binary; use pocketmine\utils\BinaryStream; use pocketmine\world\format\Chunk; +use pocketmine\world\format\PalettedBlockArray; use pocketmine\world\format\SubChunk; +use function chr; use function count; +use function str_repeat; final class ChunkSerializer{ + public const LOWER_PADDING_SIZE = 4; private function __construct(){ //NOOP @@ -58,11 +64,22 @@ final class ChunkSerializer{ public static function serializeFullChunk(Chunk $chunk, RuntimeBlockMapping $blockMapper, PacketSerializerContext $encoderContext, ?string $tiles = null) : string{ $stream = PacketSerializer::encoder($encoderContext); + + //TODO: HACK! fill in fake subchunks to make up for the new negative space client-side + for($y = 0; $y < self::LOWER_PADDING_SIZE; $y++){ + $stream->putByte(8); //subchunk version 8 + $stream->putByte(0); //0 layers - client will treat this as all-air + } + $subChunkCount = self::getSubChunkCount($chunk); for($y = Chunk::MIN_SUBCHUNK_INDEX, $writtenCount = 0; $writtenCount < $subChunkCount; ++$y, ++$writtenCount){ self::serializeSubChunk($chunk->getSubChunk($y), $blockMapper, $stream, false); } - $stream->put($chunk->getBiomeIdArray()); + + //TODO: right now we don't support 3D natively, so we just 3Dify our 2D biomes so they fill the column + $encodedBiomePalette = self::serializeBiomesAsPalette($chunk); + $stream->put(str_repeat($encodedBiomePalette, 25)); + $stream->putByte(0); //border block array count //Border block entry format: 1 byte (4 bits X, 4 bits Z). These are however useless since they crash the regular client. @@ -116,4 +133,39 @@ final class ChunkSerializer{ return $stream->getBuffer(); } + + private static function serializeBiomesAsPalette(Chunk $chunk) : string{ + $biomeIdMap = LegacyBiomeIdToStringMap::getInstance(); + $biomePalette = new PalettedBlockArray($chunk->getBiomeId(0, 0)); + for($x = 0; $x < 16; ++$x){ + for($z = 0; $z < 16; ++$z){ + $biomeId = $chunk->getBiomeId($x, $z); + if($biomeIdMap->legacyToString($biomeId) === null){ + //make sure we aren't sending bogus biomes - the 1.18.0 client crashes if we do this + $biomeId = BiomeIds::OCEAN; + } + for($y = 0; $y < 16; ++$y){ + $biomePalette->set($x, $y, $z, $biomeId); + } + } + } + + $biomePaletteBitsPerBlock = $biomePalette->getBitsPerBlock(); + $encodedBiomePalette = + chr(($biomePaletteBitsPerBlock << 1) | 1) . //the last bit is non-persistence (like for blocks), though it has no effect on biomes since they always use integer IDs + $biomePalette->getWordArray(); + + //these LSHIFT by 1 uvarints are optimizations: the client expects zigzag varints here + //but since we know they are always unsigned, we can avoid the extra fcall overhead of + //zigzag and just shift directly. + $biomePaletteArray = $biomePalette->getPalette(); + if($biomePaletteBitsPerBlock !== 0){ + $encodedBiomePalette .= Binary::writeUnsignedVarInt(count($biomePaletteArray) << 1); + } + foreach($biomePaletteArray as $p){ + $encodedBiomePalette .= Binary::writeUnsignedVarInt($p << 1); + } + + return $encodedBiomePalette; + } } From aea124af74004a2a52f0caf2befe14a48487531b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 19:17:26 +0000 Subject: [PATCH 431/710] Fix inconsistent class name --- ...yBiomeIdToStringMap.php => LegacyBiomeIdToStringIdMap.php} | 2 +- src/network/mcpe/serializer/ChunkSerializer.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/data/bedrock/{LegacyBiomeIdToStringMap.php => LegacyBiomeIdToStringIdMap.php} (92%) diff --git a/src/data/bedrock/LegacyBiomeIdToStringMap.php b/src/data/bedrock/LegacyBiomeIdToStringIdMap.php similarity index 92% rename from src/data/bedrock/LegacyBiomeIdToStringMap.php rename to src/data/bedrock/LegacyBiomeIdToStringIdMap.php index 2ccdc6abd..e377e371d 100644 --- a/src/data/bedrock/LegacyBiomeIdToStringMap.php +++ b/src/data/bedrock/LegacyBiomeIdToStringIdMap.php @@ -26,7 +26,7 @@ namespace pocketmine\data\bedrock; use pocketmine\utils\SingletonTrait; use Webmozart\PathUtil\Path; -final class LegacyBiomeIdToStringMap extends LegacyToStringBidirectionalIdMap{ +final class LegacyBiomeIdToStringIdMap extends LegacyToStringBidirectionalIdMap{ use SingletonTrait; public function __construct(){ diff --git a/src/network/mcpe/serializer/ChunkSerializer.php b/src/network/mcpe/serializer/ChunkSerializer.php index 2d76f1291..0fe5d891a 100644 --- a/src/network/mcpe/serializer/ChunkSerializer.php +++ b/src/network/mcpe/serializer/ChunkSerializer.php @@ -25,7 +25,7 @@ namespace pocketmine\network\mcpe\serializer; use pocketmine\block\tile\Spawnable; use pocketmine\data\bedrock\BiomeIds; -use pocketmine\data\bedrock\LegacyBiomeIdToStringMap; +use pocketmine\data\bedrock\LegacyBiomeIdToStringIdMap; use pocketmine\nbt\TreeRoot; use pocketmine\network\mcpe\convert\RuntimeBlockMapping; use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer; @@ -135,7 +135,7 @@ final class ChunkSerializer{ } private static function serializeBiomesAsPalette(Chunk $chunk) : string{ - $biomeIdMap = LegacyBiomeIdToStringMap::getInstance(); + $biomeIdMap = LegacyBiomeIdToStringIdMap::getInstance(); $biomePalette = new PalettedBlockArray($chunk->getBiomeId(0, 0)); for($x = 0; $x < 16; ++$x){ for($z = 0; $z < 16; ++$z){ From d560cf17fc2496161c375324ec3fb52f17057c25 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 19:27:04 +0000 Subject: [PATCH 432/710] Release 4.0.0-BETA15 --- changelogs/4.0.md | 7 +++++++ src/VersionInfo.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 27d27ac61..a08f22428 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1758,3 +1758,10 @@ Released 30th November 2021. ## Fixes - Fixed `ConsoleReaderThread` spawning many zombie processes when running a server inside a Docker container. + +# 4.0.0-BETA15 +Released 30th November 2021. + +## General +- Added support for Minecraft: Bedrock 1.18.0 +- Removed support for earlier versions. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 4699d4eb0..08f0f5d36 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.0-BETA15"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "beta"; private function __construct(){ From 2850ea1e892c8af43bbcc42fa272303bc2d58515 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 19:27:05 +0000 Subject: [PATCH 433/710] 4.0.0-BETA16 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 08f0f5d36..5a5b6139b 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA15"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.0-BETA16"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "beta"; private function __construct(){ From baeac2eb07f60c1917d9bb3effb9fdf51690afe4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 22:19:28 +0000 Subject: [PATCH 434/710] Fixed tiles not being sent with chunks --- src/pocketmine/level/format/Chunk.php | 13 ++++++++++++- src/pocketmine/level/format/io/ChunkRequestTask.php | 5 ++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/level/format/Chunk.php b/src/pocketmine/level/format/Chunk.php index 2055862c6..d20f08725 100644 --- a/src/pocketmine/level/format/Chunk.php +++ b/src/pocketmine/level/format/Chunk.php @@ -846,7 +846,7 @@ class Chunk{ /** * Serializes the chunk for sending to players */ - public function networkSerialize() : string{ + public function networkSerialize(?string $networkSerializedTiles) : string{ $result = ""; $subChunkCount = $this->getSubChunkSendCount(); @@ -866,6 +866,17 @@ class Chunk{ $result .= chr(0); //border block array count //Border block entry format: 1 byte (4 bits X, 4 bits Z). These are however useless since they crash the regular client. + $result .= $networkSerializedTiles ?? $this->networkSerializeTiles(); + + return $result; + } + + /** + * Serializes all tiles in network format for chunk sending. This is necessary because fastSerialize() doesn't + * include tiles; they have to be encoded on the main thread. + */ + public function networkSerializeTiles() : string{ + $result = ""; foreach($this->tiles as $tile){ if($tile instanceof Spawnable){ $result .= $tile->getSerializedSpawnCompound(); diff --git a/src/pocketmine/level/format/io/ChunkRequestTask.php b/src/pocketmine/level/format/io/ChunkRequestTask.php index 9cf66ce2b..1d54a2454 100644 --- a/src/pocketmine/level/format/io/ChunkRequestTask.php +++ b/src/pocketmine/level/format/io/ChunkRequestTask.php @@ -39,6 +39,7 @@ class ChunkRequestTask extends AsyncTask{ /** @var string */ protected $chunk; + private string $tiles; /** @var int */ protected $chunkX; /** @var int */ @@ -52,13 +53,15 @@ class ChunkRequestTask extends AsyncTask{ $this->compressionLevel = $level->getServer()->networkCompressionLevel; $this->chunk = $chunk->fastSerialize(); + $this->tiles = $chunk->networkSerializeTiles(); + $this->chunkX = $chunkX; $this->chunkZ = $chunkZ; } public function onRun(){ $chunk = Chunk::fastDeserialize($this->chunk); - $pk = LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $chunk->getSubChunkSendCount() + 4, $chunk->networkSerialize()); + $pk = LevelChunkPacket::withoutCache($this->chunkX, $this->chunkZ, $chunk->getSubChunkSendCount() + 4, $chunk->networkSerialize($this->tiles)); $batch = new BatchPacket(); $batch->addPacket($pk); From 6b7d0307afb36a7faca2dd65734e15000baf17ba Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 22:27:42 +0000 Subject: [PATCH 435/710] Release 3.26.1 --- changelogs/3.26.md | 3 +++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/changelogs/3.26.md b/changelogs/3.26.md index 9ee4332c0..323c49c74 100644 --- a/changelogs/3.26.md +++ b/changelogs/3.26.md @@ -9,3 +9,6 @@ Plugin developers should **only** update their required API to this version if y # 3.26.0 - Added support for Minecraft: Bedrock Edition 1.18.0. - Removed compatibility with earlier versions. + +# 3.26.1 +- Fixed a bug in chunk sending that caused double chests to not be paired, signs to be blank, and various other issues. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index d044a9e13..2473b68b4 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,5 +34,5 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.26.1"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_CHANNEL = "stable"; From 20d6b698139e740545f15584aa5a1fef09c2b4c6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 22:27:42 +0000 Subject: [PATCH 436/710] 3.26.2 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 2473b68b4..8699310ef 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.26.1"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.26.2"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_CHANNEL = "stable"; From 7665f4f443447b8c1584df794768948eb2804a51 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 23:43:17 +0000 Subject: [PATCH 437/710] start.sh: remove 7 --- start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.sh b/start.sh index fe4d95a8e..087b53db8 100755 --- a/start.sh +++ b/start.sh @@ -26,7 +26,7 @@ if [ "$PHP_BINARY" == "" ]; then elif [[ ! -z $(type php) ]]; then PHP_BINARY=$(type -p php) else - echo "Couldn't find a working PHP 7 binary, please use the installer." + echo "Couldn't find a working PHP binary, please use the installer." exit 1 fi fi From d535f020968db99fc4424f4123ab0642c7512fa1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 23:45:25 +0000 Subject: [PATCH 438/710] Make nicer errors for PHP binary not being found --- start.cmd | 17 +++++++++++++++-- start.ps1 | 7 ++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/start.cmd b/start.cmd index 929e5f7bb..747716ff8 100644 --- a/start.cmd +++ b/start.cmd @@ -2,11 +2,24 @@ TITLE PocketMine-MP server software for Minecraft: Bedrock Edition cd /d %~dp0 +set PHP_BINARY= + +where /q php.exe +if %ERRORLEVEL%==0 ( + set PHP_BINARY=php +) + if exist bin\php\php.exe ( + rem always use the local PHP binary if it exists set PHPRC="" set PHP_BINARY=bin\php\php.exe -) else ( - set PHP_BINARY=php +) + +if "%PHP_BINARY%"=="" ( + echo Couldn't find a PHP binary in system PATH or %~dp0\bin\php + echo Please refer to the installation instructions at https://doc.pmmp.io/en/rtfd/installation.html + pause + exit 1 ) if exist PocketMine-MP.phar ( diff --git a/start.ps1 b/start.ps1 index 2528dd691..19b2a6158 100644 --- a/start.ps1 +++ b/start.ps1 @@ -11,8 +11,13 @@ if($php -ne ""){ }elseif(Test-Path "bin\php\php.exe"){ $env:PHPRC = "" $binary = "bin\php\php.exe" -}else{ +}elseif((Get-Command php -ErrorAction SilentlyContinue)){ $binary = "php" +}else{ + echo "Couldn't find a PHP binary in system PATH or $pwd\bin\php" + echo "Please refer to the installation instructions at https://doc.pmmp.io/en/rtfd/installation.html" + pause + exit 1 } if($file -eq ""){ From cb0af44ccbdf948d54854fa783766c5771b5b1f8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 Nov 2021 23:51:35 +0000 Subject: [PATCH 439/710] start.sh: improve errors when PHP isn't found --- start.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/start.sh b/start.sh index 087b53db8..63a9a273b 100755 --- a/start.sh +++ b/start.sh @@ -23,10 +23,11 @@ if [ "$PHP_BINARY" == "" ]; then if [ -f ./bin/php7/bin/php ]; then export PHPRC="" PHP_BINARY="./bin/php7/bin/php" - elif [[ ! -z $(type php) ]]; then + elif [[ ! -z $(type php 2> /dev/null) ]]; then PHP_BINARY=$(type -p php) else - echo "Couldn't find a working PHP binary, please use the installer." + echo "Couldn't find a PHP binary in system PATH or $PWD/bin/php7/bin" + echo "Please refer to the installation instructions at https://doc.pmmp.io/en/rtfd/installation.html" exit 1 fi fi From 06e70308179875e3c05326758750694029bc25cb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 1 Dec 2021 22:09:34 +0000 Subject: [PATCH 440/710] Prepare changelog for 4.0.0 --- changelogs/4.0-beta.md | 1767 ++++++++++++++++++++++++++++++++++++++++ changelogs/4.0.md | 1082 ++++++++++-------------- 2 files changed, 2185 insertions(+), 664 deletions(-) create mode 100644 changelogs/4.0-beta.md diff --git a/changelogs/4.0-beta.md b/changelogs/4.0-beta.md new file mode 100644 index 000000000..a08f22428 --- /dev/null +++ b/changelogs/4.0-beta.md @@ -0,0 +1,1767 @@ +# 4.0.0-BETA1 +Released 7th September 2021. + +This major version features substantial changes throughout the core, including significant API changes, new world format support, performance improvements and a network revamp. + +Please note that this is a BETA release and is not finalized. While no significant changes are expected between now and release, the API might still be changed. + +Please also note that this changelog is provided on a best-effort basis, and it's possible some changes might not have been mentioned here. +If you find any omissions, please submit pull requests to add them. + +## WARNING +This is NOT a stable release. PMMP accepts no responsibility or liability for any damages incurred by using this build. +It should be used for TESTING purposes only. + +## Contents + * [Core](#core) + + [General](#general) + + [Configuration](#configuration) + + [World handling](#world-handling) + - [Interface](#interface) + - [Functional](#functional) + - [Performance](#performance) + + [Logger revamp](#logger-revamp) + + [Network](#network) + - [Minecraft Bedrock packet encryption](#minecraft-bedrock-packet-encryption) + - [Packet receive error handling has been overhauled](#packet-receive-error-handling-has-been-overhauled) + - [New packet handler system](#new-packet-handler-system) + * [API](#api) + + [General](#general-1) + + [Changes to `plugin.yml`](#changes-to-pluginyml) + - [Permission nesting](#permission-nesting) + - [`src-namespace-prefix`](#src-namespace-prefix) + + [Block](#block) + + [Command](#command) + + [Entity](#entity) + - [General](#general-2) + - [Effect](#effect) + - [Removal of runtime entity NBT](#removal-of-runtime-entity-nbt) + - [Entity creation](#entity-creation) + - [WIP removal of entity network metadata](#wip-removal-of-entity-network-metadata) + + [Event](#event) + - [Internal event system no longer depends on `Listener`s](#internal-event-system-no-longer-depends-on-listeners) + - [Default cancelled handling behaviour has changed](#default-cancelled-handling-behaviour-has-changed) + - [`PlayerPreLoginEvent` changes](#playerpreloginevent-changes) + - [Other changes](#other-changes) + + [Inventory](#inventory) + + [Item](#item) + - [General](#general-3) + - [NBT handling](#nbt-handling) + - [Enchantment](#enchantment) + + [Lang](#lang) + + [Network](#network-1) + + [Permission](#permission) + + [Player](#player) + + [Plugin](#plugin) + + [Scheduler](#scheduler) + - [Thread-local storage for AsyncTasks](#thread-local-storage-for-asynctasks) + - [Other changes](#other-changes-1) + + [Server](#server) + + [Level / World](#level--world) + - [General](#general-4) + - [Particles](#particles) + - [Sounds](#sounds) + + [Utils](#utils) + * [Gameplay](#gameplay) + + [Blocks](#blocks) + + [Items](#items) + +Table of contents generated with markdown-toc + +## Core +### General +- A new "plugin greylist" feature has been introduced, which allows whitelisting or blacklisting plugins from loading. +- Remote console (RCON) has been removed. The [RconServer](https://github.com/pmmp/RconServer) plugin is provided as a substitute. +- Spawn protection has been removed. The [BasicSpawnProtection](https://github.com/pmmp/BasicSpawnProtection) plugin is provided as a substitute. +- CTRL+C signal handling has been removed. The [PcntlSignalHandler](https://github.com/pmmp/PcntlSignalHandler) plugin is provided as a substitute. +- Player movement anti-cheat has been removed. +- GS4 Query no longer breaks when disabling RakLib. +- The `pocketmine_chunkutils` PHP extension has been dropped. +- New PHP extensions are required by this version: + - [chunkutils2](https://github.com/pmmp/ext-chunkutils2) + - [morton](https://github.com/pmmp/ext-morton) +- Many bugs in player respawning have been fixed, including: + - Spawning underneath bedrock when spawn position referred to ungenerated terrain + - Spawning underneath bedrock on first server join on very slow machines (or when the machine was under very high load) + - Spawning inside blocks (or above the ground) when respawning with a custom spawn position set + - Player spawn positions sticking to the old location when world spawn position changed - this was because the world spawn at time of player creation was used as the player's custom spawn, so the bug will persist for older player data, but will work as expected for new players. +- PreProcessor is removed from builds due to high maintenance cost and low benefit. Its usage is now discouraged. + +### Commands +- The `/reload` command has been removed. +- The `/effect` command no longer supports numeric IDs - it's now required to use names. +- The `/enchant` command no longer supports numeric IDs - it's now required to use names. +- Added `/clear` command with functionality equivalent to that of vanilla Minecraft. +- The following commands' outputs are now localized according to the chosen language settings: + - `/gc` + - `/status` + - `/op` + - `/deop` + +### Configuration +- World presets can now be provided as a `preset` key in `pocketmine.yml`, instead of putting them in the `generator` key. +- The following new options have been added to `pocketmine.yml`: + - `chunk-ticking.blocks-per-subchunk-per-tick` (default `3`): Increasing this value will increase the rate at which random block updates happen (e.g. grass growth). + - `network.enable-encryption` (default `true`): Controls whether Minecraft network packets are encrypted or not. +- The following options have been removed from `pocketmine.yml`: + - `chunk-ticking.light-updates`: Since lighting is needed for basic vanilla functionality to work, allowing this to be disabled without disabling chunk ticking made no sense. If you don't want light calculation to occur, you can disable chunk ticking altogether. + - `player.anti-cheat.allow-movement-cheats` + +### World handling +#### Interface +- Progress of spawn terrain chunk generation is now logged during initial world creation. + +#### Functional +- Minecraft Bedrock worlds up to 1.12.x are now supported. (1.13+ are still **not supported** due to yet another format change, which is large and requires a lot of work). +- Automatic conversion of deprecated world formats is now implemented. +- All formats except `leveldb` have been deprecated. The following world formats will be **automatically converted on load to a new format**: + - `mcregion` + - `anvil` + - `pmanvil` +- 256 build-height is now supported in all worlds (facilitated by automatic conversion). +- Extended blocks are now supported (facilitated by automatic conversion). +- Lighting is no longer stored or loaded from disk - instead, it's calculated on the fly as-needed. This fixes many long-standing bugs. + +#### Performance +- `leveldb` is now the primary supported world format. It is inherently faster than region-based formats thanks to better design. +- Partial chunk saves (only saving modified subcomponents of chunks) has been implemented. This drastically reduces the amount of data that is usually necessary to write on chunk save, which in turn **drastically reduces the time to complete world saves**. This is possible thanks to the modular design of the `leveldb` world format - this enhancement is not possible with region-based formats. +- Lighting is no longer guaranteed to be available on every chunk. It's now calculated on the fly as-needed. +- `/op`, `/deop`, `/whitelist add` and `/whitelist remove` no longer cause player data to be loaded from disk for no reason. +- Timings now use high-resolution timers provided by `hrtime()` to collect more accurate performance metrics. +- Z-order curves (morton codes) are now used for block and chunk coordinate hashes. This substantially improves performance in many areas by resolving a hashtable key hash collision performance issue. Affected areas include explosions, light calculation, and more. +- [`libdeflate`](https://github.com/ebiggers/libdeflate) is now (optionally) used for outbound Minecraft packet compression. It's more than twice as fast as zlib in most cases, providing significant performance boosts to packet broadcasts and overall network performance. +- Closures are now used for internal event handler calls. This provides a performance improvement of 10-20% over the 3.x system, which had to dynamically resolve callables for every event call. + +### Logger revamp +- Many components now have a dedicated logger which automatically adds [prefixes] to their messages. +- Main logger now includes milliseconds in timestamps. + +### Network +This version features substantial changes to the network system, improving coherency, reliability and modularity. + +#### Minecraft Bedrock packet encryption +- This fixes replay attacks where hackers steal and replay player logins. +- A new setting has been added to `pocketmine.yml`: `network.enable-encryption` which is `true` by default. + +#### Packet receive error handling has been overhauled +- Only `BadPacketException` is now caught during packet decode and handling. This requires that all decoding MUST perform proper data error checking. + - Throwing a `BadPacketException` from decoding will now cause players to be kicked with the message `Packet processing error`. + - The disconnect message includes a random hex ID to help server owners identify the problems reported by their players. +- Throwing any other exception will now cause a server crash. `Internal server error` has been removed. +- It is now illegal to send a clientbound packet to the server. Doing so will result in the client being kicked with the message `Unexpected non-serverbound packet`. + +#### New packet handler system +- Packet handlers have been separated from NetworkSession into a dedicated packet handler structure. +- A network session may have exactly 1 handler at a time, which is mutable and may be replaced at any time. This allows packet handling logic to be broken up into multiple stages: + - preventing undefined behaviour when sending wrong packets at the wrong time (they'll now be silently dropped) + - allowing the existence of ephemeral state-specific logic (for example stricter resource packs download checks) +- Packet handlers are now almost entirely absent from `Player` and instead appear in their own dedicated units. +- Almost all game logic that was previously locked up inside packet handlers in `Player` has been extracted into new API methods. See Player API changes for details. + +## API +### General +- Most places which previously allowed `callable` now only allow `\Closure`. This is because closures have more consistent behaviour and are more performant. +- `void` and `?nullable` parameter and return types have been applied in many places. +- Everything in the `pocketmine\metadata` namespace and related implementations have been removed. + +### Changes to `plugin.yml` +#### Permission nesting +Permission nesting is no longer supported in `plugin.yml`. Grouping permissions (with defaults) in `plugin.yml` had very confusing and inconsistent behaviour. +Instead of nesting permission declarations, they should each be declared separately. + +_Before_: +``` +permissions: + pmmp: + default: op + children: + pmmp.something: + default: op + pmmp.somethingElse + default: op +``` + +_After_: +``` +permissions: + pmmp.something: + default: op + pmmp.somethingElse + default: op +``` + +#### `src-namespace-prefix` +A new directive `src-namespace-prefix` has been introduced. This allows you to get rid of those useless subdirectories in a plugin's structure. +For example, a plugin whose main was `pmmp\TesterPlugin\Main` used to have to be structured like this: +``` +|-- plugin.yml +|-- src/ + |-- pmmp/ + |-- TesterPlugin/ + |-- Main.php + |-- SomeOtherClass.php + |-- SomeNamespace/ + |-- SomeNamespacedClass.php +``` +However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml`, now we can get rid of the useless directories and structure it like this instead: +``` +|-- plugin.yml +|-- src/ + |-- Main.php + |-- SomeOtherClass.php + |-- SomeNamespace/ + |-- SomeNamespacedClass.php +``` + +**Note**: The old structure will also still work just fine. This is not a required change. + +### Block +- A new `VanillaBlocks` class has been added, which contains static methods for creating any currently-known block type. This should be preferred instead of use of `BlockFactory::get()` where constants were used. +- Blocks now contain their positions instead of extending `Position`. `Block->getPosition()` has been added. +- Blocks with IDs >= 256 are now supported. +- Block state and variant metadata have been separated. + - Variant is considered an extension of ID and is immutable. + - `Block->setDamage()` has been removed. + - All blocks now have getters and setters for their appropriate block properties, such as facing, lit/unlit, colour (in some cases), and many more. These should be used instead of metadata. +- Tile entities are now created and deleted automatically when `World->setBlock()` is used with a block that requires a tile entity. +- Some tile entities' API has been exposed on their corresponding `Block` classes, with the tile entity classes being deprecated. +- The `pocketmine\tile` namespace has been relocated to `pocketmine\block\tile`. +- `Block->recalculateBoundingBox()` and `Block->recalculateCollisionBoxes()` are now expected to return AABBs relative to `0,0,0` instead of their own position. +- Block break-info has been extracted into a new dynamic `BlockBreakInfo` unit. The following methods have been moved: + - `Block->getBlastResistance()` -> `BlockBreakInfo->getBlastResistance()` + - `Block->getBreakTime()` -> `BlockBreakInfo->getBreakTime()` + - `Block->getHardness()` -> `BlockBreakInfo->getHardness()` + - `Block->getToolHarvestLevel()` -> `BlockBreakInfo->getToolHarvestLevel()` + - `Block->getToolType()` -> `BlockBreakInfo->getToolType()` + - `Block->isBreakable()` -> `BlockBreakInfo->isBreakable()` + - `Block->isCompatibleWithTool()` -> `BlockBreakInfo->isToolCompatible()` +- The following API methods have been added: + - `Block->asItem()`: returns an itemstack corresponding to the block + - `Block->isSameState()`: returns whether the block is the same as the parameter, including state information + - `Block->isSameType()`: returns whether the block is the same as the parameter, without state information + - `Block->isFullCube()` +- The following hooks have been added: + - `Block->onAttack()`: called when a player in survival left-clicks the block to try to start breaking it + - `Block->onEntityLand()`: called when an entity lands on this block after falling (from any distance) + - `Block->onPostPlace()`: called directly after placement in the world, handles things like rail connections and chest pairing +- The following API methods have been renamed: + - `Block->getDamage()` -> `Block->getMeta()` + - `Block->onActivate()` -> `Block->onInteract()` + - `Block->onEntityCollide()` -> `Block->onEntityInside()` +- The following API methods have changed signatures: + - `Block->onInteract()` now has the signature `onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool` + - `Block->getCollisionBoxes()` is now final. Classes should override `recalculateCollisionBoxes()`. +- The following API methods have been removed: + - `Block->canPassThrough()` + - `Block->setDamage()` + - `Block::get()`: this was superseded by `BlockFactory::get()` a long time ago + - `Block->getBoundingBox()` +- The following classes have been renamed: + - `BlockIds` -> `BlockLegacyIds` + - `CobblestoneWall` -> `Wall` + - `NoteBlock` -> `Note` + - `SignPost` -> `Sign` + - `StandingBanner` -> `Banner` +- The following classes have been removed: + - `Bricks` + - `BurningFurnace` + - `CobblestoneStairs` + - `Dandelion` + - `DoubleSlab` + - `DoubleStoneSlab` + - `EndStone` + - `GlowingRedstoneOre` + - `GoldOre` + - `Gold` + - `IronDoor` + - `IronOre` + - `IronTrapdoor` + - `Iron` + - `Lapis` + - `NetherBrickFence` + - `NetherBrickStairs` + - `Obsidian` + - `PurpurStairs` + - `Purpur` + - `QuartzStairs` + - `Quartz` + - `RedSandstoneStairs` + - `RedSandstone` + - `SandstoneStairs` + - `Sandstone` + - `StainedClay` + - `StainedGlassPane` + - `StainedGlass` + - `StoneBrickStairs` + - `StoneBricks` + - `StoneSlab2` + - `StoneSlab` + - `Stone` + - `WallBanner` + - `WallSign` + - `Wood2` +- `BlockToolType` constants have been renamed to remove the `TYPE_` prefix. + +### Command +- The following classes have been removed: + - `RemoteConsoleCommandSender` +- The following API methods have signature changes: + - `Command->setPermission()` argument is now mandatory (but still nullable). + - `CommandSender->setScreenLineHeight()` argument is now mandatory (but still nullable). +- Commands with spaces in the name are no longer supported. + +### Entity +#### General +- `Entity` no longer extends from `Location`. `Entity->getLocation()` and `Entity->getPosition()` should be used instead. +- Ender inventory has been refactored. It's now split into two parts: + - `EnderChestInventory` is a temporary gateway "inventory" that acts as a proxy to the player's ender inventory. It has a `Position` for holder. This is discarded when the player closes the inventory window. + - `PlayerEnderInventory` is the storage part. This is stored in `Human` and does not contain any block info. + - To open the player's ender inventory, use `Player->setCurrentWindow(new EnderChestInventory($blockPos, $player->getEnderInventory()))`. +- The following public fields have been removed: + - `Entity->chunk`: Entities no longer know which chunk they are in (the `World` now manages this instead). + - `Entity->height`: moved to `EntitySizeInfo`; use `Entity->size` instead + - `Entity->width`: moved to `EntitySizeInfo`; use `Entity->size` instead + - `Entity->eyeHeight`: moved to `EntitySizeInfo`; use `Entity->size` instead +- The following API methods have been added: + - `Entity->getFallDistance()` + - `Entity->setFallDistance()` + - `ItemEntity->getDespawnDelay()` + - `ItemEntity->setDespawnDelay()` + - `Living->calculateFallDamage()`: this is `protected`, and may be overridden by subclasses to provide custom damage logic + - `Human->getHungerManager()` + - `Human->getXpManager()` +- The following methods have signature changes: + - `Entity->entityBaseTick()` is now `protected`. + - `Entity->move()` is now `protected`. + - `Entity->setPosition()` is now `protected` (use `Entity->teleport()` instead). + - `Entity->setPositionAndRotation()` is now `protected` (use `Entity->teleport()` instead). + - `Living->knockBack()` now accepts `float, float, float` (the first two parameters have been removed). + - `Living->getEffects()` now returns `EffectManager` instead of `Effect[]`. +- The following classes have been added: + - `effect\EffectManager`: contains effect-management functionality extracted from `Living` + - `HungerManager`: contains hunger-management functionality extracted from `Human` + - `ExperienceManager`: contains XP-management functionality extracted from `Human` +- The following API methods have been moved / renamed: + - `Entity->fall()` -> `Entity->onHitGround()` (and visibility changed to `protected` from `public`) + - `Living->removeAllEffects()` -> `EffectManager->clear()` + - `Living->removeEffect()` -> `EffectManager->remove()` + - `Living->addEffect()` -> `EffectManager->add()` + - `Living->getEffect()` -> `EffectManager->get()` + - `Living->hasEffect()` -> `EffectManager->has()` + - `Living->hasEffects()` -> `EffectManager->hasEffects()` + - `Living->getEffects()` -> `EffectManager->all()` + - `Human->getFood()` -> `HungerManager->getFood()` + - `Human->setFood()` -> `HungerManager->setFood()` + - `Human->getMaxFood()` -> `HungerManager->getMaxFood()` + - `Human->addFood()` -> `HungerManager->addFood()` + - `Human->isHungry()` -> `HungerManager->isHungry()` + - `Human->getEnderChestInventory()` -> `Human->getEnderInventory()` + - `Human->getSaturation()` -> `HungerManager->getSaturation()` + - `Human->setSaturation()` -> `HungerManager->setSaturation()` + - `Human->addSaturation()` -> `HungerManager->addSaturation()` + - `Human->getExhaustion()` -> `HungerManager->getExhaustion()` + - `Human->setExhaustion()` -> `HungerManager->setExhaustion()` + - `Human->exhaust()` -> `HungerManager->exhaust()` + - `Human->getXpLevel()` -> `ExperienceManager->getXpLevel()` + - `Human->setXpLevel()` -> `ExperienceManager->setXpLevel()` + - `Human->addXpLevels()` -> `ExperienceManager->addXpLevels()` + - `Human->subtractXpLevels()` -> `ExperienceManager->subtractXpLevels()` + - `Human->getXpProgress()` -> `ExperienceManager->getXpProgress()` + - `Human->setXpProgress()` -> `ExperienceManager->setXpProgress()` + - `Human->getRemainderXp()` -> `ExperienceManager->getRemainderXp()` + - `Human->getCurrentTotalXp()` -> `ExperienceManager->getCurrentTotalXp()` + - `Human->setCurrentTotalXp()` -> `ExperienceManager->setCurrentTotalXp()` + - `Human->addXp()` -> `ExperienceManager->addXp()` + - `Human->subtractXp()` -> `ExperienceManager->subtractXp()` + - `Human->getLifetimeTotalXp()` -> `ExperienceManager->getLifetimeTotalXp()` + - `Human->setLifetimeTotalXp()` -> `ExperienceManager->setLifetimeTotalXp()` + - `Human->canPickupXp()` -> `ExperienceManager->canPickupXp()` + - `Human->onPickupXp()` -> `ExperienceManager->onPickupXp()` + - `Human->resetXpCooldown()` -> `ExperienceManager->resetXpCooldown()` +- The following API methods have been removed: + - `Human->getRawUniqueId()`: use `Human->getUniqueId()->toBinary()` instead +- The following classes have been removed: + - `Creature` + - `Damageable` + - `Monster` + - `NPC` + - `Rideable` + - `Vehicle` +- `Skin` now throws exceptions on creation if given invalid data. + +#### Effect +- All `Effect` related classes have been moved to the `pocketmine\entity\effect` namespace. +- Effect functionality embedded in the `Effect` class has been separated out into several classes. The following classes have been added: + - `AbsorptionEffect` + - `HealthBoostEffect` + - `HungerEffect` + - `InstantDamageEffect` + - `InstantEffect` + - `InstantHealthEffect` + - `InvisibilityEffect` + - `LevitationEffect` + - `PoisonEffect` + - `RegenerationEffect` + - `SaturationEffect` + - `SlownessEffect` + - `SpeedEffect` + - `WitherEffect` +- `VanillaEffects` class has been added. This exposes all vanilla effect types as static methods, replacing the old `Effect::getEffect()` nastiness. + - Example: `Effect::getEffect(Effect::NIGHT_VISION)` can be replaced by `VanillaEffects::NIGHT_VISION()`. +- Negative effect amplifiers are now explicitly disallowed due to undefined behaviour they created. +- The boundaries between MCPE effect IDs and PocketMine-MP internals are now more clear. + - ID handling is moved to `pocketmine\data\bedrock\EffectIdMap`. + - All effect ID constants have been removed from `Effect`. `pocketmine\data\bedrock\EffectIds` if you still need legacy effect IDs for some reason. +- The following API methods have been moved: + - `Effect->getId()` -> `EffectIdMap->toId()` + - `Effect::registerEffect()` -> `EffectIdMap->register()` + - `Effect::getEffect()` -> `EffectIdMap->fromId()` + - `Effect::getEffectByName()` -> `VanillaEffects::fromString()` +- The following API methods have been added: + - `Effect->getRuntimeId()`: this is a **dynamic ID** which can be used for effect type comparisons. **This cannot be stored, so don't use it in configs or NBT!** + +#### Removal of runtime entity NBT +- Entities no longer keep their NBT alive at runtime. + - `Entity->namedtag` has been removed. + - `Entity->saveNBT()` now returns a newly created `CompoundTag` instead of modifying the previous one in-place. + - `Entity->initEntity()` now accepts a `CompoundTag` parameter. + +#### Entity creation +- `Entity::createEntity()` has been removed. It's no longer needed for creating new entities at runtime - just use `new YourEntity` instead. +- `Entity` subclass constructors can now have any signature, just like a normal class. +- Loading entities from NBT is now handled by `EntityFactory`. It works quite a bit differently than `Entity::createEntity()` did. Instead of registering `YourEntity::class` to a set of Minecraft save IDs, you now need to provide a callback which will construct an entity when given some NBT and a `World`. + - The creation callback is registered using `EntityFactory::register()`. + - The creation callback must have the signature `function(World, CompoundTag) : Entity`. + - This enables `Entity` subclasses to have any constructor parameters they like. + - It also allows requiring that certain data is always provided (for example, it doesn't make much sense to create a `FallingBlock` without specifying what type of block). + - Examples: + - `ItemEntity` now requires an `Item` in its constructor, so its creation callback decodes the `Item` from the NBT to be passed to the constructor. + - `Painting` now requires a `PaintingMotive` in its constructor, so its creation callback decides which `PaintingMotive` to provide based on the NBT it receives. + - See `EntityFactory` for more examples. +- `EntityFactory::register()` (previously `Entity::registerEntity()`) will now throw exceptions on error cases instead of returning `false`. +- The following API methods have been moved: + - `Entity::registerEntity()` -> `EntityFactory::register()` +- The following classes have changed constructors: + - All projectile subclasses now require a `?Entity $thrower` parameter. + - `Arrow->__construct()` now requires a `bool $critical` parameter (in addition to the `$thrower` parameter). + - `ExperienceOrb->__construct()` now requires a `int $xpValue` parameter. + - `FallingBlock->__construct()` now requires a `Block $block` parameter. + - `ItemEntity->__construct()` now requires an `Item $item` parameter. + - `Painting->__construct()` now requires a `PaintingMotive $motive` parameter. + - `SplashPotion->__construct()` now requires a `int $potionId` parameter. +- The following API methods have been removed: + - `Entity::createBaseNBT()`: `new YourEntity` and appropriate API methods should be used instead + - `Entity->getSaveId()` + - `Entity::getKnownEntityTypes()` + - `Entity::createEntity()`: use `new YourEntity` instead (to be reviewed) + +#### WIP removal of entity network metadata +- All network metadata related constants have been removed from the `Entity` class and moved to the protocol layer. It is intended to remove network metadata from the API entirely, but this has not yet been completed. + - `Entity::DATA_FLAG_*` constants have been moved to `pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags`. + - `Entity::DATA_TYPE_*` constants have been moved to `pocketmine\network\mcpe\protocol\types\entity\EntityMetadataTypes`. + - `Entity::DATA_*` constants have been moved to `pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties`. +- `DataPropertyManager` has been moved to the `pocketmine\network\mcpe\protocol\types\entity` namespace, and as such isn't considered part of the API anymore. +- Introduced internal `Entity` hook `syncNetworkData()`. This function is expected to synchronize entity properties with the entity's network data set. +- Internal usage of network metadata sets to store internal entity properties has been removed. Entities are now expected to use regular class properties and synchronize with the network data set as-asked. +- `Entity->propertyManager` has been renamed to `Entity->networkProperties`. +- `Entity->getDataPropertyManager()` has been renamed to `Entity->getNetworkProperties()`. + +### Event +#### Internal event system no longer depends on `Listener`s +- The internal event processing system no longer depends on `Listener` objects. Arbitrary closures can now be used, provided that they satisfy the standard requirements to be a handler. + - This change improves performance of event handler calling by approximately 15%. This does not include anything plugins are doing. + - The following classes have been removed: + - `pocketmine\plugin\EventExecutor` + - `pocketmine\plugin\MethodEventExecutor` + - `RegisteredListener->__construct()` now requires `Closure` instead of `Listener, EventExecutor` as the leading parameters. + - `RegisteredListener->getListener()` has been removed. + +#### Default cancelled handling behaviour has changed +- Handler functions will now **not receive cancelled events by default**. This is a **silent BC break**, i.e. it won't raise errors, but it might cause bugs. +- `@ignoreCancelled` is now no longer respected. +- `@handleCancelled` has been added. This allows opting _into_ receiving cancelled events (it's the opposite of `@ignoreCancelled`). + +#### `PlayerPreLoginEvent` changes +- The `Player` object no longer exists at this phase of the login. Instead, a `PlayerInfo` object is provided, along with connection information. +- Ban, server-full and whitelist checks are now centralized to `PlayerPreLoginEvent`. It's no longer necessary (or possible) to intercept `PlayerKickEvent` to handle these types of disconnects. + - Multiple kick reasons may be set to ensure that the player is still removed if there are other reasons for them to be disconnected and one of them is cleared. For example, if a player is banned and the server is full, clearing the ban flag will still cause the player to be disconnected because the server is full. + - Plugins may set custom kick reasons. Any custom reason has absolute priority. + - If multiple flags are set, the kick message corresponding to the highest priority reason will be shown. The priority (as of this snapshot) is as follows: + - Custom (highest priority) + - Server full + - Whitelisted + - Banned + - The `PlayerPreLoginEvent::KICK_REASON_PRIORITY` constant contains a list of kick reason priorities, highest first. +- The following constants have been added: + - `PlayerPreLoginEvent::KICK_REASON_PLUGIN` + - `PlayerPreLoginEvent::KICK_REASON_SERVER_FULL` + - `PlayerPreLoginEvent::KICK_REASON_SERVER_WHITELISTED` + - `PlayerPreLoginEvent::KICK_REASON_BANNED` + - `PlayerPreLoginEvent::KICK_REASON_PRIORITY`: ordered list of kick reason priorities, highest first +- The following API methods have been added: + - `PlayerPreLoginEvent->clearAllKickReasons()` + - `PlayerPreLoginEvent->clearKickReason()` + - `PlayerPreLoginEvent->getFinalKickMessage()`: the message to be shown to the player with the current reason list in place + - `PlayerPreLoginEvent->getIp()` + - `PlayerPreLoginEvent->getKickReasons()`: returns an array of flags indicating kick reasons, must be empty to allow joining + - `PlayerPreLoginEvent->getPlayerInfo()` + - `PlayerPreLoginEvent->getPort()` + - `PlayerPreLoginEvent->isAllowed()` + - `PlayerPreLoginEvent->isAuthRequired()`: whether XBL authentication will be enforced + - `PlayerPreLoginEvent->isKickReasonSet()` + - `PlayerPreLoginEvent->setAuthRequired()` + - `PlayerPreLoginEvent->setKickReason()` +- The following API methods have been changed: + - `PlayerPreLoginEvent->getKickMessage()` now has the signature `getKickMessage(int $flag) : ?string` +- The following API methods have been removed: + - `PlayerPreLoginEvent->setKickMessage()` + - `PlayerPreLoginEvent->getPlayer()` +- The following API methods have been moved / renamed: + - `InventoryPickupItemEvent->getItem()` -> `InventoryPickupItemEvent->getItemEntity()` + +#### Other changes +- Disconnecting players during events no longer crashes the server (although it might cause other side effects). +- `PlayerKickEvent` is no longer fired for disconnects that occur before the player completes the initial login sequence (i.e. completing downloading resource packs). +- Cancellable events must now implement `CancellableTrait` to get the cancellable components needed to satisfy interface requirements. `Event` no longer stubs these methods. +- `PlayerInteractEvent` is no longer fired when a player activates an item. This fixes the age-old complaint of `PlayerInteractEvent` firing multiple times when interacting once. The following constants have been removed: + - `PlayerInteractEvent::LEFT_CLICK_AIR` + - `PlayerInteractEvent::RIGHT_CLICK_AIR` + - `PlayerInteractEvent::PHYSICAL` +- The following events have been added: + - `PlayerEntityInteractEvent`: player right-clicking (or long-clicking on mobile) on an entity. + - `PlayerItemUseEvent`: player activating their held item, for example to throw it. + - `BlockTeleportEvent`: block teleporting, for example dragon egg when attacked. + - `PlayerDisplayNameChangeEvent` + - `EntityItemPickupEvent`: player (or other entity) picks up a dropped item (or arrow). Replaces `InventoryPickupItemEvent` and `InventoryPickupArrowEvent`. + - Unlike its predecessors, this event supports changing the destination inventory. + - If the destination inventory is `null`, the item will be destroyed. This is usually seen for creative players with full inventories. + - `EntityTrampleFarmlandEvent`: mob (or player) jumping on farmland causing it to turn to dirt + - `StructureGrowEvent`: called when trees or bamboo grow (or any other multi-block plant structure). +- The following events have been removed: + - `EntityArmorChangeEvent` + - `EntityInventoryChangeEvent` + - `EntityLevelChangeEvent` - `EntityTeleportEvent` with world checks should be used instead. + - `InventoryPickupItemEvent` - use `EntityItemPickupEvent` instead + - `InventoryPickupArrowEvent` - use `EntityItemPickupEvent` instead + - `NetworkInterfaceCrashEvent` + - `PlayerCheatEvent` + - `PlayerIllegalMoveEvent` +- The following API methods have been added: + - `EntityDeathEvent->getXpDropAmount()` + - `EntityDeathEvent->setXpDropAmount()` + - `PlayerDeathEvent->getXpDropAmount()` + - `PlayerDeathEvent->setXpDropAmount()` +- The following API methods have been removed: + - `PlayerPreLoginEvent->getPlayer()` + - `Cancellable->setCancelled()`: this allows implementors of `Cancellable` to implement their own cancellation mechanisms, such as the complex one in `PlayerPreLoginEvent` +- The following API methods have been moved: + - `Event->isCancelled()` -> `CancellableTrait->isCancelled()`: this was a stub which threw `BadMethodCallException` if the class didn't implement `Cancellable`; now this is simply not available on non-cancellable events + - `Event->setCancelled()` has been split into `cancel()` and `uncancel()`, and moved to `CancellableTrait` + - `HandlerList::unregisterAll()` -> `HandlerListManager->unregisterAll()` + - `HandlerList::getHandlerListFor()` -> `HandlerListManager->getListFor()` + - `HandlerList::getHandlerLists()` -> `HandlerListManager->getAll()` +- The following classes have been moved: + - `pocketmine\plugin\RegisteredListener` -> `pocketmine\event\RegisteredListener` + +### Inventory +- All crafting and recipe related classes have been moved to the `pocketmine\crafting` namespace. +- The following classes have been added: + - `CallbackInventoryChangeListener` + - `CreativeInventory`: contains the creative functionality previously embedded in `pocketmine\item\Item`, see Item changes for details + - `InventoryChangeListener`: allows listening (but not interfering with) events in an inventory. + - `PlayerEnderInventory`: represents the pure storage part of the player's ender inventory, without any block information + - `transaction\CreateItemAction` + - `transaction\DestroyItemAction` +- The following classes have been renamed / moved: + - `ContainerInventory` -> `pocketmine\block\inventory\BlockInventory` +- The following classes have been moved to the `pocketmine\block\inventory` namespace: + - `AnvilInventory` + - `ChestInventory` + - `DoubleChestInventory` + - `EnchantInventory` + - `EnderChestInventory` + - `FurnaceInventory` +- The following classes have been removed: + - `CustomInventory` + - `InventoryEventProcessor` + - `Recipe` + - `transaction\CreativeInventoryAction` +- The following API methods have been added: + - `Inventory->addChangeListeners()` + - `Inventory->getChangeListeners()` + - `Inventory->removeChangeListeners()` + - `Inventory->swap()`: swaps the contents of two slots +- The following API methods have been removed: + - `BaseInventory->getDefaultSize()` + - `BaseInventory->setSize()` + - `EnderChestInventory->setHolderPosition()` + - `Inventory->close()` + - `Inventory->dropContents()` + - `Inventory->getName()` + - `Inventory->getTitle()` + - `Inventory->onSlotChange()` + - `Inventory->open()` + - `Inventory->sendContents()` + - `Inventory->sendSlot()` + - `InventoryAction->onExecuteFail()` + - `InventoryAction->onExecuteSuccess()` + - `PlayerInventory->sendCreativeContents()` +- The following API methods have signature changes: + - `Inventory->clear()` now returns `void` instead of `bool`. + - `Inventory->setItem()` now returns `void` instead of `bool`. + - `InventoryAction->execute()` now returns `void` instead of `bool`. + - `BaseInventory->construct()` no longer accepts a list of items to initialize with. +- `PlayerInventory->setItemInHand()` now sends the update to viewers of the player. + +### Item +#### General +- A new `VanillaItems` class has been added, which contains static methods for creating any currently-known item type. This should be preferred instead of use of `ItemFactory::get()` where constants were used. +- `StringToItemParser` has been added, which allows mapping any string to any item, irrespective of IDs. These mappings are used by `/give` and `/clear`, and are made with custom plugin aliases in mind. + - Yes, this means you can finally add your own custom aliases to `/give` without ugly hacks! +- `LegacyStringToItemParser` has been added, which is a slightly more dynamic (but still inadvisable) replacement for `ItemFactory::fromString()`. +- `Item->count` is no longer public. +- The hierarchy of writable books has been changed: `WritableBook` and `WrittenBook` now extend `WritableBookBase`. +- The following API methods have signature changes: + - `WritableBookBase->setPages()` now accepts `WritableBookPage[]` instead of `CompoundTag[]`. + - `ItemFactory::get()` no longer accepts `string` for the `tags` parameter. + - `ItemFactory::fromString()` no longer accepts a `$multiple` parameter and now only returns `Item`, not `Item|Item[]`. +- The following methods are now fluent: + - `WritableBookBase->setPages()` + - `Item->addEnchantment()` + - `Item->removeEnchantment()` + - `Item->removeEnchantments()` + - `Armor->setCustomColor()` + - `WrittenBook->setTitle()` + - `WrittenBook->setAuthor()` + - `WrittenBook->setGeneration()` +- The following API methods have been removed: + - `Item->getNamedTagEntry()` + - `Item->removeNamedTagEntry()` + - `Item->setDamage()`: "Damage" is now immutable for all items except `Durable` descendents. + - `Item->setNamedTagEntry()` + - `Item::get()`: this was superseded by `ItemFactory::get()` a long time ago + - `Item::fromString()`: this was superseded by `ItemFactory::fromString()` a long time ago + - `Item->setCompoundTag()` + - `Item->getCompoundTag()` + - `Item->hasCompoundTag()` + - `Potion::getPotionEffectsById()` + - `ProjectileItem->getProjectileEntityType()` +- The following constants have been removed: + - `Potion::ALL` - use `PotionType::getAll()` instead + - `Potion::WATER` + - `Potion::MUNDANE` + - `Potion::LONG_MUNDANE` + - `Potion::THICK` + - `Potion::AWKWARD` + - `Potion::NIGHT_VISION` + - `Potion::LONG_NIGHT_VISION` + - `Potion::INVISIBILITY` + - `Potion::LONG_INVISIBILITY` + - `Potion::LEAPING` + - `Potion::LONG_LEAPING` + - `Potion::STRONG_LEAPING` + - `Potion::FIRE_RESISTANCE` + - `Potion::LONG_FIRE_RESISTANCE` + - `Potion::SWIFTNESS` + - `Potion::LONG_SWIFTNESS` + - `Potion::STRONG_SWIFTNESS` + - `Potion::SLOWNESS` + - `Potion::LONG_SLOWNESS` + - `Potion::WATER_BREATHING` + - `Potion::LONG_WATER_BREATHING` + - `Potion::HEALING` + - `Potion::STRONG_HEALING` + - `Potion::HARMING` + - `Potion::STRONG_HARMING` + - `Potion::POISON` + - `Potion::LONG_POISON` + - `Potion::STRONG_POISON` + - `Potion::REGENERATION` + - `Potion::LONG_REGENERATION` + - `Potion::STRONG_REGENERATION` + - `Potion::STRENGTH` + - `Potion::LONG_STRENGTH` + - `Potion::STRONG_STRENGTH` + - `Potion::WEAKNESS` + - `Potion::LONG_WEAKNESS` + - `Potion::WITHER` +- The following methods have been renamed: + - `Item->getDamage()` -> `Item->getMeta()` +- The following methods have been moved to `pocketmine\inventory\CreativeInventory`: + - `Item::addCreativeItem()` -> `CreativeInventory::add()` + - `Item::clearCreativeItems()` -> `CreativeInventory::clear()` + - `Item::getCreativeItemIndex()` -> `CreativeInventory::getItemIndex()` + - `Item::getCreativeItems()` -> `CreativeInventory::getAll()` + - `Item::initCreativeItems()` -> `CreativeInventory::init()` + - `Item::isCreativeItem()` -> `CreativeInventory::contains()` + - `Item::removeCreativeItem()` -> `CreativeInventory::remove()` +- The following classes have been added: + - `ArmorTypeInfo` + - `Fertilizer` + - `LiquidBucket` + - `MilkBucket` + - `PotionType`: enum class containing information about vanilla potion types + - `WritableBookBase` + - `WritableBookPage` +- The following API methods have been added: + - `Armor->getArmorSlot()` + - `Item->canStackWith()`: returns whether the two items could be contained in the same inventory slot, ignoring count and stack size limits + - `Potion->getType()`: returns a `PotionType` enum object containing information such as the applied effects + - `ProjectileItem->createEntity()`: returns a new instance of the projectile entity that will be thrown +- The following classes have been removed: + - `ChainBoots` + - `ChainChestplate` + - `ChainHelmet` + - `ChainLeggings` + - `DiamondBoots` + - `DiamondChestplate` + - `DiamondHelmet` + - `DiamondLeggings` + - `GoldBoots` + - `GoldChestplate` + - `GoldHelmet` + - `GoldLeggings` + - `IronBoots` + - `IronChesplate` + - `IronHelmet` + - `IronLeggings` + - `LeatherBoots` + - `LeatherCap` + - `LeatherPants` + - `LeatherTunic` + +#### NBT handling +- Serialized NBT byte array caches are no longer stored on itemstacks. These caches were a premature optimization used for network layer serialization and as such were dependent on the network NBT format. +- Internal NBT usage has been marginalized. It's no longer necessary to immediately write changes to NBT. The following hooks have been added: + - `Item->serializeCompoundTag()` + - `Item->deserializeCompoundTag()` +- It's planned to remove runtime NBT from items completely, but this currently presents unresolved backwards-compatibility problems. + +#### Enchantment +- `VanillaEnchantments` class has been added. This exposes all vanilla enchantment types as static methods, replacing the old `Enchantment::get()` nastiness. + - Example: `Enchantment::get(Enchantment::PROTECTION)` is replaced by `VanillaEnchantments::PROTECTION()` + - These methods also provide proper type information to static analysers instead of just generic `Enchantment`, making them easier to code with. +- The boundaries between MCPE enchantment IDs and PocketMine-MP internals are now more clear. + - ID handling is moved to `pocketmine\data\bedrock\EnchantmentIdMap`. + - All enchantment ID constants have been removed from `Enchantment`. `pocketmine\data\bedrock\EnchantmentIds` if you still need legacy effect IDs for some reason. +- `Enchantment::RARITY_*` constants were moved to `Rarity` class, and the `RARITY_` prefixes removed. +- `Enchantment::SLOT_*` constants were moved to `ItemFlags` class, and the `SLOT_` prefixes removed. +- The following API methods have been moved: + - `Enchantment::registerEnchantment()` -> `EnchantmentIdMap->register()` + - `Enchantment::getEnchantment()` -> `EnchantmentIdMap->fromId()` + - `Enchantment->getId()` -> `EnchantmentIdMap->toId()` + - `Enchantment::getEnchantmentByName()` -> `VanillaEnchantments::fromString()` +- The following API methods have been added: + - `Enchantment->getRuntimeId()`: this is a **dynamic ID** which can be used for enchantment type comparisons. **This cannot be stored, so don't use it in configs or NBT!** + +### Lang +- The following classes have been renamed: + - `BaseLang` -> `Language` + - `TranslationContainer` -> `Translatable` +- The following classes have been removed: + - `TextContainer` +- The following API methods have been added: + - `Translatable->format()`: allows adding formatting (such as color codes) to a translation + - `Translatable->prefix()`: allows prefixing formatting + - `Translatable->postfix()`: allows postfixing formatting +- The following API methods have changed signatures: + - `Translatable->__construct()` now accepts `array` for parameters, instead of just `list`. + - `Translatable->getParameter()` now accepts `int|string` for the index instead of just `int`. + - `Translatable->getParameter()` now returns `Translatable|string` instead of just `string`. + - `Translatable->getParameters()` now returns `array`. +- `LanguageNotFoundException` has been added. This is thrown when trying to construct a `Language` which doesn't exist in the server files. +- `Translatable` no longer discards keys for translation parameters. Previously, only the insertion order was considered. +- `Translatable` now supports string keys for translation parameters. +- `Translatable` now supports providing other `Translatable`s as translation parameters. +- `Language->translateString()` now supports providing `Translatable`s as translation parameters. +- `Language->translateString()` no longer automatically attempts to translate string parameters. If you want them to be translated, translate them explicitly. This fixes bugs where player chat messages containing translation keys would be unexpectedly translated. +- `Language->translate()` no longer attempts to translate string parameters of `Translatable` (same rationale as previous point). + +### Network +- The following fields have been removed: + - `Network::$BATCH_THRESHOLD` +- The following classes have been renamed: + - `SourceInterface` -> `NetworkInterface` + - `AdvancedSourceInterface` -> `AdvancedNetworkInterface` +- The following classes have been moved: + - `CompressBatchedTask` -> `mcpe\CompressBatchTask` + - `level\format\io\ChunkRequestTask` -> `mcpe\ChunkRequestTask` + - `mcpe\RakLibInterface` -> `mcpe\raklib\RakLibInterface` +- The following classes have been removed: + - `mcpe\PlayerNetworkSessionAdapter` +- The following methods have been renamed: + - `UPnP::PortForward()` -> `UPnP::portForward()` + - `UPnP::RemovePortForward()` -> `UPnP::removePortForward()` +- The following methods have changed signatures: + - `UPnP::portForward()` now accepts `string $serviceURL, string $internalIP, int $internalPort, int $externalPort`. + - `UPnP::removePortForward()` now accepts `string $serviceURL, int $externalPort`. +- The following methods have been removed: + - `NetworkInterface->putPacket()` + - `NetworkInterface->close()` + - `NetworkInterface->emergencyShutdown()` +- `NetworkInterface` now represents a more generic interface to be implemented by any network component, as opposed to specifically a player network interface. +- Everything under the `rcon` subnamespace has been removed. +- `upnp\UPnP` has significant changes. It's now a network component instead of a pair of static methods. + +### Permission +- The following new permission nodes have been introduced: + - `pocketmine.group.everyone`: granted to everyone by default + - `pocketmine.group.operator`: granted to operator players and the console + These permission nodes can be assigned and overridden by permission attachments just like any other, which means it's now possible to grant **temporary operator** status which goes away when the player disconnects (or the attachment is removed). +- Permissions are now always false if they haven't been set explictly, or granted implicitly by another permission. +- Undefined permissions are now always `false` instead of following the value of `Permission::$DEFAULT_PERMISSION`. +- Permissions internally no longer have default values. Instead, they are now assigned as a child of one of the `pocketmine.group` permissions: + - `true`: add as child to `pocketmine.group.everyone` with value `true` + - `false`: do not add to any permission + - `op`: add as child to `pocketmine.group.operator` with value `true` + - `notop`: add as child to `pocketmine.group.everyone` with value `true`, and to `pocketmine.group.operator` with value `false` + However, the `default` key in `plugin.yml` permission definitions continues to be supported. +- Added `PermissibleDelegateTrait` to reduce boilerplate for users of `PermissibleBase`. This trait is used by `ConsoleCommandSender` and `Player`. +- The following API methods have been moved: + - `Permission::getByName()` -> `PermissionParser::defaultFromString()` + - `Permission::loadPermissions()` -> `PermissionParser::loadPermissions()` + - `Permission::loadPermission()` -> `PermissionParser::loadPermission()` +- The following constants have been moved: + - `Permission::DEFAULT_FALSE` -> `PermissionParser::DEFAULT_FALSE` + - `Permission::DEFAULT_TRUE` -> `PermissionParser::DEFAULT_TRUE` + - `Permission::DEFAULT_OP` -> `PermissionParser::DEFAULT_OP` + - `Permission::DEFAULT_NOT_OP` -> `PermissionParser::DEFAULT_NOT_OP` +- The following API methods have been added: + - `Permission->addChild()` + - `Permission->removeChild()` + - `Permissible->getPermissionRecalculationCallbacks()` - allows reacting to changes of permissions, such as new permissions being granted or denied + - `Permissible->setBasePermission()` - used for assigning root permissions like `pocketmine.group.operator`; plugins usually shouldn't use this + - `Permissible->unsetBasePermission()` + - `PermissionAttachmentInfo->getGroupPermissionInfo()` - returns the `PermissionAttachmentInfo` of the permission that caused the current permission value to be set, or null if the permission is explicit +- The following API methods have been removed: + - `Permissible->isOp()`: use `Permissible->hasPermission(DefaultPermissions::ROOT_OPERATOR)` instead, **but you really shouldn't directly depend on a player's op status, add your own permissions instead!** + - `Permissible->setOp()`: use `addAttachment($plugin, DefaultPermissions::ROOT_OPERATOR, true)` instead to add, and `removeAttachment()` to remove it (or addAttachment() with false to explicitly deny it, just like any other permission) + - `Permission->addParent()` + - `Permission->getDefault()` + - `Permission->setDefault()` + - `PermissionManager->getDefaultPermissions()` + - `PermissionManager->recalculatePermissionDefaults()` + - `PermissionManager->subscribeToDefaultPerms()` + - `PermissionManager->unsubscribeFromDefaultPerms()` + - `PermissionManager->getDefaultPermSubscriptions()` + - `PermissionAttachment->getPermissible()` + - `PermissionAttachmentInfo->getPermissible()` +- The following fields have been removed: + - `Permission::$DEFAULT_PERMISSION` +- The following API methods have changes: + - `PermissionParser::defaultFromString()` now throws `InvalidArgumentException` on unknown values. + - `Permission->__construct()` no longer accepts a `$defaultValue` parameter (see notes above about defaults refactor).you should add your permission as a child of `pocketmine.group.everyone` or `pocketmine.group.operator` instead). +- The following classes have been removed: + - `ServerOperator` + +### Player +- The following classes have moved to the new `pocketmine\player` namespace: + - `Achievement` + - `GameMode` + - `IPlayer` + - `OfflinePlayer` + - `PlayerInfo` + - `Player` +- The following constants have been removed: + - `Player::SURVIVAL` - use `GameMode::SURVIVAL()` + - `Player::CREATIVE` - use `GameMode::CREATIVE()` + - `Player::ADVENTURE` - use `GameMode::ADVENTURE()` + - `Player::SPECTATOR` - use `GameMode::SPECTATOR()` + - `Player::VIEW` - use `GameMode::SPECTATOR()` +- (almost) all packet handlers have been removed from `Player`. They are now encapsulated within the network layer. +- `Player->getSpawn()` no longer returns the world's safe spawn if the player's spawn position isn't set. Returning the safe spawn at the time of call made no sense, because it might not have been safe when actually used. You should pass the result of this function to `World->getSafeSpawn()` to get a safe spawn position instead. +- The following API methods have been added: + - `Player->attackBlock()`: attack (left click) the target block, e.g. to start destroying it (survival) + - `Player->attackEntity()`: melee-attack (left click) the target entity (if within range) + - `Player->breakBlock()`: destroy the target block in the current world (immediately) + - `Player->consumeHeldItem()`: consume the previously activated item, e.g. eating food + - `Player->continueBreakBlock()`: punch the target block during destruction in survival, advancing break animation and creating particles + - `Player->getItemCooldownExpiry()`: returns the tick on which the player's cooldown for a given item expires + - `Player->hasFiniteResources()` + - `Player->interactBlock()`: interact (right click) the target block in the current world + - `Player->interactEntity()`: interact (right click) the target entity, e.g. to apply a nametag (not implemented yet) + - `Player->pickBlock()`: picks (mousewheel click) the target block in the current world + - `Player->releaseHeldItem()`: release the previously activated item, e.g. shooting a bow + - `Player->selectHotbarSlot()`: select the specified hotbar slot + - `Player->stopBreakBlock()`: cease attacking a previously attacked block + - `Player->toggleFlight()`: tries to start / stop flying (fires events, may be cancelled) + - `Player->updateNextPosition()`: sets the player's next attempted move location (fires events, may be cancelled) + - `Player->useHeldItem()`: activate the held item, e.g. throwing a snowball + - `Player->getSaveData()`: returns save data generated on the fly +- The following API methods have been removed: + - `Player->addActionBarMessage()`: replaced by `sendActionBarMessage()` + - `Player->addSubTitle()`: replaced by `sendSubTitle()` + - `Player->addTitle()`: replaced by `sendTitle()` + - `Player->getAddress()`: replaced by `NetworkSession->getIp()` + - `Player->getPing()`: moved to `NetworkSession` + - `Player->getPort()`: moved to `NetworkSession` + - `Player->updatePing()`: moved to `NetworkSession` + - `Player->dataPacket()`: replaced by `NetworkSession->sendDataPacket()` + - `Player->sendDataPacket()`: replaced by `NetworkSession->sendDataPacket()` + - `Player->updateNextPosition()`: use `Player->handleMovement()` instead + - `IPlayer->isWhitelisted()`: use `Server->isWhitelisted()` instead + - `IPlayer->setWhitelisted()`: use `Server->setWhitelisted()` instead + - `IPlayer->isBanned()`: this was unreliable because it only checked name bans and didn't account for plugin custom ban systems. Use `Server->getNameBans()->isBanned()` and `Server->getIPBans()->isBanned()` instead. + - `IPlayer->setBanned()`: use `Server` APIs instead + - `IPlayer->isOp()`: use `Server` APIs instead + - `IPlayer->setOp()`: use `Server` APIs instead + +### Plugin +- API version checks are now more strict. It is no longer legal to declare multiple minimum versions on the same major version. Doing so will now cause the plugin to fail to load with the message `Multiple minimum API versions found for some major versions`. +- `plugin.yml` YAML commands loading is now internalized inside `PluginBase`. +- `PluginManager->registerEvent()` now has a simpler signature: `registerEvent(string $event, \Closure $handler, int $priority, Plugin $plugin, bool $handleCancelled = false)`. The provided closure must accept the specified event class as its only parameter. See [Event API changes](#event) for more details. +- The following classes have been removed: + - `PluginLogger` +- The following constants have been removed: + - `PluginLoadOrder::STARTUP` - use `PluginEnableOrder::STARTUP()` + - `PluginLoadOrder::POSTWORLD` - use `PluginEnableOrder::POSTWORLD()` +- The following interface requirements have been removed: + - `Plugin->onEnable()`: this is now internalized inside `PluginBase` + - `Plugin->onDisable()`: same as above + - `Plugin->onLoad()`: same as above + - `Plugin->getServer()` is no longer required to be implemented. It's implemented in `PluginBase` for convenience. + - `Plugin->isDisabled()` was removed (use `Plugin->isEnabled()` instead). + - `Plugin` no longer extends `CommandExecutor`. This means that `Plugin` implementations don't need to implement `onCommand()` anymore. +- The following hook methods have changed visibility: + - `PluginBase->onEnable()` changed from `public` to `protected` + - `PluginBase->onDisable()` changed from `public` to `protected` + - `PluginBase->onLoad()` changed from `public` to `protected` +- The following hook methods have been renamed: + - `Plugin->setEnabled()` -> `Plugin->onEnableStateChange()`. This change was made to force plugin developers misusing this hook to stop, and to give it a name that better describes what it does. +- The following (deprecated) API methods have been removed: + - `PluginManager->callEvent()`: use `Event->call()` instead + - `PluginManager->addPermission()`: use `PermissionManager` instead + - `PluginManager->getDefaultPermSubscriptions()`: use `PermissionManager` instead + - `PluginManager->getDefaultPermissions()`: use `PermissionManager` instead + - `PluginManager->getPermission()`: use `PermissionManager` instead + - `PluginManager->getPermissionSubscriptions()`: use `PermissionManager` instead + - `PluginManager->getPermissions()`: use `PermissionManager` instead + - `PluginManager->recalculatePermissionDefaults()`: use `PermissionManager` instead + - `PluginManager->removePermission()`: use `PermissionManager` instead + - `PluginManager->subscribeToDefaultPerms()`: use `PermissionManager` instead + - `PluginManager->subscribeToPermission()`: use `PermissionManager` instead + - `PluginManager->unsubscribeFromDefaultPerms()`: use `PermissionManager` instead + - `PluginManager->unsubscribeFromPermission()`: use `PermissionManager` instead +- It is no longer permitted to throw exceptions from `PluginBase->onEnable()` or `PluginBase->onLoad()`. Doing so will now cause the server to crash. + +### Scheduler +#### Thread-local storage for AsyncTasks +- TLS has been completely rewritten in this release to be self contained, more robust and easier to use. +- Now behaves more like simple properties. `storeLocal()` writes, `fetchLocal()` reads. +- Self-contained and doesn't depend on the async pool to clean up after it. +- Values are automatically removed from storage when the `AsyncTask` is garbage-collected, just like a regular property. +- Supports storing multiple values, differentiated by string names. +- `fetchLocal()` can now be used multiple times. It no longer deletes the stored value. +- The following classes have been removed: + - `FileWriteTask` +- The following methods have been removed: + - `AsyncTask->peekLocal()`: use `fetchLocal()` instead +- The following methods have signature changes: + - `AsyncTask->storeLocal()` now has the signature `storeLocal(string $key, mixed $complexData) : void` + - `AsyncTask->fetchLocal()` now has the signature `fetchLocal(string $key) : mixed` + +#### Other changes +- `AsyncPool` uses a new, significantly more performant algorithm for task collection. +- `BulkCurlTask` has had the `$complexData` constructor parameter removed. +- `BulkCurlTask->__construct()` now accepts `BulkCurlTaskOperation[]` instead of `mixed[]`. +- Added `CancelTaskException`, which can be thrown from `Task::onRun()` to cancel a task (especially useful for `ClosureTask`). +- `pocketmine\Collectable` has been removed, and is no longer extended by `AsyncTask`. +- The following hooks have been added: + - `AsyncTask->onError()`: called on the main thread when an uncontrolled error was detected in the async task, such as a memory failure +- The following hooks have signature changes: + - `AsyncTask->onCompletion()` no longer accepts a `Server` parameter, and has a `void` return type. + - `AsyncTask->onProgressUpdate()` no longer accepts a `Server` parameter, and has a `void` return type. +- The following API methods have been removed: + - `AsyncTask->getFromThreadStore()`: use `AsyncTask->worker->getFromThreadStore()` + - `AsyncTask->removeFromThreadStore()`: use `AsyncTask->worker->removeFromThreadStore()` + - `AsyncTask->saveToThreadStore()`: use `AsyncTask->worker->saveToThreadStore()` + +### Server +- New chat broadcasting APIs have been implemented, which don't depend on the permission system. + - The following API methods have been added: + - `subscribeToBroadcastChannel()` - allows subscribing a `CommandSender` to receive chat messages (and other message types) on any channel + - `unsubscribeFromBroadcastChannel()` + - `unsubscribeFromAllBroadcastChannels()` + - `getBroadcastChannelSubscribers()` + - Giving `Player` any `pocketmine.broadcast.*` permissions will cause them to automatically subscribe to the corresponding broadcast channel (and removing them will unsubscribe it). + - It's now possible to create and subscribe to custom broadcast channels without using permissions. + - However, `Player`s may automatically unsubscribe themselves from the builtin broadcast channels if they don't have the proper permissions. + - Automatic subscribe/unsubscribe from custom broadcast channels can be implemented using the new `Permissible` permission recalculation callbacks API. +- The following API methods have been removed: + - `reloadWhitelist()` + - `getLevelMetadata()` + - `getPlayerMetadata()` + - `getEntityMetadata()` + - `getDefaultGamemode()` + - `getLoggedInPlayers()` + - `onPlayerLogout()` + - `addPlayer()` + - `removePlayer()` + - `reload()` + - `getSpawnRadius()` + - `enablePlugin()` + - `disablePlugin()` + - `getGamemodeString()` - replaced by `pocketmine\player\GameMode->getTranslationKey()` + - `getGamemodeName()` - replaced by `pocketmine\player\GameMode->name()` + - `getGamemodeFromString()` - replaced by `GameMode::fromString()` + - `broadcast()` - use `broadcastMessage()` instead +- The following API methods have changed: + - `getOfflinePlayerData()` no longer creates data when it doesn't exist. +- The following API methods have been renamed: + - `getPlayer()` -> `getPlayerByPrefix()` (consider using `getPlayerExact()` instead where possible) + +### Level / World +#### General +- All references to `Level` in the context of "world" have been changed to `World`. + - The `pocketmine\level` namespace has been renamed to `pocketmine\world` + - All classes containing the world `Level` in the name in the "world" context have been changed to `World`. + - `Position->getLevel()` has been renamed to `Position->getWorld()`, and `Position->level` has been renamed to `Position->world`. +- Extracted a `WorldManager` unit from `Server` + - `Server->findEntity()` -> `WorldManager->findEntity()` + - `Server->generateLevel()` -> `WorldManager->generateWorld()` + - `Server->getAutoSave()` -> `WorldManager->getAutoSave()` + - `Server->getDefaultLevel()` -> `WorldManager->getDefaultWorld()` + - `Server->getLevel()` -> `WorldManager->getWorld()` + - `Server->getLevelByName()` -> `WorldManager->getWorldByName()` + - `Server->getLevels()` -> `WorldManager->getWorlds()` + - `Server->isLevelGenerated()` -> `WorldManager->isWorldGenerated()` + - `Server->isLevelLoaded()` -> `WorldManager->isWorldLoaded()` + - `Server->loadLevel()` -> `WorldManager->loadWorld()` + - `WorldManager->loadWorld()` may convert worlds if requested (the `$autoUpgrade` parameter must be provided). + - `Server->setAutoSave()` -> `WorldManager->setAutoSave()` + - `Server->setDefaultLevel()` -> `WorldManager->setDefaultWorld()` + - `Server->unloadLevel()` -> `WorldManager->unloadWorld()` +- Added `WorldManager->getAutoSaveTicks()` and `WorldManager->setAutoSaveTicks()` to allow controlling the autosave interval. +- The following classes have been added: + - `BlockTransaction`: allows creating batch commits of block changes with validation conditions - if any block can't be applied, the whole transaction fails to apply. + - `ChunkListenerNoOpTrait`: contains default no-op stubs for chunk listener implementations + - `ChunkListener`: interface allowing subscribing to events happening on a given chunk + - `TickingChunkLoader`: a `ChunkLoader` specialization that allows ticking chunks +- `ChunkLoader` no longer requires implementing `getX()` and `getZ()`. +- `ChunkLoader` no longer causes chunks to get random updates. If this behaviour is needed, implement `TickingChunkLoader`. +- The following classes have been renamed: + - `pocketmine\world\utils\SubChunkIteratorManager` -> `pocketmine\world\utils\SubChunkExplorer` +- The following API methods have been added: + - `World->registerChunkListener()` + - `World->unregisterChunkListener()` + - `World->getBlockAt()` (accepts int x/y/z instead of Vector3, faster for some use cases) + - `World->setBlockAt()` (accepts int x/y/z instead of Vector3, faster for some use cases) + - `Chunk->isDirty()` (replacement for `Chunk->hasChanged()`) + - `Chunk->getDirtyFlag()` (more granular component-based chunk dirty-flagging, used to avoid saving unmodified parts of the chunk) + - `Chunk->setDirty()` + - `Chunk->setDirtyFlag()` +- The following API methods have been removed: + - `ChunkLoader->getLoaderId()` (now object ID is used) + - `ChunkLoader->isLoaderActive()` + - `ChunkLoader->getPosition()` + - `ChunkLoader->getLevel()` + - `Chunk->fastSerialize()` (use `FastChunkSerializer::serialize()` instead) + - `Chunk->getBlockData()` + - `Chunk->getBlockDataColumn()` + - `Chunk->getBlockId()` + - `Chunk->getBlockIdColumn()` + - `Chunk->getBlockLight()` + - `Chunk->getBlockLightColumn()` + - `Chunk->getBlockSkyLight()` + - `Chunk->getBlockSkyLightColumn()` + - `Chunk->getMaxY()` + - `Chunk->getSubChunkSendCount()` (this was specialized for protocol usage) + - `Chunk->getX()` + - `Chunk->getZ()` + - `Chunk->hasChanged()` (use `Chunk->isDirty()` or `Chunk->getDirtyFlag()` instead) + - `Chunk->isGenerated()` + - `Chunk->networkSerialize()` (see `ChunkSerializer` in the `network\mcpe\serializer` package) + - `Chunk->populateSkyLight()` (use `SkyLightUpdate->recalculateChunk()` instead) + - `Chunk->recalculateHeightMap()` (moved to `SkyLightUpdate`) + - `Chunk->recalculateHeightMapColumn()` (moved to `SkyLightUpdate`) + - `Chunk->setAllBlockLight()` + - `Chunk->setAllBlockSkyLight()` + - `Chunk->setBlock()` + - `Chunk->setBlockData()` + - `Chunk->setBlockId()` + - `Chunk->setBlockLight()` + - `Chunk->setBlockSkyLight()` + - `Chunk->setChanged()` (use `Chunk->setDirty()` or `Chunk->setDirtyFlag()` instead) + - `Chunk->setGenerated()` + - `Chunk->setX()` + - `Chunk->setZ()` + - `Chunk::fastDeserialize()` (use `FastChunkSerializer::deserialize()` instead) + - `World->isFullBlock()` + - `World->getFullBlock()` + - `World->getBlockIdAt()` + - `World->setBlockIdAt()` + - `World->getBlockDataAt()` + - `World->setBlockDataAt()` + - `World->setBlockLightAt()` + - `World->setBlockSkyLightAt()` + - `World->getBlockSkyLightAt()` (use `World->getRealBlockSkyLightAt()` or `World->getPotentialBlockSkyLightAt()`, depending on use-case) + - `World->getHeightMap()` (misleading name, only actually useful for sky light calculation - you probably want `getHighestBlockAt()` instead) + - `World->setHeightMap()` (misleading name, only actually useful for sky light calculation) + - `World->getChunkEntities()` + - `World->getChunkTiles()` + - `World->getTileById()` + - `World->checkSpawnProtection()` + - `World->updateBlockLight()` + - `World->updateSkyLight()` + - `World->isFullBlock()` (use `Block->isFullCube()` instead) + - `World->sendBlocks()` + - `World->sendTime()` + - `World->addGlobalPacket()` + - `World->broadcastGlobalPacket()` + - `World->addChunkPacket()` + - `World->broadcastLevelSoundEvent()` + - `World->broadcastLevelEvent()` + - `World->getTickRate()` + - `World->setTickRate()` + - `World::generateChunkLoaderId()` +- The following API methods have changed signatures: + - `World->addParticle()` now has the signature `addParticle(Vector3 $pos, Particle $particle, ?Player[] $players = null) : void` + - `World->addSound()` now has the signature `addSound(?Vector3 $pos, Sound $sound, ?Player[] $players = null) : void` + - `World->getRandomTickedBlocks()` now returns `bool[]` instead of `SplFixedArray`. + - `World->addRandomTickedBlock()` now accepts `Block` instead of `int, int`. + - `World->removeRandomTickedBlock()` now accepts `Block` instead of `int, int`. + - `World->setBlock()` has had the `$direct` parameter removed. + - `World->loadChunk()` now returns `?Chunk`, and the `$create` parameter has been removed. + - `World->getChunk()` no longer accepts a `$create` parameter. + - `World->updateAllLight()` now accepts `int, int, int` instead of `Vector3`. + - `ChunkManager->setChunk()` (and its notable implementations in `World` and `SimpleChunkManager`) no longer accepts NULL for the `$chunk` parameter. + - `Chunk->__construct()` now has the signature `array $subChunks, ?list $entities, ?list $tiles, ?BiomeArray $biomeArray, ?HeightArray $heightArray`. + - `Chunk->getSubChunk()` now returns `SubChunk` instead of `SubChunkInterface|null` (and throws `InvalidArgumentException` on out-of-bounds coordinates). + - `Chunk->setSubChunk()` no longer accepts `SubChunkInterface`, and the `$allowEmpty` parameter has been removed. + - `WorldManager->generateWorld()` (previously `Server->generateWorld()`) now accepts `WorldCreationOptions` instead of `int $seed, class-string $generator, mixed[] $options`. +- The following API methods have been renamed / moved: + - `Level->getChunks()` -> `World->getLoadedChunks()` + - `Level->getCollisionCubes()` -> `World->getCollisionBoxes()` + - `World->getName()` -> `World->getDisplayName()` + - `World->populateChunk()` has been split into `World->requestChunkPopulation()` and `World->orderChunkPopulation()`. +- The following API methods have changed behaviour: + - `World->getChunk()` no longer tries to load chunks from disk. If the chunk is not already in memory, null is returned. (This behaviour now properly matches other `ChunkManager` implementations.) + - `World->getHighestBlockAt()` now returns `null` instead of `-1` if the target X/Z column contains no blocks. + - The following methods now throw `WorldException` when targeting ungenerated terrain: + - `World->getSafeSpawn()` (previously it just silently returned the input position) + - `World->getHighestBlockAt()` (previously it returned -1) + - `World->loadChunk()` no longer creates an empty chunk when the target chunk doesn't exist on disk. + - `World->setChunk()` now fires `ChunkLoadEvent` and `ChunkListener->onChunkLoaded()` when replacing a chunk that didn't previously exist. + - `World->useBreakOn()` now returns `false` when the target position is in an ungenerated or unloaded chunk (or chunk locked for generation). + - `World->useItemOn()` now returns `false` when the target position is in an ungenerated or unloaded chunk (or chunk locked for generation). +- A `ChunkListener` interface has been extracted from `ChunkLoader`. The following methods have been moved: + - `ChunkLoader->onBlockChanged()` -> `ChunkListener->onBlockChanged()` + - `ChunkLoader->onChunkChanged()` -> `ChunkListener->onChunkChanged()` + - `ChunkLoader->onChunkLoaded()` -> `ChunkListener->onChunkLoaded()` + - `ChunkLoader->onChunkPopulated()` -> `ChunkListener->onChunkPopulated()` + - `ChunkLoader->onChunkUnloaded()` -> `ChunkListener->onChunkUnloaded()` +- `Location` has been moved to `pocketmine\entity\Location`. + +#### Particles +- `DestroyBlockParticle` has been renamed to `BlockBreakParticle` for consistency. +- `DustParticle->__construct()` now accepts a `pocketmine\color\Color` object instead of `r, g, b, a`. +- `pocketmine\world\particle\Particle` no longer extends `pocketmine\math\Vector3`, and has been converted to an interface. +- Added the following `Particle` classes: + - `DragonEggTeleportParticle` + - `PunchBlockParticle` + +#### Sounds +- `pocketmine\world\sound\Sound` no longer extends `pocketmine\math\Vector3`, and has been converted to an interface. +- `Sound->encode()` now accepts `?\pocketmine\math\Vector3`. `NULL` may be passed for sounds which are global. +- Added the following classes: + - `ArrowHitSound` + - `BlockBreakSound` + - `BlockPlaceSound` + - `BowShootSound` + - `BucketEmptyLavaSound` + - `BucketEmptyWaterSound` + - `BucketFillLavaSound` + - `BucketFillWaterSound` + - `ChestCloseSound` + - `ChestOpenSound` + - `EnderChestCloseSound` + - `EnderChestOpenSound` + - `ExplodeSound` + - `FlintSteelSound` + - `ItemBreakSound` + - `NoteInstrument` + - `NoteSound` + - `PaintingPlaceSound` + - `PotionSplashSound` + - `RedstonePowerOffSound` + - `RedstonePowerOnSound` + - `ThrowSound` + - `XpCollectSound` + - `XpLevelUpSound` + +### Utils +- The `Color` class was removed. It's now found as `pocketmine\color\Color` in the [`pocketmine/color`](https://github.com/pmmp/Color) package. +- The `UUID` class was removed. [`ramsey/uuid`](https://github.com/ramsey/uuid) version 4.1 is now used instead. + - `UUID::fromData()` can be replaced by `Ramsey\Uuid\Uuid::uuid3()` + - `UUID::fromRandom()` can be replaced by `Ramsey\Uuid\Uuid::uuid4()` + - `UUID::fromBinary()` can be replaced by `Ramsey\Uuid\Uuid::fromBytes()` (use `Ramsey\Uuid\Uuid::isValid()` to check validity) + - `UUID::toBinary()` is replaced by `Ramsey\Uuid\UuidInterface::getBytes()` + - See the documentation at https://uuid.ramsey.dev/en/latest/introduction.html for more information. +- `Terminal::hasFormattingCodes()` no longer auto-detects the availability of formatting codes. Instead it's necessary to use `Terminal::init()` with no parameters to initialize, or `true` or `false` to override. +- `Config->save()` no longer catches exceptions thrown during emitting to disk. +- The following new classes have been added: + - `InternetException` + - `Internet` + - `Process` +- The following API methods have been added: + - `Config->getPath()`: returns the path to the config on disk + - `Terminal::write()`: emits a Minecraft-formatted text line without newline + - `Terminal::writeLine()`: emits a Minecraft-formatted text line with newline + - `Utils::recursiveUnlink()`: recursively deletes a directory and its contents +- The following API class constants have been added: + - `TextFormat::COLORS`: lists all known color codes + - `TextFormat::FORMATS`: lists all known formatting codes (e.g. italic, bold). (`RESET` is not included because it _removes_ formats, rather than adding them.) +- The following deprecated API redirects have been removed: + - `Utils::execute()`: moved to `Process` + - `Utils::getIP()`: moved to `Internet` + - `Utils::getMemoryUsage()`: moved to `Process` + - `Utils::getRealMemoryUsage()`: moved to `Process` + - `Utils::getThreadCount()`: moved to `Process` + - `Utils::getURL()`: moved to `Internet` + - `Utils::kill()`: moved to `Process` + - `Utils::postURL()`: moved to `Internet` + - `Utils::simpleCurl()`: moved to `Internet` +- The following API fields have been removed / hidden: + - `Utils::$ip` + - `Utils::$online` + - `Utils::$os` +- The following API methods have signature changes: + - `Internet::simpleCurl()` now requires a `Closure` for its `onSuccess` parameter instead of `callable`. +- The following API methods have been removed: + - `TextFormat::toJSON()` + - `Utils::getCallableIdentifier()` + +## Gameplay +### Blocks +- Implemented the following blocks: + - bamboo + - bamboo sapling + - barrel + - barrier + - blast furnace + - blue ice + - carved pumpkin + - coral block + - daylight sensor + - dried kelp + - elements (from Minecraft: Education Edition) + - hard (stained and unstained) glass (from Minecraft: Education Edition) + - hard (stained and unstained) glass pane (from Minecraft: Education Edition) + - jukebox + - note block + - red, green, blue and purple torches (from Minecraft: Education Edition) + - sea pickle + - slime + - smoker + - underwater torches (from Minecraft: Education Edition) + - additional wood variants of the following: + - buttons + - pressure plates + - signs + - trapdoors + - stairs of the following materials: + - andesite (smooth and natural) + - diorite (smooth and natural) + - end stone + - end stone brick + - granite (smooth and natural) + - mossy cobblestone + - prismarine (natural, dark and bricks) + - red nether brick + - red sandstone (and variants) + - stone-like slabs of many variants +- Non-player entities now bounce when falling on beds. +- Players and mobs now receive reduced fall damage when falling on beds. + +### Items +- Implemented the following items: + - records + - compounds (from Minecraft: Education Edition) + - black, brown, blue and white dyes + +### Inventory +- Implemented offhand inventory. +- Block-picking is now supported in survival mode. +- Block picking behaviour now matches vanilla (no longer overwrites held item, jumps to existing item where possible). +- Armor can now be equipped by right-clicking while holding it. + +# 4.0.0-BETA2 +Released 10th September 2021. + +## General +- ext-chunkutils 0.3.x is now required. +- Reduced memory usage of light storage after garbage collection. +- Reduced memory usage of uniform subchunks which only contain 1 type of block. +- The title bar no longer displays heap memory usage numbers (nobody seemed to know that was what it was, anyway). +- `/status` no longer displays heap memory usage numbers. +- `start.sh` no longer specifically mentions PHP 7 when erroring because of a missing PHP binary. +- Debug messages are now logged when reach distance checks prevent players from doing something. + +## Fixes +- Fixed players getting disconnected when using `/tp` to ungenerated chunks (or when teleported by players). +- Fixed a potential memory leak in block updating when chunks are unloaded. +- Fixed `Living->lookAt()` not taking eye height into account. +- Fixed grass replacing itself when placing grass (and consuming inventory items). +- Fixed players taking fall damage when falling next to a wall. + +## API changes +- The following API methods have been added: + - `World->getChunkEntities()` + - `World->notifyNeighbourBlockUpdate()` +- The following API methods have been removed: + - `Chunk->getEntities()` + - `Chunk->getSavableEntities()` + - `Chunk->addEntity()` + - `Chunk->removeEntity()` +- The following classes have been added: + - `pocketmine\inventory\transaction\TransactionBuilderInventory`: facilitates building `InventoryTransaction`s using standard `Inventory` API methods +- The following class constants have been added: + - `Chunk::EDGE_LENGTH` + - `Chunk::COORD_BIT_SIZE` + - `Chunk::COORD_MASK` + - `SubChunk::EDGE_LENGTH` + - `SubChunk::COORD_BIT_SIZE` + - `SubChunk::COORD_MASK` + +# 4.0.0-BETA3 + + +## General +- Added support for Minecraft: Bedrock Edition 1.17.30. +- Dropped support for Minecraft: Bedrock Edition 1.17.1x. +- `tools/convert-world.php` now writes errors to stderr and sets the proper exit code. +- Explosions now use the standard mechanism for processing block updates. Previously, it used a special mechanism due to prohibitively poor efficiency of the standard algorithm. Since these inefficiencies have now been addressed, explosions can now be consistent with everything else, with minimal performance impact. +- Command usage strings are no longer automatically translated (use `Translatable` instead of bare string keys). +- Command description strings are no longer automatically translated (use `Translatable` instead of bare string keys). + +## Fixes +- `ItemFactory->isRegistered()` no longer crashes when given negative item IDs. +- Furnaces now continue to operate after reloading the chunk they were contained in. +- Fixed being unable to reconnect for 10 seconds after disconnecting in some cases. + +## API changes +- The following API methods have been added: + - `Liquid->getMinAdjacentSourcesToFormSource()`: returns how many adjacent source blocks of the same liquid must be present in order for the current block to become a source itself + - `Player->getPlayerInfo()` +- `Liquid` minimum-cost flow calculation code has been extracted to `MinimumCostFlowCalculator`. + +# 4.0.0-BETA4 +Released 6th October 2021. + +## General +- Improved performance of lighting calculation by avoiding copies of useless data from the main thread. +- Resource pack loading now accepts `dependencies` and `capabilities` fields in the `manifest.json` (although it doesn't currently check them). +- `/help` is now localized according to language set in `server.properties`. +- Various messages related to world loading, generation and conversion are now localized according to the language set in `server.properties`. +- Compasses now point to the correct (current) world's spawn point after teleporting players to a different world. Previously, they would continue to point to the spawn of the world that the player initially spawned in. +- The `--bootstrap` CLI option has been removed. +- RakLib 0.14.2 is now required. This fixes the following issues: + - Fixed incorrect handling of sessions on client disconnect (leading to timeout debug messages). + - Fixed transferring players often not working correctly. + - Fixed disconnect screens sometimes not displaying. + +## Fixes +- Fixed server crash when UPnP encounters an error. +- Fixed server crash when clients sent items with bad NBT in inventory transactions. +- Fixed server crash when loading a plugin with legacy nested permission structure (now the plugin will fail to load, but the server won't crash). +- Fixed server crash when using `/give` with bad NBT on any item. +- Fixed server crash when loading a plugin with improperly formatted API version (now the plugin will fail to load, but the server won't crash). +- Fixed server crash when changing player gamemode during `PlayerLoginEvent`. +- Incorrect structure of `commands` in plugin manifest is now detected earlier and handled more gracefully. +- Fixed console reader subprocess lingering on server crash on Windows and screwing up the terminal. +- Fixed `Player` object memory leak when kicking players during `PlayerLoginEvent` (this caused the `World` to report warnings about leaked entities on shutdown). +- Fixed `Projectile->move()` ignoring the `dx`/`dy`/`dz` parameters given and using its own `motion` instead. +- Fixed `BlockFactory->get()` erroneously accepting meta values of `16`. +- Fixed `Block->isSameState()` false negatives for some types of slabs. +- Fixed being unable to place slabs of the same type on top of each other to create double slabs. + +## API changes +- Plugin commands in `plugin.yml` must now declare `permission` for each command. Previously, the `permission` key was optional, causing anyone to be able to use the command. + - This behaviour was removed because of the potential for security issues - a typo in `plugin.yml` could lead to dangerous functionality being exposed to everyone. + - If you want to make a command that everyone can use, declare a permission with a `default` of `true` and assign it to the command. +- Plugin permissions in `plugin.yml` must now declare `default` for each permission. Previously, the `default` key was optional, causing the permission to silently be denied to everyone (PM4) or granted to ops implicitly (PM3). + +### Block +- Added the following classes: + - `pocketmine\block\utils\LeverFacing` +- Added the following API methods: + - `pocketmine\block\Lever->isActivated()` + - `pocketmine\block\Lever->setActivated()` + - `pocketmine\block\Lever->getFacing()` + - `pocketmine\block\Lever->setFacing()` + +### World +- The following API methods have signature changes: + - `Chunk->getSubChunks()` now returns `array` instead of `SplFixedArray`. +- The following API methods have been removed: + - `FastChunkSerializer::serialize()` + - `FastChunkSerializer::deserialize()` +- The following API methods have been added: + - `FastChunkSerializer::serializeTerrain()`: serializes blocks and biomes only + - `FastChunkSerializer::deserializeTerrain()`: deserializes the output of `serializeTerrain()` + +### Utils +- The following API methods have signature changes: + - `Process::kill()` now requires an additional `bool $subprocesses` parameter. + +# 4.0.0-BETA5 +Released 12th October 2021. + +## General +- Exception log format has been changed. Now, exception info is logged in one big block message. This saves space on the console and improves readability, as well as reducing the ability for bad `ThreadedLoggerAttachment`s to break exception output. +- Log messages are now pushed to `server.log` before calling logger attachment, instead of after. This fixes messages not being written to disk when an error occurs in a logger attachment. +- Improved startup performance when loading many plugins. +- The `worlds` config in `pocketmine.yml` no longer supports attaching the generator settings to the `generator` key (use the `preset` key instead). +- Using an unknown generator in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world. +- Using invalid/incorrect world generator options (presets) in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world. +- Generator options of existing worlds are now validated before loading them. If they are invalid, the server will fail to load them. +- Several more log messages have been localized, including plugin loading errors. + +## Fixes +- Fixed server crash when using `/give` to give an item by ID which doesn't exist in Minecraft. +- Fixed server crash when boolean `server.properties` options were given an integer value (e.g. `0` or `1` instead of `false` or `true`). +- Fixed stats reporting checking for a nonexistent `pocketmine.yml` setting. +- Fixed use of commands without the proper permission sending a message `commands.generic.permission` instead of the proper message. +- Fixed entities set on fire appearing to stay on fire, although not taking any damage. +- Fixed a duplicate `MB` suffix on the `Memory freed` output of `/gc`. +- Fixed the server attempting to generate a world if it failed to load. + +## API +### Block +- The following API methods have been renamed: + - `Block->getPositionOffset()` -> `Block->getModelPositionOffset()`. + +### Event +- `@handleCancelled` PhpDoc annotation can no longer be used on event handlers for non-cancellable events. +- The following API methods have been added: + - `StructureGrowEvent->getPlayer()` + +### Inventory +- The following API methods have been added: + - `Inventory->getAddableItemQuantity()` + +### Scheduler +- `ClosureTask` now permits closures without an explicit return type (useful for arrow functions). + +### Utils +- The following API methods have been added: + - `Config::parseProperties()` + - `Config::writeProperties()` + - `Config::parseList()` + - `Config::writeList()` + +### World +- The following API methods have signature changes: + - `GeneratorManager->registerGenerator()` now requires a `\Closure $presetValidator` parameter. This is used to check generator options of worlds and configs before attempting to use them. + +# 4.0.0-BETA6 +Released 19th October 2021. + +## General +- Added support for Minecraft: Bedrock Edition 1.17.40. +- Removed support for earlier versions. +- CTRL+C signal handling has been restored, and is now supported on Windows. Pressing CTRL+C while the server is running will behave as if the `/stop` command was invoked. +- Added a script `tools/generate-permission-doc.php` to generate a Markdown file with a list of all permissions and their relationships. In the future, this will be used to maintain the official documentation, but plugin developers might find it useful for their own purposes too. +- [`respect/validation`](https://packagist.org/packages/respect/validation) is no longer a core dependency. + +## Fixes +- Fixed server crash when using `/give` to give an item with a too-large item ID, or `/clear` to clear an item that does not exist. + - Now, `LegacyStringToItemParser` is used exclusively, and numeric IDs are no longer parsed. + +## Gameplay +- Picking up some items from a dropped stack of items is now supported. This fixes various bugs with being unable to pick up items with an almost-full inventory. + +# 4.0.0-BETA7 +Released 28th October 2021. + +## General +- Phar plugins are now able to depend on folder plugins loaded by DevTools. +- Now uses [`pocketmine/bedrock-protocol@58c53a259e819a076bf8fe875d2a012da7d19d65`](https://github.com/pmmp/BedrockProtocol/tree/58c53a259e819a076bf8fe875d2a012da7d19d65). This version features significant changes, including: + - Standardisation of various field names (e.g. `eid` -> `actorRuntimeId`, `evid` -> `eventId`) + - Rename of `entity` related fields to `actor` where appropriate (e.g. `entityRuntimeId` -> `actorRuntimeId`) + - Block position `x`/`y`/`z` fields replaced by `BlockPosition` + - Static `::create()` functions for all packets, which ensure that fields can't be forgotten + +## Fixes +- Fixed server crash when clients send itemstacks with unmappable dynamic item IDs. +- Fixed server crash on invalid ItemStackRequest action types. +- Fixed autosave bug that caused unmodified chunks to be saved at least once (during the first autosave after they were loaded). +- Fixed `ConsoleReaderThread` returning strings with newlines still on the end. +- Fixed changes made to adjacent chunks in `ChunkPopulateEvent` (e.g. setting blocks) sometimes getting overwritten. + +## API +### Event +- `PlayerCreationEvent` now verifies that the player class set is instantiable - this ensures that plugins get properly blamed for breaking things. + +### World +- `World->generateChunkCallback()` has been specialized for use by `PopulationTask`. This allows fixing various inconsistencies involving `ChunkPopulateEvent` (e.g. modifications to adjacent chunks in `ChunkPopulationEvent` might be wiped out, if the population of the target chunk modified the adjacent chunk). + - It now accepts `Chunk $centerChunk, array $adjacentChunks` (instead of `?Chunk $chunk`). + - It's no longer expected to be used by plugins - plugins should be using `World->setChunk()` anyway. +- `Chunk->getModificationCounter()` has been added. This is a number starting from `0` when the `Chunk` object is first created (unless overridden by the constructor). It's incremented every time blocks or biomes are changed in the chunk. It resets after the chunk is unloaded and reloaded. +- The following API methods have changed signatures: + - `Sound->encode()` no longer accepts `null` for the position. + - `Chunk->__construct()`: removed `HeightArray $heightMap` parameter, added `bool $terrainPopulated` and `int $modificationCounter` parameters. + +### Plugin +- `PluginManager->loadPlugins()` now accepts paths to files as well as directories, in which case it will load only the plugin found in the target file. +- The following API methods have been removed: + - `PluginManager->loadPlugin()`: use `PluginManager->loadPlugins()` instead + +# 4.0.0-BETA8 +Released 29th October 2021. + +## General +- Chunk packet caches are now cleared by the memory manager on low memory. +- `Entity->spawnTo()` now has an additional sanity check for matching worlds (might expose a few new errors in plugins). +- [`pocketmine/math` 0.4.0](https://github.com/pmmp/Math/releases/tag/0.4.0) is now used. Please see its release notes for changes. + +## Fixes +- Zlib raw check for LevelDB is now done directly on startup, avoiding crashes when later trying to load worlds. +- Fixed tiles and entities getting deleted from adjacent chunks during chunk population. +- Fixed players being unable to open their inventories more than once. +- Fixed entities not getting updated when a nearby chunk is replaced (e.g. dropped items would float in midair if the ground was lower than before) + +## API +### World +- `World::setChunk()` has the following changes: + - `$deleteEntitiesAndTiles` parameter has been removed. + - Entities are no longer deleted on chunk replacement. + - Tiles are no longer deleted on chunk replacement, unless one of the following conditions is met: + - the target block in the new chunk doesn't expect a tile + - the target block in the new chunk expects a different type of tile (responsibility of the plugin developer to create the new tile) + - there's already a tile in the target chunk which conflicts with the old one +- `Location::__construct()` has the following changes: + - `world` parameter is now 4th instead of last. + - All parameters are now mandatory. +- Reverted addition of chunk modification counters in previous beta. +- `Chunk::DIRTY_FLAG_TERRAIN` has been renamed to `Chunk::DIRTY_FLAG_BLOCKS`. + +# 4.0.0-BETA9 +Released 2nd November 2021. + +## General +- Now analysed using level 9 on PHPStan 1.0.0. +- `ext-pthreads` v4.0.0 or newer is now required. +- `resources/vanilla` submodule has been removed. BedrockData is now included via Composer dependency [`pocketmine/bedrock-data`](https://packagist.org/packages/pocketmine/bedrock-data). +- `pocketmine/spl` Composer dependency has been dropped. +- The following Composer dependency versions are now required: + - [`pocketmine/bedrock-protocol` v5.0.0](https://github.com/pmmp/BedrockProtocol/tree/5.0.0+bedrock-1.17.40) features substantial changes to its API compared to 3.0.1, which was used in 4.0.0-BETA8. Please see its [release notes](https://github.com/pmmp/BedrockData/releases/tag/5.0.0+bedrock-1.17.40). + - [`pocketmine/log` v0.4.0](https://github.com/pmmp/Log/tree/0.4.0) removes the `LoggerAttachment` interface and replaces logger attachment objects with closures. + - [`pocketmine/log-pthreads` v0.4.0](https://github.com/pmmp/LogPthreads/tree/0.4.0) + - [`pocketmine/classloader` v0.2.0](https://github.com/pmmp/ClassLoader/tree/0.2.0) +- A noisy debug message in `World->updateAllLight()` has been removed. + +## API +### Entity +- `Human->setLifetimeTotalXp()` now limits the maximum value to 2^31. + +### Event +- `BlockGrowEvent` is now called when cocoa pods grow. + +### Item +- Added `Releasable->canStartUsingItem()`. + +### Network +- Added `NetworkInterfaceStartException`, which may be thrown by `Network->registerInterface()` and `NetworkInterface->start()`. + +### Player +- `SurvivalBlockBreakHandler::createIfNecessary()` has been removed. +- `SurvivalBlockBreakHandler->__construct()` is now public. +- `UsedChunkStatus::REQUESTED()` has been renamed to `REQUESTED_SENDING`. +- `UsedChunkStatus::REQUESTED_GENERATION()` has been added. + +### Utils +- `Promise` API has changed: + - Promise-related classes have been moved to `pocketmine\promise` namespace. + - It's now split into `Promise` and `PromiseResolver`. + - `PromiseResolver` provides only `resolve()` and `reject()`. It should be used by callbacks to resolve a promise. + - `Promise` now provides only `onCompletion()` and `isResolved()` APIs. This should be given to consumers to allow them to handle the result of the async operation. + - `PromiseResolver` must not be created directly. Use `new PromiseResolver` and `PromiseResolver->getPromise()`. + +### World +- Improved performance of `setBlock()` by around 35% when the `$update` parameter is set to `true`. +- Improved performance of `setBlock()` by around 30% when the `$update` parameter is set to `false`. +- `World->generateChunkCallback()` is no longer exposed to public API. +- `World->getAdjacentChunks()` now returns an array indexed using `World::chunkHash()`, where the `x` and `z` components are the relative offsets from the target chunk (range -1 to +1). +- `World->lockChunk()` now requires `ChunkLockId $lockId` parameter. +- `World->unlockChunk()` now requires a `?ChunkLockId $lockId` parameter. If a non-null lockID is given, the lock on the chunk will only be removed if it matches the given lockID. +- `World->unlockChunk()` now returns `bool` instead of `void` (to signal whether unlocking succeded or not). +- Added `ChunkLockId` class. + +## Fixes +### World +- Fixed server crash when tiles with colliding positions are loaded from saved data. Now, an error is logged, but the server won't crash. +- Fixed server crash when liquids and other items flow into terrain locked for population. Now, an advisory locking mechanism is used, and population results will be discarded and recalculated if modifications are detected. +- Fixed various crashes that could occur if a chunk was flagged with `setPopulated(true)` after a promise had already been created for its population. +- Fixed `AssumptionFailedError` in `PopulationTask` when workers previously used for generation are shutdown, and then restarted on the fly by a generation request. +- Fixed assertion failure in `World->drainPopulationRequestQueue()` when requesting, cancelling and then re-requesting generation of a chunk while the generator was busy. +- Fixed generation potentially getting stuck if a population request was cancelled while the population task was running (failure to remove locks from used chunks). +- Fixed `World->requestChunkPopulation()` not taking into account that the target chunk may already be populated. This caused a variety of strange bugs and performance issues. +- Fixed potential memory leak caused by `World->unregisterChunkListenerFromAll()` not taking players into account. +- Fixed debug spam of `chunk has no loaders registered` messages during chunk generation. + +### Other fixes +- Fixed server crash when unable to bind to the desired port. Now, the server will show an error and gracefully stop without a crashdump instead. +- Fixed server crash in `Player->showPlayer()` when the target is not in the same world. +- Fixed players, who died in hardcore mode and were unbanned, getting re-banned on next server join. +- Fixed cake block desync when attempting to eat in creative (eating in creative is not yet supported, but the block rollback was missing). +- Fixed players being able to eat items more quickly by dropping them while eating. +- Fixed arrows getting added to creative players' inventories when picked up. +- Fixed players re-requesting the same ungenerated chunks multiple times before they were sent. +- Fixed commands not working in some cases after using some control sequences on the console. + +# 4.0.0-BETA10 +Released 2nd November 2021. + +## Fixes +- Fixed an issue with BedrockData JSON minification which broke the release build of 4.0.0-BETA9. + +# 4.0.0-BETA11 +Released 6th November 2021. + +## General +- `resources/locale` submodule has been removed. Language files are now included via Composer dependency [`pocketmine/locale-data`](https://packagist.org/packages/pocketmine/locale-data). + - This means it's now possible to run a server from git sources without cloning submodules :) + - All remaining submodules (DevTools, build/php) are non-essential for building and running a server. +- Added a tool `tools/simulate-chunk-sending.php` to visualise the behaviour of `ChunkSelector`. + +## Fixes +- Fixed server crash on saving when player XP has reached int32 max (XP is now capped, similar to Java Edition). +- Fixed another edge case in chunk generation that led to assertion failures. +- Fixed server crash when finding a list of `TAG_Float` for entity positions instead of `TAG_Double`. +- Fixed fast eating when picking up items. +- Fixed terrain being invisible for a long time when teleporting into ungenerated terrain. +- Fixed weird chunk loading when teleporting into ungenerated terrain (sometimes farther chunks would render before closer ones, leaving holes in the map temporarily). +- Fixed players re-requesting chunks when turning their heads or jumping. +- Fixed bonemeal sometimes being consumed even when cancelling `BlockGrowEvent` and `StructureGrowEvent`. + +## API +### Event +- Added `PlayerEmoteEvent`. + +### Gameplay +- Chunks are now sent in proper circles. This improves the experience when flying quickly parallel to X or Z axis, since now more chunks in front of the player will load sooner. +- Added support for emotes. + +# 4.0.0-BETA12 +Released 9th November 2021. + +## General +- Introduced support for connecting via IPv6. + - PHP binary used must now always be built with IPv6 support, even if IPv6 is disabled. This is because RakNet may still send link-local IPv6 loopback addresses in connection packets even when only using IPv4. + - The default port for IPv6 is `19133` (similar to Bedrock Dedicated Server). + - Port `19133` is used by default so that Minecraft Bedrock can detect IPv6 servers on LAN. + - GS4 Query is supported on both IPv4 and IPv6 according to `server.properties` settings. + - The following `server.properties` settings are influential: + - `enable-ipv6`: `on` by default. Disabling this completely disables IPv6 support. + - `server-ipv6`: `::` by default (equivalent to "any IP", like `0.0.0.0` for IPv4). Most users shouldn't need to change this setting, and it doesn't appear in `server.properties` by default. + - `server-portv6`: `19133` by default. You may run both IPv4 and IPv6 on the same port. +- Various internal changes have been made to prepare for negative Y axis support (upcoming 1.18). + +## Fixes +- Fixed resource packs not applying. +- Fixed inventory windows being unopenable after dying with inventory windows open. +- Fixed plugins being able to alter other plugins' permission defaults by redeclaring them in the `plugin.yml`. + +## API +### Block +- `VanillaBlocks::fromString()` has been removed. +- Added `CraftingTableInventory`. This exclusively represents a crafting table's 3x3 crafting grid. + +### Crafting +- `CraftingGrid` is now abstract. +- Removed `CraftingGrid->getHolder()`. +- The constructor of `CraftingGrid` no longer accepts a `Player` parameter. + +### Entity +#### Effect +- `Effect->__construct()` once again accepts an `int $defaultDuration` parameter. +- Removed `VanillaEffects::fromString()`. +- Added `StringToEffectParser` + - Supports custom aliases! + - This is used by `/effect` to provide name support. + +### Event +- `InventoryOpenEvent` is now fired when a player opens a crafting table's UI. +- `InventoryCloseEvent` is now fired when a player closes a crafting table's UI. +- `PlayerDropItemEvent` will now prevent the drops from force-closing of the following inventories: + - anvil + - enchanting table + - loom + +### Inventory +- Added `TemporaryInventory`. This should be implemented by any inventory whose contents should be evacuated when closing. +- Added `PlayerCraftingInventory`. This exclusively represents the player's own 2x2 crafting grid. + +### Item +- Removed `VanillaItems::fromString()` + - Obsoleted by the far superior, much more dynamic, and plugin-customizable `StringToItemParser`. + - `StringToItemParser` allows mapping strings to closure callbacks, allowing you to create aliases for `/give` for any item, including custom ones. + +#### Enchantment +- Removed `VanillaEnchantments::fromString()`. +- Added `StringToEnchantmentParser` + - Supports custom aliases! + - This is used by `/enchant` to provide name support. + +### Player +- Removed `Player->setCraftingGrid()`. To open a 3x3 crafting grid to a player, use `setCurrentWindow(new CraftingTableInventory)`. + +### Server +- Added the following API methods: + - `Server->getIpV6()` + - `Server->getPortV6()` + +# 4.0.0-BETA13 +Released 25th November 2021. + +## General +- Improved error messages when a plugin command name or alias contains an illegal character. +- Fixed script plugins reading tags from non-docblocks before the actual docblock. +- Added a sanity check to `Human->setCurrentTotalXp()` to try and catch an elusive bug that's been appearing in the wild - please get in touch if you know how to reproduce it! +- Updated `BUILDING.md` to reflect the fact that submodules are no longer required to build or run the server. + +## Internals +- Crashdump rendering has been separated from crashdump data generation. This allows rendering crashdumps from existing JSON data. +- Direct iteration of arrays with string keys is now disallowed by a custom PHPStan rule. This is because numeric strings are casted to integers when used as array keys, which produces a variety of unexpected behaviour particularly for iteration. + - To iterate on arrays with string keys, `Utils::stringifyKeys()` must now be used. + +## Fixes +- Fixed various crashes involving bad entity data saved on disk (e.g. an item entity with invalid item would crash the server). +- Fixed various crashes involving arrays with numeric string keys. +- Fixed crash when players try to pickup XP while already having max XP. +- Fixed ungenerated chunks saved on disk by old versions of PocketMine-MP (before 3.0.0) being treated as corrupted during world conversion (they are now ignored instead). +- Fixed misleading corruption error message when saved chunks have missing NBT tags. + +## Gameplay +- Fixed `/setworldspawn` setting incorrect positions based on player position when in negative coordinates. +- `/setworldspawn` now accepts relative coordinates when used as a player. +- Added some extra aliases for `/give` and `/clear`: `chipped_anvil`, `coarse_dirt`, `damaged_anvil`, `dark_oak_standing_sign`, `jungle_wood_stairs`, `jungle_wooden_stairs` and `oak_standing_sign`. + - Some of these were added for quality-of-life, others were added just to be consistent. +- Fixed explosions dropping incorrect items when destroying blocks with tile data (e.g. banners, beds). +- Fixed the bounding box of skulls when mounted on a wall. +- Fixed podzol dropping itself when mined (instead of dirt). + +## API +### Entity +- `Projectile->move()` is now protected, like its parent. + +### Utils +- `Utils::parseDocComment()` now allows `-` in tag names. + +# 4.0.0-BETA14 +Released 30th November 2021. + +## General +- The server will now log an EMERGENCY-level message when `forceShutdown()` is used for any other reason than a graceful shutdown. +- The server will now attempt to translate invalid blocks to valid equivalents when loading chunks. This fixes many issues with `update!` blocks appearing in worlds, particularly ghost structures (these would appear when world editors previously erased some blocks by setting their IDs but not metadata). + +## Fixes +- Fixed `ConsoleReaderThread` spawning many zombie processes when running a server inside a Docker container. + +# 4.0.0-BETA15 +Released 30th November 2021. + +## General +- Added support for Minecraft: Bedrock 1.18.0 +- Removed support for earlier versions. diff --git a/changelogs/4.0.md b/changelogs/4.0.md index a08f22428..213ab4f7d 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1,111 +1,174 @@ -# 4.0.0-BETA1 -Released 7th September 2021. +# 4.0.0 +Released 1st December 2021. This major version features substantial changes throughout the core, including significant API changes, new world format support, performance improvements and a network revamp. -Please note that this is a BETA release and is not finalized. While no significant changes are expected between now and release, the API might still be changed. - Please also note that this changelog is provided on a best-effort basis, and it's possible some changes might not have been mentioned here. If you find any omissions, please submit pull requests to add them. -## WARNING -This is NOT a stable release. PMMP accepts no responsibility or liability for any damages incurred by using this build. -It should be used for TESTING purposes only. - -## Contents - * [Core](#core) - + [General](#general) - + [Configuration](#configuration) - + [World handling](#world-handling) - - [Interface](#interface) - - [Functional](#functional) - - [Performance](#performance) - + [Logger revamp](#logger-revamp) - + [Network](#network) - - [Minecraft Bedrock packet encryption](#minecraft-bedrock-packet-encryption) - - [Packet receive error handling has been overhauled](#packet-receive-error-handling-has-been-overhauled) - - [New packet handler system](#new-packet-handler-system) - * [API](#api) - + [General](#general-1) - + [Changes to `plugin.yml`](#changes-to-pluginyml) - - [Permission nesting](#permission-nesting) - - [`src-namespace-prefix`](#src-namespace-prefix) - + [Block](#block) - + [Command](#command) - + [Entity](#entity) - - [General](#general-2) - - [Effect](#effect) - - [Removal of runtime entity NBT](#removal-of-runtime-entity-nbt) - - [Entity creation](#entity-creation) - - [WIP removal of entity network metadata](#wip-removal-of-entity-network-metadata) - + [Event](#event) - - [Internal event system no longer depends on `Listener`s](#internal-event-system-no-longer-depends-on-listeners) - - [Default cancelled handling behaviour has changed](#default-cancelled-handling-behaviour-has-changed) - - [`PlayerPreLoginEvent` changes](#playerpreloginevent-changes) - - [Other changes](#other-changes) - + [Inventory](#inventory) - + [Item](#item) - - [General](#general-3) - - [NBT handling](#nbt-handling) - - [Enchantment](#enchantment) - + [Lang](#lang) - + [Network](#network-1) - + [Permission](#permission) - + [Player](#player) - + [Plugin](#plugin) - + [Scheduler](#scheduler) - - [Thread-local storage for AsyncTasks](#thread-local-storage-for-asynctasks) - - [Other changes](#other-changes-1) - + [Server](#server) - + [Level / World](#level--world) - - [General](#general-4) - - [Particles](#particles) - - [Sounds](#sounds) - + [Utils](#utils) - * [Gameplay](#gameplay) - + [Blocks](#blocks) - + [Items](#items) +* [Core](#core) + + [General](#general) + + [Dependency changes](#dependency-changes) + + [Performance](#performance) + + [Tools](#tools) + + [Commands](#commands) + + [Configuration](#configuration) + + [World handling](#world-handling) + - [Interface](#interface) + - [Functional](#functional) + - [Performance](#performance-1) + + [Logging](#logging) + + [Network](#network) + - [Performance](#performance-2) + - [Minecraft Bedrock packet encryption](#minecraft-bedrock-packet-encryption) + - [Error handling](#error-handling) + - [New packet handler system](#new-packet-handler-system) + + [Plugin loading](#plugin-loading) + + [Internals](#internals) +* [API](#api) + + [General](#general-1) + + [Changes to `plugin.yml`](#changes-to-pluginyml) + - [Permission nesting](#permission-nesting) + - [`src-namespace-prefix`](#src-namespace-prefix) + + [Other changes](#other-changes) + + [Block](#block) + + [Command](#command) + + [Entity](#entity) + - [General](#general-2) + - [Effect](#effect) + - [Removal of runtime entity NBT](#removal-of-runtime-entity-nbt) + - [Entity creation](#entity-creation) + - [WIP removal of entity network metadata](#wip-removal-of-entity-network-metadata) + + [Event](#event) + - [Internal event system no longer depends on `Listener`s](#internal-event-system-no-longer-depends-on-listeners) + - [Default cancelled handling behaviour has changed](#default-cancelled-handling-behaviour-has-changed) + - [`PlayerPreLoginEvent` changes](#playerpreloginevent-changes) + - [Other changes](#other-changes-1) + + [Inventory](#inventory) + + [Item](#item) + - [General](#general-3) + - [NBT handling](#nbt-handling) + - [Enchantment](#enchantment) + + [Lang](#lang) + + [Network](#network-1) + + [Permission](#permission) + + [Player](#player) + + [Plugin](#plugin) + + [Promise](#promise) + + [Scheduler](#scheduler) + - [Thread-local storage for AsyncTasks](#thread-local-storage-for-asynctasks) + - [Other AsyncTask changes](#other-asynctask-changes) + - [Non-AsyncTask changes](#non-asynctask-changes) + + [Server](#server) + + [Level / World](#level--world) + - [General](#general-4) + - [Particles](#particles) + - [Sounds](#sounds) + + [Utils](#utils) +* [Gameplay](#gameplay) + + [World loading](#world-loading) + + [Blocks](#blocks) + + [Items](#items) + + [Inventory](#inventory-1) + + [Misc](#misc) Table of contents generated with markdown-toc ## Core ### General -- A new "plugin greylist" feature has been introduced, which allows whitelisting or blacklisting plugins from loading. - Remote console (RCON) has been removed. The [RconServer](https://github.com/pmmp/RconServer) plugin is provided as a substitute. - Spawn protection has been removed. The [BasicSpawnProtection](https://github.com/pmmp/BasicSpawnProtection) plugin is provided as a substitute. -- CTRL+C signal handling has been removed. The [PcntlSignalHandler](https://github.com/pmmp/PcntlSignalHandler) plugin is provided as a substitute. - Player movement anti-cheat has been removed. - GS4 Query no longer breaks when disabling RakLib. -- The `pocketmine_chunkutils` PHP extension has been dropped. -- New PHP extensions are required by this version: - - [chunkutils2](https://github.com/pmmp/ext-chunkutils2) - - [morton](https://github.com/pmmp/ext-morton) -- Many bugs in player respawning have been fixed, including: - - Spawning underneath bedrock when spawn position referred to ungenerated terrain - - Spawning underneath bedrock on first server join on very slow machines (or when the machine was under very high load) - - Spawning inside blocks (or above the ground) when respawning with a custom spawn position set - - Player spawn positions sticking to the old location when world spawn position changed - this was because the world spawn at time of player creation was used as the player's custom spawn, so the bug will persist for older player data, but will work as expected for new players. - PreProcessor is removed from builds due to high maintenance cost and low benefit. Its usage is now discouraged. +- The title bar no longer displays heap memory usage numbers (nobody seemed to know that was what it was, anyway). +- `start.sh` no longer specifically mentions PHP 7 when erroring because of a missing PHP binary. +- The `--bootstrap` CLI option has been removed. +- Introduced support for connecting via IPv6: + - PHP binary used must now always be built with IPv6 support, even if IPv6 is disabled. This is because RakNet may still send link-local IPv6 loopback addresses in connection packets even when only using IPv4. + - Port `19133` is used for IPv6 by default so that Minecraft Bedrock can detect IPv6 servers on LAN. + - GS4 Query is supported on both IPv4 and IPv6 according to `server.properties` settings. + - New `server.properties` options `enable-ipv6`, `server-ipv6`, `server-portv6` have been added (see below). + +### Dependency changes +- The `pocketmine_chunkutils` PHP extension has been dropped. +- IPv6 support in PHP is now mandatory. +- New PHP extensions are required by this version: + - [crypto](https://github.com/bukka/php-crypto) + - [chunkutils2](https://github.com/pmmp/ext-chunkutils2) + - [gmp](https://www.php.net/manual/en/book.gmp.php) + - [igbinary](https://github.com/igbinary/igbinary) + - [leveldb](https://github.com/pmmp/php-leveldb) (must be built with [pmmp/leveldb](https://github.com/pmmp/leveldb/tree/mojang-compatible)) + - [morton](https://github.com/pmmp/ext-morton) +- The following Composer dependency versions have changed (**PLEASE READ, dependency API changes are not mentioned in this changelog!**): + - `pocketmine/bedrock-protocol` has been added at [7.0.0](https://github.com/pmmp/BedrockProtocol/releases/tag/7.0.0+bedrock-1.18.0). + - `pocketmine/classloader` has been updated from 0.1.0 to [0.2.0](https://github.com/pmmp/ClassLoader/releases/tag/0.2.0) (**significant API changes, new features**). + - `pocketmine/color` has been added at [0.2.0](https://github.com/pmmp/Color/releases/tag/0.2.0). + - `pocketmine/errorhandler` has been added at [0.3.0](https://github.com/pmmp/ErrorHandler/releases/tag/0.3.0). + - `pocketmine/locale-data` has been added at [2.0.16](https://github.com/pmmp/Language/releases/tag/2.0.16). + - `pocketmine/log` has been updated from 0.2.0 to [0.4.0](https://github.com/pmmp/Log/releases/tag/0.4.0) (**minor API changes**, see also [0.3.0](https://github.com/pmmp/Log/releases/tag/0.3.0)). + - `pocketmine/nbt` has been updated from 0.2.18 to [0.3.0](https://github.com/pmmp/NBT/releases/tag/0.3.0) (**significant API changes**). + - `pocketmine/raklib` has been updated from 0.12.7 to [0.14.2](https://github.com/pmmp/RakLib/releases/tag/0.14.2) (**significant API changes**, see also [0.13.0](https://github.com/pmmp/RakLib/releases/tag/0.13.0)). + - `pocketmine/raklib-ipc` has been added at [0.1.0](https://github.com/pmmp/RakLibIpc/releases/tag/0.1.0) (components extracted from RakLib). + - `pocketmine/snooze` has been updated from 0.1.0 to [0.3.0](https://github.com/pmmp/Snooze/releases/tag/0.3.0) (**minor API changes**, see also [0.2.0](https://github.com/pmmp/Snooze/releases/tag/0.2.0)). + - `pocketmine/spl` has been dropped. +- Minecraft Bedrock protocol is now developed in a separate repository, [pmmp/BedrockProtocol](https://github.com/pmmp/BedrockProtocol). + - It has significant changes compared to PM3. Please read its changelogs. +- The following submodules have been removed: + - `resources/vanilla`: BedrockData is now included via Composer dependency [`pocketmine/bedrock-data`](https://packagist.org/packages/pocketmine/bedrock-data). + - `resources/locale`: Language files are now included via Composer dependency [`pocketmine/locale-data`](https://packagist.org/packages/pocketmine/locale-data). + - This means it's now possible to run a server from git sources without cloning submodules :) + - All remaining submodules (DevTools, build/php) are non-essential for building and running a server. + +### Performance +- `/op`, `/deop`, `/whitelist add` and `/whitelist remove` no longer cause player data to be loaded from disk for no reason. +- Timings now use high-resolution timers provided by `hrtime()` to collect more accurate performance metrics. +- Closures are now used for internal event handler calls. This provides a performance improvement of 10-20% over the 3.x system, which had to dynamically resolve callables for every event call. +- Improved startup performance when loading many plugins. +- See more in the [Worlds / Performance](#performance-2) and [Network / Performance](#performance-3) sections. + +### Tools +Some new scripts have been added in the `tools/` directory of the repository. These scripts may use the PocketMine-MP core library, but are intended to be run standalone. + + - `convert-world.php`: allows converting a world to a new format without a running server + - `compact-regions.php`: repacks files in legacy Region worlds to clean up wasted disk space + - `generate-permission-doc.php`: generates a Markdown document of all core permissions (see [example](https://gist.github.com/dktapps/eed6d6a4571f01b676236bf9ff2779b2)) + - `simulate-chunk-selector.php`: generates a series of images to visualize the behaviour of the chunk sending algorithm; these images can then be stitched into video using a tool such as [ffmpeg](https://ffmpeg.org/) ### Commands -- The `/reload` command has been removed. - The `/effect` command no longer supports numeric IDs - it's now required to use names. - The `/enchant` command no longer supports numeric IDs - it's now required to use names. +- The `/give` command no longer permits giving items with invalid NBT (e.g. incorrect types). Previously, this was the cause of random server crashes when using items on PM3. +- The `/give` command now supports many new aliases like in Java, e.g. it's now possible to do `/give someone bonemeal` or `/give someone lapis_lazuli` instead of using legacy id:metadata. +- The `/help` command is now localized according to language set in `server.properties`. +- The `/reload` command has been removed. +- The `/setworldspawn` command now accepts relative coordinates when used as a player. +- The `/status` command no longer displays heap memory usage numbers. - Added `/clear` command with functionality equivalent to that of vanilla Minecraft. - The following commands' outputs are now localized according to the chosen language settings: - `/gc` - `/status` - `/op` - `/deop` +- Fixed use of commands without the proper permission sending a message `commands.generic.permission` instead of the proper message. +- Fixed commands not working in some cases after using some control sequences on the console. +- Fixed `/setworldspawn` setting incorrect positions based on player position when in negative coordinates. ### Configuration - World presets can now be provided as a `preset` key in `pocketmine.yml`, instead of putting them in the `generator` key. +- The `worlds` config no longer supports attaching the generator settings to the `generator` key (use the `preset` key instead). +- Using an unknown generator in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world. +- Using invalid/incorrect world generator options (presets) in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world. - The following new options have been added to `pocketmine.yml`: - `chunk-ticking.blocks-per-subchunk-per-tick` (default `3`): Increasing this value will increase the rate at which random block updates happen (e.g. grass growth). - `network.enable-encryption` (default `true`): Controls whether Minecraft network packets are encrypted or not. - The following options have been removed from `pocketmine.yml`: - - `chunk-ticking.light-updates`: Since lighting is needed for basic vanilla functionality to work, allowing this to be disabled without disabling chunk ticking made no sense. If you don't want light calculation to occur, you can disable chunk ticking altogether. + - `chunk-ticking.light-updates`: Since lighting is needed for basic vanilla functionality to work, allowing this to be disabled without disabling chunk ticking made no sense. If you don't want light calculation to occur, you can disable chunk ticking altogether by setting `chunk-ticking.per-tick` to `0` in `pocketmine.yml`. - `player.anti-cheat.allow-movement-cheats` +- The following new options have been added to `server.properties`: + - `enable-ipv6`: `on` by default. Disabling this completely disables IPv6 support. + - `server-ipv6`: `::` by default (equivalent to "any IP", like `0.0.0.0` for IPv4). Most users shouldn't need to change this setting, and it doesn't appear in `server.properties` by default. + - `server-portv6`: `19133` by default. You may run both IPv4 and IPv6 on the same port, but since Bedrock scans on 19133 by default, PM also uses the same. ### World handling #### Interface @@ -118,37 +181,52 @@ It should be used for TESTING purposes only. - `mcregion` - `anvil` - `pmanvil` +- Generator options of existing worlds are now validated before loading them. If they are invalid, the server will fail to load them. +- Fixed the server attempting to generate a world if it failed to load. - 256 build-height is now supported in all worlds (facilitated by automatic conversion). - Extended blocks are now supported (facilitated by automatic conversion). +- The server will now attempt to translate invalid blocks to valid equivalents when loading chunks. This fixes many issues with `update!` blocks appearing in worlds, particularly ghost structures (these would appear when world editors previously erased some blocks by setting their IDs but not metadata). - Lighting is no longer stored or loaded from disk - instead, it's calculated on the fly as-needed. This fixes many long-standing bugs. +- Explosions now use the standard mechanism for processing block updates. Previously, it used a special mechanism due to prohibitively poor efficiency of the standard algorithm. Since these inefficiencies have now been addressed, explosions can now be consistent with everything else, with minimal performance impact. +- Fixed debug spam of `chunk has no loaders registered` messages during chunk generation. +- Various cases of corrupted data in chunks will now cause an error to be logged instead of a server crash. This includes tiles with colliding positions and tiles in incorrect, non-loaded chunks. +- Fixed players re-requesting the same ungenerated chunks multiple times before they were sent. +- Fixed players re-requesting chunks when turning their heads or jumping. #### Performance - `leveldb` is now the primary supported world format. It is inherently faster than region-based formats thanks to better design. - Partial chunk saves (only saving modified subcomponents of chunks) has been implemented. This drastically reduces the amount of data that is usually necessary to write on chunk save, which in turn **drastically reduces the time to complete world saves**. This is possible thanks to the modular design of the `leveldb` world format - this enhancement is not possible with region-based formats. - Lighting is no longer guaranteed to be available on every chunk. It's now calculated on the fly as-needed. -- `/op`, `/deop`, `/whitelist add` and `/whitelist remove` no longer cause player data to be loaded from disk for no reason. -- Timings now use high-resolution timers provided by `hrtime()` to collect more accurate performance metrics. - Z-order curves (morton codes) are now used for block and chunk coordinate hashes. This substantially improves performance in many areas by resolving a hashtable key hash collision performance issue. Affected areas include explosions, light calculation, and more. -- [`libdeflate`](https://github.com/ebiggers/libdeflate) is now (optionally) used for outbound Minecraft packet compression. It's more than twice as fast as zlib in most cases, providing significant performance boosts to packet broadcasts and overall network performance. -- Closures are now used for internal event handler calls. This provides a performance improvement of 10-20% over the 3.x system, which had to dynamically resolve callables for every event call. +- Improved performance of `World->setBlock()` by around 35% when the `$update` parameter is set to `true`. +- Improved performance of `World->setBlock()` by around 30% when the `$update` parameter is set to `false`. -### Logger revamp +### Logging - Many components now have a dedicated logger which automatically adds [prefixes] to their messages. - Main logger now includes milliseconds in timestamps. +- Debug messages are now logged when reach distance checks prevent players from doing something. +- Various messages related to world loading/generation/conversion and plugin loading errors are now localized according to the language set in `server.properties`. +- Exception log format has been changed. Now, exception info is logged in one big block message. This saves space on the console and improves readability, as well as reducing the ability for bad `ThreadedLoggerAttachment`s to break exception output. +- Improved error messages when a plugin command name or alias contains an illegal character. +- The server will now log an EMERGENCY-level message when `Server->forceShutdown()` is used for any other reason than a graceful shutdown. ### Network This version features substantial changes to the network system, improving coherency, reliability and modularity. +#### Performance +- [`libdeflate`](https://github.com/ebiggers/libdeflate) is now (optionally) used for outbound Minecraft packet compression. It's more than twice as fast as zlib in most cases, providing significant performance boosts to packet broadcasts and overall network performance. + #### Minecraft Bedrock packet encryption - This fixes replay attacks where hackers steal and replay player logins. - A new setting has been added to `pocketmine.yml`: `network.enable-encryption` which is `true` by default. -#### Packet receive error handling has been overhauled +#### Error handling - Only `BadPacketException` is now caught during packet decode and handling. This requires that all decoding MUST perform proper data error checking. - Throwing a `BadPacketException` from decoding will now cause players to be kicked with the message `Packet processing error`. - The disconnect message includes a random hex ID to help server owners identify the problems reported by their players. - Throwing any other exception will now cause a server crash. `Internal server error` has been removed. - It is now illegal to send a clientbound packet to the server. Doing so will result in the client being kicked with the message `Unexpected non-serverbound packet`. +- Fixed server crash when unable to bind to the desired port. Now, the server will show an error and gracefully stop without a crashdump instead. #### New packet handler system - Packet handlers have been separated from NetworkSession into a dedicated packet handler structure. @@ -158,6 +236,16 @@ This version features substantial changes to the network system, improving coher - Packet handlers are now almost entirely absent from `Player` and instead appear in their own dedicated units. - Almost all game logic that was previously locked up inside packet handlers in `Player` has been extracted into new API methods. See Player API changes for details. +### Plugin loading +- Phar plugins are now able to depend on folder plugins loaded by DevTools. +- A new "plugin greylist" feature has been introduced, which allows whitelisting or blacklisting plugins from loading. See `plugin_list.yml`. + +### Internals +- Crashdump rendering has been separated from crashdump data generation. This allows rendering crashdumps from existing JSON data. +- Direct iteration of arrays with string keys is now disallowed by a custom PHPStan rule. This is because numeric strings are casted to integers when used as array keys, which produces a variety of unexpected behaviour particularly for iteration. + - To iterate on arrays with string keys, `Utils::stringifyKeys()` must now be used. +- Fixed various crashes involving arrays with numeric string keys. + ## API ### General - Most places which previously allowed `callable` now only allow `\Closure`. This is because closures have more consistent behaviour and are more performant. @@ -215,14 +303,26 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` **Note**: The old structure will also still work just fine. This is not a required change. +### Other changes +- Incorrect structure of `commands` is now detected earlier and handled more gracefully. +- Commands must now declare `permission` for each command. Previously, the `permission` key was optional, causing anyone to be able to use the command. + - This behaviour was removed because of the potential for security issues - a typo in `plugin.yml` could lead to dangerous functionality being exposed to everyone. + - If you want to make a command that everyone can use, declare a permission with a `default` of `true` and assign it to the command. +- Permissions must now declare `default` for each permission. Previously, the `default` key was optional, causing the permission to silently be denied to everyone (PM4) or granted to ops implicitly (PM3). + ### Block - A new `VanillaBlocks` class has been added, which contains static methods for creating any currently-known block type. This should be preferred instead of use of `BlockFactory::get()` where constants were used. +- `BlockFactory` is now a singleton, and its methods are no longer static. `BlockFactory::whatever()` should be replaced with `BlockFactory::getInstance()->whatever()`. +- `BlockFactory->get()` is now **deprecated**. + - For most cases, `VanillaBlocks::WHATEVER_BLOCK()` should fill your needs. + - `BlockFactory` should now only be used for loading old save data from, for example, a database, config or a world save. + - To refer to blocks by name, consider using `StringToItemParser` to accept names instead of IDs. - Blocks now contain their positions instead of extending `Position`. `Block->getPosition()` has been added. - Blocks with IDs >= 256 are now supported. - Block state and variant metadata have been separated. - Variant is considered an extension of ID and is immutable. - `Block->setDamage()` has been removed. - - All blocks now have getters and setters for their appropriate block properties, such as facing, lit/unlit, colour (in some cases), and many more. These should be used instead of metadata. +- All blocks now have getters and setters for their appropriate block properties, such as facing, lit/unlit, colour (in some cases), and many more. These should be used instead of metadata. - Tile entities are now created and deleted automatically when `World->setBlock()` is used with a block that requires a tile entity. - Some tile entities' API has been exposed on their corresponding `Block` classes, with the tile entity classes being deprecated. - The `pocketmine\tile` namespace has been relocated to `pocketmine\block\tile`. @@ -237,9 +337,11 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Block->isCompatibleWithTool()` -> `BlockBreakInfo->isToolCompatible()` - The following API methods have been added: - `Block->asItem()`: returns an itemstack corresponding to the block + - `Block->getModelPositionOffset()`: used to offset the bounding box of blocks like bamboo based on coordinates - `Block->isSameState()`: returns whether the block is the same as the parameter, including state information - `Block->isSameType()`: returns whether the block is the same as the parameter, without state information - `Block->isFullCube()` + - `Liquid->getMinAdjacentSourcesToFormSource()`: returns how many adjacent source blocks of the same liquid must be present in order for the current block to become a source itself - The following hooks have been added: - `Block->onAttack()`: called when a player in survival left-clicks the block to try to start breaking it - `Block->onEntityLand()`: called when an entity lands on this block after falling (from any distance) @@ -256,12 +358,16 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Block->setDamage()` - `Block::get()`: this was superseded by `BlockFactory::get()` a long time ago - `Block->getBoundingBox()` +- The following classes have been added: + - `inventory\CraftingTableInventory`: represents a crafting table's 3x3 crafting grid + - `utils\LeverFacing` + - `utils\MinimumFlowCostCalculator`: encapsulates flow calculation logic previously locked inside `Liquid`. - The following classes have been renamed: - `BlockIds` -> `BlockLegacyIds` - `CobblestoneWall` -> `Wall` - `NoteBlock` -> `Note` - - `SignPost` -> `Sign` - - `StandingBanner` -> `Banner` + - `SignPost` -> `FloorSign` + - `StandingBanner` -> `FloorBanner` - The following classes have been removed: - `Bricks` - `BurningFurnace` @@ -308,7 +414,14 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - The following API methods have signature changes: - `Command->setPermission()` argument is now mandatory (but still nullable). - `CommandSender->setScreenLineHeight()` argument is now mandatory (but still nullable). + - `Command->getDescription()` now returns `Translatable|string`. + - `Command->getUsage()` now returns `Translatable|string`. + - `Command->setDescription()` now accepts `Translatable|string`. + - `Command->setUsage()` now accepts `Translatable|string`. +- `Command->setPermission()` now throws an exception if given a string containing non-existing permissions. Previously, it would silently default to allowing ops to use the command, which may not have been desired. + - This is usually caused by a typo or forgotten permission declaration. - Commands with spaces in the name are no longer supported. +- Command usage strings and description strings are no longer automatically translated (use `Translatable` instead of bare string keys). ### Entity #### General @@ -337,6 +450,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Entity->setPositionAndRotation()` is now `protected` (use `Entity->teleport()` instead). - `Living->knockBack()` now accepts `float, float, float` (the first two parameters have been removed). - `Living->getEffects()` now returns `EffectManager` instead of `Effect[]`. + - `Location->__construct()` now accepts `?World $world` in the 4th parameter, and all parameters are now mandatory. - The following classes have been added: - `effect\EffectManager`: contains effect-management functionality extracted from `Living` - `HungerManager`: contains hunger-management functionality extracted from `Human` @@ -388,6 +502,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Rideable` - `Vehicle` - `Skin` now throws exceptions on creation if given invalid data. +- Fixed `Living->lookAt()` not taking eye height into account. #### Effect - All `Effect` related classes have been moved to the `pocketmine\entity\effect` namespace. @@ -416,9 +531,10 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Effect->getId()` -> `EffectIdMap->toId()` - `Effect::registerEffect()` -> `EffectIdMap->register()` - `Effect::getEffect()` -> `EffectIdMap->fromId()` - - `Effect::getEffectByName()` -> `VanillaEffects::fromString()` -- The following API methods have been added: - - `Effect->getRuntimeId()`: this is a **dynamic ID** which can be used for effect type comparisons. **This cannot be stored, so don't use it in configs or NBT!** + - `Effect::getEffectByName()` -> `StringToEffectParser->parse()` +- Added `StringToEffectParser` singleton: + - Supports custom aliases! + - This is used by `/effect` to provide name support. #### Removal of runtime entity NBT - Entities no longer keep their NBT alive at runtime. @@ -430,17 +546,18 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Entity::createEntity()` has been removed. It's no longer needed for creating new entities at runtime - just use `new YourEntity` instead. - `Entity` subclass constructors can now have any signature, just like a normal class. - Loading entities from NBT is now handled by `EntityFactory`. It works quite a bit differently than `Entity::createEntity()` did. Instead of registering `YourEntity::class` to a set of Minecraft save IDs, you now need to provide a callback which will construct an entity when given some NBT and a `World`. - - The creation callback is registered using `EntityFactory::register()`. - - The creation callback must have the signature `function(World, CompoundTag) : Entity`. + - `EntityFactory` is a singleton. You can get its instance by using `EntityFactory::getInstance()`. + - Creation callbacks are registered using `EntityFactory->register()`. + - Creation callbacks must have the signature `function(World, CompoundTag) : Entity`. - This enables `Entity` subclasses to have any constructor parameters they like. - It also allows requiring that certain data is always provided (for example, it doesn't make much sense to create a `FallingBlock` without specifying what type of block). - Examples: - `ItemEntity` now requires an `Item` in its constructor, so its creation callback decodes the `Item` from the NBT to be passed to the constructor. - `Painting` now requires a `PaintingMotive` in its constructor, so its creation callback decides which `PaintingMotive` to provide based on the NBT it receives. - See `EntityFactory` for more examples. -- `EntityFactory::register()` (previously `Entity::registerEntity()`) will now throw exceptions on error cases instead of returning `false`. +- `EntityFactory->register()` (previously `Entity::registerEntity()`) will now throw exceptions on error cases instead of returning `false`. - The following API methods have been moved: - - `Entity::registerEntity()` -> `EntityFactory::register()` + - `Entity::registerEntity()` -> `EntityFactory->register()` - The following classes have changed constructors: - All projectile subclasses now require a `?Entity $thrower` parameter. - `Arrow->__construct()` now requires a `bool $critical` parameter (in addition to the `$thrower` parameter). @@ -480,6 +597,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - Handler functions will now **not receive cancelled events by default**. This is a **silent BC break**, i.e. it won't raise errors, but it might cause bugs. - `@ignoreCancelled` is now no longer respected. - `@handleCancelled` has been added. This allows opting _into_ receiving cancelled events (it's the opposite of `@ignoreCancelled`). + - `@handleCancelled` may not be used on non-cancellable events (an exception will be thrown during registration). #### `PlayerPreLoginEvent` changes - The `Player` object no longer exists at this phase of the login. Instead, a `PlayerInfo` object is provided, along with connection information. @@ -521,28 +639,39 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` #### Other changes - Disconnecting players during events no longer crashes the server (although it might cause other side effects). -- `PlayerKickEvent` is no longer fired for disconnects that occur before the player completes the initial login sequence (i.e. completing downloading resource packs). - Cancellable events must now implement `CancellableTrait` to get the cancellable components needed to satisfy interface requirements. `Event` no longer stubs these methods. - `PlayerInteractEvent` is no longer fired when a player activates an item. This fixes the age-old complaint of `PlayerInteractEvent` firing multiple times when interacting once. The following constants have been removed: - `PlayerInteractEvent::LEFT_CLICK_AIR` - `PlayerInteractEvent::RIGHT_CLICK_AIR` - `PlayerInteractEvent::PHYSICAL` - The following events have been added: - - `PlayerEntityInteractEvent`: player right-clicking (or long-clicking on mobile) on an entity. - - `PlayerItemUseEvent`: player activating their held item, for example to throw it. - `BlockTeleportEvent`: block teleporting, for example dragon egg when attacked. - - `PlayerDisplayNameChangeEvent` - `EntityItemPickupEvent`: player (or other entity) picks up a dropped item (or arrow). Replaces `InventoryPickupItemEvent` and `InventoryPickupArrowEvent`. - Unlike its predecessors, this event supports changing the destination inventory. - If the destination inventory is `null`, the item will be destroyed. This is usually seen for creative players with full inventories. - `EntityTrampleFarmlandEvent`: mob (or player) jumping on farmland causing it to turn to dirt + - `PlayerDisplayNameChangeEvent` + - `PlayerEmoteEvent` + - `PlayerEntityInteractEvent`: player right-clicking (or long-clicking on mobile) on an entity. + - `PlayerItemUseEvent`: player activating their held item, for example to throw it. - `StructureGrowEvent`: called when trees or bamboo grow (or any other multi-block plant structure). +- The following events have changed behaviour: + - Bone meal is now consistently never consumed when `BlockGrowEvent` or `StructureGrowEvent` is cancelled. + - `BlockGrowEvent` is now called when cocoa pods grow. + - `ChunkPopulateEvent` is now called after all adjacent chunks modified during population have been updated. This fixes issues with modifications made in the event sometimes disappearing. + - `InventoryOpenEvent` is now fired when a player opens a crafting table's UI. + - `InventoryCloseEvent` is now fired when a player closes a crafting table's UI. + - `PlayerDropItemEvent` will now prevent the drops from force-closing of the following inventories: + - anvil + - enchanting table + - loom + - `PlayerKickEvent` is no longer fired for disconnects that occur before the player completes the initial login sequence (i.e. completing downloading resource packs). - The following events have been removed: - `EntityArmorChangeEvent` - `EntityInventoryChangeEvent` - `EntityLevelChangeEvent` - `EntityTeleportEvent` with world checks should be used instead. - - `InventoryPickupItemEvent` - use `EntityItemPickupEvent` instead - `InventoryPickupArrowEvent` - use `EntityItemPickupEvent` instead + - `InventoryPickupItemEvent` - use `EntityItemPickupEvent` instead - `NetworkInterfaceCrashEvent` - `PlayerCheatEvent` - `PlayerIllegalMoveEvent` @@ -560,6 +689,8 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `HandlerList::unregisterAll()` -> `HandlerListManager->unregisterAll()` - `HandlerList::getHandlerListFor()` -> `HandlerListManager->getListFor()` - `HandlerList::getHandlerLists()` -> `HandlerListManager->getAll()` +- The following API methods have changed behaviour: + - `PlayerCreationEvent->setPlayerClass()` now verifies that the player class set is instantiable. - The following classes have been moved: - `pocketmine\plugin\RegisteredListener` -> `pocketmine\event\RegisteredListener` @@ -569,9 +700,12 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `CallbackInventoryChangeListener` - `CreativeInventory`: contains the creative functionality previously embedded in `pocketmine\item\Item`, see Item changes for details - `InventoryChangeListener`: allows listening (but not interfering with) events in an inventory. + - `PlayerCraftingInventory`: represents the player's own 2x2 crafting grid. - `PlayerEnderInventory`: represents the pure storage part of the player's ender inventory, without any block information + - `TemporaryInventory`: interface which should be implemented by any inventory whose contents should be evacuated when closing. - `transaction\CreateItemAction` - `transaction\DestroyItemAction` + - `transaction\TransactionBuilderInventory`: facilitates building `InventoryTransaction`s using standard `Inventory` API methods - The following classes have been renamed / moved: - `ContainerInventory` -> `pocketmine\block\inventory\BlockInventory` - The following classes have been moved to the `pocketmine\block\inventory` namespace: @@ -591,9 +725,11 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Inventory->getChangeListeners()` - `Inventory->removeChangeListeners()` - `Inventory->swap()`: swaps the contents of two slots + - `Inventory->getAddableItemQuantity()`: returns how many items from the given stack can be added to the inventory, used for partial pickups of itemstacks with a full inventory - The following API methods have been removed: - `BaseInventory->getDefaultSize()` - `BaseInventory->setSize()` + - `CraftingGrid->getHolder()` - `EnderChestInventory->setHolderPosition()` - `Inventory->close()` - `Inventory->dropContents()` @@ -607,24 +743,28 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `InventoryAction->onExecuteSuccess()` - `PlayerInventory->sendCreativeContents()` - The following API methods have signature changes: + - `BaseInventory->__construct()` no longer accepts a list of items to initialize with. + - `CraftingGrid->__construct()` no longer accepts a `Player` parameter. - `Inventory->clear()` now returns `void` instead of `bool`. - `Inventory->setItem()` now returns `void` instead of `bool`. - `InventoryAction->execute()` now returns `void` instead of `bool`. - - `BaseInventory->construct()` no longer accepts a list of items to initialize with. - `PlayerInventory->setItemInHand()` now sends the update to viewers of the player. +- `CraftingGrid` is now abstract. ### Item #### General - A new `VanillaItems` class has been added, which contains static methods for creating any currently-known item type. This should be preferred instead of use of `ItemFactory::get()` where constants were used. -- `StringToItemParser` has been added, which allows mapping any string to any item, irrespective of IDs. These mappings are used by `/give` and `/clear`, and are made with custom plugin aliases in mind. +- `StringToItemParser` singleton has been added: + - This allows mapping any string to any item, irrespective of IDs + - These mappings are used by `/give` and `/clear`, and are made with custom plugin aliases in mind. - Yes, this means you can finally add your own custom aliases to `/give` without ugly hacks! -- `LegacyStringToItemParser` has been added, which is a slightly more dynamic (but still inadvisable) replacement for `ItemFactory::fromString()`. +- `LegacyStringToItemParser` singleton has been added. This supports id:meta parsing in the same way that `ItemFactory::fromString()` used to, but its use is discouraged. +- `ItemFactory` is now a singleton instead of static class, and its remaining methods are no longer static. You can get its instance by `ItemFactory::getInstance()`. - `Item->count` is no longer public. - The hierarchy of writable books has been changed: `WritableBook` and `WrittenBook` now extend `WritableBookBase`. - The following API methods have signature changes: - `WritableBookBase->setPages()` now accepts `WritableBookPage[]` instead of `CompoundTag[]`. - - `ItemFactory::get()` no longer accepts `string` for the `tags` parameter. - - `ItemFactory::fromString()` no longer accepts a `$multiple` parameter and now only returns `Item`, not `Item|Item[]`. + - `ItemFactory->get()` no longer accepts `string` for the `tags` parameter. - The following methods are now fluent: - `WritableBookBase->setPages()` - `Item->addEnchantment()` @@ -639,8 +779,9 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Item->removeNamedTagEntry()` - `Item->setDamage()`: "Damage" is now immutable for all items except `Durable` descendents. - `Item->setNamedTagEntry()` - - `Item::get()`: this was superseded by `ItemFactory::get()` a long time ago - - `Item::fromString()`: this was superseded by `ItemFactory::fromString()` a long time ago + - `Item::get()`: prefer `VanillaItems` or `StringToItemParser` if possible; use `ItemFactory->get()` if you have no other choice + - `Item::fromString()`: use `StringToItemParser->parse()` or `LegacyStringToItemParser->parse()` instead + - `ItemFactory::fromString()` - `Item->setCompoundTag()` - `Item->getCompoundTag()` - `Item->hasCompoundTag()` @@ -701,6 +842,8 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `LiquidBucket` - `MilkBucket` - `PotionType`: enum class containing information about vanilla potion types + - `Releasable`: this interface is implemented by items like bows which have a "release" action + - `StringToItemParser`: allows converting string IDs into any item, used by `/give` and `/clear` - `WritableBookBase` - `WritableBookPage` - The following API methods have been added: @@ -742,7 +885,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - Example: `Enchantment::get(Enchantment::PROTECTION)` is replaced by `VanillaEnchantments::PROTECTION()` - These methods also provide proper type information to static analysers instead of just generic `Enchantment`, making them easier to code with. - The boundaries between MCPE enchantment IDs and PocketMine-MP internals are now more clear. - - ID handling is moved to `pocketmine\data\bedrock\EnchantmentIdMap`. + - ID handling is moved to `pocketmine\data\bedrock\EnchantmentIdMap` singleton. - All enchantment ID constants have been removed from `Enchantment`. `pocketmine\data\bedrock\EnchantmentIds` if you still need legacy effect IDs for some reason. - `Enchantment::RARITY_*` constants were moved to `Rarity` class, and the `RARITY_` prefixes removed. - `Enchantment::SLOT_*` constants were moved to `ItemFlags` class, and the `SLOT_` prefixes removed. @@ -750,9 +893,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Enchantment::registerEnchantment()` -> `EnchantmentIdMap->register()` - `Enchantment::getEnchantment()` -> `EnchantmentIdMap->fromId()` - `Enchantment->getId()` -> `EnchantmentIdMap->toId()` - - `Enchantment::getEnchantmentByName()` -> `VanillaEnchantments::fromString()` -- The following API methods have been added: - - `Enchantment->getRuntimeId()`: this is a **dynamic ID** which can be used for enchantment type comparisons. **This cannot be stored, so don't use it in configs or NBT!** + - `Enchantment::getEnchantmentByName()` -> `StringToEnchantmentParser->parse()` ### Lang - The following classes have been renamed: @@ -780,6 +921,8 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` ### Network - The following fields have been removed: - `Network::$BATCH_THRESHOLD` +- The following classes have been added: + - `NetworkInterfaceStartException`: this may be thrown by `Network->registerInterface()` and `NetworkInterface->start()` to cause a graceful failure without crashing - this should be used when, for example, you are unable to bind a port - The following classes have been renamed: - `SourceInterface` -> `NetworkInterface` - `AdvancedSourceInterface` -> `AdvancedNetworkInterface` @@ -855,13 +998,15 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `ServerOperator` ### Player -- The following classes have moved to the new `pocketmine\player` namespace: +- The following classes have been added/moved to the new `pocketmine\player` namespace: - `Achievement` - `GameMode` - `IPlayer` - `OfflinePlayer` - `PlayerInfo` - `Player` + - `SurvivalBlockBreakHandler`: handles cracking animation, sounds and particles when mining a block in creative + - `UsedChunkStatus`: enum used internally by the chunk sending system - The following constants have been removed: - `Player::SURVIVAL` - use `GameMode::SURVIVAL()` - `Player::CREATIVE` - use `GameMode::CREATIVE()` @@ -876,35 +1021,45 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Player->breakBlock()`: destroy the target block in the current world (immediately) - `Player->consumeHeldItem()`: consume the previously activated item, e.g. eating food - `Player->continueBreakBlock()`: punch the target block during destruction in survival, advancing break animation and creating particles + - `Player->getCurrentWindow()`: returns the inventory window the player is currently viewing, or null if they aren't viewing an inventory - `Player->getItemCooldownExpiry()`: returns the tick on which the player's cooldown for a given item expires + - `Player->getPlayerInfo()`: returns a `PlayerInfo` object containing various metadata about the player + - `Player->getSaveData()`: returns save data generated on the fly - `Player->hasFiniteResources()` - `Player->interactBlock()`: interact (right click) the target block in the current world - `Player->interactEntity()`: interact (right click) the target entity, e.g. to apply a nametag (not implemented yet) - `Player->pickBlock()`: picks (mousewheel click) the target block in the current world - `Player->releaseHeldItem()`: release the previously activated item, e.g. shooting a bow + - `Player->removeCurrentWindow()`: removes the inventory window the player is currently viewing, if any - `Player->selectHotbarSlot()`: select the specified hotbar slot + - `Player->setCurrentWindow()`: sets the inventory the player is currently viewing - `Player->stopBreakBlock()`: cease attacking a previously attacked block - `Player->toggleFlight()`: tries to start / stop flying (fires events, may be cancelled) - `Player->updateNextPosition()`: sets the player's next attempted move location (fires events, may be cancelled) - `Player->useHeldItem()`: activate the held item, e.g. throwing a snowball - - `Player->getSaveData()`: returns save data generated on the fly - The following API methods have been removed: + - `IPlayer->isBanned()`: this was unreliable because it only checked name bans and didn't account for plugin custom ban systems. Use `Server->getNameBans()->isBanned()` and `Server->getIPBans()->isBanned()` instead. + - `IPlayer->isOp()`: use `Server` APIs instead + - `IPlayer->isWhitelisted()`: use `Server->isWhitelisted()` instead + - `IPlayer->setBanned()`: use `Server` APIs instead + - `IPlayer->setOp()`: use `Server` APIs instead + - `IPlayer->setWhitelisted()`: use `Server->setWhitelisted()` instead - `Player->addActionBarMessage()`: replaced by `sendActionBarMessage()` - `Player->addSubTitle()`: replaced by `sendSubTitle()` - `Player->addTitle()`: replaced by `sendTitle()` + - `Player->addWindow()`: use `Player->setCurrentWindow()` instead + - `Player->dataPacket()`: replaced by `NetworkSession->sendDataPacket()` - `Player->getAddress()`: replaced by `NetworkSession->getIp()` - `Player->getPing()`: moved to `NetworkSession` - `Player->getPort()`: moved to `NetworkSession` - - `Player->updatePing()`: moved to `NetworkSession` - - `Player->dataPacket()`: replaced by `NetworkSession->sendDataPacket()` + - `Player->getWindow()`: use `Player->getCurrentWindow()` instead + - `Player->getWindowId()` + - `Player->removeAllWindows()` + - `Player->removeWindow()`: use `Player->removeCurrentWindow()` instead - `Player->sendDataPacket()`: replaced by `NetworkSession->sendDataPacket()` + - `Player->setCraftingGrid()`: crafting tables now work the same way as other containers; use `Player->setCurrentWindow()` - `Player->updateNextPosition()`: use `Player->handleMovement()` instead - - `IPlayer->isWhitelisted()`: use `Server->isWhitelisted()` instead - - `IPlayer->setWhitelisted()`: use `Server->setWhitelisted()` instead - - `IPlayer->isBanned()`: this was unreliable because it only checked name bans and didn't account for plugin custom ban systems. Use `Server->getNameBans()->isBanned()` and `Server->getIPBans()->isBanned()` instead. - - `IPlayer->setBanned()`: use `Server` APIs instead - - `IPlayer->isOp()`: use `Server` APIs instead - - `IPlayer->setOp()`: use `Server` APIs instead + - `Player->updatePing()`: moved to `NetworkSession` ### Plugin - API version checks are now more strict. It is no longer legal to declare multiple minimum versions on the same major version. Doing so will now cause the plugin to fail to load with the message `Multiple minimum API versions found for some major versions`. @@ -928,22 +1083,33 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `PluginBase->onLoad()` changed from `public` to `protected` - The following hook methods have been renamed: - `Plugin->setEnabled()` -> `Plugin->onEnableStateChange()`. This change was made to force plugin developers misusing this hook to stop, and to give it a name that better describes what it does. -- The following (deprecated) API methods have been removed: - - `PluginManager->callEvent()`: use `Event->call()` instead +- The following API methods have been removed: - `PluginManager->addPermission()`: use `PermissionManager` instead + - `PluginManager->callEvent()`: use `Event->call()` instead - `PluginManager->getDefaultPermSubscriptions()`: use `PermissionManager` instead - `PluginManager->getDefaultPermissions()`: use `PermissionManager` instead - `PluginManager->getPermission()`: use `PermissionManager` instead - `PluginManager->getPermissionSubscriptions()`: use `PermissionManager` instead - `PluginManager->getPermissions()`: use `PermissionManager` instead + - `PluginManager->loadPlugin()`: use `PluginManager->loadPlugins()` instead - `PluginManager->recalculatePermissionDefaults()`: use `PermissionManager` instead - `PluginManager->removePermission()`: use `PermissionManager` instead - `PluginManager->subscribeToDefaultPerms()`: use `PermissionManager` instead - `PluginManager->subscribeToPermission()`: use `PermissionManager` instead - `PluginManager->unsubscribeFromDefaultPerms()`: use `PermissionManager` instead - `PluginManager->unsubscribeFromPermission()`: use `PermissionManager` instead +- The following API methods have changed behaviour: + - `PluginManager->loadPlugins()` now accepts paths to files as well as directories, in which case it will load only the plugin found in the target file. - It is no longer permitted to throw exceptions from `PluginBase->onEnable()` or `PluginBase->onLoad()`. Doing so will now cause the server to crash. +### Promise +A very basic in-house implementation of Promises has been added. This is currently used for handling world generation requests. + +- `PromiseResolver` is created by the creator of the task. The task should call `PromiseResolver->resolve()` when the result is ready. +- `Promise` can be obtained by using `PromiseResolver->getPromise()` and should be returned to API consumers. + +Please note that this was not written with plugins in mind and its API may change in a future version. + ### Scheduler #### Thread-local storage for AsyncTasks - TLS has been completely rewritten in this release to be self contained, more robust and easier to use. @@ -960,11 +1126,10 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `AsyncTask->storeLocal()` now has the signature `storeLocal(string $key, mixed $complexData) : void` - `AsyncTask->fetchLocal()` now has the signature `fetchLocal(string $key) : mixed` -#### Other changes +#### Other AsyncTask changes - `AsyncPool` uses a new, significantly more performant algorithm for task collection. - `BulkCurlTask` has had the `$complexData` constructor parameter removed. - `BulkCurlTask->__construct()` now accepts `BulkCurlTaskOperation[]` instead of `mixed[]`. -- Added `CancelTaskException`, which can be thrown from `Task::onRun()` to cancel a task (especially useful for `ClosureTask`). - `pocketmine\Collectable` has been removed, and is no longer extended by `AsyncTask`. - The following hooks have been added: - `AsyncTask->onError()`: called on the main thread when an uncontrolled error was detected in the async task, such as a memory failure @@ -976,39 +1141,47 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `AsyncTask->removeFromThreadStore()`: use `AsyncTask->worker->removeFromThreadStore()` - `AsyncTask->saveToThreadStore()`: use `AsyncTask->worker->saveToThreadStore()` +#### Non-AsyncTask changes +- Added `CancelTaskException`, which can be thrown from `Task->onRun()` to cancel a task (especially useful for `ClosureTask`). +- The `$currentTick` parameter of `Task->onRun()` has been removed (use `Server->getTick()` instead if needed). +- Callables given to `ClosureTask` are no longer required to declare a `void` typehint (useful for arrow functions). + ### Server - New chat broadcasting APIs have been implemented, which don't depend on the permission system. - The following API methods have been added: - - `subscribeToBroadcastChannel()` - allows subscribing a `CommandSender` to receive chat messages (and other message types) on any channel - - `unsubscribeFromBroadcastChannel()` - - `unsubscribeFromAllBroadcastChannels()` - - `getBroadcastChannelSubscribers()` + - `Server->subscribeToBroadcastChannel()` - allows subscribing a `CommandSender` to receive chat messages (and other message types) on any channel + - `Server->unsubscribeFromBroadcastChannel()` + - `Server->unsubscribeFromAllBroadcastChannels()` + - `Server->getBroadcastChannelSubscribers()` - Giving `Player` any `pocketmine.broadcast.*` permissions will cause them to automatically subscribe to the corresponding broadcast channel (and removing them will unsubscribe it). - It's now possible to create and subscribe to custom broadcast channels without using permissions. - However, `Player`s may automatically unsubscribe themselves from the builtin broadcast channels if they don't have the proper permissions. - Automatic subscribe/unsubscribe from custom broadcast channels can be implemented using the new `Permissible` permission recalculation callbacks API. +- The following API methods have been added: + - `Server->getIpV6()` + - `Server->getPortV6()` - The following API methods have been removed: - - `reloadWhitelist()` - - `getLevelMetadata()` - - `getPlayerMetadata()` - - `getEntityMetadata()` - - `getDefaultGamemode()` - - `getLoggedInPlayers()` - - `onPlayerLogout()` - - `addPlayer()` - - `removePlayer()` - - `reload()` - - `getSpawnRadius()` - - `enablePlugin()` - - `disablePlugin()` - - `getGamemodeString()` - replaced by `pocketmine\player\GameMode->getTranslationKey()` - - `getGamemodeName()` - replaced by `pocketmine\player\GameMode->name()` - - `getGamemodeFromString()` - replaced by `GameMode::fromString()` - - `broadcast()` - use `broadcastMessage()` instead + - `Server->reloadWhitelist()` + - `Server->getLevelMetadata()` + - `Server->getPlayerMetadata()` + - `Server->getEntityMetadata()` + - `Server->getDefaultGamemode()` + - `Server->getLoggedInPlayers()` + - `Server->onPlayerLogout()` + - `Server->addPlayer()` + - `Server->removePlayer()` + - `Server->reload()` + - `Server->getSpawnRadius()` + - `Server->enablePlugin()` + - `Server->disablePlugin()` + - `Server->getGamemodeString()` - replaced by `pocketmine\player\GameMode->getTranslationKey()` + - `Server->getGamemodeName()` - replaced by `pocketmine\player\GameMode->name()` + - `Server->getGamemodeFromString()` - replaced by `GameMode::fromString()` + - `Server->broadcast()` - use `Server->broadcastMessage()` instead - The following API methods have changed: - - `getOfflinePlayerData()` no longer creates data when it doesn't exist. + - `Server->getOfflinePlayerData()` no longer creates data when it doesn't exist. - The following API methods have been renamed: - - `getPlayer()` -> `getPlayerByPrefix()` (consider using `getPlayerExact()` instead where possible) + - `Server->getPlayer()` -> `Server->getPlayerByPrefix()` (consider using `Server->getPlayerExact()` instead where possible) ### Level / World #### General @@ -1031,17 +1204,35 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Server->setAutoSave()` -> `WorldManager->setAutoSave()` - `Server->setDefaultLevel()` -> `WorldManager->setDefaultWorld()` - `Server->unloadLevel()` -> `WorldManager->unloadWorld()` -- Added `WorldManager->getAutoSaveTicks()` and `WorldManager->setAutoSaveTicks()` to allow controlling the autosave interval. +- The following static classes have been un-static-ified and converted to singletons (use `Whatever::getInstance()->method()` instead of `Whatever::method()`): + - `GeneratorManager` + - `WorldProviderManager` - The following classes have been added: - `BlockTransaction`: allows creating batch commits of block changes with validation conditions - if any block can't be applied, the whole transaction fails to apply. - `ChunkListenerNoOpTrait`: contains default no-op stubs for chunk listener implementations - `ChunkListener`: interface allowing subscribing to events happening on a given chunk + - `ChunkLockId`: used by `World->lockChunk()` and `World->unlockChunk()` - `TickingChunkLoader`: a `ChunkLoader` specialization that allows ticking chunks + - `format\io\FastChunkSerializer`: provides methods to encode a chunk for transmitting to another thread + - `WorldCreationOptions`: used for passing world generator options to `WorldManager->generateWorld()` - `ChunkLoader` no longer requires implementing `getX()` and `getZ()`. - `ChunkLoader` no longer causes chunks to get random updates. If this behaviour is needed, implement `TickingChunkLoader`. - The following classes have been renamed: - `pocketmine\world\utils\SubChunkIteratorManager` -> `pocketmine\world\utils\SubChunkExplorer` +- The following class constants have been added: + - `Chunk::COORD_BIT_SIZE` + - `Chunk::COORD_MASK` + - `Chunk::DIRTY_FLAG_BLOCKS` + - `Chunk::DIRTY_FLAG_TERRAIN` + - `Chunk::EDGE_LENGTH` + - `SubChunk::COORD_BIT_SIZE` + - `SubChunk::COORD_MASK` + - `SubChunk::EDGE_LENGTH` + - `World::Y_MIN` - The following API methods have been added: + - `WorldManager->getAutoSaveTicks()` + - `WorldManager->setAutoSaveTicks()` + - `World->notifyNeighbourBlockUpdate()` - `World->registerChunkListener()` - `World->unregisterChunkListener()` - `World->getBlockAt()` (accepts int x/y/z instead of Vector3, faster for some use cases) @@ -1050,12 +1241,9 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Chunk->getDirtyFlag()` (more granular component-based chunk dirty-flagging, used to avoid saving unmodified parts of the chunk) - `Chunk->setDirty()` - `Chunk->setDirtyFlag()` -- The following API methods have been removed: - - `ChunkLoader->getLoaderId()` (now object ID is used) - - `ChunkLoader->isLoaderActive()` - - `ChunkLoader->getPosition()` - - `ChunkLoader->getLevel()` - - `Chunk->fastSerialize()` (use `FastChunkSerializer::serialize()` instead) +- The following API methods have been removed from the public API: + - `Chunk->addEntity()` + - `Chunk->fastSerialize()` (use `FastChunkSerializer::serializeTerrain()` instead) - `Chunk->getBlockData()` - `Chunk->getBlockDataColumn()` - `Chunk->getBlockId()` @@ -1064,7 +1252,9 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Chunk->getBlockLightColumn()` - `Chunk->getBlockSkyLight()` - `Chunk->getBlockSkyLightColumn()` + - `Chunk->getEntities()` - `Chunk->getMaxY()` + - `Chunk->getSavableEntities()` - `Chunk->getSubChunkSendCount()` (this was specialized for protocol usage) - `Chunk->getX()` - `Chunk->getZ()` @@ -1074,6 +1264,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Chunk->populateSkyLight()` (use `SkyLightUpdate->recalculateChunk()` instead) - `Chunk->recalculateHeightMap()` (moved to `SkyLightUpdate`) - `Chunk->recalculateHeightMapColumn()` (moved to `SkyLightUpdate`) + - `Chunk->removeEntity()` - `Chunk->setAllBlockLight()` - `Chunk->setAllBlockSkyLight()` - `Chunk->setBlock()` @@ -1085,63 +1276,82 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Chunk->setGenerated()` - `Chunk->setX()` - `Chunk->setZ()` - - `Chunk::fastDeserialize()` (use `FastChunkSerializer::deserialize()` instead) - - `World->isFullBlock()` - - `World->getFullBlock()` - - `World->getBlockIdAt()` - - `World->setBlockIdAt()` - - `World->getBlockDataAt()` - - `World->setBlockDataAt()` - - `World->setBlockLightAt()` - - `World->setBlockSkyLightAt()` - - `World->getBlockSkyLightAt()` (use `World->getRealBlockSkyLightAt()` or `World->getPotentialBlockSkyLightAt()`, depending on use-case) - - `World->getHeightMap()` (misleading name, only actually useful for sky light calculation - you probably want `getHighestBlockAt()` instead) - - `World->setHeightMap()` (misleading name, only actually useful for sky light calculation) - - `World->getChunkEntities()` - - `World->getChunkTiles()` - - `World->getTileById()` + - `Chunk::fastDeserialize()` (use `FastChunkSerializer::deserializeTerrain()` instead) + - `ChunkLoader->getLevel()` + - `ChunkLoader->getLoaderId()` (now object ID is used) + - `ChunkLoader->getPosition()` + - `ChunkLoader->isLoaderActive()` + - `World->addChunkPacket()` + - `World->addGlobalPacket()` + - `World->broadcastGlobalPacket()` + - `World->broadcastLevelEvent()` + - `World->broadcastLevelSoundEvent()` - `World->checkSpawnProtection()` - - `World->updateBlockLight()` - - `World->updateSkyLight()` + - `World->generateChunkCallback()` + - `World->getBlockDataAt()` + - `World->getBlockIdAt()` + - `World->getBlockSkyLightAt()` (use `World->getRealBlockSkyLightAt()` or `World->getPotentialBlockSkyLightAt()`, depending on use-case) + - `World->getChunkTiles()` + - `World->getFullBlock()` + - `World->getHeightMap()` (misleading name, only actually useful for sky light calculation - you probably want `getHighestBlockAt()` instead) + - `World->getTickRate()` + - `World->getTileById()` + - `World->isFullBlock()` - `World->isFullBlock()` (use `Block->isFullCube()` instead) - `World->sendBlocks()` - `World->sendTime()` - - `World->addGlobalPacket()` - - `World->broadcastGlobalPacket()` - - `World->addChunkPacket()` - - `World->broadcastLevelSoundEvent()` - - `World->broadcastLevelEvent()` - - `World->getTickRate()` + - `World->setBlockDataAt()` + - `World->setBlockIdAt()` + - `World->setBlockLightAt()` + - `World->setBlockSkyLightAt()` + - `World->setHeightMap()` (misleading name, only actually useful for sky light calculation) - `World->setTickRate()` + - `World->updateBlockLight()` + - `World->updateSkyLight()` - `World::generateChunkLoaderId()` - The following API methods have changed signatures: + - `Chunk->__construct()` now has the signature `array $subChunks, BiomeArray $biomeIds, bool $terrainPopulated`. + - `Chunk->getSubChunk()` now returns `SubChunk` instead of `SubChunkInterface|null` (and throws `InvalidArgumentException` on out-of-bounds coordinates). + - `Chunk->getSubChunks()` now returns `array` instead of `SplFixedArray`. + - `Chunk->setSubChunk()` no longer accepts `SubChunkInterface`, and the `$allowEmpty` parameter has been removed. + - `ChunkManager->setChunk()` (and its notable implementations in `World` and `SimpleChunkManager`) no longer accepts NULL for the `$chunk` parameter. + - `GeneratorManager->registerGenerator()` now requires a `\Closure $presetValidator` parameter. This is used to check generator options of worlds and configs before attempting to use them. + - `Position->__construct()` now requires the `$world` parameter (it's no longer optional). - `World->addParticle()` now has the signature `addParticle(Vector3 $pos, Particle $particle, ?Player[] $players = null) : void` - - `World->addSound()` now has the signature `addSound(?Vector3 $pos, Sound $sound, ?Player[] $players = null) : void` - - `World->getRandomTickedBlocks()` now returns `bool[]` instead of `SplFixedArray`. - `World->addRandomTickedBlock()` now accepts `Block` instead of `int, int`. + - `World->addSound()` now has the signature `addSound(?Vector3 $pos, Sound $sound, ?Player[] $players = null) : void` + - `World->getChunk()` no longer accepts a `$create` parameter. + - `World->getRandomTickedBlocks()` now returns `bool[]` instead of `SplFixedArray`. + - `World->loadChunk()` now returns `?Chunk`, and the `$create` parameter has been removed. - `World->removeRandomTickedBlock()` now accepts `Block` instead of `int, int`. - `World->setBlock()` has had the `$direct` parameter removed. - - `World->loadChunk()` now returns `?Chunk`, and the `$create` parameter has been removed. - - `World->getChunk()` no longer accepts a `$create` parameter. + - `World->setChunks()` no longer accepts a `$deleteEntitiesAndTiles` parameter. - `World->updateAllLight()` now accepts `int, int, int` instead of `Vector3`. - - `ChunkManager->setChunk()` (and its notable implementations in `World` and `SimpleChunkManager`) no longer accepts NULL for the `$chunk` parameter. - - `Chunk->__construct()` now has the signature `array $subChunks, ?list $entities, ?list $tiles, ?BiomeArray $biomeArray, ?HeightArray $heightArray`. - - `Chunk->getSubChunk()` now returns `SubChunk` instead of `SubChunkInterface|null` (and throws `InvalidArgumentException` on out-of-bounds coordinates). - - `Chunk->setSubChunk()` no longer accepts `SubChunkInterface`, and the `$allowEmpty` parameter has been removed. - - `WorldManager->generateWorld()` (previously `Server->generateWorld()`) now accepts `WorldCreationOptions` instead of `int $seed, class-string $generator, mixed[] $options`. + - `WorldManager->generateWorld()` (previously `Server->generateWorld()`) now accepts `WorldCreationOptions` instead of `int $seed, class-string $generator, mixed[] $options` + - `World->lockChunk()` now requires `ChunkLockId $lockId` parameter. + - `World->unlockChunk()` now requires a `?ChunkLockId $lockId` parameter. If a non-null lockID is given, the lock on the chunk will only be removed if it matches the given lockID. + - `World->unlockChunk()` now returns `bool` instead of `void` (to signal whether unlocking succeded or not). - The following API methods have been renamed / moved: - - `Level->getChunks()` -> `World->getLoadedChunks()` - - `Level->getCollisionCubes()` -> `World->getCollisionBoxes()` + - `World->getChunks()` -> `World->getLoadedChunks()` + - `World->getCollisionCubes()` -> `World->getCollisionBoxes()` - `World->getName()` -> `World->getDisplayName()` - `World->populateChunk()` has been split into `World->requestChunkPopulation()` and `World->orderChunkPopulation()`. - The following API methods have changed behaviour: + - `World->getAdjacentChunks()` now returns an array indexed using `World::chunkHash()`, where the `x` and `z` components are the relative offsets from the target chunk (range -1 to +1). - `World->getChunk()` no longer tries to load chunks from disk. If the chunk is not already in memory, null is returned. (This behaviour now properly matches other `ChunkManager` implementations.) - `World->getHighestBlockAt()` now returns `null` instead of `-1` if the target X/Z column contains no blocks. - The following methods now throw `WorldException` when targeting ungenerated terrain: - `World->getSafeSpawn()` (previously it just silently returned the input position) - `World->getHighestBlockAt()` (previously it returned -1) - `World->loadChunk()` no longer creates an empty chunk when the target chunk doesn't exist on disk. - - `World->setChunk()` now fires `ChunkLoadEvent` and `ChunkListener->onChunkLoaded()` when replacing a chunk that didn't previously exist. + - `World->setChunk()` has the following behavioural changes: + - Now fires `ChunkLoadEvent` and `ChunkListener->onChunkLoaded()` when replacing a chunk that didn't previously exist. + - Now updates entities in the replaced chunk and its neighbours. This fixes bugs such as paintings not dropping and dropped items floating in midair if the ground was lower than before. + - Entities are no longer deleted on chunk replacement. + - Tiles are no longer deleted on chunk replacement, unless one of the following conditions is met: + - the target block in the new chunk doesn't expect a tile + - the target block in the new chunk expects a different type of tile (responsibility of the plugin developer to create the new tile) + - there's already a tile in the target chunk which conflicts with the old one - `World->useBreakOn()` now returns `false` when the target position is in an ungenerated or unloaded chunk (or chunk locked for generation). - `World->useItemOn()` now returns `false` when the target position is in an ungenerated or unloaded chunk (or chunk locked for generation). - A `ChunkListener` interface has been extracted from `ChunkLoader`. The following methods have been moved: @@ -1162,7 +1372,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` #### Sounds - `pocketmine\world\sound\Sound` no longer extends `pocketmine\math\Vector3`, and has been converted to an interface. -- `Sound->encode()` now accepts `?\pocketmine\math\Vector3`. `NULL` may be passed for sounds which are global. +- `Sound->encode()` now accepts `pocketmine\math\Vector3`. - Added the following classes: - `ArrowHitSound` - `BlockBreakSound` @@ -1196,7 +1406,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `UUID::fromRandom()` can be replaced by `Ramsey\Uuid\Uuid::uuid4()` - `UUID::fromBinary()` can be replaced by `Ramsey\Uuid\Uuid::fromBytes()` (use `Ramsey\Uuid\Uuid::isValid()` to check validity) - `UUID::toBinary()` is replaced by `Ramsey\Uuid\UuidInterface::getBytes()` - - See the documentation at https://uuid.ramsey.dev/en/latest/introduction.html for more information. + - See the [documentation for `ramsey/uuid`](https://uuid.ramsey.dev/en/latest/introduction.html) for more information. - `Terminal::hasFormattingCodes()` no longer auto-detects the availability of formatting codes. Instead it's necessary to use `Terminal::init()` with no parameters to initialize, or `true` or `false` to override. - `Config->save()` no longer catches exceptions thrown during emitting to disk. - The following new classes have been added: @@ -1205,6 +1415,10 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Process` - The following API methods have been added: - `Config->getPath()`: returns the path to the config on disk + - `Config::parseList()`: parses a list of entries like `ops.txt` into an array + - `Config::parseProperties()`: parses a properties file like `server.properties` into an array + - `Config::writeList()` + - `Config::writeProperties()` - `Terminal::write()`: emits a Minecraft-formatted text line without newline - `Terminal::writeLine()`: emits a Minecraft-formatted text line with newline - `Utils::recursiveUnlink()`: recursively deletes a directory and its contents @@ -1227,11 +1441,23 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Utils::$os` - The following API methods have signature changes: - `Internet::simpleCurl()` now requires a `Closure` for its `onSuccess` parameter instead of `callable`. + - `Process::kill()` now requires an additional `bool $subprocesses` parameter. +- The following API methods have behavioural changes: + - `Utils::parseDocComment()` now allows `-` in tag names. - The following API methods have been removed: - `TextFormat::toJSON()` - `Utils::getCallableIdentifier()` +- `MainLogger` now pushes log messages to `server.log` before calling logger attachments. This fixes messages not being written to disk when an uncaught error is thrown from a logger attachment. ## Gameplay +### World loading +- Chunks are now sent in proper circles. This improves the experience when flying quickly parallel to X or Z axis, since now more chunks in front of the player will load sooner. +- Many bugs in player respawning have been fixed, including: + - Spawning underneath bedrock when spawn position referred to ungenerated terrain + - Spawning underneath bedrock on first server join on very slow machines (or when the machine was under very high load) + - Spawning inside blocks (or above the ground) when respawning with a custom spawn position set + - Player spawn positions sticking to the old location when world spawn position changed - this was because the world spawn at time of player creation was used as the player's custom spawn, so the bug will persist for older player data, but will work as expected for new players. + ### Blocks - Implemented the following blocks: - bamboo @@ -1272,496 +1498,24 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - stone-like slabs of many variants - Non-player entities now bounce when falling on beds. - Players and mobs now receive reduced fall damage when falling on beds. +- Fixed cake block desync when attempting to eat in creative (eating in creative is not yet supported, but the block rollback was missing). +- Fixed the bounding box of skulls when mounted on a wall. +- Fixed podzol dropping itself when mined (instead of dirt). ### Items - Implemented the following items: - records - compounds (from Minecraft: Education Edition) - black, brown, blue and white dyes +- Compasses now point to the correct (current) world's spawn point after teleporting players to a different world. Previously, they would continue to point to the spawn of the world that the player initially spawned in. ### Inventory - Implemented offhand inventory. - Block-picking is now supported in survival mode. - Block picking behaviour now matches vanilla (no longer overwrites held item, jumps to existing item where possible). - Armor can now be equipped by right-clicking while holding it. - -# 4.0.0-BETA2 -Released 10th September 2021. - -## General -- ext-chunkutils 0.3.x is now required. -- Reduced memory usage of light storage after garbage collection. -- Reduced memory usage of uniform subchunks which only contain 1 type of block. -- The title bar no longer displays heap memory usage numbers (nobody seemed to know that was what it was, anyway). -- `/status` no longer displays heap memory usage numbers. -- `start.sh` no longer specifically mentions PHP 7 when erroring because of a missing PHP binary. -- Debug messages are now logged when reach distance checks prevent players from doing something. - -## Fixes -- Fixed players getting disconnected when using `/tp` to ungenerated chunks (or when teleported by players). -- Fixed a potential memory leak in block updating when chunks are unloaded. -- Fixed `Living->lookAt()` not taking eye height into account. -- Fixed grass replacing itself when placing grass (and consuming inventory items). -- Fixed players taking fall damage when falling next to a wall. - -## API changes -- The following API methods have been added: - - `World->getChunkEntities()` - - `World->notifyNeighbourBlockUpdate()` -- The following API methods have been removed: - - `Chunk->getEntities()` - - `Chunk->getSavableEntities()` - - `Chunk->addEntity()` - - `Chunk->removeEntity()` -- The following classes have been added: - - `pocketmine\inventory\transaction\TransactionBuilderInventory`: facilitates building `InventoryTransaction`s using standard `Inventory` API methods -- The following class constants have been added: - - `Chunk::EDGE_LENGTH` - - `Chunk::COORD_BIT_SIZE` - - `Chunk::COORD_MASK` - - `SubChunk::EDGE_LENGTH` - - `SubChunk::COORD_BIT_SIZE` - - `SubChunk::COORD_MASK` - -# 4.0.0-BETA3 - - -## General -- Added support for Minecraft: Bedrock Edition 1.17.30. -- Dropped support for Minecraft: Bedrock Edition 1.17.1x. -- `tools/convert-world.php` now writes errors to stderr and sets the proper exit code. -- Explosions now use the standard mechanism for processing block updates. Previously, it used a special mechanism due to prohibitively poor efficiency of the standard algorithm. Since these inefficiencies have now been addressed, explosions can now be consistent with everything else, with minimal performance impact. -- Command usage strings are no longer automatically translated (use `Translatable` instead of bare string keys). -- Command description strings are no longer automatically translated (use `Translatable` instead of bare string keys). - -## Fixes -- `ItemFactory->isRegistered()` no longer crashes when given negative item IDs. -- Furnaces now continue to operate after reloading the chunk they were contained in. -- Fixed being unable to reconnect for 10 seconds after disconnecting in some cases. - -## API changes -- The following API methods have been added: - - `Liquid->getMinAdjacentSourcesToFormSource()`: returns how many adjacent source blocks of the same liquid must be present in order for the current block to become a source itself - - `Player->getPlayerInfo()` -- `Liquid` minimum-cost flow calculation code has been extracted to `MinimumCostFlowCalculator`. - -# 4.0.0-BETA4 -Released 6th October 2021. - -## General -- Improved performance of lighting calculation by avoiding copies of useless data from the main thread. -- Resource pack loading now accepts `dependencies` and `capabilities` fields in the `manifest.json` (although it doesn't currently check them). -- `/help` is now localized according to language set in `server.properties`. -- Various messages related to world loading, generation and conversion are now localized according to the language set in `server.properties`. -- Compasses now point to the correct (current) world's spawn point after teleporting players to a different world. Previously, they would continue to point to the spawn of the world that the player initially spawned in. -- The `--bootstrap` CLI option has been removed. -- RakLib 0.14.2 is now required. This fixes the following issues: - - Fixed incorrect handling of sessions on client disconnect (leading to timeout debug messages). - - Fixed transferring players often not working correctly. - - Fixed disconnect screens sometimes not displaying. - -## Fixes -- Fixed server crash when UPnP encounters an error. -- Fixed server crash when clients sent items with bad NBT in inventory transactions. -- Fixed server crash when loading a plugin with legacy nested permission structure (now the plugin will fail to load, but the server won't crash). -- Fixed server crash when using `/give` with bad NBT on any item. -- Fixed server crash when loading a plugin with improperly formatted API version (now the plugin will fail to load, but the server won't crash). -- Fixed server crash when changing player gamemode during `PlayerLoginEvent`. -- Incorrect structure of `commands` in plugin manifest is now detected earlier and handled more gracefully. -- Fixed console reader subprocess lingering on server crash on Windows and screwing up the terminal. -- Fixed `Player` object memory leak when kicking players during `PlayerLoginEvent` (this caused the `World` to report warnings about leaked entities on shutdown). -- Fixed `Projectile->move()` ignoring the `dx`/`dy`/`dz` parameters given and using its own `motion` instead. -- Fixed `BlockFactory->get()` erroneously accepting meta values of `16`. -- Fixed `Block->isSameState()` false negatives for some types of slabs. -- Fixed being unable to place slabs of the same type on top of each other to create double slabs. - -## API changes -- Plugin commands in `plugin.yml` must now declare `permission` for each command. Previously, the `permission` key was optional, causing anyone to be able to use the command. - - This behaviour was removed because of the potential for security issues - a typo in `plugin.yml` could lead to dangerous functionality being exposed to everyone. - - If you want to make a command that everyone can use, declare a permission with a `default` of `true` and assign it to the command. -- Plugin permissions in `plugin.yml` must now declare `default` for each permission. Previously, the `default` key was optional, causing the permission to silently be denied to everyone (PM4) or granted to ops implicitly (PM3). - -### Block -- Added the following classes: - - `pocketmine\block\utils\LeverFacing` -- Added the following API methods: - - `pocketmine\block\Lever->isActivated()` - - `pocketmine\block\Lever->setActivated()` - - `pocketmine\block\Lever->getFacing()` - - `pocketmine\block\Lever->setFacing()` - -### World -- The following API methods have signature changes: - - `Chunk->getSubChunks()` now returns `array` instead of `SplFixedArray`. -- The following API methods have been removed: - - `FastChunkSerializer::serialize()` - - `FastChunkSerializer::deserialize()` -- The following API methods have been added: - - `FastChunkSerializer::serializeTerrain()`: serializes blocks and biomes only - - `FastChunkSerializer::deserializeTerrain()`: deserializes the output of `serializeTerrain()` - -### Utils -- The following API methods have signature changes: - - `Process::kill()` now requires an additional `bool $subprocesses` parameter. - -# 4.0.0-BETA5 -Released 12th October 2021. - -## General -- Exception log format has been changed. Now, exception info is logged in one big block message. This saves space on the console and improves readability, as well as reducing the ability for bad `ThreadedLoggerAttachment`s to break exception output. -- Log messages are now pushed to `server.log` before calling logger attachment, instead of after. This fixes messages not being written to disk when an error occurs in a logger attachment. -- Improved startup performance when loading many plugins. -- The `worlds` config in `pocketmine.yml` no longer supports attaching the generator settings to the `generator` key (use the `preset` key instead). -- Using an unknown generator in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world. -- Using invalid/incorrect world generator options (presets) in `server.properties` or `pocketmine.yml` will now cause a failure to generate the world. -- Generator options of existing worlds are now validated before loading them. If they are invalid, the server will fail to load them. -- Several more log messages have been localized, including plugin loading errors. - -## Fixes -- Fixed server crash when using `/give` to give an item by ID which doesn't exist in Minecraft. -- Fixed server crash when boolean `server.properties` options were given an integer value (e.g. `0` or `1` instead of `false` or `true`). -- Fixed stats reporting checking for a nonexistent `pocketmine.yml` setting. -- Fixed use of commands without the proper permission sending a message `commands.generic.permission` instead of the proper message. -- Fixed entities set on fire appearing to stay on fire, although not taking any damage. -- Fixed a duplicate `MB` suffix on the `Memory freed` output of `/gc`. -- Fixed the server attempting to generate a world if it failed to load. - -## API -### Block -- The following API methods have been renamed: - - `Block->getPositionOffset()` -> `Block->getModelPositionOffset()`. - -### Event -- `@handleCancelled` PhpDoc annotation can no longer be used on event handlers for non-cancellable events. -- The following API methods have been added: - - `StructureGrowEvent->getPlayer()` - -### Inventory -- The following API methods have been added: - - `Inventory->getAddableItemQuantity()` - -### Scheduler -- `ClosureTask` now permits closures without an explicit return type (useful for arrow functions). - -### Utils -- The following API methods have been added: - - `Config::parseProperties()` - - `Config::writeProperties()` - - `Config::parseList()` - - `Config::writeList()` - -### World -- The following API methods have signature changes: - - `GeneratorManager->registerGenerator()` now requires a `\Closure $presetValidator` parameter. This is used to check generator options of worlds and configs before attempting to use them. - -# 4.0.0-BETA6 -Released 19th October 2021. - -## General -- Added support for Minecraft: Bedrock Edition 1.17.40. -- Removed support for earlier versions. -- CTRL+C signal handling has been restored, and is now supported on Windows. Pressing CTRL+C while the server is running will behave as if the `/stop` command was invoked. -- Added a script `tools/generate-permission-doc.php` to generate a Markdown file with a list of all permissions and their relationships. In the future, this will be used to maintain the official documentation, but plugin developers might find it useful for their own purposes too. -- [`respect/validation`](https://packagist.org/packages/respect/validation) is no longer a core dependency. - -## Fixes -- Fixed server crash when using `/give` to give an item with a too-large item ID, or `/clear` to clear an item that does not exist. - - Now, `LegacyStringToItemParser` is used exclusively, and numeric IDs are no longer parsed. - -## Gameplay - Picking up some items from a dropped stack of items is now supported. This fixes various bugs with being unable to pick up items with an almost-full inventory. - -# 4.0.0-BETA7 -Released 28th October 2021. - -## General -- Phar plugins are now able to depend on folder plugins loaded by DevTools. -- Now uses [`pocketmine/bedrock-protocol@58c53a259e819a076bf8fe875d2a012da7d19d65`](https://github.com/pmmp/BedrockProtocol/tree/58c53a259e819a076bf8fe875d2a012da7d19d65). This version features significant changes, including: - - Standardisation of various field names (e.g. `eid` -> `actorRuntimeId`, `evid` -> `eventId`) - - Rename of `entity` related fields to `actor` where appropriate (e.g. `entityRuntimeId` -> `actorRuntimeId`) - - Block position `x`/`y`/`z` fields replaced by `BlockPosition` - - Static `::create()` functions for all packets, which ensure that fields can't be forgotten - -## Fixes -- Fixed server crash when clients send itemstacks with unmappable dynamic item IDs. -- Fixed server crash on invalid ItemStackRequest action types. -- Fixed autosave bug that caused unmodified chunks to be saved at least once (during the first autosave after they were loaded). -- Fixed `ConsoleReaderThread` returning strings with newlines still on the end. -- Fixed changes made to adjacent chunks in `ChunkPopulateEvent` (e.g. setting blocks) sometimes getting overwritten. - -## API -### Event -- `PlayerCreationEvent` now verifies that the player class set is instantiable - this ensures that plugins get properly blamed for breaking things. - -### World -- `World->generateChunkCallback()` has been specialized for use by `PopulationTask`. This allows fixing various inconsistencies involving `ChunkPopulateEvent` (e.g. modifications to adjacent chunks in `ChunkPopulationEvent` might be wiped out, if the population of the target chunk modified the adjacent chunk). - - It now accepts `Chunk $centerChunk, array $adjacentChunks` (instead of `?Chunk $chunk`). - - It's no longer expected to be used by plugins - plugins should be using `World->setChunk()` anyway. -- `Chunk->getModificationCounter()` has been added. This is a number starting from `0` when the `Chunk` object is first created (unless overridden by the constructor). It's incremented every time blocks or biomes are changed in the chunk. It resets after the chunk is unloaded and reloaded. -- The following API methods have changed signatures: - - `Sound->encode()` no longer accepts `null` for the position. - - `Chunk->__construct()`: removed `HeightArray $heightMap` parameter, added `bool $terrainPopulated` and `int $modificationCounter` parameters. - -### Plugin -- `PluginManager->loadPlugins()` now accepts paths to files as well as directories, in which case it will load only the plugin found in the target file. -- The following API methods have been removed: - - `PluginManager->loadPlugin()`: use `PluginManager->loadPlugins()` instead - -# 4.0.0-BETA8 -Released 29th October 2021. - -## General -- Chunk packet caches are now cleared by the memory manager on low memory. -- `Entity->spawnTo()` now has an additional sanity check for matching worlds (might expose a few new errors in plugins). -- [`pocketmine/math` 0.4.0](https://github.com/pmmp/Math/releases/tag/0.4.0) is now used. Please see its release notes for changes. - -## Fixes -- Zlib raw check for LevelDB is now done directly on startup, avoiding crashes when later trying to load worlds. -- Fixed tiles and entities getting deleted from adjacent chunks during chunk population. -- Fixed players being unable to open their inventories more than once. -- Fixed entities not getting updated when a nearby chunk is replaced (e.g. dropped items would float in midair if the ground was lower than before) - -## API -### World -- `World::setChunk()` has the following changes: - - `$deleteEntitiesAndTiles` parameter has been removed. - - Entities are no longer deleted on chunk replacement. - - Tiles are no longer deleted on chunk replacement, unless one of the following conditions is met: - - the target block in the new chunk doesn't expect a tile - - the target block in the new chunk expects a different type of tile (responsibility of the plugin developer to create the new tile) - - there's already a tile in the target chunk which conflicts with the old one -- `Location::__construct()` has the following changes: - - `world` parameter is now 4th instead of last. - - All parameters are now mandatory. -- Reverted addition of chunk modification counters in previous beta. -- `Chunk::DIRTY_FLAG_TERRAIN` has been renamed to `Chunk::DIRTY_FLAG_BLOCKS`. - -# 4.0.0-BETA9 -Released 2nd November 2021. - -## General -- Now analysed using level 9 on PHPStan 1.0.0. -- `ext-pthreads` v4.0.0 or newer is now required. -- `resources/vanilla` submodule has been removed. BedrockData is now included via Composer dependency [`pocketmine/bedrock-data`](https://packagist.org/packages/pocketmine/bedrock-data). -- `pocketmine/spl` Composer dependency has been dropped. -- The following Composer dependency versions are now required: - - [`pocketmine/bedrock-protocol` v5.0.0](https://github.com/pmmp/BedrockProtocol/tree/5.0.0+bedrock-1.17.40) features substantial changes to its API compared to 3.0.1, which was used in 4.0.0-BETA8. Please see its [release notes](https://github.com/pmmp/BedrockData/releases/tag/5.0.0+bedrock-1.17.40). - - [`pocketmine/log` v0.4.0](https://github.com/pmmp/Log/tree/0.4.0) removes the `LoggerAttachment` interface and replaces logger attachment objects with closures. - - [`pocketmine/log-pthreads` v0.4.0](https://github.com/pmmp/LogPthreads/tree/0.4.0) - - [`pocketmine/classloader` v0.2.0](https://github.com/pmmp/ClassLoader/tree/0.2.0) -- A noisy debug message in `World->updateAllLight()` has been removed. - -## API -### Entity -- `Human->setLifetimeTotalXp()` now limits the maximum value to 2^31. - -### Event -- `BlockGrowEvent` is now called when cocoa pods grow. - -### Item -- Added `Releasable->canStartUsingItem()`. - -### Network -- Added `NetworkInterfaceStartException`, which may be thrown by `Network->registerInterface()` and `NetworkInterface->start()`. - -### Player -- `SurvivalBlockBreakHandler::createIfNecessary()` has been removed. -- `SurvivalBlockBreakHandler->__construct()` is now public. -- `UsedChunkStatus::REQUESTED()` has been renamed to `REQUESTED_SENDING`. -- `UsedChunkStatus::REQUESTED_GENERATION()` has been added. - -### Utils -- `Promise` API has changed: - - Promise-related classes have been moved to `pocketmine\promise` namespace. - - It's now split into `Promise` and `PromiseResolver`. - - `PromiseResolver` provides only `resolve()` and `reject()`. It should be used by callbacks to resolve a promise. - - `Promise` now provides only `onCompletion()` and `isResolved()` APIs. This should be given to consumers to allow them to handle the result of the async operation. - - `PromiseResolver` must not be created directly. Use `new PromiseResolver` and `PromiseResolver->getPromise()`. - -### World -- Improved performance of `setBlock()` by around 35% when the `$update` parameter is set to `true`. -- Improved performance of `setBlock()` by around 30% when the `$update` parameter is set to `false`. -- `World->generateChunkCallback()` is no longer exposed to public API. -- `World->getAdjacentChunks()` now returns an array indexed using `World::chunkHash()`, where the `x` and `z` components are the relative offsets from the target chunk (range -1 to +1). -- `World->lockChunk()` now requires `ChunkLockId $lockId` parameter. -- `World->unlockChunk()` now requires a `?ChunkLockId $lockId` parameter. If a non-null lockID is given, the lock on the chunk will only be removed if it matches the given lockID. -- `World->unlockChunk()` now returns `bool` instead of `void` (to signal whether unlocking succeded or not). -- Added `ChunkLockId` class. - -## Fixes -### World -- Fixed server crash when tiles with colliding positions are loaded from saved data. Now, an error is logged, but the server won't crash. -- Fixed server crash when liquids and other items flow into terrain locked for population. Now, an advisory locking mechanism is used, and population results will be discarded and recalculated if modifications are detected. -- Fixed various crashes that could occur if a chunk was flagged with `setPopulated(true)` after a promise had already been created for its population. -- Fixed `AssumptionFailedError` in `PopulationTask` when workers previously used for generation are shutdown, and then restarted on the fly by a generation request. -- Fixed assertion failure in `World->drainPopulationRequestQueue()` when requesting, cancelling and then re-requesting generation of a chunk while the generator was busy. -- Fixed generation potentially getting stuck if a population request was cancelled while the population task was running (failure to remove locks from used chunks). -- Fixed `World->requestChunkPopulation()` not taking into account that the target chunk may already be populated. This caused a variety of strange bugs and performance issues. -- Fixed potential memory leak caused by `World->unregisterChunkListenerFromAll()` not taking players into account. -- Fixed debug spam of `chunk has no loaders registered` messages during chunk generation. - -### Other fixes -- Fixed server crash when unable to bind to the desired port. Now, the server will show an error and gracefully stop without a crashdump instead. -- Fixed server crash in `Player->showPlayer()` when the target is not in the same world. -- Fixed players, who died in hardcore mode and were unbanned, getting re-banned on next server join. -- Fixed cake block desync when attempting to eat in creative (eating in creative is not yet supported, but the block rollback was missing). -- Fixed players being able to eat items more quickly by dropping them while eating. - Fixed arrows getting added to creative players' inventories when picked up. -- Fixed players re-requesting the same ungenerated chunks multiple times before they were sent. -- Fixed commands not working in some cases after using some control sequences on the console. -# 4.0.0-BETA10 -Released 2nd November 2021. - -## Fixes -- Fixed an issue with BedrockData JSON minification which broke the release build of 4.0.0-BETA9. - -# 4.0.0-BETA11 -Released 6th November 2021. - -## General -- `resources/locale` submodule has been removed. Language files are now included via Composer dependency [`pocketmine/locale-data`](https://packagist.org/packages/pocketmine/locale-data). - - This means it's now possible to run a server from git sources without cloning submodules :) - - All remaining submodules (DevTools, build/php) are non-essential for building and running a server. -- Added a tool `tools/simulate-chunk-sending.php` to visualise the behaviour of `ChunkSelector`. - -## Fixes -- Fixed server crash on saving when player XP has reached int32 max (XP is now capped, similar to Java Edition). -- Fixed another edge case in chunk generation that led to assertion failures. -- Fixed server crash when finding a list of `TAG_Float` for entity positions instead of `TAG_Double`. -- Fixed fast eating when picking up items. -- Fixed terrain being invisible for a long time when teleporting into ungenerated terrain. -- Fixed weird chunk loading when teleporting into ungenerated terrain (sometimes farther chunks would render before closer ones, leaving holes in the map temporarily). -- Fixed players re-requesting chunks when turning their heads or jumping. -- Fixed bonemeal sometimes being consumed even when cancelling `BlockGrowEvent` and `StructureGrowEvent`. - -## API -### Event -- Added `PlayerEmoteEvent`. - -### Gameplay -- Chunks are now sent in proper circles. This improves the experience when flying quickly parallel to X or Z axis, since now more chunks in front of the player will load sooner. +### Misc - Added support for emotes. - -# 4.0.0-BETA12 -Released 9th November 2021. - -## General -- Introduced support for connecting via IPv6. - - PHP binary used must now always be built with IPv6 support, even if IPv6 is disabled. This is because RakNet may still send link-local IPv6 loopback addresses in connection packets even when only using IPv4. - - The default port for IPv6 is `19133` (similar to Bedrock Dedicated Server). - - Port `19133` is used by default so that Minecraft Bedrock can detect IPv6 servers on LAN. - - GS4 Query is supported on both IPv4 and IPv6 according to `server.properties` settings. - - The following `server.properties` settings are influential: - - `enable-ipv6`: `on` by default. Disabling this completely disables IPv6 support. - - `server-ipv6`: `::` by default (equivalent to "any IP", like `0.0.0.0` for IPv4). Most users shouldn't need to change this setting, and it doesn't appear in `server.properties` by default. - - `server-portv6`: `19133` by default. You may run both IPv4 and IPv6 on the same port. -- Various internal changes have been made to prepare for negative Y axis support (upcoming 1.18). - -## Fixes -- Fixed resource packs not applying. -- Fixed inventory windows being unopenable after dying with inventory windows open. -- Fixed plugins being able to alter other plugins' permission defaults by redeclaring them in the `plugin.yml`. - -## API -### Block -- `VanillaBlocks::fromString()` has been removed. -- Added `CraftingTableInventory`. This exclusively represents a crafting table's 3x3 crafting grid. - -### Crafting -- `CraftingGrid` is now abstract. -- Removed `CraftingGrid->getHolder()`. -- The constructor of `CraftingGrid` no longer accepts a `Player` parameter. - -### Entity -#### Effect -- `Effect->__construct()` once again accepts an `int $defaultDuration` parameter. -- Removed `VanillaEffects::fromString()`. -- Added `StringToEffectParser` - - Supports custom aliases! - - This is used by `/effect` to provide name support. - -### Event -- `InventoryOpenEvent` is now fired when a player opens a crafting table's UI. -- `InventoryCloseEvent` is now fired when a player closes a crafting table's UI. -- `PlayerDropItemEvent` will now prevent the drops from force-closing of the following inventories: - - anvil - - enchanting table - - loom - -### Inventory -- Added `TemporaryInventory`. This should be implemented by any inventory whose contents should be evacuated when closing. -- Added `PlayerCraftingInventory`. This exclusively represents the player's own 2x2 crafting grid. - -### Item -- Removed `VanillaItems::fromString()` - - Obsoleted by the far superior, much more dynamic, and plugin-customizable `StringToItemParser`. - - `StringToItemParser` allows mapping strings to closure callbacks, allowing you to create aliases for `/give` for any item, including custom ones. - -#### Enchantment -- Removed `VanillaEnchantments::fromString()`. -- Added `StringToEnchantmentParser` - - Supports custom aliases! - - This is used by `/enchant` to provide name support. - -### Player -- Removed `Player->setCraftingGrid()`. To open a 3x3 crafting grid to a player, use `setCurrentWindow(new CraftingTableInventory)`. - -### Server -- Added the following API methods: - - `Server->getIpV6()` - - `Server->getPortV6()` - -# 4.0.0-BETA13 -Released 25th November 2021. - -## General -- Improved error messages when a plugin command name or alias contains an illegal character. -- Fixed script plugins reading tags from non-docblocks before the actual docblock. -- Added a sanity check to `Human->setCurrentTotalXp()` to try and catch an elusive bug that's been appearing in the wild - please get in touch if you know how to reproduce it! -- Updated `BUILDING.md` to reflect the fact that submodules are no longer required to build or run the server. - -## Internals -- Crashdump rendering has been separated from crashdump data generation. This allows rendering crashdumps from existing JSON data. -- Direct iteration of arrays with string keys is now disallowed by a custom PHPStan rule. This is because numeric strings are casted to integers when used as array keys, which produces a variety of unexpected behaviour particularly for iteration. - - To iterate on arrays with string keys, `Utils::stringifyKeys()` must now be used. - -## Fixes -- Fixed various crashes involving bad entity data saved on disk (e.g. an item entity with invalid item would crash the server). -- Fixed various crashes involving arrays with numeric string keys. -- Fixed crash when players try to pickup XP while already having max XP. -- Fixed ungenerated chunks saved on disk by old versions of PocketMine-MP (before 3.0.0) being treated as corrupted during world conversion (they are now ignored instead). -- Fixed misleading corruption error message when saved chunks have missing NBT tags. - -## Gameplay -- Fixed `/setworldspawn` setting incorrect positions based on player position when in negative coordinates. -- `/setworldspawn` now accepts relative coordinates when used as a player. -- Added some extra aliases for `/give` and `/clear`: `chipped_anvil`, `coarse_dirt`, `damaged_anvil`, `dark_oak_standing_sign`, `jungle_wood_stairs`, `jungle_wooden_stairs` and `oak_standing_sign`. - - Some of these were added for quality-of-life, others were added just to be consistent. -- Fixed explosions dropping incorrect items when destroying blocks with tile data (e.g. banners, beds). -- Fixed the bounding box of skulls when mounted on a wall. -- Fixed podzol dropping itself when mined (instead of dirt). - -## API -### Entity -- `Projectile->move()` is now protected, like its parent. - -### Utils -- `Utils::parseDocComment()` now allows `-` in tag names. - -# 4.0.0-BETA14 -Released 30th November 2021. - -## General -- The server will now log an EMERGENCY-level message when `forceShutdown()` is used for any other reason than a graceful shutdown. -- The server will now attempt to translate invalid blocks to valid equivalents when loading chunks. This fixes many issues with `update!` blocks appearing in worlds, particularly ghost structures (these would appear when world editors previously erased some blocks by setting their IDs but not metadata). - -## Fixes -- Fixed `ConsoleReaderThread` spawning many zombie processes when running a server inside a Docker container. - -# 4.0.0-BETA15 -Released 30th November 2021. - -## General -- Added support for Minecraft: Bedrock 1.18.0 -- Removed support for earlier versions. From bd8308cc6f784f00bce12c88417c3e212c97ed26 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 1 Dec 2021 22:15:38 +0000 Subject: [PATCH 441/710] changelog: mention pocketmine subdirectory removal --- changelogs/4.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 213ab4f7d..2f0673699 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -241,6 +241,7 @@ This version features substantial changes to the network system, improving coher - A new "plugin greylist" feature has been introduced, which allows whitelisting or blacklisting plugins from loading. See `plugin_list.yml`. ### Internals +- The `pocketmine` subdirectory has been removed from `src`. [PSR-4 autoloading is now used thanks to Composer](https://github.com/pmmp/PocketMine-MP/blob/4.0.0/composer.json#L63). - Crashdump rendering has been separated from crashdump data generation. This allows rendering crashdumps from existing JSON data. - Direct iteration of arrays with string keys is now disallowed by a custom PHPStan rule. This is because numeric strings are casted to integers when used as array keys, which produces a variety of unexpected behaviour particularly for iteration. - To iterate on arrays with string keys, `Utils::stringifyKeys()` must now be used. From 468faa464b2bc5c97f23fafbb71ea61035f6f218 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 1 Dec 2021 22:33:52 +0000 Subject: [PATCH 442/710] Release 4.0.0 --- changelogs/4.0.md | 2 ++ src/VersionInfo.php | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 2f0673699..23c307551 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1,3 +1,5 @@ +**For Minecraft: Bedrock Edition 1.18.0** + # 4.0.0 Released 1st December 2021. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 5a5b6139b..b3a48ebfd 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,9 +31,9 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0-BETA16"; - public const IS_DEVELOPMENT_BUILD = true; - public const BUILD_CHANNEL = "beta"; + public const BASE_VERSION = "4.0.0"; + public const IS_DEVELOPMENT_BUILD = false; + public const BUILD_CHANNEL = "stable"; private function __construct(){ //NOOP From 2da65c5a6e76745740fc70cdf47cc5385a1bd975 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 1 Dec 2021 22:33:58 +0000 Subject: [PATCH 443/710] 4.0.1 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index b3a48ebfd..dc3ab18a7 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.0"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.1"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 1669d33f7e6d27f80722d848ed64376819eeddbb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 2 Dec 2021 00:58:15 +0000 Subject: [PATCH 444/710] Updated DevTools submodule to pmmp/DevTools@39510af5bcf19eef3b3157c8c51d88a736811591 --- tests/plugins/DevTools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plugins/DevTools b/tests/plugins/DevTools index 6af57741e..39510af5b 160000 --- a/tests/plugins/DevTools +++ b/tests/plugins/DevTools @@ -1 +1 @@ -Subproject commit 6af57741e67a928e2782cebe8dd422044d16dc04 +Subproject commit 39510af5bcf19eef3b3157c8c51d88a736811591 From 1b86355c406dc7b2d1655818ccc1ec92729b6247 Mon Sep 17 00:00:00 2001 From: marshall Date: Fri, 3 Dec 2021 04:28:28 +0800 Subject: [PATCH 445/710] Server: Suppress "Minecraft network interface running" messages if RakLibInterface registration is cancelled (#4603) --- src/Server.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index f10a6b689..75971a108 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1143,7 +1143,9 @@ class Server{ ))); return false; } - $this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port))); + if($rakLibRegistered){ + $this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port))); + } if($useQuery){ if(!$rakLibRegistered){ //RakLib would normally handle the transport for Query packets From e61aaacccac9fb3063d2ffe84c3477672a34e983 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 4 Dec 2021 16:20:57 +0000 Subject: [PATCH 446/710] LevelDB: removed hack for problem fixed by 1f9400f9011546ab914090853069aaa76192a722 --- src/world/format/io/leveldb/LevelDB.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index 3fe2e359c..dbdf40894 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -175,11 +175,6 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $id = $idMap->stringToLegacy($tag->getString("name")) ?? BlockLegacyIds::INFO_UPDATE; $data = $tag->getShort("val"); - if($id === BlockLegacyIds::AIR){ - //TODO: quick and dirty hack for artifacts left behind by broken world editors - //we really need a proper state fixer, but this is a pressing issue. - $data = 0; - } $palette[] = ($id << Block::INTERNAL_METADATA_BITS) | $data; } From 1a046c6cd54183982eed40cdc42af4be70a2465c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 4 Dec 2021 18:17:17 +0000 Subject: [PATCH 447/710] LevelDB: fixed server crash when corrupted / invalid blockstate NBT is encountered --- src/world/format/io/leveldb/LevelDB.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index dbdf40894..acd8ffed4 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -29,6 +29,7 @@ use pocketmine\data\bedrock\BiomeIds; use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap; use pocketmine\nbt\LittleEndianNbtSerializer; use pocketmine\nbt\NbtDataException; +use pocketmine\nbt\NbtException; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\TreeRoot; use pocketmine\utils\Binary; @@ -157,6 +158,9 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ BedrockWorldData::generate($path, $name, $options); } + /** + * @throws CorruptedChunkException + */ protected function deserializePaletted(BinaryStream $stream) : PalettedBlockArray{ $bitsPerBlock = $stream->getByte() >> 1; @@ -169,13 +173,18 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ $palette = []; $idMap = LegacyBlockIdToStringIdMap::getInstance(); for($i = 0, $paletteSize = $stream->getLInt(); $i < $paletteSize; ++$i){ - $offset = $stream->getOffset(); - $tag = $nbt->read($stream->getBuffer(), $offset)->mustGetCompoundTag(); - $stream->setOffset($offset); + try{ + $offset = $stream->getOffset(); - $id = $idMap->stringToLegacy($tag->getString("name")) ?? BlockLegacyIds::INFO_UPDATE; - $data = $tag->getShort("val"); - $palette[] = ($id << Block::INTERNAL_METADATA_BITS) | $data; + $tag = $nbt->read($stream->getBuffer(), $offset)->mustGetCompoundTag(); + $stream->setOffset($offset); + + $id = $idMap->stringToLegacy($tag->getString("name")) ?? BlockLegacyIds::INFO_UPDATE; + $data = $tag->getShort("val"); + $palette[] = ($id << Block::INTERNAL_METADATA_BITS) | $data; + }catch(NbtException $e){ + throw new CorruptedChunkException("Invalid blockstate NBT at offset $i in paletted storage: " . $e->getMessage(), 0, $e); + } } //TODO: exceptions From 8e8cee45b8cc725d4186d911671e07e122b6ac85 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 4 Dec 2021 21:44:12 +0000 Subject: [PATCH 448/710] Config: use JSON_THROW_ON_ERROR for encoding --- src/utils/Config.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/Config.php b/src/utils/Config.php index 1a5125496..6397bd13d 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -53,6 +53,7 @@ use function yaml_parse; use const CASE_LOWER; use const JSON_BIGINT_AS_STRING; use const JSON_PRETTY_PRINT; +use const JSON_THROW_ON_ERROR; /** * Config Class for simple config manipulation of multiple formats. @@ -212,7 +213,7 @@ class Config{ $content = self::writeProperties($this->config); break; case Config::JSON: - $content = json_encode($this->config, $this->jsonOptions); + $content = json_encode($this->config, $this->jsonOptions | JSON_THROW_ON_ERROR); break; case Config::YAML: $content = yaml_emit($this->config, YAML_UTF8_ENCODING); From 8e37f86480b9ad50acba3a04edfef89429ff815a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 5 Dec 2021 00:26:48 +0000 Subject: [PATCH 449/710] Avoid file_put_contents() when overwriting files this fixes many cases of corruption during disk-full situations - file_put_contents() would write an empty file, destroying the original data. fixes #3152 --- src/Server.php | 4 +- src/utils/Config.php | 3 +- src/utils/Filesystem.php | 52 +++++++++++++++++++ src/world/format/io/data/BedrockWorldData.php | 3 +- src/world/format/io/data/JavaWorldData.php | 7 ++- 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/Server.php b/src/Server.php index 75971a108..e46525b4c 100644 --- a/src/Server.php +++ b/src/Server.php @@ -538,8 +538,8 @@ class Server{ Timings::$syncPlayerDataSave->time(function() use ($name, $ev) : void{ $nbt = new BigEndianNbtSerializer(); try{ - file_put_contents($this->getPlayerDataPath($name), zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP)); - }catch(\ErrorException $e){ + Filesystem::safeFilePutContents($this->getPlayerDataPath($name), zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP)); + }catch(\RuntimeException | \ErrorException $e){ $this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage()))); $this->logger->logException($e); } diff --git a/src/utils/Config.php b/src/utils/Config.php index 6397bd13d..c3a791095 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -33,7 +33,6 @@ use function date; use function explode; use function file_exists; use function file_get_contents; -use function file_put_contents; use function implode; use function is_array; use function is_bool; @@ -228,7 +227,7 @@ class Config{ throw new AssumptionFailedError("Config type is unknown, has not been set or not detected"); } - file_put_contents($this->file, $content); + Filesystem::safeFilePutContents($this->file, $content); $this->changed = false; } diff --git a/src/utils/Filesystem.php b/src/utils/Filesystem.php index 2d107af6e..fd3eca26b 100644 --- a/src/utils/Filesystem.php +++ b/src/utils/Filesystem.php @@ -26,9 +26,11 @@ namespace pocketmine\utils; use Webmozart\PathUtil\Path; use function copy; use function dirname; +use function disk_free_space; use function fclose; use function fflush; use function file_exists; +use function file_put_contents; use function flock; use function fopen; use function ftruncate; @@ -40,6 +42,7 @@ use function ltrim; use function mkdir; use function preg_match; use function realpath; +use function rename; use function rmdir; use function rtrim; use function scandir; @@ -221,4 +224,53 @@ final class Filesystem{ @unlink($lockFilePath); } } + + /** + * Wrapper around file_put_contents() which writes to a temporary file before overwriting the original. If the disk + * is full, writing to the temporary file will fail before the original file is modified, leaving it untouched. + * + * This is necessary because file_put_contents() destroys the data currently in the file if it fails to write the + * new contents. + * + * @param resource|null $context Context to pass to file_put_contents + */ + public static function safeFilePutContents(string $fileName, string $contents, int $flags = 0, $context = null) : void{ + $directory = dirname($fileName); + if(!is_dir($directory)){ + throw new \RuntimeException("Target directory path does not exist or is not a directory"); + } + if(is_dir($fileName)){ + throw new \RuntimeException("Target file path already exists and is not a file"); + } + + $counter = 0; + do{ + //we don't care about overwriting any preexisting tmpfile but we can't write if a directory is already here + $temporaryFileName = $fileName . ".$counter.tmp"; + $counter++; + }while(is_dir($temporaryFileName)); + + $writeTemporaryFileResult = $context !== null ? + file_put_contents($temporaryFileName, $contents, $flags, $context) : + file_put_contents($temporaryFileName, $contents, $flags); + + if($writeTemporaryFileResult !== strlen($contents)){ + $context !== null ? + @unlink($temporaryFileName, $context) : + @unlink($temporaryFileName); + $diskSpace = disk_free_space($directory); + if($diskSpace !== false && $diskSpace < strlen($contents)){ + throw new \RuntimeException("Failed to write to temporary file $temporaryFileName (out of free disk space)"); + } + throw new \RuntimeException("Failed to write to temporary file $temporaryFileName (possibly out of free disk space)"); + } + + $renameTemporaryFileResult = $context !== null ? + rename($temporaryFileName, $fileName, $context) : + rename($temporaryFileName, $fileName); + + if(!$renameTemporaryFileResult){ + throw new \RuntimeException("Failed to move temporary file contents into target file"); + } + } } diff --git a/src/world/format/io/data/BedrockWorldData.php b/src/world/format/io/data/BedrockWorldData.php index 50a4184fe..32fde0439 100644 --- a/src/world/format/io/data/BedrockWorldData.php +++ b/src/world/format/io/data/BedrockWorldData.php @@ -31,6 +31,7 @@ use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\TreeRoot; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\utils\Binary; +use pocketmine\utils\Filesystem; use pocketmine\utils\Limits; use pocketmine\world\format\io\exception\CorruptedWorldException; use pocketmine\world\format\io\exception\UnsupportedWorldFormatException; @@ -165,7 +166,7 @@ class BedrockWorldData extends BaseNbtWorldData{ $nbt = new LittleEndianNbtSerializer(); $buffer = $nbt->write(new TreeRoot($this->compoundTag)); - file_put_contents($this->dataPath, Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer); + Filesystem::safeFilePutContents($this->dataPath, Binary::writeLInt(self::CURRENT_STORAGE_VERSION) . Binary::writeLInt(strlen($buffer)) . $buffer); } public function getDifficulty() : int{ diff --git a/src/world/format/io/data/JavaWorldData.php b/src/world/format/io/data/JavaWorldData.php index c2f488876..cacecae29 100644 --- a/src/world/format/io/data/JavaWorldData.php +++ b/src/world/format/io/data/JavaWorldData.php @@ -29,6 +29,8 @@ use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\TreeRoot; +use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Filesystem; use pocketmine\world\format\io\exception\CorruptedWorldException; use pocketmine\world\generator\GeneratorManager; use pocketmine\world\World; @@ -111,7 +113,10 @@ class JavaWorldData extends BaseNbtWorldData{ public function save() : void{ $nbt = new BigEndianNbtSerializer(); $buffer = zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag("Data", $this->compoundTag))), ZLIB_ENCODING_GZIP); - file_put_contents($this->dataPath, $buffer); + if($buffer === false){ + throw new AssumptionFailedError("zlib_encode() failed unexpectedly"); + } + Filesystem::safeFilePutContents($this->dataPath, $buffer); } public function getDifficulty() : int{ From 527e975fa92a831f27970bebfec1bf372727be1d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 5 Dec 2021 00:45:23 +0000 Subject: [PATCH 450/710] shut --- src/Server.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index e46525b4c..f40667786 100644 --- a/src/Server.php +++ b/src/Server.php @@ -537,8 +537,12 @@ class Server{ if(!$ev->isCancelled()){ Timings::$syncPlayerDataSave->time(function() use ($name, $ev) : void{ $nbt = new BigEndianNbtSerializer(); + $contents = zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP); + if($contents === false){ + throw new AssumptionFailedError("zlib_encode() failed unexpectedly"); + } try{ - Filesystem::safeFilePutContents($this->getPlayerDataPath($name), zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP)); + Filesystem::safeFilePutContents($this->getPlayerDataPath($name), $contents); }catch(\RuntimeException | \ErrorException $e){ $this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage()))); $this->logger->logException($e); From 27f599793a93e2d9f32b4a9f62a5e4157e9303d2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 5 Dec 2021 01:00:24 +0000 Subject: [PATCH 451/710] tools: added old-but-gold server-ping.php --- tools/ping-server.php | 125 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 tools/ping-server.php diff --git a/tools/ping-server.php b/tools/ping-server.php new file mode 100644 index 000000000..aaf468281 --- /dev/null +++ b/tools/ping-server.php @@ -0,0 +1,125 @@ +sendPingTime = hrtime_ms(); + $ping->clientId = $rakNetClientId; + $serializer = new PacketSerializer(); + $ping->encode($serializer); + if(@socket_sendto($socket, $serializer->getBuffer(), strlen($serializer->getBuffer()), MSG_DONTROUTE, $serverIp, $serverPort) === false){ + \GlobalLogger::get()->error("Failed to send ping: " . socket_strerror(socket_last_error($socket))); + return false; + } + \GlobalLogger::get()->info("Ping sent to $serverIp on port $serverPort, waiting for response (press CTRL+C to abort)"); + + $r = [$socket]; + $w = $e = null; + if(socket_select($r, $w, $e, $timeoutSeconds) === 1){ + $response = @socket_recvfrom($socket, $recvBuffer, 65535, 0, $recvAddr, $recvPort); + if($response === false){ + \GlobalLogger::get()->error("Error reading from socket: " . socket_strerror(socket_last_error($socket))); + return false; + } + if($recvAddr === $serverIp and $recvPort === $serverPort and $recvBuffer !== "" and ord($recvBuffer[0]) === MessageIdentifiers::ID_UNCONNECTED_PONG){ + $pong = new UnconnectedPong(); + $pong->decode(new PacketSerializer($recvBuffer)); + \GlobalLogger::get()->info("--- Response received ---"); + \GlobalLogger::get()->info("Payload: $pong->serverName"); + \GlobalLogger::get()->info("Response time: " . (hrtime_ms() - $pong->sendPingTime) . " ms"); + return true; + }else{ + \GlobalLogger::get()->debug("Garbage packet from $recvAddr $recvPort: " . bin2hex($recvBuffer)); + } + } + + \GlobalLogger::get()->info("No ping response after $timeoutSeconds seconds"); + return false; +} + +if(count($argv) > 3){ + echo "Usage: " . PHP_BINARY . " " . __FILE__ . " [server IP] [server port]\n"; + exit(1); +} + +if(count($argv) > 1){ + $hostName = $argv[1]; +}else{ + do{ + $hostName = read_stdin("Server address"); + }while($hostName === ""); +} + +$serverIps = gethostbynamel($hostName); +if($serverIps === false){ + \GlobalLogger::get()->critical("Unable to resolve hostname $hostName to an IP address"); + exit(1); +} +if(count($serverIps) > 1){ + \GlobalLogger::get()->warning("Multiple IP addresses found for hostname $hostName, using the first one: " . $serverIps[0]); +} +$server = $serverIps[0]; +\GlobalLogger::get()->info("Resolved hostname to $server"); + +if(count($argv) > 2){ + $port = (int) $argv[2]; +}elseif(count($argv) > 1){ + $port = 19132; +}else{ + $portRaw = read_stdin("Server port (empty for 19132)"); + $port = $portRaw === "" ? 19132 : (int) $portRaw; +} + +$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); +if($sock === false) throw new AssumptionFailedError(); + +socket_bind($sock, "0.0.0.0"); +socket_getsockname($sock, $bindAddr, $bindPort); +\GlobalLogger::get()->info("Bound to $bindAddr on port $bindPort"); + +$start = time(); +while(time() < $start + 60_000 && !ping_server($sock, $server, $port, 5, mt_rand(0, PHP_INT_MAX))){ + sleep(1); +} + +socket_close($sock); + + From 13340a21d3b195638eb8d00f74f8784c3bd25e43 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 5 Dec 2021 01:01:16 +0000 Subject: [PATCH 452/710] fix CS --- tools/ping-server.php | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tools/ping-server.php b/tools/ping-server.php index aaf468281..400985246 100644 --- a/tools/ping-server.php +++ b/tools/ping-server.php @@ -1,5 +1,24 @@ Date: Sun, 5 Dec 2021 01:09:03 +0000 Subject: [PATCH 453/710] CS again --- tools/ping-server.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/ping-server.php b/tools/ping-server.php index 400985246..912119d5c 100644 --- a/tools/ping-server.php +++ b/tools/ping-server.php @@ -30,8 +30,17 @@ use raklib\protocol\UnconnectedPing; use raklib\protocol\UnconnectedPong; use function bin2hex; use function count; +use function fgets; +use function gethostbynamel; +use function hrtime; +use function intdiv; use function mt_rand; use function ord; +use function sleep; +use function socket_bind; +use function socket_close; +use function socket_create; +use function socket_getsockname; use function socket_last_error; use function socket_recvfrom; use function socket_select; @@ -39,6 +48,7 @@ use function socket_sendto; use function socket_strerror; use function strlen; use function time; +use function trim; use const MSG_DONTROUTE; use const PHP_BINARY; use const PHP_INT_MAX; From cac9db9bcc575fa5f0276695f723e933501c8e58 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Sun, 5 Dec 2021 15:01:45 +0000 Subject: [PATCH 454/710] changelog: fixed mistake in CreativeInventory documentation, closes #4616 --- changelogs/4.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 23c307551..7f5a25a91 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -836,7 +836,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Item::clearCreativeItems()` -> `CreativeInventory::clear()` - `Item::getCreativeItemIndex()` -> `CreativeInventory::getItemIndex()` - `Item::getCreativeItems()` -> `CreativeInventory::getAll()` - - `Item::initCreativeItems()` -> `CreativeInventory::init()` + - `Item::initCreativeItems()` -> `CreativeInventory::reset()` - `Item::isCreativeItem()` -> `CreativeInventory::contains()` - `Item::removeCreativeItem()` -> `CreativeInventory::remove()` - The following classes have been added: From 9256afd4398df062b4705e4f53191ae85ff85250 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 5 Dec 2021 16:06:29 +0000 Subject: [PATCH 455/710] Call BlockSpreadEvent when spreading fire to incinerated blocks --- src/block/Fire.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/block/Fire.php b/src/block/Fire.php index 82c08bfe0..36b340338 100644 --- a/src/block/Fire.php +++ b/src/block/Fire.php @@ -27,6 +27,7 @@ use pocketmine\block\utils\BlockDataSerializer; use pocketmine\entity\Entity; use pocketmine\entity\projectile\Arrow; use pocketmine\event\block\BlockBurnEvent; +use pocketmine\event\block\BlockSpreadEvent; use pocketmine\event\entity\EntityCombustByBlockEvent; use pocketmine\event\entity\EntityDamageByBlockEvent; use pocketmine\event\entity\EntityDamageEvent; @@ -172,14 +173,27 @@ class Fire extends Flowable{ if(!$ev->isCancelled()){ $block->onIncinerate(); + $spreadedFire = false; if(mt_rand(0, $this->age + 9) < 5){ //TODO: check rain $fire = clone $this; $fire->age = min(15, $fire->age + (mt_rand(0, 4) >> 2)); - $this->position->getWorld()->setBlock($block->position, $fire); - }else{ + $spreadedFire = $this->spreadBlock($block, $fire); + } + if(!$spreadedFire){ $this->position->getWorld()->setBlock($block->position, VanillaBlocks::AIR()); } } } } + + private function spreadBlock(Block $block, Block $newState) : bool{ + $ev = new BlockSpreadEvent($block, $this, $newState); + $ev->call(); + if(!$ev->isCancelled()){ + $block->position->getWorld()->setBlock($block->position, $ev->getNewState()); + return true; + } + + return false; + } } From 98c31cf07be7042514ff0da5da2e8594faa5e68a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 5 Dec 2021 16:07:20 +0000 Subject: [PATCH 456/710] Update version number --- src/VersionInfo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index dc3ab18a7..94b8dabda 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,7 +31,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.1"; + public const BASE_VERSION = "4.1.0"; public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; From 4d2d0f1d35947167c5a445865565f6b4d5102b37 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 6 Dec 2021 00:58:05 +0000 Subject: [PATCH 457/710] changelog: mention removal of Player->getLowerCaseName() closes #4618 --- changelogs/4.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 7f5a25a91..6a97299c3 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1026,6 +1026,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Player->continueBreakBlock()`: punch the target block during destruction in survival, advancing break animation and creating particles - `Player->getCurrentWindow()`: returns the inventory window the player is currently viewing, or null if they aren't viewing an inventory - `Player->getItemCooldownExpiry()`: returns the tick on which the player's cooldown for a given item expires + - `Player->getLowerCaseName()`: use `strtolower(Player->getName())` instead - `Player->getPlayerInfo()`: returns a `PlayerInfo` object containing various metadata about the player - `Player->getSaveData()`: returns save data generated on the fly - `Player->hasFiniteResources()` From 2486dabd8a3c64891a7494a57b3c429848bd7269 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 6 Dec 2021 01:04:59 +0000 Subject: [PATCH 458/710] Fire: extract more unrelated changes from #4617 --- src/block/Fire.php | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/block/Fire.php b/src/block/Fire.php index 36b340338..0e2410341 100644 --- a/src/block/Fire.php +++ b/src/block/Fire.php @@ -138,16 +138,7 @@ class Fire extends Flowable{ $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(30, 40)); if($canSpread){ - //TODO: raise upper bound for chance in humid biomes - - foreach($this->getHorizontalSides() as $side){ - $this->burnBlock($side, 300); - } - - //vanilla uses a 250 upper bound here, but I don't think they intended to increase the chance of incineration - $this->burnBlock($this->getSide(Facing::UP), 350); - $this->burnBlock($this->getSide(Facing::DOWN), 350); - + $this->burnBlocksAround(); //TODO: fire spread } } @@ -166,6 +157,18 @@ class Fire extends Flowable{ return false; } + private function burnBlocksAround() : void{ + //TODO: raise upper bound for chance in humid biomes + + foreach($this->getHorizontalSides() as $side){ + $this->burnBlock($side, 300); + } + + //vanilla uses a 250 upper bound here, but I don't think they intended to increase the chance of incineration + $this->burnBlock($this->getSide(Facing::UP), 350); + $this->burnBlock($this->getSide(Facing::DOWN), 350); + } + private function burnBlock(Block $block, int $chanceBound) : void{ if(mt_rand(0, $chanceBound) < $block->getFlammability()){ $ev = new BlockBurnEvent($block, $this); From 8ed9551ac9c34e2344fb02abd00d4fc09aaa0ac9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Dec 2021 14:59:42 +0000 Subject: [PATCH 459/710] Bump pocketmine/binaryutils from 0.2.2 to 0.2.3 (#4620) Bumps [pocketmine/binaryutils](https://github.com/pmmp/BinaryUtils) from 0.2.2 to 0.2.3. - [Release notes](https://github.com/pmmp/BinaryUtils/releases) - [Commits](https://github.com/pmmp/BinaryUtils/compare/0.2.2...0.2.3) --- updated-dependencies: - dependency-name: pocketmine/binaryutils dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index 284b6914d..3804b7fc6 100644 --- a/composer.lock +++ b/composer.lock @@ -322,16 +322,16 @@ }, { "name": "pocketmine/binaryutils", - "version": "0.2.2", + "version": "0.2.3", "source": { "type": "git", "url": "https://github.com/pmmp/BinaryUtils.git", - "reference": "f883e1cf9099ed6a757a10a2f75b3333eeb2cdf9" + "reference": "dc94786fc6c30012b1892f548dbb8a8c9c0a8cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/f883e1cf9099ed6a757a10a2f75b3333eeb2cdf9", - "reference": "f883e1cf9099ed6a757a10a2f75b3333eeb2cdf9", + "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/dc94786fc6c30012b1892f548dbb8a8c9c0a8cd9", + "reference": "dc94786fc6c30012b1892f548dbb8a8c9c0a8cd9", "shasum": "" }, "require": { @@ -340,8 +340,10 @@ }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.99", - "phpstan/phpstan-strict-rules": "^0.12.4" + "phpstan/phpstan": "1.2.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0.0", + "phpunit/phpunit": "^9.5" }, "type": "library", "autoload": { @@ -356,9 +358,9 @@ "description": "Classes and methods for conveniently handling binary data", "support": { "issues": "https://github.com/pmmp/BinaryUtils/issues", - "source": "https://github.com/pmmp/BinaryUtils/tree/0.2.2" + "source": "https://github.com/pmmp/BinaryUtils/tree/0.2.3" }, - "time": "2021-10-22T19:54:16+00:00" + "time": "2021-12-04T20:56:05+00:00" }, { "name": "pocketmine/callback-validator", From 62f150586fa378d67ba008bcfec4d9487c2c53eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Dec 2021 15:01:12 +0000 Subject: [PATCH 460/710] Bump pocketmine/locale-data from 2.0.20 to 2.0.22 (#4621) Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.0.20 to 2.0.22. - [Release notes](https://github.com/pmmp/Language/releases) - [Commits](https://github.com/pmmp/Language/compare/2.0.20...2.0.22) --- updated-dependencies: - dependency-name: pocketmine/locale-data dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 3804b7fc6..d745c0eae 100644 --- a/composer.lock +++ b/composer.lock @@ -535,16 +535,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.0.20", + "version": "2.0.22", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "a6e4eb22587e0014f6d658732cf633262723f8d3" + "reference": "181eb9d42653296e65d55a1bbba10e0dd76bbd61" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/a6e4eb22587e0014f6d658732cf633262723f8d3", - "reference": "a6e4eb22587e0014f6d658732cf633262723f8d3", + "url": "https://api.github.com/repos/pmmp/Language/zipball/181eb9d42653296e65d55a1bbba10e0dd76bbd61", + "reference": "181eb9d42653296e65d55a1bbba10e0dd76bbd61", "shasum": "" }, "type": "library", @@ -552,9 +552,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.0.20" + "source": "https://github.com/pmmp/Language/tree/2.0.22" }, - "time": "2021-11-25T20:56:12+00:00" + "time": "2021-12-04T22:37:10+00:00" }, { "name": "pocketmine/log", From 6e4b73c1835474d20241e45f56a598168697961b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 6 Dec 2021 16:40:32 +0000 Subject: [PATCH 461/710] FallingBlock: fixed crash when block is unable to be determined --- src/entity/object/FallingBlock.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/entity/object/FallingBlock.php b/src/entity/object/FallingBlock.php index 5376b866e..9957453b6 100644 --- a/src/entity/object/FallingBlock.php +++ b/src/entity/object/FallingBlock.php @@ -26,6 +26,7 @@ namespace pocketmine\entity\object; use pocketmine\block\Block; use pocketmine\block\BlockFactory; use pocketmine\block\utils\Fallable; +use pocketmine\data\SavedDataLoadingException; use pocketmine\entity\Entity; use pocketmine\entity\EntitySizeInfo; use pocketmine\entity\Location; @@ -71,7 +72,7 @@ class FallingBlock extends Entity{ } if($blockId === 0){ - throw new \UnexpectedValueException("Missing block info from NBT"); + throw new SavedDataLoadingException("Missing block info from NBT"); } $damage = $nbt->getByte("Data", 0); From e7deffa9af108fa8eb67c2d9731b3ae61f78ca38 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 6 Dec 2021 16:41:43 +0000 Subject: [PATCH 462/710] Update in-house dependency versions --- composer.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/composer.lock b/composer.lock index d745c0eae..b92d072e5 100644 --- a/composer.lock +++ b/composer.lock @@ -643,16 +643,16 @@ }, { "name": "pocketmine/math", - "version": "0.4.0", + "version": "0.4.2", "source": { "type": "git", "url": "https://github.com/pmmp/Math.git", - "reference": "6d64e2555bd2e95ed024574f75d1cefc135c89fc" + "reference": "aacc3759a508a69dfa5bc4dfa770ab733c5c94bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Math/zipball/6d64e2555bd2e95ed024574f75d1cefc135c89fc", - "reference": "6d64e2555bd2e95ed024574f75d1cefc135c89fc", + "url": "https://api.github.com/repos/pmmp/Math/zipball/aacc3759a508a69dfa5bc4dfa770ab733c5c94bf", + "reference": "aacc3759a508a69dfa5bc4dfa770ab733c5c94bf", "shasum": "" }, "require": { @@ -660,10 +660,10 @@ "php-64bit": "*" }, "require-dev": { - "irstea/phpunit-shim": "^8.5 || ^9.5", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.99", - "phpstan/phpstan-strict-rules": "^0.12.4" + "phpstan/phpstan": "1.2.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^8.5 || ^9.5" }, "type": "library", "autoload": { @@ -678,22 +678,22 @@ "description": "PHP library containing math related code used in PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Math/issues", - "source": "https://github.com/pmmp/Math/tree/0.4.0" + "source": "https://github.com/pmmp/Math/tree/0.4.2" }, - "time": "2021-10-29T20:33:10+00:00" + "time": "2021-12-05T01:15:17+00:00" }, { "name": "pocketmine/nbt", - "version": "0.3.0", + "version": "0.3.1", "source": { "type": "git", "url": "https://github.com/pmmp/NBT.git", - "reference": "98c4a04b55a915e18f83d3b0c9beb24a71abcd31" + "reference": "f43db89b8216b772407cdcedd90147db8eef34bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/NBT/zipball/98c4a04b55a915e18f83d3b0c9beb24a71abcd31", - "reference": "98c4a04b55a915e18f83d3b0c9beb24a71abcd31", + "url": "https://api.github.com/repos/pmmp/NBT/zipball/f43db89b8216b772407cdcedd90147db8eef34bc", + "reference": "f43db89b8216b772407cdcedd90147db8eef34bc", "shasum": "" }, "require": { @@ -704,7 +704,7 @@ "require-dev": { "irstea/phpunit-shim": "^9.5", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.85", + "phpstan/phpstan": "0.12.99", "phpstan/phpstan-strict-rules": "^0.12.4" }, "type": "library", @@ -720,9 +720,9 @@ "description": "PHP library for working with Named Binary Tags", "support": { "issues": "https://github.com/pmmp/NBT/issues", - "source": "https://github.com/pmmp/NBT/tree/0.3.0" + "source": "https://github.com/pmmp/NBT/tree/0.3.1" }, - "time": "2021-05-18T15:46:33+00:00" + "time": "2021-12-06T16:19:10+00:00" }, { "name": "pocketmine/raklib", From ee060f3e02911d7110c5fe26e910b82b246b7c9d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 6 Dec 2021 16:42:40 +0000 Subject: [PATCH 463/710] Update PHPUnit dependency junk --- composer.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/composer.lock b/composer.lock index b92d072e5..2979bb4ab 100644 --- a/composer.lock +++ b/composer.lock @@ -1506,16 +1506,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.1", + "version": "v4.13.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd" + "reference": "210577fe3cf7badcc5814d99455df46564f3c077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd", - "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077", "shasum": "" }, "require": { @@ -1556,9 +1556,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" }, - "time": "2021-11-03T20:52:16+00:00" + "time": "2021-11-30T19:35:32+00:00" }, { "name": "phar-io/manifest", @@ -2070,16 +2070,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.9", + "version": "9.2.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b" + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", - "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687", + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687", "shasum": "" }, "require": { @@ -2135,7 +2135,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10" }, "funding": [ { @@ -2143,20 +2143,20 @@ "type": "github" } ], - "time": "2021-11-19T15:21:02+00:00" + "time": "2021-12-05T09:12:13+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.5", + "version": "3.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { @@ -2195,7 +2195,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" }, "funding": [ { @@ -2203,7 +2203,7 @@ "type": "github" } ], - "time": "2020-09-28T05:57:25+00:00" + "time": "2021-12-02T12:48:52+00:00" }, { "name": "phpunit/php-invoker", From cd850b111d18928e5a14343b851f064532aadd6c Mon Sep 17 00:00:00 2001 From: xxAROX Date: Mon, 6 Dec 2021 21:29:01 +0100 Subject: [PATCH 464/710] SplashPotion: added getType() (#4613) --- src/item/SplashPotion.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/item/SplashPotion.php b/src/item/SplashPotion.php index 1b338a96b..e25cbf843 100644 --- a/src/item/SplashPotion.php +++ b/src/item/SplashPotion.php @@ -37,6 +37,8 @@ class SplashPotion extends ProjectileItem{ $this->potionType = $potionType; } + public function getType() : PotionType{ return $this->potionType; } + public function getMaxStackSize() : int{ return 1; } From ce54d268f2412bd10905abab56cf6f267df2e18c Mon Sep 17 00:00:00 2001 From: Drew B Date: Mon, 6 Dec 2021 16:14:22 -0500 Subject: [PATCH 465/710] Player: allow controlling client-sided block collisions irrespective of Spectator Mode (#4563) - Added the following API methods: - `Player::hasBlockCollision()` - `Player::setHasBlockCollision()` This enables spectator-like noclip behaviour in other gamemodes (could be useful for builders). --- src/network/mcpe/NetworkSession.php | 2 +- src/player/Player.php | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 2fe44e3ac..0b7a8253b 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -797,7 +797,7 @@ class NetworkSession{ $pk->setFlag(AdventureSettingsPacket::NO_PVP, $for->isSpectator()); $pk->setFlag(AdventureSettingsPacket::AUTO_JUMP, $for->hasAutoJump()); $pk->setFlag(AdventureSettingsPacket::ALLOW_FLIGHT, $for->getAllowFlight()); - $pk->setFlag(AdventureSettingsPacket::NO_CLIP, $for->isSpectator()); + $pk->setFlag(AdventureSettingsPacket::NO_CLIP, !$for->hasBlockCollision()); $pk->setFlag(AdventureSettingsPacket::FLYING, $for->isFlying()); //TODO: permission flags diff --git a/src/player/Player.php b/src/player/Player.php index aab421014..e7c5f7041 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -234,6 +234,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ //TODO: Abilities protected bool $autoJump = true; protected bool $allowFlight = false; + protected bool $blockCollision = true; protected bool $flying = false; protected ?int $lineHeight = null; @@ -394,6 +395,15 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ return $this->allowFlight; } + public function setHasBlockCollision(bool $value) : void{ + $this->blockCollision = $value; + $this->getNetworkSession()->syncAdventureSettings($this); + } + + public function hasBlockCollision() : bool{ + return $this->blockCollision; + } + public function setFlying(bool $value) : void{ if($this->flying !== $value){ $this->flying = $value; @@ -970,6 +980,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if($this->isSpectator()){ $this->setFlying(true); + $this->setHasBlockCollision(false); $this->setSilent(); $this->onGround = false; @@ -980,6 +991,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if($this->isSurvival()){ $this->setFlying(false); } + $this->setHasBlockCollision(true); $this->setSilent(false); $this->checkGroundState(0, 0, 0, 0, 0, 0); } From 8f2ca92f0283f63da7707a4b722bc44e19fd6d6f Mon Sep 17 00:00:00 2001 From: Rush2929 <76860328+Rush2929@users.noreply.github.com> Date: Tue, 7 Dec 2021 07:23:18 +0900 Subject: [PATCH 466/710] Implement dropped item merging (#4419) - The following classes have been added: - `ItemMergeEvent` - `ItemEntityStackSizeChangeAnimation` - The following API methods have been added: - `ItemEntity->isMergeable()` - `ItemEntity->tryMergeInto()` - `ItemEntity->setStackSize()` --- .../ItemEntityStackSizeChangeAnimation.php | 40 ++++++++++++ src/entity/object/ItemEntity.php | 63 +++++++++++++++++++ src/event/entity/ItemMergeEvent.php | 52 +++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 src/entity/animation/ItemEntityStackSizeChangeAnimation.php create mode 100644 src/event/entity/ItemMergeEvent.php diff --git a/src/entity/animation/ItemEntityStackSizeChangeAnimation.php b/src/entity/animation/ItemEntityStackSizeChangeAnimation.php new file mode 100644 index 000000000..40dab0ab4 --- /dev/null +++ b/src/entity/animation/ItemEntityStackSizeChangeAnimation.php @@ -0,0 +1,40 @@ +itemEntity->getId(), ActorEvent::ITEM_ENTITY_MERGE, $this->newStackSize)]; + } +} \ No newline at end of file diff --git a/src/entity/object/ItemEntity.php b/src/entity/object/ItemEntity.php index 899cbc279..d3c7aa70d 100644 --- a/src/entity/object/ItemEntity.php +++ b/src/entity/object/ItemEntity.php @@ -23,11 +23,13 @@ declare(strict_types=1); namespace pocketmine\entity\object; +use pocketmine\entity\animation\ItemEntityStackSizeChangeAnimation; use pocketmine\entity\Entity; use pocketmine\entity\EntitySizeInfo; use pocketmine\entity\Location; use pocketmine\event\entity\EntityItemPickupEvent; use pocketmine\event\entity\ItemDespawnEvent; +use pocketmine\event\entity\ItemMergeEvent; use pocketmine\event\entity\ItemSpawnEvent; use pocketmine\item\Item; use pocketmine\math\Vector3; @@ -43,6 +45,7 @@ class ItemEntity extends Entity{ public static function getNetworkTypeId() : string{ return EntityIds::ITEM; } + public const MERGE_CHECK_PERIOD = 2; //0.1 seconds public const DEFAULT_DESPAWN_DELAY = 6000; //5 minutes public const NEVER_DESPAWN = -1; public const MAX_DESPAWN_DELAY = 32767 + self::DEFAULT_DESPAWN_DELAY; //max value storable by mojang NBT :( @@ -105,6 +108,27 @@ class ItemEntity extends Entity{ if($this->pickupDelay < 0){ $this->pickupDelay = 0; } + if($this->hasMovementUpdate() and $this->despawnDelay % self::MERGE_CHECK_PERIOD === 0){ + $mergeable = [$this]; //in case the merge target ends up not being this + $mergeTarget = $this; + foreach($this->getWorld()->getNearbyEntities($this->boundingBox->expandedCopy(0.5, 0.5, 0.5), $this) as $entity){ + if(!$entity instanceof ItemEntity or $entity->isFlaggedForDespawn()){ + continue; + } + + if($entity->isMergeable($this)){ + $mergeable[] = $entity; + if($entity->item->getCount() > $mergeTarget->item->getCount()){ + $mergeTarget = $entity; + } + } + } + foreach($mergeable as $itemEntity){ + if($itemEntity !== $mergeTarget){ + $itemEntity->tryMergeInto($mergeTarget); + } + } + } $this->despawnDelay -= $tickDiff; if($this->despawnDelay <= 0){ @@ -122,6 +146,37 @@ class ItemEntity extends Entity{ return $hasUpdate; } + /** + * Returns whether this item entity can merge with the given one. + */ + public function isMergeable(ItemEntity $entity) : bool{ + $item = $entity->item; + return $entity !== $this && $entity->pickupDelay !== self::NEVER_DESPAWN and $item->canStackWith($this->item) and $item->getCount() + $this->item->getCount() <= $item->getMaxStackSize(); + } + + /** + * Attempts to merge this item entity into the given item entity. Returns true if it was successful. + */ + public function tryMergeInto(ItemEntity $consumer) : bool{ + if(!$this->isMergeable($consumer)){ + return false; + } + + $ev = new ItemMergeEvent($this, $consumer); + $ev->call(); + + if($ev->isCancelled()){ + return false; + } + + $consumer->setStackSize($consumer->item->getCount() + $this->item->getCount()); + $this->flagForDespawn(); + $consumer->pickupDelay = max($consumer->pickupDelay, $this->pickupDelay); + $consumer->despawnDelay = max($consumer->despawnDelay, $this->despawnDelay); + + return true; + } + protected function tryChangeMovement() : void{ $this->checkObstruction($this->location->x, $this->location->y, $this->location->z); parent::tryChangeMovement(); @@ -217,6 +272,14 @@ class ItemEntity extends Entity{ )); } + public function setStackSize(int $newCount) : void{ + if($newCount <= 0){ + throw new \InvalidArgumentException("Stack size must be at least 1"); + } + $this->item->setCount($newCount); + $this->broadcastAnimation(new ItemEntityStackSizeChangeAnimation($this, $newCount)); + } + public function getOffsetPosition(Vector3 $vector3) : Vector3{ return $vector3->add(0, 0.125, 0); } diff --git a/src/event/entity/ItemMergeEvent.php b/src/event/entity/ItemMergeEvent.php new file mode 100644 index 000000000..061c61b87 --- /dev/null +++ b/src/event/entity/ItemMergeEvent.php @@ -0,0 +1,52 @@ + + */ +class ItemMergeEvent extends EntityEvent implements Cancellable{ + use CancellableTrait; + + public function __construct( + ItemEntity $entity, + protected ItemEntity $target + ){ + $this->entity = $entity; + } + + /** + * Returns the merge destination. + */ + public function getTarget() : ItemEntity{ + return $this->target; + } + +} \ No newline at end of file From 0530cb72df2d90f61dd47316d8f3c872b931dec6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 6 Dec 2021 23:44:41 +0000 Subject: [PATCH 467/710] StringToItemParser: fixed some bogus aliases inherited from Item::fromString() --- src/item/StringToItemParser.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index df0b8944f..7fe82cfb5 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -97,7 +97,7 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("anvil", fn() => VanillaBlocks::ANVIL()); $result->registerBlock("ateupd_block", fn() => VanillaBlocks::INFO_UPDATE2()); $result->registerBlock("azure_bluet", fn() => VanillaBlocks::AZURE_BLUET()); - $result->registerBlock("bamboo", fn() => VanillaBlocks::BAMBOO_SAPLING()); + $result->registerBlock("bamboo", fn() => VanillaBlocks::BAMBOO()); $result->registerBlock("bamboo_sapling", fn() => VanillaBlocks::BAMBOO_SAPLING()); $result->registerBlock("banner", fn() => VanillaBlocks::BANNER()); $result->registerBlock("barrel", fn() => VanillaBlocks::BARREL()); @@ -798,7 +798,7 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("sea_lantern", fn() => VanillaBlocks::SEA_LANTERN()); $result->registerBlock("sea_pickle", fn() => VanillaBlocks::SEA_PICKLE()); $result->registerBlock("sealantern", fn() => VanillaBlocks::SEA_LANTERN()); - $result->registerBlock("shulker_box", fn() => VanillaBlocks::DYED_SHULKER_BOX()); + $result->registerBlock("shulker_box", fn() => VanillaBlocks::SHULKER_BOX()); $result->registerBlock("sign", fn() => VanillaBlocks::OAK_SIGN()); $result->registerBlock("sign_post", fn() => VanillaBlocks::OAK_SIGN()); $result->registerBlock("silver_glazed_terracotta", fn() => VanillaBlocks::LIGHT_GRAY_GLAZED_TERRACOTTA()); @@ -859,11 +859,11 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("stone_bricks", fn() => VanillaBlocks::STONE_BRICKS()); $result->registerBlock("stone_button", fn() => VanillaBlocks::STONE_BUTTON()); $result->registerBlock("stone_pressure_plate", fn() => VanillaBlocks::STONE_PRESSURE_PLATE()); - $result->registerBlock("stone_slab", fn() => VanillaBlocks::SMOOTH_STONE_SLAB()); + $result->registerBlock("stone_slab", fn() => VanillaBlocks::STONE_SLAB()); $result->registerBlock("stone_slab2", fn() => VanillaBlocks::RED_SANDSTONE_SLAB()); $result->registerBlock("stone_slab3", fn() => VanillaBlocks::END_STONE_BRICK_SLAB()); $result->registerBlock("stone_slab4", fn() => VanillaBlocks::MOSSY_STONE_BRICK_SLAB()); - $result->registerBlock("stone_stairs", fn() => VanillaBlocks::COBBLESTONE_STAIRS()); + $result->registerBlock("stone_stairs", fn() => VanillaBlocks::STONE_STAIRS()); $result->registerBlock("stone_wall", fn() => VanillaBlocks::COBBLESTONE_WALL()); $result->registerBlock("stonebrick", fn() => VanillaBlocks::STONE_BRICKS()); $result->registerBlock("stonecutter", fn() => VanillaBlocks::LEGACY_STONECUTTER()); @@ -885,7 +885,7 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("sugarcane_block", fn() => VanillaBlocks::SUGARCANE()); $result->registerBlock("sunflower", fn() => VanillaBlocks::SUNFLOWER()); $result->registerBlock("sweet_berry_bush", fn() => VanillaBlocks::SWEET_BERRY_BUSH()); - $result->registerBlock("tall_grass", fn() => VanillaBlocks::FERN()); + $result->registerBlock("tall_grass", fn() => VanillaBlocks::TALL_GRASS()); $result->registerBlock("tallgrass", fn() => VanillaBlocks::FERN()); $result->registerBlock("terracotta", fn() => VanillaBlocks::STAINED_CLAY()); $result->registerBlock("tnt", fn() => VanillaBlocks::TNT()); From 0c012ca5d9d58d21330409d59851758131191212 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 6 Dec 2021 23:45:36 +0000 Subject: [PATCH 468/710] Replace usages of ItemFactory in tests with VanillaItems --- tests/phpunit/inventory/BaseInventoryTest.php | 6 ++---- tests/phpunit/item/ItemTest.php | 9 +++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/phpunit/inventory/BaseInventoryTest.php b/tests/phpunit/inventory/BaseInventoryTest.php index 0354b2696..39ddd34ac 100644 --- a/tests/phpunit/inventory/BaseInventoryTest.php +++ b/tests/phpunit/inventory/BaseInventoryTest.php @@ -25,16 +25,14 @@ namespace pocketmine\inventory; use PHPUnit\Framework\TestCase; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; -use pocketmine\item\ItemIds; use pocketmine\item\VanillaItems; class BaseInventoryTest extends TestCase{ public function testAddItemDifferentUserData() : void{ $inv = new SimpleInventory(1); - $item1 = ItemFactory::getInstance()->get(ItemIds::ARROW, 0, 1); - $item2 = ItemFactory::getInstance()->get(ItemIds::ARROW, 0, 1)->setCustomName("TEST"); + $item1 = VanillaItems::ARROW()->setCount(1); + $item2 = VanillaItems::ARROW()->setCount(1)->setCustomName("TEST"); $inv->addItem(clone $item1); self::assertFalse($inv->canAddItem($item2), "Item WITHOUT userdata should not stack with item WITH userdata"); diff --git a/tests/phpunit/item/ItemTest.php b/tests/phpunit/item/ItemTest.php index 846b23f5f..95aafd8a7 100644 --- a/tests/phpunit/item/ItemTest.php +++ b/tests/phpunit/item/ItemTest.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\item; use PHPUnit\Framework\TestCase; +use pocketmine\block\VanillaBlocks; use pocketmine\item\enchantment\EnchantmentInstance; use pocketmine\item\enchantment\VanillaEnchantments; @@ -33,14 +34,14 @@ class ItemTest extends TestCase{ private $item; public function setUp() : void{ - $this->item = ItemFactory::getInstance()->get(ItemIds::DIAMOND_SWORD); + $this->item = VanillaItems::DIAMOND_SWORD(); } /** * Test for issue #1145 (items aren't considered equal after NBT serializing and deserializing */ public function testItemEquals() : void{ - $item = ItemFactory::getInstance()->get(ItemIds::STONE)->setCustomName("HI"); + $item = VanillaBlocks::STONE()->asItem()->setCustomName("HI"); $item2 = Item::nbtDeserialize($item->nbtSerialize()); self::assertTrue($item2->equals($item)); self::assertTrue($item->equals($item2)); @@ -50,7 +51,7 @@ class ItemTest extends TestCase{ * Test that same items without NBT are considered equal */ public function testItemEqualsNoNbt() : void{ - $item1 = ItemFactory::getInstance()->get(ItemIds::DIAMOND_SWORD); + $item1 = VanillaItems::DIAMOND_SWORD(); $item2 = clone $item1; self::assertTrue($item1->equals($item2)); } @@ -62,7 +63,7 @@ class ItemTest extends TestCase{ public function testItemPersistsDisplayProperties() : void{ $lore = ["Line A", "Line B"]; $name = "HI"; - $item = ItemFactory::getInstance()->get(ItemIds::DIAMOND_SWORD); + $item = VanillaItems::DIAMOND_SWORD(); $item->setCustomName($name); $item->setLore($lore); $item = Item::nbtDeserialize($item->nbtSerialize()); From 5a351d3b17cc9073e764560703271cadefda1450 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 6 Dec 2021 23:51:30 +0000 Subject: [PATCH 469/710] StringToItemParser: fixed not recognizing slime or slime_block --- src/item/StringToItemParser.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index 7fe82cfb5..e2ae03a97 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -805,6 +805,8 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("skull_block", fn() => VanillaBlocks::MOB_HEAD()); $result->registerBlock("slab", fn() => VanillaBlocks::SMOOTH_STONE_SLAB()); $result->registerBlock("slabs", fn() => VanillaBlocks::SMOOTH_STONE_SLAB()); + $result->registerBlock("slime", fn() => VanillaBlocks::SLIME()); + $result->registerBlock("slime_block", fn() => VanillaBlocks::SLIME()); $result->registerBlock("smoker", fn() => VanillaBlocks::SMOKER()); $result->registerBlock("smooth_quartz", fn() => VanillaBlocks::SMOOTH_QUARTZ()); $result->registerBlock("smooth_quartz_slab", fn() => VanillaBlocks::SMOOTH_QUARTZ_SLAB()); From 3728ddbf24f6ca772bab7510c3a3b8203249d7dd Mon Sep 17 00:00:00 2001 From: Matthew Jordan Date: Mon, 6 Dec 2021 17:57:07 -0600 Subject: [PATCH 470/710] ClearCommand: Cleanup logic & fix vanilla disparities (#4619) --- changelogs/4.0.md | 2 +- src/command/defaults/ClearCommand.php | 109 +++++++++++++------------- 2 files changed, 55 insertions(+), 56 deletions(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 23c307551..7f5a25a91 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -836,7 +836,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Item::clearCreativeItems()` -> `CreativeInventory::clear()` - `Item::getCreativeItemIndex()` -> `CreativeInventory::getItemIndex()` - `Item::getCreativeItems()` -> `CreativeInventory::getAll()` - - `Item::initCreativeItems()` -> `CreativeInventory::init()` + - `Item::initCreativeItems()` -> `CreativeInventory::reset()` - `Item::isCreativeItem()` -> `CreativeInventory::contains()` - `Item::removeCreativeItem()` -> `CreativeInventory::remove()` - The following classes have been added: diff --git a/src/command/defaults/ClearCommand.php b/src/command/defaults/ClearCommand.php index 59bee1e5b..02f8d0c9e 100644 --- a/src/command/defaults/ClearCommand.php +++ b/src/command/defaults/ClearCommand.php @@ -26,6 +26,8 @@ namespace pocketmine\command\defaults; use pocketmine\command\Command; use pocketmine\command\CommandSender; use pocketmine\command\utils\InvalidCommandSyntaxException; +use pocketmine\inventory\Inventory; +use pocketmine\item\Item; use pocketmine\item\LegacyStringToItemParser; use pocketmine\item\LegacyStringToItemParserException; use pocketmine\item\StringToItemParser; @@ -33,9 +35,9 @@ use pocketmine\lang\KnownTranslationFactory; use pocketmine\permission\DefaultPermissionNames; use pocketmine\player\Player; use pocketmine\utils\TextFormat; -use function array_merge; use function count; use function implode; +use function min; class ClearCommand extends VanillaCommand{ @@ -57,7 +59,6 @@ class ClearCommand extends VanillaCommand{ throw new InvalidCommandSyntaxException(); } - $target = null; if(isset($args[0])){ $target = $sender->getServer()->getPlayerByPrefix($args[0]); if($target === null){ @@ -77,14 +78,14 @@ class ClearCommand extends VanillaCommand{ throw new InvalidCommandSyntaxException(); } - $item = null; + $targetItem = null; $maxCount = -1; if(isset($args[1])){ try{ - $item = StringToItemParser::getInstance()->parse($args[1]) ?? LegacyStringToItemParser::getInstance()->parse($args[1]); + $targetItem = StringToItemParser::getInstance()->parse($args[1]) ?? LegacyStringToItemParser::getInstance()->parse($args[1]); if(isset($args[2])){ - $item->setCount($maxCount = $this->getInteger($sender, $args[2], 0)); + $targetItem->setCount($maxCount = $this->getInteger($sender, $args[2], -1)); } }catch(LegacyStringToItemParserException $e){ //vanilla checks this at argument parsing layer, can't come up with a better alternative @@ -93,14 +94,18 @@ class ClearCommand extends VanillaCommand{ } } - //checking players inventory for all the items matching the criteria - if($item !== null and $maxCount === 0){ - $count = 0; - $contents = array_merge($target->getInventory()->all($item), $target->getArmorInventory()->all($item)); - foreach($contents as $content){ - $count += $content->getCount(); - } + /** + * @var Inventory[] $inventories - This is the order that vanilla would clear items in. + */ + $inventories = [ + $target->getInventory(), + $target->getCursorInventory(), + $target->getArmorInventory() + ]; + // Checking player's inventory for all the items matching the criteria + if($targetItem !== null and $maxCount === 0){ + $count = $this->countItems($inventories, $targetItem); if($count > 0){ $sender->sendMessage(KnownTranslationFactory::commands_clear_testing($target->getName(), (string) $count)); }else{ @@ -110,65 +115,59 @@ class ClearCommand extends VanillaCommand{ return true; } - $cleared = 0; - - //clear everything from the targets inventory - if($item === null){ - $contents = array_merge($target->getInventory()->getContents(), $target->getArmorInventory()->getContents()); - foreach($contents as $content){ - $cleared += $content->getCount(); + $clearedCount = 0; + if($targetItem === null){ + // Clear all items from the inventories + $clearedCount += $this->countItems($inventories, null); + foreach($inventories as $inventory){ + $inventory->clearAll(); } - - $target->getInventory()->clearAll(); - $target->getArmorInventory()->clearAll(); - //TODO: should the cursor inv be cleared? }else{ - //clear the item from targets inventory irrelevant of the count + // Clear the item from target's inventory irrelevant of the count if($maxCount === -1){ - if(($slot = $target->getArmorInventory()->first($item)) !== -1){ - $cleared++; - $target->getArmorInventory()->clear($slot); - } - - foreach($target->getInventory()->all($item) as $index => $i){ - $cleared += $i->getCount(); - $target->getInventory()->clear($index); + $clearedCount += $this->countItems($inventories, $targetItem); + foreach($inventories as $inventory){ + $inventory->remove($targetItem); } }else{ - //clear only the given amount of that particular item from targets inventory - if(($slot = $target->getArmorInventory()->first($item)) !== -1){ - $cleared++; - $maxCount--; - $target->getArmorInventory()->clear($slot); - } - - if($maxCount > 0){ - foreach($target->getInventory()->all($item) as $index => $i){ - if($i->getCount() >= $maxCount){ - $i->pop($maxCount); - $cleared += $maxCount; - $target->getInventory()->setItem($index, $i); - break; - } + // Clear the item from target's inventory up to maxCount + foreach($inventories as $inventory){ + foreach($inventory->all($targetItem) as $index => $item){ + // The count to reduce from the item and max count + $reductionCount = min($item->getCount(), $maxCount); + $item->pop($reductionCount); + $clearedCount += $reductionCount; + $inventory->setItem($index, $item); + $maxCount -= $reductionCount; if($maxCount <= 0){ - break; + break 2; } - - $cleared += $i->getCount(); - $maxCount -= $i->getCount(); - $target->getInventory()->clear($index); } } } } - if($cleared > 0){ - Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_clear_success($target->getName(), (string) $cleared)); + if($clearedCount > 0){ + Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_clear_success($target->getName(), (string) $clearedCount)); }else{ $sender->sendMessage(KnownTranslationFactory::commands_clear_failure_no_items($target->getName())->prefix(TextFormat::RED)); } return true; } -} + + /** + * @param Inventory[] $inventories + */ + protected function countItems(array $inventories, ?Item $target) : int{ + $count = 0; + foreach($inventories as $inventory){ + $contents = $target !== null ? $inventory->all($target) : $inventory->getContents(); + foreach($contents as $item){ + $count += $item->getCount(); + } + } + return $count; + } +} \ No newline at end of file From ed4978c31b1def8c0b066933726c2b2d0dc724d9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Dec 2021 00:41:07 +0000 Subject: [PATCH 471/710] Added VanillaItems::AIR() we don't usually add VanillaItems entries for blocks since they already exist in VanillaBlocks, but air has a special use case specifically as an itemstack, so we make an exception for this case. --- src/block/tile/ItemFrame.php | 6 +++--- src/crafting/ShapedRecipe.php | 4 ++-- src/inventory/BaseInventory.php | 6 +++--- src/inventory/SimpleInventory.php | 6 +++--- src/inventory/transaction/TransactionBuilderInventory.php | 4 ++-- src/inventory/transaction/action/CreateItemAction.php | 4 ++-- src/inventory/transaction/action/DestroyItemAction.php | 4 ++-- src/inventory/transaction/action/DropItemAction.php | 4 ++-- src/item/Food.php | 2 +- src/item/Item.php | 2 +- src/item/ItemFactory.php | 4 ++++ src/item/VanillaItems.php | 3 +++ src/world/Explosion.php | 4 ++-- src/world/World.php | 4 ++-- 14 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/block/tile/ItemFrame.php b/src/block/tile/ItemFrame.php index 32d55f201..eb8ff3d32 100644 --- a/src/block/tile/ItemFrame.php +++ b/src/block/tile/ItemFrame.php @@ -24,7 +24,7 @@ declare(strict_types=1); namespace pocketmine\block\tile; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; use pocketmine\world\World; @@ -46,7 +46,7 @@ class ItemFrame extends Spawnable{ private $itemDropChance = 1.0; public function __construct(World $world, Vector3 $pos){ - $this->item = ItemFactory::air(); + $this->item = VanillaItems::AIR(); parent::__construct($world, $pos); } @@ -76,7 +76,7 @@ class ItemFrame extends Spawnable{ if($item !== null and !$item->isNull()){ $this->item = clone $item; }else{ - $this->item = ItemFactory::air(); + $this->item = VanillaItems::AIR(); } } diff --git a/src/crafting/ShapedRecipe.php b/src/crafting/ShapedRecipe.php index e346f22ad..5fc881a97 100644 --- a/src/crafting/ShapedRecipe.php +++ b/src/crafting/ShapedRecipe.php @@ -24,7 +24,7 @@ declare(strict_types=1); namespace pocketmine\crafting; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; use pocketmine\utils\Utils; use function array_values; use function count; @@ -155,7 +155,7 @@ class ShapedRecipe implements CraftingRecipe{ public function getIngredient(int $x, int $y) : Item{ $exists = $this->ingredientList[$this->shape[$y][$x]] ?? null; - return $exists !== null ? clone $exists : ItemFactory::air(); + return $exists !== null ? clone $exists : VanillaItems::AIR(); } /** diff --git a/src/inventory/BaseInventory.php b/src/inventory/BaseInventory.php index c5b854a6d..589254d85 100644 --- a/src/inventory/BaseInventory.php +++ b/src/inventory/BaseInventory.php @@ -24,7 +24,7 @@ declare(strict_types=1); namespace pocketmine\inventory; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; use pocketmine\player\Player; use pocketmine\utils\ObjectSet; use function array_slice; @@ -89,7 +89,7 @@ abstract class BaseInventory implements Inventory{ public function setItem(int $index, Item $item) : void{ if($item->isNull()){ - $item = ItemFactory::air(); + $item = VanillaItems::AIR(); }else{ $item = clone $item; } @@ -290,7 +290,7 @@ abstract class BaseInventory implements Inventory{ } public function clear(int $index) : void{ - $this->setItem($index, ItemFactory::air()); + $this->setItem($index, VanillaItems::AIR()); } public function clearAll() : void{ diff --git a/src/inventory/SimpleInventory.php b/src/inventory/SimpleInventory.php index f05b527a2..cab3f06e3 100644 --- a/src/inventory/SimpleInventory.php +++ b/src/inventory/SimpleInventory.php @@ -24,7 +24,7 @@ declare(strict_types=1); namespace pocketmine\inventory; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; /** * This class provides a complete implementation of a regular inventory. @@ -49,7 +49,7 @@ class SimpleInventory extends BaseInventory{ } public function getItem(int $index) : Item{ - return $this->slots[$index] !== null ? clone $this->slots[$index] : ItemFactory::air(); + return $this->slots[$index] !== null ? clone $this->slots[$index] : VanillaItems::AIR(); } /** @@ -62,7 +62,7 @@ class SimpleInventory extends BaseInventory{ if($slot !== null){ $contents[$i] = clone $slot; }elseif($includeEmpty){ - $contents[$i] = ItemFactory::air(); + $contents[$i] = VanillaItems::AIR(); } } diff --git a/src/inventory/transaction/TransactionBuilderInventory.php b/src/inventory/transaction/TransactionBuilderInventory.php index 8888b4a45..58efacd16 100644 --- a/src/inventory/transaction/TransactionBuilderInventory.php +++ b/src/inventory/transaction/TransactionBuilderInventory.php @@ -27,7 +27,7 @@ use pocketmine\inventory\BaseInventory; use pocketmine\inventory\Inventory; use pocketmine\inventory\transaction\action\SlotChangeAction; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; /** * This class facilitates generating SlotChangeActions to build an inventory transaction. @@ -62,7 +62,7 @@ final class TransactionBuilderInventory extends BaseInventory{ protected function internalSetItem(int $index, Item $item) : void{ if(!$item->equalsExact($this->actualInventory->getItem($index))){ - $this->changedSlots[$index] = $item->isNull() ? ItemFactory::air() : clone $item; + $this->changedSlots[$index] = $item->isNull() ? VanillaItems::AIR() : clone $item; } } diff --git a/src/inventory/transaction/action/CreateItemAction.php b/src/inventory/transaction/action/CreateItemAction.php index dbe02798e..a7a28b47e 100644 --- a/src/inventory/transaction/action/CreateItemAction.php +++ b/src/inventory/transaction/action/CreateItemAction.php @@ -26,7 +26,7 @@ namespace pocketmine\inventory\transaction\action; use pocketmine\inventory\CreativeInventory; use pocketmine\inventory\transaction\TransactionValidationException; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; use pocketmine\player\Player; /** @@ -36,7 +36,7 @@ use pocketmine\player\Player; class CreateItemAction extends InventoryAction{ public function __construct(Item $sourceItem){ - parent::__construct($sourceItem, ItemFactory::air()); + parent::__construct($sourceItem, VanillaItems::AIR()); } public function validate(Player $source) : void{ diff --git a/src/inventory/transaction/action/DestroyItemAction.php b/src/inventory/transaction/action/DestroyItemAction.php index 6edd30af2..a623d5700 100644 --- a/src/inventory/transaction/action/DestroyItemAction.php +++ b/src/inventory/transaction/action/DestroyItemAction.php @@ -25,7 +25,7 @@ namespace pocketmine\inventory\transaction\action; use pocketmine\inventory\transaction\TransactionValidationException; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; use pocketmine\player\Player; /** @@ -35,7 +35,7 @@ use pocketmine\player\Player; class DestroyItemAction extends InventoryAction{ public function __construct(Item $targetItem){ - parent::__construct(ItemFactory::air(), $targetItem); + parent::__construct(VanillaItems::AIR(), $targetItem); } public function validate(Player $source) : void{ diff --git a/src/inventory/transaction/action/DropItemAction.php b/src/inventory/transaction/action/DropItemAction.php index 2e20d5f93..62db5abac 100644 --- a/src/inventory/transaction/action/DropItemAction.php +++ b/src/inventory/transaction/action/DropItemAction.php @@ -26,7 +26,7 @@ namespace pocketmine\inventory\transaction\action; use pocketmine\event\player\PlayerDropItemEvent; use pocketmine\inventory\transaction\TransactionValidationException; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; use pocketmine\player\Player; /** @@ -35,7 +35,7 @@ use pocketmine\player\Player; class DropItemAction extends InventoryAction{ public function __construct(Item $targetItem){ - parent::__construct(ItemFactory::air(), $targetItem); + parent::__construct(VanillaItems::AIR(), $targetItem); } public function validate(Player $source) : void{ diff --git a/src/item/Food.php b/src/item/Food.php index ddaa77da6..e58924a30 100644 --- a/src/item/Food.php +++ b/src/item/Food.php @@ -32,7 +32,7 @@ abstract class Food extends Item implements FoodSourceItem{ } public function getResidue() : Item{ - return ItemFactory::air(); + return VanillaItems::AIR(); } public function getAdditionalEffects() : array{ diff --git a/src/item/Item.php b/src/item/Item.php index bceb92142..a1a3b8c89 100644 --- a/src/item/Item.php +++ b/src/item/Item.php @@ -691,7 +691,7 @@ class Item implements \JsonSerializable{ $item = LegacyStringToItemParser::getInstance()->parse($idTag->getValue() . ":$meta"); }catch(LegacyStringToItemParserException $e){ //TODO: improve error handling - return ItemFactory::air(); + return VanillaItems::AIR(); } $item->setCount($count); }else{ diff --git a/src/item/ItemFactory.php b/src/item/ItemFactory.php index 95622b4e9..ae6a596fb 100644 --- a/src/item/ItemFactory.php +++ b/src/item/ItemFactory.php @@ -478,6 +478,10 @@ class ItemFactory{ return $item; } + /** + * @deprecated + * @see VanillaItems::AIR() + */ public static function air() : Item{ return self::getInstance()->get(ItemIds::AIR, 0, 0); } diff --git a/src/item/VanillaItems.php b/src/item/VanillaItems.php index c817ae686..79676945e 100644 --- a/src/item/VanillaItems.php +++ b/src/item/VanillaItems.php @@ -32,6 +32,7 @@ use pocketmine\utils\CloningRegistryTrait; * @generate-registry-docblock * * @method static Boat ACACIA_BOAT() + * @method static ItemBlock AIR() * @method static Apple APPLE() * @method static Arrow ARROW() * @method static Potion AWKWARD_POTION() @@ -392,6 +393,8 @@ final class VanillaItems{ protected static function setup() : void{ $factory = ItemFactory::getInstance(); + self::register("air", $factory->get(ItemIds::AIR, 0, 0)); + self::register("acacia_boat", $factory->get(333, 4)); self::register("apple", $factory->get(260)); self::register("arrow", $factory->get(262)); diff --git a/src/world/Explosion.php b/src/world/Explosion.php index 4fc1a1fb0..b02964dd6 100644 --- a/src/world/Explosion.php +++ b/src/world/Explosion.php @@ -32,7 +32,7 @@ use pocketmine\event\entity\EntityDamageByBlockEvent; use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityExplodeEvent; -use pocketmine\item\ItemFactory; +use pocketmine\item\VanillaItems; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector3; use pocketmine\world\format\SubChunk; @@ -208,7 +208,7 @@ class Explosion{ } } - $air = ItemFactory::air(); + $air = VanillaItems::AIR(); $airBlock = VanillaBlocks::AIR(); foreach($this->affectedBlocks as $block){ diff --git a/src/world/World.php b/src/world/World.php index 37236de22..22900f744 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -52,9 +52,9 @@ use pocketmine\event\world\ChunkUnloadEvent; use pocketmine\event\world\SpawnChangeEvent; use pocketmine\event\world\WorldSaveEvent; use pocketmine\item\Item; -use pocketmine\item\ItemFactory; use pocketmine\item\ItemUseResult; use pocketmine\item\LegacyStringToItemParser; +use pocketmine\item\VanillaItems; use pocketmine\lang\KnownTranslationFactory; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector3; @@ -1687,7 +1687,7 @@ class World implements ChunkManager{ $affectedBlocks = $target->getAffectedBlocks(); if($item === null){ - $item = ItemFactory::air(); + $item = VanillaItems::AIR(); } $drops = []; From 78ffad5ffc1016f584a502605542315631903b94 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Dec 2021 16:41:52 +0000 Subject: [PATCH 472/710] World: add checks for tile position outside of world bounds, closes #4622 --- src/world/World.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/world/World.php b/src/world/World.php index 37236de22..2980493de 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2373,6 +2373,9 @@ class World implements ChunkManager{ if(!$pos->isValid() || $pos->getWorld() !== $this){ throw new \InvalidArgumentException("Invalid Tile world"); } + if(!$this->isInWorld($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ())){ + throw new \InvalidArgumentException("Tile position is outside the world bounds"); + } $chunkX = $pos->getFloorX() >> Chunk::COORD_BIT_SIZE; $chunkZ = $pos->getFloorZ() >> Chunk::COORD_BIT_SIZE; @@ -2530,6 +2533,8 @@ class World implements ChunkManager{ $logger->warning("Deleted unknown tile entity type " . $nbt->getString("id", "")); }elseif(!$this->isChunkLoaded($tile->getPosition()->getFloorX() >> Chunk::COORD_BIT_SIZE, $tile->getPosition()->getFloorZ() >> Chunk::COORD_BIT_SIZE)){ $logger->error("Found tile saved on wrong chunk - unable to fix due to correct chunk not loaded"); + }elseif(!$this->isInWorld(($tilePosition = $tile->getPosition())->getFloorX(), $tilePosition->getFloorY(), $tilePosition->getFloorZ())){ + $logger->error("Cannot add tile with position outside the world bounds: x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z"); }elseif($this->getTile($tilePosition = $tile->getPosition()) !== null){ $logger->error("Cannot add tile at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z: Another tile is already at that position"); }else{ From e0eeb87ea09a10bb8c5aba9324df5baba019e091 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Dec 2021 16:45:20 +0000 Subject: [PATCH 473/710] World: simplify tile position checking code --- src/world/World.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 2980493de..6d3aa6712 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2531,11 +2531,15 @@ class World implements ChunkManager{ } if($tile === null){ $logger->warning("Deleted unknown tile entity type " . $nbt->getString("id", "")); - }elseif(!$this->isChunkLoaded($tile->getPosition()->getFloorX() >> Chunk::COORD_BIT_SIZE, $tile->getPosition()->getFloorZ() >> Chunk::COORD_BIT_SIZE)){ + continue; + } + + $tilePosition = $tile->getPosition(); + if(!$this->isChunkLoaded($tilePosition->getFloorX() >> Chunk::COORD_BIT_SIZE, $tilePosition->getFloorZ() >> Chunk::COORD_BIT_SIZE)){ $logger->error("Found tile saved on wrong chunk - unable to fix due to correct chunk not loaded"); - }elseif(!$this->isInWorld(($tilePosition = $tile->getPosition())->getFloorX(), $tilePosition->getFloorY(), $tilePosition->getFloorZ())){ + }elseif(!$this->isInWorld($tilePosition->getFloorX(), $tilePosition->getFloorY(), $tilePosition->getFloorZ())){ $logger->error("Cannot add tile with position outside the world bounds: x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z"); - }elseif($this->getTile($tilePosition = $tile->getPosition()) !== null){ + }elseif($this->getTile($tilePosition) !== null){ $logger->error("Cannot add tile at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z: Another tile is already at that position"); }else{ $this->addTile($tile); From 503c8888388161294d822af80b9f5012111dec6c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Dec 2021 22:50:16 +0000 Subject: [PATCH 474/710] bootstrap: use phpversion() for checking extension presence fixes 2 PHPStan errors on level 7 --- src/PocketMine.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/PocketMine.php b/src/PocketMine.php index e251fd614..a587a7704 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -112,8 +112,7 @@ namespace pocketmine { } } - if(extension_loaded("pthreads")){ - $pthreads_version = phpversion("pthreads"); + if(($pthreads_version = phpversion("pthreads")) !== false){ if(substr_count($pthreads_version, ".") < 2){ $pthreads_version = "0.$pthreads_version"; } @@ -122,8 +121,7 @@ namespace pocketmine { } } - if(extension_loaded("leveldb")){ - $leveldb_version = phpversion("leveldb"); + if(($leveldb_version = phpversion("leveldb")) !== false){ if(version_compare($leveldb_version, "0.2.1") < 0){ $messages[] = "php-leveldb >= 0.2.1 is required, while you have $leveldb_version."; } From bf29409a45ef57b291b63aae5ab69dd08d232d0e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Dec 2021 23:06:10 +0000 Subject: [PATCH 475/710] Server: fixed PHPStan level 7 error in crashDump() --- src/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index f40667786..f31a730aa 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1564,7 +1564,7 @@ class Server{ $stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash"); $crashInterval = 120; //2 minutes - if(file_exists($stamp) and !($report = (filemtime($stamp) + $crashInterval < time()))){ + if(($lastReportTime = @filemtime($stamp)) !== false and !($report = ($lastReportTime + $crashInterval < time()))){ $this->logger->debug("Not sending crashdump due to last crash less than $crashInterval seconds ago"); } @touch($stamp); //update file timestamp From 45b4fa0e96ad62d2205b0f5e05dfd084c469ed94 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Dec 2021 23:08:06 +0000 Subject: [PATCH 476/710] Server: improve confusing condition in crashDump() --- src/Server.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index f31a730aa..90d96d047 100644 --- a/src/Server.php +++ b/src/Server.php @@ -1564,7 +1564,8 @@ class Server{ $stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash"); $crashInterval = 120; //2 minutes - if(($lastReportTime = @filemtime($stamp)) !== false and !($report = ($lastReportTime + $crashInterval < time()))){ + if(($lastReportTime = @filemtime($stamp)) !== false and $lastReportTime + $crashInterval >= time()){ + $report = false; $this->logger->debug("Not sending crashdump due to last crash less than $crashInterval seconds ago"); } @touch($stamp); //update file timestamp From 3d9e19546fadc0dbcd834a8bf7b67ab7f65e2019 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 7 Dec 2021 23:35:45 +0000 Subject: [PATCH 477/710] EntityShootBowEvent: fixed incorrect field type --- src/event/entity/EntityShootBowEvent.php | 2 +- tests/phpstan/configs/actual-problems.neon | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/event/entity/EntityShootBowEvent.php b/src/event/entity/EntityShootBowEvent.php index 32f4f4d70..5a871f282 100644 --- a/src/event/entity/EntityShootBowEvent.php +++ b/src/event/entity/EntityShootBowEvent.php @@ -39,7 +39,7 @@ class EntityShootBowEvent extends EntityEvent implements Cancellable{ /** @var Item */ private $bow; - /** @var Projectile */ + /** @var Entity */ private $projectile; /** @var float */ private $force; diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 52b727319..5776a837b 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -600,11 +600,6 @@ parameters: count: 1 path: ../../../src/entity/projectile/Projectile.php - - - message: "#^Property pocketmine\\\\event\\\\entity\\\\EntityShootBowEvent\\:\\:\\$projectile \\(pocketmine\\\\entity\\\\projectile\\\\Projectile\\) does not accept pocketmine\\\\entity\\\\Entity\\.$#" - count: 1 - path: ../../../src/event/entity/EntityShootBowEvent.php - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" count: 1 From c6466a6da921fda1680f011682592ef75f36da71 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 18:58:39 +0000 Subject: [PATCH 478/710] Utils: added crutch assumeNotFalse() this can be used to get PHPStan to shut up about stuff that will never return false in normal contexts. It's more fine-grained than @phpstan-ignore-line and less hassle than ignoreErrors (and works in PhpStorm too). In addition, it's easy to search for references. --- src/utils/Utils.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/utils/Utils.php b/src/utils/Utils.php index d761f772f..396c5aa07 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -592,4 +592,17 @@ final class Utils{ throw new \InvalidArgumentException("Text must be valid UTF-8"); } } + + /** + * @phpstan-template TValue + * @phpstan-param TValue|false $value + * @phpstan-param string|\Closure() : string $context + * @phpstan-return TValue + */ + public static function assumeNotFalse(mixed $value, \Closure|string $context = "This should never be false") : mixed{ + if($value === false){ + throw new AssumptionFailedError("Assumption failure: " . (is_string($context) ? $context : $context()) . " (THIS IS A BUG)"); + } + return $value; + } } From 8b7354935574ed8955d033aa21d96cc7ad54a66c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 19:14:07 +0000 Subject: [PATCH 479/710] Use JSON_THROW_ON_ERROR for json_encode() and json_decode() --- build/generate-build-info-json.php | 2 +- src/MemoryManager.php | 15 +++++++------- src/crash/CrashDump.php | 7 ++----- src/entity/Skin.php | 3 ++- src/network/mcpe/NetworkSession.php | 8 ++------ .../mcpe/convert/LegacySkinAdapter.php | 8 ++------ src/stats/SendUsageTask.php | 7 ++----- tests/phpstan/configs/actual-problems.neon | 20 ------------------- .../block/regenerate_consistency_check.php | 1 + 9 files changed, 20 insertions(+), 51 deletions(-) diff --git a/build/generate-build-info-json.php b/build/generate-build-info-json.php index 00ca2adc8..dd353fd7c 100644 --- a/build/generate-build-info-json.php +++ b/build/generate-build-info-json.php @@ -40,4 +40,4 @@ echo json_encode([ "details_url" => "https://github.com/$argv[3]/releases/tag/$argv[2]", "download_url" => "https://github.com/$argv[3]/releases/download/$argv[2]/PocketMine-MP.phar", "source_url" => "https://github.com/$argv[3]/tree/$argv[2]", -], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; +], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n"; diff --git a/src/MemoryManager.php b/src/MemoryManager.php index 020532f82..3bf0f5455 100644 --- a/src/MemoryManager.php +++ b/src/MemoryManager.php @@ -65,6 +65,7 @@ use function sprintf; use function strlen; use function substr; use const JSON_PRETTY_PRINT; +use const JSON_THROW_ON_ERROR; use const JSON_UNESCAPED_SLASHES; use const SORT_NUMERIC; @@ -349,7 +350,7 @@ class MemoryManager{ } } - file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $logger->info("Wrote $staticCount static properties"); $globalVariables = []; @@ -376,7 +377,7 @@ class MemoryManager{ $globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize); } - file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $logger->info("Wrote $globalCount global variables"); foreach(get_defined_functions()["user"] as $function){ @@ -391,7 +392,7 @@ class MemoryManager{ $functionStaticVarsCount += count($vars); } } - file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $logger->info("Wrote $functionStaticVarsCount function static variables"); $data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize); @@ -454,7 +455,7 @@ class MemoryManager{ } } - fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES) . "\n"); + fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n"); } }while($continue); @@ -463,11 +464,11 @@ class MemoryManager{ fclose($obData); - file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); - file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); + file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); arsort($instanceCounts, SORT_NUMERIC); - file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR)); $logger->info("Finished!"); diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php index f5a3213f1..f72c05fec 100644 --- a/src/crash/CrashDump.php +++ b/src/crash/CrashDump.php @@ -41,7 +41,6 @@ use function file_exists; use function file_get_contents; use function get_loaded_extensions; use function json_encode; -use function json_last_error_msg; use function ksort; use function max; use function mb_strtoupper; @@ -60,6 +59,7 @@ use function substr; use function zend_version; use function zlib_encode; use const FILE_IGNORE_NEW_LINES; +use const JSON_THROW_ON_ERROR; use const JSON_UNESCAPED_SLASHES; use const PHP_OS; use const PHP_VERSION; @@ -104,10 +104,7 @@ class CrashDump{ $this->extraData(); - $json = json_encode($this->data, JSON_UNESCAPED_SLASHES); - if($json === false){ - throw new \RuntimeException("Failed to encode crashdump JSON: " . json_last_error_msg()); - } + $json = json_encode($this->data, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR); $zlibEncoded = zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9); if($zlibEncoded === false) throw new AssumptionFailedError("ZLIB compression failed"); $this->encodedData = $zlibEncoded; diff --git a/src/entity/Skin.php b/src/entity/Skin.php index 0542bd75a..d9489772f 100644 --- a/src/entity/Skin.php +++ b/src/entity/Skin.php @@ -29,6 +29,7 @@ use function in_array; use function json_encode; use function json_last_error_msg; use function strlen; +use const JSON_THROW_ON_ERROR; final class Skin{ public const ACCEPTED_SKIN_SIZES = [ @@ -73,7 +74,7 @@ final class Skin{ * Not only that, they are pretty-printed. * TODO: find out what model crap can be safely dropped from the packet (unless it gets fixed first) */ - $geometryData = json_encode($decodedGeometry); + $geometryData = json_encode($decodedGeometry, JSON_THROW_ON_ERROR); } $this->skinId = $skinId; diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 0b7a8253b..66b77fbb3 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -124,12 +124,12 @@ use function count; use function get_class; use function in_array; use function json_encode; -use function json_last_error_msg; use function strlen; use function strtolower; use function substr; use function time; use function ucfirst; +use const JSON_THROW_ON_ERROR; class NetworkSession{ private \PrefixedLogger $logger; @@ -900,11 +900,7 @@ class NetworkSession{ } public function onFormSent(int $id, Form $form) : bool{ - $formData = json_encode($form); - if($formData === false){ - throw new \InvalidArgumentException("Failed to encode form JSON: " . json_last_error_msg()); - } - return $this->sendDataPacket(ModalFormRequestPacket::create($id, $formData)); + return $this->sendDataPacket(ModalFormRequestPacket::create($id, json_encode($form, JSON_THROW_ON_ERROR))); } /** diff --git a/src/network/mcpe/convert/LegacySkinAdapter.php b/src/network/mcpe/convert/LegacySkinAdapter.php index 31d4ae92b..60bb29d57 100644 --- a/src/network/mcpe/convert/LegacySkinAdapter.php +++ b/src/network/mcpe/convert/LegacySkinAdapter.php @@ -31,9 +31,9 @@ use function is_array; use function is_string; use function json_decode; use function json_encode; -use function json_last_error_msg; use function random_bytes; use function str_repeat; +use const JSON_THROW_ON_ERROR; class LegacySkinAdapter implements SkinAdapter{ @@ -44,14 +44,10 @@ class LegacySkinAdapter implements SkinAdapter{ if($geometryName === ""){ $geometryName = "geometry.humanoid.custom"; } - $resourcePatch = json_encode(["geometry" => ["default" => $geometryName]]); - if($resourcePatch === false){ - throw new \RuntimeException("json_encode() failed: " . json_last_error_msg()); - } return new SkinData( $skin->getSkinId(), "", //TODO: playfab ID - $resourcePatch, + json_encode(["geometry" => ["default" => $geometryName]], JSON_THROW_ON_ERROR), SkinImage::fromLegacy($skin->getSkinData()), [], $capeImage, $skin->getGeometryData() diff --git a/src/stats/SendUsageTask.php b/src/stats/SendUsageTask.php index 9440ae779..2064caf08 100644 --- a/src/stats/SendUsageTask.php +++ b/src/stats/SendUsageTask.php @@ -27,7 +27,6 @@ use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\player\Player; use pocketmine\scheduler\AsyncTask; use pocketmine\Server; -use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Internet; use pocketmine\utils\Process; use pocketmine\utils\Utils; @@ -37,11 +36,11 @@ use function array_map; use function array_values; use function count; use function json_encode; -use function json_last_error_msg; use function md5; use function microtime; use function php_uname; use function strlen; +use const JSON_THROW_ON_ERROR; use const PHP_VERSION; class SendUsageTask extends AsyncTask{ @@ -150,9 +149,7 @@ class SendUsageTask extends AsyncTask{ } $this->endpoint = $endpoint . "api/post"; - $data = json_encode($data/*, JSON_PRETTY_PRINT*/); - if($data === false) throw new AssumptionFailedError("Statistics JSON should never fail to encode: " . json_last_error_msg()); - $this->data = $data; + $this->data = json_encode($data, /*JSON_PRETTY_PRINT |*/ JSON_THROW_ON_ERROR); } public function onRun() : void{ diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 52b727319..bbf723ac2 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -40,31 +40,16 @@ parameters: count: 1 path: ../../../src/PocketMine.php - - - message: "#^Parameter \\#1 \\$haystack of function substr_count expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/PocketMine.php - - message: "#^Parameter \\#1 \\$path of function realpath expects string, string\\|false given\\.$#" count: 2 path: ../../../src/PocketMine.php - - - message: "#^Parameter \\#1 \\$version1 of function version_compare expects string, string\\|false given\\.$#" - count: 3 - path: ../../../src/PocketMine.php - - message: "#^Cannot cast mixed to string\\.$#" count: 1 path: ../../../src/Server.php - - - message: "#^Only numeric types are allowed in \\+, int\\|false given on the left side\\.$#" - count: 1 - path: ../../../src/Server.php - - message: "#^Parameter \\#1 \\$array of static method pocketmine\\\\plugin\\\\PluginGraylist\\:\\:fromArray\\(\\) expects array, mixed given\\.$#" count: 1 @@ -545,11 +530,6 @@ parameters: count: 1 path: ../../../src/entity/Living.php - - - message: "#^Property pocketmine\\\\entity\\\\Skin\\:\\:\\$geometryData \\(string\\) does not accept string\\|false\\.$#" - count: 1 - path: ../../../src/entity/Skin.php - - message: "#^Parameter \\#2 \\$x of method pocketmine\\\\block\\\\Block\\:\\:position\\(\\) expects int, float\\|int given\\.$#" count: 1 diff --git a/tests/phpunit/block/regenerate_consistency_check.php b/tests/phpunit/block/regenerate_consistency_check.php index c8dd68dc5..c18b94532 100644 --- a/tests/phpunit/block/regenerate_consistency_check.php +++ b/tests/phpunit/block/regenerate_consistency_check.php @@ -72,4 +72,5 @@ file_put_contents(__DIR__ . '/block_factory_consistency_check.json', json_encode "knownStates" => $new, "remaps" => $remaps ], + JSON_THROW_ON_ERROR )); From 889d048ca39d794c38a3e7220e709776ec5b64f2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 19:33:45 +0000 Subject: [PATCH 480/710] Make use of Utils::assumeNotFalse() in a bunch of places I've stuck to only doing this in the places where I'm sure we should never get false back. Other places I'm less sure of (and I found more bugs along the way). --- build/make-release.php | 2 +- src/MemoryManager.php | 6 +- src/PocketMine.php | 9 +- src/Server.php | 7 +- src/command/defaults/TimingsCommand.php | 3 +- src/console/ConsoleReader.php | 6 +- src/console/ConsoleReaderThread.php | 12 ++- .../CraftingManagerFromDataHelper.php | 3 +- src/crash/CrashDump.php | 4 +- .../LegacyToStringBidirectionalIdMap.php | 3 +- src/item/LegacyStringToItemParser.php | 4 +- src/lang/Language.php | 3 +- src/network/mcpe/JwtUtils.php | 7 +- .../mcpe/compression/ZlibCompressor.php | 6 +- .../mcpe/convert/GlobalItemTypeDictionary.php | 4 +- src/network/mcpe/convert/ItemTranslator.php | 3 +- .../mcpe/convert/RuntimeBlockMapping.php | 18 ++-- .../mcpe/encryption/EncryptionUtils.php | 3 +- src/network/upnp/UPnP.php | 20 ++--- src/permission/BanEntry.php | 5 +- src/plugin/PluginManager.php | 3 +- src/resourcepacks/ZippedResourcePack.php | 5 +- src/utils/Filesystem.php | 8 +- src/utils/Timezone.php | 2 +- src/world/format/io/data/JavaWorldData.php | 7 +- tests/phpstan/configs/actual-problems.neon | 85 ------------------- 26 files changed, 67 insertions(+), 171 deletions(-) diff --git a/build/make-release.php b/build/make-release.php index e3a3dad81..c33364481 100644 --- a/build/make-release.php +++ b/build/make-release.php @@ -50,7 +50,7 @@ use const STR_PAD_LEFT; require_once dirname(__DIR__) . '/vendor/autoload.php'; function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev, string $channel) : void{ - $versionInfo = file_get_contents($versionInfoPath); + $versionInfo = Utils::assumeNotFalse(file_get_contents($versionInfoPath), $versionInfoPath . " should always exist"); $versionInfo = preg_replace( $pattern = '/^([\t ]*public )?const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m', '$1const BASE_VERSION = "' . $newVersion . '";', diff --git a/src/MemoryManager.php b/src/MemoryManager.php index 3bf0f5455..beffbf7e2 100644 --- a/src/MemoryManager.php +++ b/src/MemoryManager.php @@ -28,7 +28,6 @@ use pocketmine\network\mcpe\cache\ChunkCache; use pocketmine\scheduler\DumpWorkerMemoryTask; use pocketmine\scheduler\GarbageCollectionTask; use pocketmine\timings\Timings; -use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Process; use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; @@ -292,8 +291,7 @@ class MemoryManager{ * @param mixed $startingObject */ public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{ - $hardLimit = ini_get('memory_limit'); - if($hardLimit === false) throw new AssumptionFailedError("memory_limit INI directive should always exist"); + $hardLimit = Utils::assumeNotFalse(ini_get('memory_limit'), "memory_limit INI directive should always exist"); ini_set('memory_limit', '-1'); gc_disable(); @@ -301,7 +299,7 @@ class MemoryManager{ mkdir($outputFolder, 0777, true); } - $obData = fopen(Path::join($outputFolder, "objects.js"), "wb+"); + $obData = Utils::assumeNotFalse(fopen(Path::join($outputFolder, "objects.js"), "wb+")); $objects = []; diff --git a/src/PocketMine.php b/src/PocketMine.php index a587a7704..0ff3b5c64 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -32,14 +32,16 @@ namespace pocketmine { use pocketmine\utils\ServerKiller; use pocketmine\utils\Terminal; use pocketmine\utils\Timezone; + use pocketmine\utils\Utils; use pocketmine\wizard\SetupWizard; use Webmozart\PathUtil\Path; use function defined; use function extension_loaded; + use function getcwd; use function phpversion; use function preg_match; use function preg_quote; - use function strpos; + use function realpath; use function version_compare; require_once __DIR__ . '/VersionInfo.php'; @@ -249,8 +251,9 @@ JIT_WARNING $opts = getopt("", ["data:", "plugins:", "no-wizard", "enable-ansi", "disable-ansi"]); - $dataPath = isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR; - $pluginPath = isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : realpath(getcwd()) . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR; + $cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd()))); + $dataPath = isset($opts["data"]) ? $opts["data"] . DIRECTORY_SEPARATOR : $cwd . DIRECTORY_SEPARATOR; + $pluginPath = isset($opts["plugins"]) ? $opts["plugins"] . DIRECTORY_SEPARATOR : $cwd . DIRECTORY_SEPARATOR . "plugins" . DIRECTORY_SEPARATOR; Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX); if(!file_exists($dataPath)){ diff --git a/src/Server.php b/src/Server.php index 90d96d047..fc0be90af 100644 --- a/src/Server.php +++ b/src/Server.php @@ -537,10 +537,7 @@ class Server{ if(!$ev->isCancelled()){ Timings::$syncPlayerDataSave->time(function() use ($name, $ev) : void{ $nbt = new BigEndianNbtSerializer(); - $contents = zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP); - if($contents === false){ - throw new AssumptionFailedError("zlib_encode() failed unexpectedly"); - } + $contents = Utils::assumeNotFalse(zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP), "zlib_encode() failed unexpectedly"); try{ Filesystem::safeFilePutContents($this->getPlayerDataPath($name), $contents); }catch(\RuntimeException | \ErrorException $e){ @@ -791,7 +788,7 @@ class Server{ $this->logger->info("Loading server configuration"); $pocketmineYmlPath = Path::join($this->dataPath, "pocketmine.yml"); if(!file_exists($pocketmineYmlPath)){ - $content = file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "pocketmine.yml")); + $content = Utils::assumeNotFalse(file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, "pocketmine.yml")), "Missing required resource file"); if(VersionInfo::IS_DEVELOPMENT_BUILD){ $content = str_replace("preferred-channel: stable", "preferred-channel: beta", $content); } diff --git a/src/command/defaults/TimingsCommand.php b/src/command/defaults/TimingsCommand.php index 26839b312..c894bb94f 100644 --- a/src/command/defaults/TimingsCommand.php +++ b/src/command/defaults/TimingsCommand.php @@ -34,6 +34,7 @@ use pocketmine\scheduler\BulkCurlTaskOperation; use pocketmine\timings\TimingsHandler; use pocketmine\utils\InternetException; use pocketmine\utils\InternetRequestResult; +use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; use function count; use function fclose; @@ -105,7 +106,7 @@ class TimingsCommand extends VanillaCommand{ }elseif($mode === "merged" or $mode === "report" or $paste){ $timings = ""; if($paste){ - $fileTimings = fopen("php://temp", "r+b"); + $fileTimings = Utils::assumeNotFalse(fopen("php://temp", "r+b"), "Opening php://temp should never fail"); }else{ $index = 0; $timingFolder = Path::join($sender->getServer()->getDataPath(), "timings"); diff --git a/src/console/ConsoleReader.php b/src/console/ConsoleReader.php index 77a3f4b6f..ac7b6f644 100644 --- a/src/console/ConsoleReader.php +++ b/src/console/ConsoleReader.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace pocketmine\console; -use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Utils; use function fclose; use function fgets; use function fopen; @@ -45,9 +45,7 @@ final class ConsoleReader{ fclose($this->stdin); } - $stdin = fopen("php://stdin", "r"); - if($stdin === false) throw new AssumptionFailedError("Opening stdin should never fail"); - $this->stdin = $stdin; + $this->stdin = Utils::assumeNotFalse(fopen("php://stdin", "r"), "Opening stdin should never fail"); } /** diff --git a/src/console/ConsoleReaderThread.php b/src/console/ConsoleReaderThread.php index bdfccd80f..519d01121 100644 --- a/src/console/ConsoleReaderThread.php +++ b/src/console/ConsoleReaderThread.php @@ -26,6 +26,7 @@ namespace pocketmine\console; use pocketmine\snooze\SleeperNotifier; use pocketmine\thread\Thread; use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; use function base64_encode; use function fgets; @@ -81,21 +82,18 @@ final class ConsoleReaderThread extends Thread{ if($server === false){ throw new \RuntimeException("Failed to open console reader socket server"); } - $address = stream_socket_get_name($server, false); - if($address === false) throw new AssumptionFailedError("stream_socket_get_name() shouldn't return false here"); + $address = Utils::assumeNotFalse(stream_socket_get_name($server, false), "stream_socket_get_name() shouldn't return false here"); //Windows sucks, and likes to corrupt UTF-8 file paths when they travel to the subprocess, so we base64 encode //the path to avoid the problem. This is an abysmally shitty hack, but here we are :( - $sub = proc_open( + $sub = Utils::assumeNotFalse(proc_open( [PHP_BINARY, '-r', sprintf('require base64_decode("%s", true);', base64_encode(Path::join(__DIR__, 'ConsoleReaderChildProcess.php'))), $address], [ 2 => fopen("php://stderr", "w"), ], $pipes - ); - if($sub === false){ - throw new AssumptionFailedError("Something has gone horribly wrong"); - } + ), "Something has gone horribly wrong"); + $client = stream_socket_accept($server, 15); if($client === false){ throw new AssumptionFailedError("stream_socket_accept() returned false"); diff --git a/src/crafting/CraftingManagerFromDataHelper.php b/src/crafting/CraftingManagerFromDataHelper.php index 6660bb602..bd8465b1b 100644 --- a/src/crafting/CraftingManagerFromDataHelper.php +++ b/src/crafting/CraftingManagerFromDataHelper.php @@ -25,6 +25,7 @@ namespace pocketmine\crafting; use pocketmine\item\Item; use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Utils; use function array_map; use function file_get_contents; use function is_array; @@ -33,7 +34,7 @@ use function json_decode; final class CraftingManagerFromDataHelper{ public static function make(string $filePath) : CraftingManager{ - $recipes = json_decode(file_get_contents($filePath), true); + $recipes = json_decode(Utils::assumeNotFalse(file_get_contents($filePath), "Missing required resource file"), true); if(!is_array($recipes)){ throw new AssumptionFailedError("recipes.json root should contain a map of recipe types"); } diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php index f72c05fec..c265aad57 100644 --- a/src/crash/CrashDump.php +++ b/src/crash/CrashDump.php @@ -105,9 +105,7 @@ class CrashDump{ $this->extraData(); $json = json_encode($this->data, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR); - $zlibEncoded = zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9); - if($zlibEncoded === false) throw new AssumptionFailedError("ZLIB compression failed"); - $this->encodedData = $zlibEncoded; + $this->encodedData = Utils::assumeNotFalse(zlib_encode($json, ZLIB_ENCODING_DEFLATE, 9), "ZLIB compression failed"); } public function getEncodedData() : string{ diff --git a/src/data/bedrock/LegacyToStringBidirectionalIdMap.php b/src/data/bedrock/LegacyToStringBidirectionalIdMap.php index 0dcc7ff0f..a7ce83b1f 100644 --- a/src/data/bedrock/LegacyToStringBidirectionalIdMap.php +++ b/src/data/bedrock/LegacyToStringBidirectionalIdMap.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\data\bedrock; use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Utils; use function file_get_contents; use function is_array; use function is_int; @@ -44,7 +45,7 @@ abstract class LegacyToStringBidirectionalIdMap{ private $stringToLegacy = []; public function __construct(string $file){ - $stringToLegacyId = json_decode(file_get_contents($file), true); + $stringToLegacyId = json_decode(Utils::assumeNotFalse(file_get_contents($file), "Missing required resource file"), true); if(!is_array($stringToLegacyId)){ throw new AssumptionFailedError("Invalid format of ID map"); } diff --git a/src/item/LegacyStringToItemParser.php b/src/item/LegacyStringToItemParser.php index ccc824b0d..3065cb1bd 100644 --- a/src/item/LegacyStringToItemParser.php +++ b/src/item/LegacyStringToItemParser.php @@ -25,6 +25,7 @@ namespace pocketmine\item; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; +use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; use function explode; use function file_get_contents; @@ -55,8 +56,7 @@ final class LegacyStringToItemParser{ private static function make() : self{ $result = new self(ItemFactory::getInstance()); - $mappingsRaw = @file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, 'item_from_string_bc_map.json')); - if($mappingsRaw === false) throw new AssumptionFailedError("Missing required resource file"); + $mappingsRaw = Utils::assumeNotFalse(@file_get_contents(Path::join(\pocketmine\RESOURCE_PATH, 'item_from_string_bc_map.json')), "Missing required resource file"); $mappings = json_decode($mappingsRaw, true); if(!is_array($mappings)) throw new AssumptionFailedError("Invalid mappings format, expected array"); diff --git a/src/lang/Language.php b/src/lang/Language.php index 33ad93888..f86b1bba5 100644 --- a/src/lang/Language.php +++ b/src/lang/Language.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\lang; +use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; use function array_filter; use function array_map; @@ -123,7 +124,7 @@ class Language{ protected static function loadLang(string $path, string $languageCode) : array{ $file = Path::join($path, $languageCode . ".ini"); if(file_exists($file)){ - return array_map('\stripcslashes', parse_ini_file($file, false, INI_SCANNER_RAW)); + return array_map('\stripcslashes', Utils::assumeNotFalse(parse_ini_file($file, false, INI_SCANNER_RAW), "Missing or inaccessible required resource files")); } throw new LanguageNotFoundException("Language \"$languageCode\" not found"); diff --git a/src/network/mcpe/JwtUtils.php b/src/network/mcpe/JwtUtils.php index 06d5cdfee..7a0a706c8 100644 --- a/src/network/mcpe/JwtUtils.php +++ b/src/network/mcpe/JwtUtils.php @@ -27,6 +27,7 @@ use FG\ASN1\Exception\ParserException; use FG\ASN1\Universal\Integer; use FG\ASN1\Universal\Sequence; use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Utils; use function base64_decode; use function base64_encode; use function count; @@ -185,11 +186,7 @@ final class JwtUtils{ } public static function emitDerPublicKey(\OpenSSLAsymmetricKey $opensslKey) : string{ - $details = openssl_pkey_get_details($opensslKey); - if($details === false){ - throw new AssumptionFailedError("Failed to get details from OpenSSL key resource"); - } - + $details = Utils::assumeNotFalse(openssl_pkey_get_details($opensslKey), "Failed to get details from OpenSSL key resource"); /** @var string $pemKey */ $pemKey = $details['key']; if(preg_match("@^-----BEGIN[A-Z\d ]+PUBLIC KEY-----\n([A-Za-z\d+/\n]+)\n-----END[A-Z\d ]+PUBLIC KEY-----\n$@", $pemKey, $matches) === 1){ diff --git a/src/network/mcpe/compression/ZlibCompressor.php b/src/network/mcpe/compression/ZlibCompressor.php index b5bd33bcb..284a8dcb7 100644 --- a/src/network/mcpe/compression/ZlibCompressor.php +++ b/src/network/mcpe/compression/ZlibCompressor.php @@ -23,8 +23,8 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\compression; -use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; +use pocketmine\utils\Utils; use function function_exists; use function libdeflate_deflate_compress; use function strlen; @@ -75,9 +75,7 @@ final class ZlibCompressor implements Compressor{ } private static function zlib_encode(string $data, int $level) : string{ - $result = zlib_encode($data, ZLIB_ENCODING_RAW, $level); - if($result === false) throw new AssumptionFailedError("ZLIB compression failed"); - return $result; + return Utils::assumeNotFalse(zlib_encode($data, ZLIB_ENCODING_RAW, $level), "ZLIB compression failed"); } public function compress(string $payload) : string{ diff --git a/src/network/mcpe/convert/GlobalItemTypeDictionary.php b/src/network/mcpe/convert/GlobalItemTypeDictionary.php index d3ab00f53..61510e590 100644 --- a/src/network/mcpe/convert/GlobalItemTypeDictionary.php +++ b/src/network/mcpe/convert/GlobalItemTypeDictionary.php @@ -27,6 +27,7 @@ use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary; use pocketmine\network\mcpe\protocol\types\ItemTypeEntry; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; +use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; use function file_get_contents; use function is_array; @@ -39,8 +40,7 @@ final class GlobalItemTypeDictionary{ use SingletonTrait; private static function make() : self{ - $data = file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'required_item_list.json')); - if($data === false) throw new AssumptionFailedError("Missing required resource file"); + $data = Utils::assumeNotFalse(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'required_item_list.json')), "Missing required resource file"); $table = json_decode($data, true); if(!is_array($table)){ throw new AssumptionFailedError("Invalid item list format"); diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index 4aa82f32b..87e1a6ae6 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -67,8 +67,7 @@ final class ItemTranslator{ private $complexNetToCoreMapping = []; private static function make() : self{ - $data = file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'r16_to_current_item_map.json')); - if($data === false) throw new AssumptionFailedError("Missing required resource file"); + $data = Utils::assumeNotFalse(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'r16_to_current_item_map.json')), "Missing required resource file"); $json = json_decode($data, true); if(!is_array($json) or !isset($json["simple"], $json["complex"]) || !is_array($json["simple"]) || !is_array($json["complex"])){ throw new AssumptionFailedError("Invalid item table format"); diff --git a/src/network/mcpe/convert/RuntimeBlockMapping.php b/src/network/mcpe/convert/RuntimeBlockMapping.php index dfa69168e..75835be0f 100644 --- a/src/network/mcpe/convert/RuntimeBlockMapping.php +++ b/src/network/mcpe/convert/RuntimeBlockMapping.php @@ -30,8 +30,8 @@ use pocketmine\nbt\tag\CompoundTag; use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext; -use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\SingletonTrait; +use pocketmine\utils\Utils; use Webmozart\PathUtil\Path; use function file_get_contents; @@ -49,11 +49,11 @@ final class RuntimeBlockMapping{ private $bedrockKnownStates; private function __construct(){ - $canonicalBlockStatesFile = file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "canonical_block_states.nbt")); - if($canonicalBlockStatesFile === false){ - throw new AssumptionFailedError("Missing required resource file"); - } - $stream = PacketSerializer::decoder($canonicalBlockStatesFile, 0, new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())); + $stream = PacketSerializer::decoder( + Utils::assumeNotFalse(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "canonical_block_states.nbt")), "Missing required resource file"), + 0, + new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()) + ); $list = []; while(!$stream->feof()){ $list[] = $stream->getNbtCompoundRoot(); @@ -67,7 +67,11 @@ final class RuntimeBlockMapping{ $legacyIdMap = LegacyBlockIdToStringIdMap::getInstance(); /** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */ $legacyStateMap = []; - $legacyStateMapReader = PacketSerializer::decoder(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "r12_to_current_block_map.bin")), 0, new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())); + $legacyStateMapReader = PacketSerializer::decoder( + Utils::assumeNotFalse(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "r12_to_current_block_map.bin")), "Missing required resource file"), + 0, + new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary()) + ); $nbtReader = new NetworkNbtSerializer(); while(!$legacyStateMapReader->feof()){ $id = $legacyStateMapReader->getString(); diff --git a/src/network/mcpe/encryption/EncryptionUtils.php b/src/network/mcpe/encryption/EncryptionUtils.php index 0ad2ebfee..0aec6b445 100644 --- a/src/network/mcpe/encryption/EncryptionUtils.php +++ b/src/network/mcpe/encryption/EncryptionUtils.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\encryption; use pocketmine\network\mcpe\JwtUtils; +use pocketmine\utils\Utils; use function base64_encode; use function bin2hex; use function gmp_init; @@ -49,7 +50,7 @@ final class EncryptionUtils{ } public static function generateKey(\GMP $secret, string $salt) : string{ - return openssl_digest($salt . hex2bin(str_pad(gmp_strval($secret, 16), 96, "0", STR_PAD_LEFT)), 'sha256', true); + return Utils::assumeNotFalse(openssl_digest($salt . hex2bin(str_pad(gmp_strval($secret, 16), 96, "0", STR_PAD_LEFT)), 'sha256', true)); } public static function generateServerHandshakeJwt(\OpenSSLAsymmetricKey $serverPriv, string $salt) : string{ diff --git a/src/network/upnp/UPnP.php b/src/network/upnp/UPnP.php index c2ed90f6e..1c14cead8 100644 --- a/src/network/upnp/UPnP.php +++ b/src/network/upnp/UPnP.php @@ -55,8 +55,8 @@ declare(strict_types=1); */ namespace pocketmine\network\upnp; -use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Internet; +use pocketmine\utils\Utils; use function count; use function libxml_use_internal_errors; use function parse_url; @@ -99,13 +99,8 @@ class UPnP{ * @throws UPnPException */ public static function getServiceUrl() : string{ - $socket = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); - if($socket === false){ - throw new AssumptionFailedError("Socket error: " . trim(socket_strerror(socket_last_error()))); - } - if(!@socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec" => 3, "usec" => 0])){ - throw new AssumptionFailedError("Socket error: " . trim(socket_strerror(socket_last_error($socket)))); - } + $socket = Utils::assumeNotFalse(@socket_create(AF_INET, SOCK_DGRAM, SOL_UDP), fn() => "Socket error: " . trim(socket_strerror(socket_last_error()))); + Utils::assumeNotFalse(@socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec" => 3, "usec" => 0]), "Socket error: " . trim(socket_strerror(socket_last_error($socket)))); $contents = "M-SEARCH * HTTP/1.1\r\n" . "MX: 2\r\n" . @@ -171,17 +166,14 @@ class UPnP{ } libxml_use_internal_errors($defaultInternalError); $root->registerXPathNamespace("upnp", "urn:schemas-upnp-org:device-1-0"); - $xpathResult = $root->xpath( + $xpathResult = Utils::assumeNotFalse($root->xpath( '//upnp:device[upnp:deviceType="urn:schemas-upnp-org:device:InternetGatewayDevice:1"]' . '/upnp:deviceList/upnp:device[upnp:deviceType="urn:schemas-upnp-org:device:WANDevice:1"]' . '/upnp:deviceList/upnp:device[upnp:deviceType="urn:schemas-upnp-org:device:WANConnectionDevice:1"]' . '/upnp:serviceList/upnp:service[upnp:serviceType="urn:schemas-upnp-org:service:WANIPConnection:1"]' . '/upnp:controlURL' - ); - if($xpathResult === false){ - //this should be an array of 0 if there is no matching elements; false indicates a problem with the query itself - throw new AssumptionFailedError("xpath query should not error here"); - } + ), "xpath query is borked"); + if(count($xpathResult) === 0){ throw new UPnPException("Your router does not support portforwarding"); } diff --git a/src/permission/BanEntry.php b/src/permission/BanEntry.php index 63858d39c..596edfeb5 100644 --- a/src/permission/BanEntry.php +++ b/src/permission/BanEntry.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace pocketmine\permission; -use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Utils; use function array_shift; use function count; use function explode; @@ -143,8 +143,7 @@ class BanEntry{ private static function parseDate(string $date) : \DateTime{ $datetime = \DateTime::createFromFormat(self::$format, $date); if(!($datetime instanceof \DateTime)){ - $lastErrors = \DateTime::getLastErrors(); - if($lastErrors === false) throw new AssumptionFailedError("DateTime::getLastErrors() should not be returning false in here"); + $lastErrors = Utils::assumeNotFalse(\DateTime::getLastErrors(), "DateTime::getLastErrors() should not be returning false in here"); throw new \RuntimeException("Corrupted date/time: " . implode(", ", $lastErrors["errors"])); } diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index de8413097..49f8ed06b 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -237,8 +237,7 @@ class PluginManager{ $files = iterator_to_array(new \FilesystemIterator($path, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS)); shuffle($files); //this prevents plugins implicitly relying on the filesystem name order when they should be using dependency properties }elseif(is_file($path)){ - $realPath = realpath($path); - if($realPath === false) throw new AssumptionFailedError("realpath() should not return false on an accessible, existing file"); + $realPath = Utils::assumeNotFalse(realpath($path), "realpath() should not return false on an accessible, existing file"); $files = [$realPath]; }else{ return; diff --git a/src/resourcepacks/ZippedResourcePack.php b/src/resourcepacks/ZippedResourcePack.php index 9f2593c84..3642f657e 100644 --- a/src/resourcepacks/ZippedResourcePack.php +++ b/src/resourcepacks/ZippedResourcePack.php @@ -25,6 +25,7 @@ namespace pocketmine\resourcepacks; use Ahc\Json\Comment as CommentedJsonDecoder; use pocketmine\resourcepacks\json\Manifest; +use pocketmine\utils\Utils; use function assert; use function fclose; use function feof; @@ -73,7 +74,7 @@ class ZippedResourcePack implements ResourcePack{ $manifestPath = null; $manifestIdx = null; for($i = 0; $i < $archive->numFiles; ++$i){ - $name = $archive->getNameIndex($i); + $name = Utils::assumeNotFalse($archive->getNameIndex($i), "This index should be valid"); if( ($manifestPath === null or strlen($name) < strlen($manifestPath)) and preg_match('#.*/manifest.json$#', $name) === 1 @@ -156,6 +157,6 @@ class ZippedResourcePack implements ResourcePack{ if(feof($this->fileResource)){ throw new \InvalidArgumentException("Requested a resource pack chunk with invalid start offset"); } - return fread($this->fileResource, $length); + return Utils::assumeNotFalse(fread($this->fileResource, $length), "Already checked that we're not at EOF"); } } diff --git a/src/utils/Filesystem.php b/src/utils/Filesystem.php index fd3eca26b..df50e0134 100644 --- a/src/utils/Filesystem.php +++ b/src/utils/Filesystem.php @@ -79,8 +79,7 @@ final class Filesystem{ public static function recursiveUnlink(string $dir) : void{ if(is_dir($dir)){ - $objects = scandir($dir, SCANDIR_SORT_NONE); - if($objects === false) throw new AssumptionFailedError("scandir() shouldn't return false when is_dir() returns true"); + $objects = Utils::assumeNotFalse(scandir($dir, SCANDIR_SORT_NONE), "scandir() shouldn't return false when is_dir() returns true"); foreach($objects as $object){ if($object !== "." and $object !== ".."){ $fullObject = Path::join($dir, $object); @@ -127,8 +126,7 @@ final class Filesystem{ } mkdir($destination); //TODO: access permissions? } - $objects = scandir($origin, SCANDIR_SORT_NONE); - if($objects === false) throw new AssumptionFailedError("scandir() shouldn't return false when is_dir() returns true"); + $objects = Utils::assumeNotFalse(scandir($origin, SCANDIR_SORT_NONE)); foreach($objects as $object){ if($object === "." || $object === ".."){ continue; @@ -193,7 +191,7 @@ final class Filesystem{ //wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the //other server wrote its PID and released exclusive lock before we get our lock flock($resource, LOCK_SH); - $pid = stream_get_contents($resource); + $pid = Utils::assumeNotFalse(stream_get_contents($resource), "This is a known valid file resource, at worst we should receive an empty string"); if(preg_match('/^\d+$/', $pid) === 1){ return (int) $pid; } diff --git a/src/utils/Timezone.php b/src/utils/Timezone.php index fdd39c865..79884751a 100644 --- a/src/utils/Timezone.php +++ b/src/utils/Timezone.php @@ -55,7 +55,7 @@ abstract class Timezone{ } public static function init() : void{ - $timezone = ini_get("date.timezone"); + $timezone = Utils::assumeNotFalse(ini_get("date.timezone"), "date.timezone should always be set in ini"); if($timezone !== ""){ /* * This is here so that people don't come to us complaining and fill up the issue tracker when they put diff --git a/src/world/format/io/data/JavaWorldData.php b/src/world/format/io/data/JavaWorldData.php index cacecae29..e3cb20b6c 100644 --- a/src/world/format/io/data/JavaWorldData.php +++ b/src/world/format/io/data/JavaWorldData.php @@ -29,8 +29,8 @@ use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\TreeRoot; -use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Filesystem; +use pocketmine\utils\Utils; use pocketmine\world\format\io\exception\CorruptedWorldException; use pocketmine\world\generator\GeneratorManager; use pocketmine\world\World; @@ -112,10 +112,7 @@ class JavaWorldData extends BaseNbtWorldData{ public function save() : void{ $nbt = new BigEndianNbtSerializer(); - $buffer = zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag("Data", $this->compoundTag))), ZLIB_ENCODING_GZIP); - if($buffer === false){ - throw new AssumptionFailedError("zlib_encode() failed unexpectedly"); - } + $buffer = Utils::assumeNotFalse(zlib_encode($nbt->write(new TreeRoot(CompoundTag::create()->setTag("Data", $this->compoundTag))), ZLIB_ENCODING_GZIP)); Filesystem::safeFilePutContents($this->dataPath, $buffer); } diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index bbf723ac2..28e5ca266 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -1,10 +1,5 @@ parameters: ignoreErrors: - - - message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false given\\.$#" - count: 1 - path: ../../../build/make-release.php - - message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" count: 2 @@ -20,16 +15,6 @@ parameters: count: 1 path: ../../../build/server-phar.php - - - message: "#^Parameter \\#1 \\$stream of function fclose expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/MemoryManager.php - - - - message: "#^Parameter \\#1 \\$stream of function fwrite expects resource, resource\\|false given\\.$#" - count: 1 - path: ../../../src/MemoryManager.php - - message: "#^Binary operation \"\\.\" between array\\\\|string\\|false and '/'\\|'\\\\\\\\' results in an error\\.$#" count: 2 @@ -40,11 +25,6 @@ parameters: count: 1 path: ../../../src/PocketMine.php - - - message: "#^Parameter \\#1 \\$path of function realpath expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/PocketMine.php - - message: "#^Cannot cast mixed to string\\.$#" count: 1 @@ -60,11 +40,6 @@ parameters: count: 1 path: ../../../src/Server.php - - - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|false given\\.$#" - count: 1 - path: ../../../src/Server.php - - message: "#^Cannot cast array\\\\|string\\|false to string\\.$#" count: 1 @@ -495,21 +470,11 @@ parameters: count: 2 path: ../../../src/console/ConsoleReader.php - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/crafting/CraftingManagerFromDataHelper.php - - message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#" count: 1 path: ../../../src/crash/CrashDump.php - - - message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/data/bedrock/LegacyToStringBidirectionalIdMap.php - - message: "#^Parameter \\#1 \\$index of method pocketmine\\\\inventory\\\\BaseInventory\\:\\:setItem\\(\\) expects int, int\\|string given\\.$#" count: 1 @@ -615,11 +580,6 @@ parameters: count: 1 path: ../../../src/item/Item.php - - - message: "#^Parameter \\#2 \\$array of function array_map expects array, array\\|false given\\.$#" - count: 1 - path: ../../../src/lang/Language.php - - message: "#^Parameter \\#1 \\$result of method pocketmine\\\\network\\\\mcpe\\\\compression\\\\CompressBatchPromise\\:\\:resolve\\(\\) expects string, mixed given\\.$#" count: 1 @@ -735,16 +695,6 @@ parameters: count: 1 path: ../../../src/network/mcpe/compression/CompressBatchTask.php - - - message: "#^Parameter \\#1 \\$buffer of static method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\serializer\\\\PacketSerializer\\:\\:decoder\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/network/mcpe/convert/RuntimeBlockMapping.php - - - - message: "#^Method pocketmine\\\\network\\\\mcpe\\\\encryption\\\\EncryptionUtils\\:\\:generateKey\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/network/mcpe/encryption/EncryptionUtils.php - - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\encryption\\\\PrepareEncryptionTask\\:\\:\\$serverPrivateKey \\(string\\) does not accept string\\|null\\.$#" count: 1 @@ -865,11 +815,6 @@ parameters: count: 4 path: ../../../src/plugin/PluginManager.php - - - message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getPackChunk\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: ../../../src/resourcepacks/ZippedResourcePack.php - - message: "#^Method pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:getPackSize\\(\\) should return int but returns int\\<0, max\\>\\|false\\.$#" count: 1 @@ -880,11 +825,6 @@ parameters: count: 1 path: ../../../src/resourcepacks/ZippedResourcePack.php - - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" - count: 2 - path: ../../../src/resourcepacks/ZippedResourcePack.php - - message: "#^Parameter \\#2 \\$code of class pocketmine\\\\resourcepacks\\\\ResourcePackException constructor expects int, mixed given\\.$#" count: 1 @@ -895,11 +835,6 @@ parameters: count: 1 path: ../../../src/resourcepacks/ZippedResourcePack.php - - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/resourcepacks/ZippedResourcePack.php - - message: "#^Property pocketmine\\\\resourcepacks\\\\ZippedResourcePack\\:\\:\\$fileResource \\(resource\\) does not accept resource\\|false\\.$#" count: 1 @@ -980,11 +915,6 @@ parameters: count: 1 path: ../../../src/utils/Config.php - - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/utils/Filesystem.php - - message: "#^Parameter \\#2 \\$offset of function substr expects int, mixed given\\.$#" count: 1 @@ -995,26 +925,11 @@ parameters: count: 1 path: ../../../src/utils/Internet.php - - - message: "#^Parameter \\#1 \\$abbr of function timezone_name_from_abbr expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/utils/Timezone.php - - - - message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/utils/Timezone.php - - message: "#^Parameter \\#1 \\$string of function trim expects string, string\\|false given\\.$#" count: 1 path: ../../../src/utils/Timezone.php - - - message: "#^Parameter \\#1 \\$timezoneId of function date_default_timezone_set expects string, string\\|false given\\.$#" - count: 1 - path: ../../../src/utils/Timezone.php - - message: "#^Cannot cast mixed to string\\.$#" count: 1 From 77a74d84e2ad57d7e09bef1a6a9f0831ee9c584d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 19:58:28 +0000 Subject: [PATCH 481/710] CrashDump: phpversion() could return false for a loaded extension if the extension wrote NULL into the zend_module_entry->version field, phpversion() will return false. --- src/crash/CrashDump.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php index c265aad57..c2979e53b 100644 --- a/src/crash/CrashDump.php +++ b/src/crash/CrashDump.php @@ -164,8 +164,7 @@ class CrashDump{ $extensions = []; foreach(get_loaded_extensions() as $ext){ $version = phpversion($ext); - if($version === false) throw new AssumptionFailedError(); - $extensions[$ext] = $version; + $extensions[$ext] = $version !== false ? $version : "**UNKNOWN**"; } $this->data->extensions = $extensions; From 2254f31bec457bbbf75c0e3c9b12514baaf83e52 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 20:01:19 +0000 Subject: [PATCH 482/710] Use Utils::assumeNotFalse() in tools/ --- tools/generate-permission-doc.php | 6 +----- tools/ping-server.php | 5 ++--- tools/simulate-chunk-selector.php | 30 ++++++++---------------------- 3 files changed, 11 insertions(+), 30 deletions(-) diff --git a/tools/generate-permission-doc.php b/tools/generate-permission-doc.php index 944d2aae3..32a92cbb9 100644 --- a/tools/generate-permission-doc.php +++ b/tools/generate-permission-doc.php @@ -25,7 +25,6 @@ namespace pocketmine\generate_permission_doc; use pocketmine\permission\DefaultPermissions; use pocketmine\permission\PermissionManager; -use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Utils; use pocketmine\VersionInfo; use Webmozart\PathUtil\Path; @@ -48,10 +47,7 @@ function markdownify(string $name) : string{ } DefaultPermissions::registerCorePermissions(); -$cwd = getcwd(); -if($cwd === false){ - throw new AssumptionFailedError("getcwd() returned false"); -} +$cwd = Utils::assumeNotFalse(getcwd()); $output = Path::join($cwd, "core-permissions.md"); echo "Writing output to $output\n"; $doc = fopen($output, "wb"); diff --git a/tools/ping-server.php b/tools/ping-server.php index 912119d5c..ad2bd59ef 100644 --- a/tools/ping-server.php +++ b/tools/ping-server.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace pocketmine\tools\ping_server; -use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Utils; use raklib\protocol\MessageIdentifiers; use raklib\protocol\PacketSerializer; use raklib\protocol\UnconnectedPing; @@ -137,8 +137,7 @@ if(count($argv) > 2){ $port = $portRaw === "" ? 19132 : (int) $portRaw; } -$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); -if($sock === false) throw new AssumptionFailedError(); +$sock = Utils::assumeNotFalse(socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)); socket_bind($sock, "0.0.0.0"); socket_getsockname($sock, $bindAddr, $bindPort); diff --git a/tools/simulate-chunk-selector.php b/tools/simulate-chunk-selector.php index b30355f7c..03355bee6 100644 --- a/tools/simulate-chunk-selector.php +++ b/tools/simulate-chunk-selector.php @@ -37,16 +37,10 @@ use const STR_PAD_LEFT; require dirname(__DIR__) . '/vendor/autoload.php'; function newImage(int $scale, int $radius) : \GdImage{ - $image = imagecreatetruecolor($scale * $radius * 2, $scale * $radius * 2); - if($image === false){ - throw new AssumptionFailedError(); - } + $image = Utils::assumeNotFalse(imagecreatetruecolor($scale * $radius * 2, $scale * $radius * 2)); imagesavealpha($image, true); - $black = imagecolorallocate($image, 0, 0, 0); - if($black === false){ - throw new AssumptionFailedError(); - } + $black = Utils::assumeNotFalse(imagecolorallocate($image, 0, 0, 0)); imagefill($image, 0, 0, $black); return $image; } @@ -58,10 +52,9 @@ function render(int $radius, int $baseX, int $baseZ, int $chunksPerStep, int $sc $middleOffsetX = $scale * ($radius + $offsetX); $middleOffsetZ = $scale * ($radius + $offsetZ); - $black = imagecolorallocate($image, 0, 0, 0); - $yellow = imagecolorallocate($image, 255, 255, 51); - $red = imagecolorallocate($image, 255, 0, 0); - if($black === false || $yellow === false || $red === false) throw new AssumptionFailedError(); + $black = Utils::assumeNotFalse(imagecolorallocate($image, 0, 0, 0)); + $yellow = Utils::assumeNotFalse(imagecolorallocate($image, 255, 255, 51)); + $red = Utils::assumeNotFalse(imagecolorallocate($image, 255, 0, 0)); $frame = 0; $seen = []; @@ -152,11 +145,7 @@ foreach(Utils::stringifyKeys(getopt("", ["output:"])) as $name => $value){ fwrite(STDERR, "Output directory $value is not empty\n"); exit(1); } - $realPath = realpath($value); - if($realPath === false){ - throw new AssumptionFailedError(); - } - $outputDirectory = $realPath; + $outputDirectory = Utils::assumeNotFalse(realpath($value), "We just created this directory, we should be able to get its realpath"); } if($outputDirectory === null){ fwrite(STDERR, "Please specify an output directory using --output\n"); @@ -164,9 +153,6 @@ if($outputDirectory === null){ } $image = newImage($scale, $radius); -$black = imagecolorallocate($image, 0, 0, 0); -$green = imagecolorallocate($image, 0, 220, 0); -if($black === false || $green === false){ - throw new AssumptionFailedError(); -} +$black = Utils::assumeNotFalse(imagecolorallocate($image, 0, 0, 0)); +$green = Utils::assumeNotFalse(imagecolorallocate($image, 0, 220, 0)); render($radius, $baseX, $baseZ, $nChunksPerStep, $scale, $image, $green, 0, 0, $outputDirectory); From 7a385ddc8b4b0b6f4dcdbbda082811755c7b05c3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 20:04:03 +0000 Subject: [PATCH 483/710] simulate-chunk-selector: remove unused colour allocation --- tools/simulate-chunk-selector.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/simulate-chunk-selector.php b/tools/simulate-chunk-selector.php index 03355bee6..86ae01491 100644 --- a/tools/simulate-chunk-selector.php +++ b/tools/simulate-chunk-selector.php @@ -153,6 +153,5 @@ if($outputDirectory === null){ } $image = newImage($scale, $radius); -$black = Utils::assumeNotFalse(imagecolorallocate($image, 0, 0, 0)); $green = Utils::assumeNotFalse(imagecolorallocate($image, 0, 220, 0)); render($radius, $baseX, $baseZ, $nChunksPerStep, $scale, $image, $green, 0, 0, $outputDirectory); From 0793e7e094cdeb431939f1fe2934f81ae6c7473b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 20:08:53 +0000 Subject: [PATCH 484/710] PluginLoadabilityChecker: fixed logic of extension compatibility check if the extension doesn't specify any version, we can't do any constraint other than *. --- src/plugin/PluginLoadabilityChecker.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugin/PluginLoadabilityChecker.php b/src/plugin/PluginLoadabilityChecker.php index a293f33c0..74696749e 100644 --- a/src/plugin/PluginLoadabilityChecker.php +++ b/src/plugin/PluginLoadabilityChecker.php @@ -30,6 +30,7 @@ use pocketmine\utils\Utils; use pocketmine\utils\VersionString; use function array_intersect; use function count; +use function extension_loaded; use function implode; use function in_array; use function phpversion; @@ -77,9 +78,13 @@ final class PluginLoadabilityChecker{ } foreach(Utils::stringifyKeys($description->getRequiredExtensions()) as $extensionName => $versionConstrs){ + if(!extension_loaded($extensionName)){ + return KnownTranslationFactory::pocketmine_plugin_extensionNotLoaded($extensionName); + } $gotVersion = phpversion($extensionName); if($gotVersion === false){ - return KnownTranslationFactory::pocketmine_plugin_extensionNotLoaded($extensionName); + //extensions may set NULL as the extension version, in which case phpversion() may return false + $gotVersion = "**UNKNOWN**"; } foreach($versionConstrs as $k => $constr){ // versionConstrs_loop From 3aabfa4ab068ecde0c90419e19baedafd56155a9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 20:48:44 +0000 Subject: [PATCH 485/710] bootstrap: display value of PHPRC when PHP binary is borked PHPRC overrides the search path for php.ini, which might break the php.ini locating. --- src/pocketmine/PocketMine.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index 2c6c1fdd8..bb162ec13 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -197,6 +197,8 @@ JIT_WARNING } critical_error("PHP binary used: " . $binary); critical_error("Loaded php.ini: " . (($file = php_ini_loaded_file()) !== false ? $file : "none")); + $phprc = getenv("PHPRC"); + critical_error("Value of PHPRC environment variable: " . ($phprc === false ? "" : $phprc)); critical_error("Please recompile PHP with the needed configuration, or refer to the installation instructions at http://pmmp.rtfd.io/en/rtfd/installation.html."); echo PHP_EOL; exit(1); From 264cff70ec94588b0d0bb042fbd6acb25a71a598 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 21:55:12 +0000 Subject: [PATCH 486/710] Release new PM3 builds onto pm3 channel --- src/pocketmine/VersionInfo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 8699310ef..50e35a882 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -35,4 +35,4 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.26.2"; const IS_DEVELOPMENT_BUILD = true; -const BUILD_CHANNEL = "stable"; +const BUILD_CHANNEL = "pm3"; From f48cf68cac1c1a197a485f709358590795f4edf1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 21:55:44 +0000 Subject: [PATCH 487/710] updater: log a message when an update was found, but it's an older version --- src/pocketmine/updater/AutoUpdater.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pocketmine/updater/AutoUpdater.php b/src/pocketmine/updater/AutoUpdater.php index e0d35adcc..33d0472ef 100644 --- a/src/pocketmine/updater/AutoUpdater.php +++ b/src/pocketmine/updater/AutoUpdater.php @@ -192,6 +192,8 @@ class AutoUpdater{ if($currentVersion->compare($newVersion) > 0 and ($currentVersion->getFullVersion() !== $newVersion->getFullVersion() or $currentVersion->getBuild() > 0)){ $this->newVersion = $newVersion; + }else{ + $this->server->getLogger()->debug("[AutoUpdater] API reported version is an older version or the same version (" . $newVersion->getFullVersion() . "), not showing notification"); } } From b081394125f90c14d6894b24e2edb32f3284b3a0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 21:57:16 +0000 Subject: [PATCH 488/710] Do not restrict the allowed update channels client-side we really should have an endpoint on the server that deals with this. --- src/pocketmine/updater/AutoUpdater.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/pocketmine/updater/AutoUpdater.php b/src/pocketmine/updater/AutoUpdater.php index 33d0472ef..9e505dfe1 100644 --- a/src/pocketmine/updater/AutoUpdater.php +++ b/src/pocketmine/updater/AutoUpdater.php @@ -201,12 +201,7 @@ class AutoUpdater{ * Returns the channel used for update checking (stable, beta, dev) */ public function getChannel() : string{ - $channel = strtolower($this->server->getProperty("auto-updater.preferred-channel", "stable")); - if($channel !== "stable" and $channel !== "beta" and $channel !== "alpha" and $channel !== "development"){ - $channel = "stable"; - } - - return $channel; + return strtolower($this->server->getProperty("auto-updater.preferred-channel", "stable")); } /** From 40895a86e57fac865eb3b0ae730babbcc0b5eb5d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 8 Dec 2021 23:55:43 +0000 Subject: [PATCH 489/710] draft-release: stick a banner on the release notes to declare obsolescence --- .github/workflows/draft-release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml index 1c8f3eb57..8ff34f30a 100644 --- a/.github/workflows/draft-release.yml +++ b/.github/workflows/draft-release.yml @@ -105,6 +105,11 @@ jobs: Please see the [changelogs](/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details. + ## WARNING + + The 3.x line of releases is now OBSOLETE. It will be discontinued after **March 1st, 2022**. + Please prepare to upgrade to 4.0 or newer before that date. + - name: Upload preprocessor diffs uses: actions/upload-artifact@v2 if: always() From 1e56ed2ea35f1d7b3747ff776de26c1c4aa6a790 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 9 Dec 2021 00:26:59 +0000 Subject: [PATCH 490/710] Release 3.26.2 --- changelogs/3.26.md | 5 +++++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/changelogs/3.26.md b/changelogs/3.26.md index 323c49c74..e28ea3e04 100644 --- a/changelogs/3.26.md +++ b/changelogs/3.26.md @@ -12,3 +12,8 @@ Plugin developers should **only** update their required API to this version if y # 3.26.1 - Fixed a bug in chunk sending that caused double chests to not be paired, signs to be blank, and various other issues. + +# 3.26.2 +- Improved error messages shown by `start.cmd`, `start.sh` and `start.ps1` when the PHP binary was not found. +- The value of PHPRC is now shown when erroring out due to unsatisfied PHP requirements. +- Removed restriction on the range of valid channels for `auto-updater.channel` in `pocketmine.yml`. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 50e35a882..cbc8b770b 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,5 +34,5 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.26.2"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_CHANNEL = "pm3"; From 06eaf9f273fddd83f33b320371a5f22bb59fd157 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 9 Dec 2021 00:27:03 +0000 Subject: [PATCH 491/710] 3.26.3 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 cbc8b770b..db375f456 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.26.2"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.26.3"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_CHANNEL = "pm3"; From 036b90d2472ab317305d3724f69dc498d424e07c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 9 Dec 2021 00:48:42 +0000 Subject: [PATCH 492/710] Release 4.0.1 --- changelogs/4.0.md | 24 ++++++++++++++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 6a97299c3..4fc8c4af4 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1523,3 +1523,27 @@ Please note that this was not written with plugins in mind and its API may chang ### Misc - Added support for emotes. + +# 4.0.1 +Released 9th December 2021. + +## General +- Added a script `tools/ping-server.php`. This was sitting in my workspace for many years. +- `Minecraft network interface running` messages are no longer shown if RakLib was prevented from starting. + +## Fixes +### Core +- Fixed server crash when `FallingBlock` has invalid block data that it can't understand. +- Fixed server crash when loading chunks containing tiles outside the world bounds. +- Fixed server crash when loading LevelDB chunks containing blockstates which are invalid or not yet supported - they are now treated as corrupted instead. +- Fixed `level.dat` becoming corrupted by world saves when the disk is full - now it will still fail to save, but it will leave the original data intact. Previously it would destroy the data and leave behind an empty file. +- Fixed configs becoming corrupted when saved when the disk is full - now they'll still fail to save, but the original file will remain intact. + +### API +- Fixed mistakes in the 4.0.0 changelog: + - Removal of `Player->getLowerCaseName()` is now mentioned. + - `CreativeInventory::reset()` is the successor to `Item::initCreativeItems()`, not `CreativeInventory::init()`. + - Note that the changelog when viewing from the 4.0.0 GitHub release will remain the same; only the changelog in the current repo will be different. +- `Config->save()` will no longer write empty data to the file when using JSON and the data fails to encode - an exception will be thrown instead. +- `StringToItemParser` now returns the correct items for `bamboo`, `shulker_box`, `stone_slab`, `stone_stairs` and `tall_grass`. +- `StringToItemParser` now recognizes `slime` and `slime_block` (these were previously missing). diff --git a/src/VersionInfo.php b/src/VersionInfo.php index dc3ab18a7..9310a2c14 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.1"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 6ddaed97fa8fa1586953b83996a15cea25c32673 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 9 Dec 2021 00:48:45 +0000 Subject: [PATCH 493/710] 4.0.2 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 9310a2c14..d5cd1d7f1 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.1"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.2"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From f8ed23cc1ed5fd6dbe44038c66bcf22bf2ca3730 Mon Sep 17 00:00:00 2001 From: Matthew Jordan Date: Thu, 9 Dec 2021 05:19:33 -0600 Subject: [PATCH 494/710] ClearCommand: Add OffHandInventory to $inventories (#4631) --- src/command/defaults/ClearCommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/command/defaults/ClearCommand.php b/src/command/defaults/ClearCommand.php index 02f8d0c9e..e4a359432 100644 --- a/src/command/defaults/ClearCommand.php +++ b/src/command/defaults/ClearCommand.php @@ -100,7 +100,8 @@ class ClearCommand extends VanillaCommand{ $inventories = [ $target->getInventory(), $target->getCursorInventory(), - $target->getArmorInventory() + $target->getArmorInventory(), + $target->getOffHandInventory() ]; // Checking player's inventory for all the items matching the criteria From 292827a311a8792718b6405975518ef923a47475 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 9 Dec 2021 13:53:53 +0000 Subject: [PATCH 495/710] Switch to PlayerAuthInputPacket for movement handling sticking with the non-rewind version for now, for simplicity's sake. We do want the rewind version at some point for server side knockback, but that's a job for later. For now, using this packet fixes various problems with slightly-incorrect positions and rotations (e.g. AimTP no longer requires you to jump to get the exact correct rotation; previously it would hit the wrong block at long distances due to errors of a fraction of a degree due to the client not sending its position. Note that this might cause some performance degradation since the packet is sent every tick. This has yet to be assessed, but the advantages offered are undeniable in any case. --- src/network/mcpe/handler/InGamePacketHandler.php | 15 ++++++++------- .../mcpe/handler/PreSpawnPacketHandler.php | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index e4553c49b..ac09d90ee 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -68,9 +68,9 @@ use pocketmine\network\mcpe\protocol\MapInfoRequestPacket; use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket; use pocketmine\network\mcpe\protocol\MobEquipmentPacket; use pocketmine\network\mcpe\protocol\ModalFormResponsePacket; -use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket; use pocketmine\network\mcpe\protocol\PlayerActionPacket; +use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket; use pocketmine\network\mcpe\protocol\PlayerHotbarPacket; use pocketmine\network\mcpe\protocol\PlayerInputPacket; use pocketmine\network\mcpe\protocol\PlayerSkinPacket; @@ -150,17 +150,17 @@ class InGamePacketHandler extends PacketHandler{ return false; } - public function handleMovePlayer(MovePlayerPacket $packet) : bool{ - $rawPos = $packet->position; - foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->yaw, $packet->headYaw, $packet->pitch] as $float){ + public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{ + $rawPos = $packet->getPosition(); + foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->getYaw(), $packet->getHeadYaw(), $packet->getPitch()] as $float){ if(is_infinite($float) || is_nan($float)){ $this->session->getLogger()->debug("Invalid movement received, contains NAN/INF components"); return false; } } - $yaw = fmod($packet->yaw, 360); - $pitch = fmod($packet->pitch, 360); + $yaw = fmod($packet->getYaw(), 360); + $pitch = fmod($packet->getPitch(), 360); if($yaw < 0){ $yaw += 360; } @@ -168,7 +168,7 @@ class InGamePacketHandler extends PacketHandler{ $this->player->setRotation($yaw, $pitch); $curPos = $this->player->getLocation(); - $newPos = $packet->position->round(4)->subtract(0, 1.62, 0); + $newPos = $rawPos->round(4)->subtract(0, 1.62, 0); if($this->forceMoveSync and $newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks $this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos); @@ -179,6 +179,7 @@ class InGamePacketHandler extends PacketHandler{ // Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock $this->forceMoveSync = false; + //TODO: this packet has WAYYYYY more useful information that we're not using $this->player->handleMovement($newPos); return true; diff --git a/src/network/mcpe/handler/PreSpawnPacketHandler.php b/src/network/mcpe/handler/PreSpawnPacketHandler.php index dbad9ab6c..626f7a3eb 100644 --- a/src/network/mcpe/handler/PreSpawnPacketHandler.php +++ b/src/network/mcpe/handler/PreSpawnPacketHandler.php @@ -97,7 +97,7 @@ class PreSpawnPacketHandler extends PacketHandler{ $this->server->getMotd(), "", false, - new PlayerMovementSettings(PlayerMovementType::LEGACY, 0, false), + new PlayerMovementSettings(PlayerMovementType::SERVER_AUTHORITATIVE_V1, 0, false), 0, 0, "", From b3dab0beef206df5a4d2c7cbf0592232254cb3de Mon Sep 17 00:00:00 2001 From: Dylan T Date: Fri, 10 Dec 2021 00:40:29 +0000 Subject: [PATCH 496/710] readme: added total downloads & latest downloads badges [ci skip] --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 802f9c1dc..e3aa3a6b1 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ GitHub release (latest SemVer) Docker image version (latest semver) Discord +
+ GitHub all releases + GitHub release (latest by SemVer)

## Getting started From 1ed9302f5a80b645f61bca90dc48bc6a348c1a42 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 10 Dec 2021 16:31:56 +0000 Subject: [PATCH 497/710] ItemEntity: clone items given to the constructor directly this fixes some bizarre mutability issues that occurred when using World->dropItem() with the same object multiple times. --- src/entity/object/ItemEntity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entity/object/ItemEntity.php b/src/entity/object/ItemEntity.php index 899cbc279..dd7561412 100644 --- a/src/entity/object/ItemEntity.php +++ b/src/entity/object/ItemEntity.php @@ -68,7 +68,7 @@ class ItemEntity extends Entity{ if($item->isNull()){ throw new \InvalidArgumentException("Item entity must have a non-air item with a count of at least 1"); } - $this->item = $item; + $this->item = clone $item; parent::__construct($location, $nbt); } From 3b774629350ef4c05b6d959e897f889f55c35250 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 10 Dec 2021 16:39:13 +0000 Subject: [PATCH 498/710] WritableBookBase: fixed crash when finding pages containing corrupted UTF-8 characters maybe we should treat this as corrupted? but for now, it's consistent with how we deal with signs. --- src/item/WritableBookBase.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/item/WritableBookBase.php b/src/item/WritableBookBase.php index b19de34ba..db0b37574 100644 --- a/src/item/WritableBookBase.php +++ b/src/item/WritableBookBase.php @@ -31,6 +31,7 @@ use function array_push; use function array_slice; use function array_values; use function count; +use function mb_scrub; abstract class WritableBookBase extends Item{ public const TAG_PAGES = "pages"; //TAG_List @@ -168,12 +169,12 @@ abstract class WritableBookBase extends Item{ if($pages->getTagType() === NBT::TAG_Compound){ //PE format /** @var CompoundTag $page */ foreach($pages as $page){ - $this->pages[] = new WritableBookPage($page->getString(self::TAG_PAGE_TEXT), $page->getString(self::TAG_PAGE_PHOTONAME, "")); + $this->pages[] = new WritableBookPage(mb_scrub($page->getString(self::TAG_PAGE_TEXT), 'UTF-8'), $page->getString(self::TAG_PAGE_PHOTONAME, "")); } }elseif($pages->getTagType() === NBT::TAG_String){ //PC format /** @var StringTag $page */ foreach($pages as $page){ - $this->pages[] = new WritableBookPage($page->getValue()); + $this->pages[] = new WritableBookPage(mb_scrub($page->getValue(), 'UTF-8')); } } } From 911ad344c9ad8d76c1cd21ce3a52394de9cc1afb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 10 Dec 2021 17:27:28 +0000 Subject: [PATCH 499/710] Human: do not mutate parameter variables in setXpAndProgress() this caused a mystery that took 3 entire years to debug. --- src/pocketmine/entity/Human.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 835b7baf1..b80ecb45d 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -447,24 +447,26 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ } protected function setXpAndProgress(?int $level, ?float $progress) : bool{ + $newLevel = $level; + $newProgress = $progress; if(!$this->justCreated){ - $ev = new PlayerExperienceChangeEvent($this, $this->getXpLevel(), $this->getXpProgress(), $level, $progress); + $ev = new PlayerExperienceChangeEvent($this, $this->getXpLevel(), $this->getXpProgress(), $newLevel, $newProgress); $ev->call(); if($ev->isCancelled()){ return false; } - $level = $ev->getNewLevel(); - $progress = $ev->getNewProgress(); + $newLevel = $ev->getNewLevel(); + $newProgress = $ev->getNewProgress(); } - if($level !== null){ - $this->getAttributeMap()->getAttribute(Attribute::EXPERIENCE_LEVEL)->setValue($level); + if($newLevel !== null){ + $this->getAttributeMap()->getAttribute(Attribute::EXPERIENCE_LEVEL)->setValue($newLevel); } - if($progress !== null){ - $this->getAttributeMap()->getAttribute(Attribute::EXPERIENCE)->setValue($progress); + if($newProgress !== null){ + $this->getAttributeMap()->getAttribute(Attribute::EXPERIENCE)->setValue($newProgress); } return true; From 6d5c463bdda1a1636e810f46d22d219cc142ec72 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 10 Dec 2021 17:29:57 +0000 Subject: [PATCH 500/710] PlayerExperienceChangeEvent: added range checks to setNewProgress() WE FINALLY FUCKING FOUND IT This took several years to identify because PHP's exception stack traces don't show the actual values of parameters, but rather the values of the variables they were assigned to. This means that if the parameter variable is mutated, the exception trace will show the value of the variable inside the function, not the value that was actually passed. --- src/pocketmine/entity/Human.php | 5 ----- src/pocketmine/event/player/PlayerExperienceChangeEvent.php | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index b80ecb45d..85cfeceee 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -57,7 +57,6 @@ use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; use pocketmine\network\mcpe\protocol\types\PlayerListEntry; use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton; use pocketmine\Player; -use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\UUID; use function array_filter; use function array_merge; @@ -70,7 +69,6 @@ use function max; use function min; use function mt_rand; use function random_int; -use function sprintf; use function strlen; use const INT32_MAX; use const INT32_MIN; @@ -397,9 +395,6 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $xpLevel = (int) $newLevel; $xpProgress = $newLevel - (int) $newLevel; - if($xpProgress > 1.0){ - throw new AssumptionFailedError(sprintf("newLevel - (int) newLevel should never be bigger than 1, but have %.53f (newLevel=%.53f)", $xpProgress, $newLevel)); - } return $this->setXpAndProgress($xpLevel, $xpProgress); } diff --git a/src/pocketmine/event/player/PlayerExperienceChangeEvent.php b/src/pocketmine/event/player/PlayerExperienceChangeEvent.php index 3322a91b8..4d889a37d 100644 --- a/src/pocketmine/event/player/PlayerExperienceChangeEvent.php +++ b/src/pocketmine/event/player/PlayerExperienceChangeEvent.php @@ -79,6 +79,9 @@ class PlayerExperienceChangeEvent extends EntityEvent implements Cancellable{ } public function setNewProgress(?float $newProgress) : void{ + if($newProgress < 0.0 || $newProgress > 1.0){ + throw new \InvalidArgumentException("XP progress must be in range 0-1"); + } $this->newProgress = $newProgress; } } From 549fb923bf0725259ed61737d05f8661f869d016 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 10 Dec 2021 17:55:07 +0000 Subject: [PATCH 501/710] Release 3.26.3 --- changelogs/3.26.md | 4 ++++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/changelogs/3.26.md b/changelogs/3.26.md index e28ea3e04..86a3a2d2e 100644 --- a/changelogs/3.26.md +++ b/changelogs/3.26.md @@ -17,3 +17,7 @@ Plugin developers should **only** update their required API to this version if y - Improved error messages shown by `start.cmd`, `start.sh` and `start.ps1` when the PHP binary was not found. - The value of PHPRC is now shown when erroring out due to unsatisfied PHP requirements. - Removed restriction on the range of valid channels for `auto-updater.channel` in `pocketmine.yml`. + +# 3.26.3 +- `PlayerExperienceChangeEvent->setNewProgress()` now performs range checks. This fixes the root of a very old and confusing crash bug which took several years to identify the cause of. + - Note that the defective plugin(s) which caused this problem will still cause a server crash, but the plugin responsible will now get blamed correctly. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index db375f456..19714b931 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,5 +34,5 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.26.3"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_CHANNEL = "pm3"; From 69d5bfa0d4d5355790a9b3fc8ea8333adabf1385 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 10 Dec 2021 17:55:11 +0000 Subject: [PATCH 502/710] 3.26.4 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 19714b931..31fcdcb9e 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.26.3"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.26.4"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_CHANNEL = "pm3"; From fa48100da5c4bb4e85e2e30812df98b2e1b66732 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 10 Dec 2021 18:08:50 +0000 Subject: [PATCH 503/710] PluginDescription: ensure base type of decoded document is actually an array fixes #4628 --- src/plugin/PluginDescription.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/plugin/PluginDescription.php b/src/plugin/PluginDescription.php index c1ab144fe..22949e673 100644 --- a/src/plugin/PluginDescription.php +++ b/src/plugin/PluginDescription.php @@ -28,6 +28,7 @@ use pocketmine\permission\PermissionParser; use pocketmine\permission\PermissionParserException; use function array_map; use function array_values; +use function get_debug_type; use function is_array; use function is_string; use function preg_match; @@ -85,7 +86,18 @@ class PluginDescription{ * @param string|mixed[] $yamlString */ public function __construct($yamlString){ - $this->loadMap(!is_array($yamlString) ? yaml_parse($yamlString) : $yamlString); + if(is_string($yamlString)){ + $map = yaml_parse($yamlString); + if($map === false){ + throw new PluginDescriptionParseException("YAML parsing error in plugin manifest"); + } + if(!is_array($map)){ + throw new PluginDescriptionParseException("Invalid structure of plugin manifest, expected array but have " . get_debug_type($map)); + } + }else{ + $map = $yamlString; + } + $this->loadMap($map); } /** From 448f26cefcd748533921605c616de5c335f823f9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 10 Dec 2021 18:27:49 +0000 Subject: [PATCH 504/710] SimpleCommandMap: do not strip backslashes from unquoted command arguments --- src/command/SimpleCommandMap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/SimpleCommandMap.php b/src/command/SimpleCommandMap.php index 6b8f392e6..2d18972c5 100644 --- a/src/command/SimpleCommandMap.php +++ b/src/command/SimpleCommandMap.php @@ -206,7 +206,7 @@ class SimpleCommandMap implements CommandMap{ foreach($matches[0] as $k => $_){ for($i = 1; $i <= 2; ++$i){ if($matches[$i][$k] !== ""){ - $args[$k] = stripslashes($matches[$i][$k]); + $args[$k] = $i === 1 ? stripslashes($matches[$i][$k]) : $matches[$i][$k]; break; } } From 9e75c1463a78cc130c1d0aa860d08740caedc8ee Mon Sep 17 00:00:00 2001 From: Leo Lee Date: Sat, 11 Dec 2021 03:45:15 +0800 Subject: [PATCH 505/710] Implement carving pumpkin (#4637) --- src/block/BlockFactory.php | 2 +- src/block/Pumpkin.php | 45 +++++++++++++++++++++++++++++++++++++ src/block/VanillaBlocks.php | 2 +- 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/block/Pumpkin.php diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index fd98293c5..2cda5bcdd 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -291,7 +291,7 @@ class BlockFactory{ $this->registerAllMeta(new Stair(new BID(Ids::PRISMARINE_STAIRS, 0), "Prismarine Stairs", $prismarineBreakInfo)); $pumpkinBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE); - $this->registerAllMeta($pumpkin = new Opaque(new BID(Ids::PUMPKIN, 0), "Pumpkin", $pumpkinBreakInfo)); + $this->registerAllMeta(new Pumpkin(new BID(Ids::PUMPKIN, 0), "Pumpkin", $pumpkinBreakInfo)); $this->registerAllMeta(new CarvedPumpkin(new BID(Ids::CARVED_PUMPKIN, 0), "Carved Pumpkin", $pumpkinBreakInfo)); $this->registerAllMeta(new LitPumpkin(new BID(Ids::JACK_O_LANTERN, 0), "Jack o'Lantern", $pumpkinBreakInfo)); diff --git a/src/block/Pumpkin.php b/src/block/Pumpkin.php new file mode 100644 index 000000000..57d305806 --- /dev/null +++ b/src/block/Pumpkin.php @@ -0,0 +1,45 @@ +applyDamage(1); + $this->position->getWorld()->setBlock($this->position, VanillaBlocks::CARVED_PUMPKIN()->setFacing($face)); + $this->position->getWorld()->dropItem($this->position->add(0.5, 0.5, 0.5), VanillaItems::PUMPKIN_SEEDS()->setCount(1)); + return true; + } + return false; + } +} diff --git a/src/block/VanillaBlocks.php b/src/block/VanillaBlocks.php index 7d2d947c5..f9ec337a4 100644 --- a/src/block/VanillaBlocks.php +++ b/src/block/VanillaBlocks.php @@ -445,7 +445,7 @@ use pocketmine\utils\CloningRegistryTrait; * @method static Slab PRISMARINE_SLAB() * @method static Stair PRISMARINE_STAIRS() * @method static Wall PRISMARINE_WALL() - * @method static Opaque PUMPKIN() + * @method static Pumpkin PUMPKIN() * @method static PumpkinStem PUMPKIN_STEM() * @method static GlazedTerracotta PURPLE_GLAZED_TERRACOTTA() * @method static Torch PURPLE_TORCH() From b50591303b4a0d7db066bcbfebdc236778ac1caf Mon Sep 17 00:00:00 2001 From: Dylan T Date: Fri, 10 Dec 2021 20:23:48 +0000 Subject: [PATCH 506/710] README: make shield show download count for 4.0.1, not 3.26.3 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e3aa3a6b1..402558916 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Discord
GitHub all releases - GitHub release (latest by SemVer) + GitHub release (latest by SemVer)

## Getting started From e6b85988b231a61975b25563656aaae851cc6085 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Dec 2021 22:37:28 +0000 Subject: [PATCH 507/710] Bump fgrosse/phpasn1 from 2.3.0 to 2.3.1 (#4636) Bumps [fgrosse/phpasn1](https://github.com/fgrosse/PHPASN1) from 2.3.0 to 2.3.1. - [Release notes](https://github.com/fgrosse/PHPASN1/releases) - [Changelog](https://github.com/fgrosse/PHPASN1/blob/master/CHANGELOG.md) - [Commits](https://github.com/fgrosse/PHPASN1/compare/v2.3.0...v2.3.1) --- updated-dependencies: - dependency-name: fgrosse/phpasn1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index 2979bb4ab..b342d4dcd 100644 --- a/composer.lock +++ b/composer.lock @@ -123,24 +123,24 @@ }, { "name": "fgrosse/phpasn1", - "version": "v2.3.0", + "version": "v2.3.1", "source": { "type": "git", "url": "https://github.com/fgrosse/PHPASN1.git", - "reference": "20299033c35f4300eb656e7e8e88cf52d1d6694e" + "reference": "6edcecb4df8b6881e79080d5e363dc8b90d4558c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/20299033c35f4300eb656e7e8e88cf52d1d6694e", - "reference": "20299033c35f4300eb656e7e8e88cf52d1d6694e", + "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/6edcecb4df8b6881e79080d5e363dc8b90d4558c", + "reference": "6edcecb4df8b6881e79080d5e363dc8b90d4558c", "shasum": "" }, "require": { "php": ">=7.0.0" }, "require-dev": { - "phpunit/phpunit": "~6.3", - "satooshi/php-coveralls": "~2.0" + "php-coveralls/php-coveralls": "~2.0", + "phpunit/phpunit": "^6.3 | ^7.0" }, "suggest": { "ext-bcmath": "BCmath is the fallback extension for big integer calculations", @@ -192,9 +192,9 @@ ], "support": { "issues": "https://github.com/fgrosse/PHPASN1/issues", - "source": "https://github.com/fgrosse/PHPASN1/tree/v2.3.0" + "source": "https://github.com/fgrosse/PHPASN1/tree/v2.3.1" }, - "time": "2021-04-24T19:01:55+00:00" + "time": "2021-12-09T20:59:31+00:00" }, { "name": "netresearch/jsonmapper", From e81bee3866c8d92b559dae584b5ad9836850e0c3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 10 Dec 2021 23:24:18 +0000 Subject: [PATCH 508/710] ConsoleReaderThread: disable opcache for console reader subprocess --- src/console/ConsoleReaderThread.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/console/ConsoleReaderThread.php b/src/console/ConsoleReaderThread.php index bdfccd80f..29e44d9f6 100644 --- a/src/console/ConsoleReaderThread.php +++ b/src/console/ConsoleReaderThread.php @@ -87,7 +87,7 @@ final class ConsoleReaderThread extends Thread{ //Windows sucks, and likes to corrupt UTF-8 file paths when they travel to the subprocess, so we base64 encode //the path to avoid the problem. This is an abysmally shitty hack, but here we are :( $sub = proc_open( - [PHP_BINARY, '-r', sprintf('require base64_decode("%s", true);', base64_encode(Path::join(__DIR__, 'ConsoleReaderChildProcess.php'))), $address], + [PHP_BINARY, '-dopcache.enable_cli=0', '-r', sprintf('require base64_decode("%s", true);', base64_encode(Path::join(__DIR__, 'ConsoleReaderChildProcess.php'))), $address], [ 2 => fopen("php://stderr", "w"), ], From ede07c431419c03627fc334b599f2bd21c1aa70c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 11 Dec 2021 21:24:18 +0000 Subject: [PATCH 509/710] Mark KnownTranslationKeys and KnownTranslationFactory as @internal --- build/generate-known-translation-apis.php | 4 ++++ src/lang/KnownTranslationFactory.php | 2 ++ src/lang/KnownTranslationKeys.php | 2 ++ 3 files changed, 8 insertions(+) diff --git a/build/generate-known-translation-apis.php b/build/generate-known-translation-apis.php index feee9b183..e4f35893b 100644 --- a/build/generate-known-translation-apis.php +++ b/build/generate-known-translation-apis.php @@ -95,6 +95,8 @@ function generate_known_translation_keys(array $languageDefinitions) : void{ /** * This class contains constants for all the translations known to PocketMine-MP as per the used version of pmmp/Language. * This class is generated automatically, do NOT modify it by hand. + * + * @internal */ final class KnownTranslationKeys{ @@ -127,6 +129,8 @@ function generate_known_translation_factory(array $languageDefinitions) : void{ * This class contains factory methods for all the translations known to PocketMine-MP as per the used version of * pmmp/Language. * This class is generated automatically, do NOT modify it by hand. + * + * @internal */ final class KnownTranslationFactory{ diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 35418d18c..c8536d885 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -27,6 +27,8 @@ namespace pocketmine\lang; * This class contains factory methods for all the translations known to PocketMine-MP as per the used version of * pmmp/Language. * This class is generated automatically, do NOT modify it by hand. + * + * @internal */ final class KnownTranslationFactory{ public static function ability_flight() : Translatable{ diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 7b77513dc..805f0a686 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -26,6 +26,8 @@ namespace pocketmine\lang; /** * This class contains constants for all the translations known to PocketMine-MP as per the used version of pmmp/Language. * This class is generated automatically, do NOT modify it by hand. + * + * @internal */ final class KnownTranslationKeys{ public const ABILITY_FLIGHT = "ability.flight"; From e06eefeab017867f7a42bd9c3e7e827d7eb2e5c3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 11 Dec 2021 21:28:52 +0000 Subject: [PATCH 510/710] build/generate-known-translation-apis: fixed incorrect positional parameter order closes #4639 --- build/generate-known-translation-apis.php | 6 ++++++ src/lang/KnownTranslationFactory.php | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/build/generate-known-translation-apis.php b/build/generate-known-translation-apis.php index e4f35893b..a85cbb1b3 100644 --- a/build/generate-known-translation-apis.php +++ b/build/generate-known-translation-apis.php @@ -41,6 +41,7 @@ use function preg_match_all; use function str_replace; use function strtoupper; use const INI_SCANNER_RAW; +use const SORT_NUMERIC; use const SORT_STRING; use const STDERR; @@ -142,15 +143,20 @@ HEADER; $translationContainerClass = (new \ReflectionClass(Translatable::class))->getShortName(); foreach(Utils::stringifyKeys($languageDefinitions) as $key => $value){ $parameters = []; + $allParametersPositional = true; if(preg_match_all($parameterRegex, $value, $matches) > 0){ foreach($matches[1] as $parameterName){ if(is_numeric($parameterName)){ $parameters[$parameterName] = "param$parameterName"; }else{ $parameters[$parameterName] = $parameterName; + $allParametersPositional = false; } } } + if($allParametersPositional){ + ksort($parameters, SORT_NUMERIC); + } echo "\tpublic static function " . functionify($key) . "(" . implode(", ", array_map(fn(string $paramName) => "$translationContainerClass|string \$$paramName", $parameters)) . ") : $translationContainerClass{\n"; diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index c8536d885..6aea89053 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -244,10 +244,10 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::COMMANDS_ENCHANT_USAGE, []); } - public static function commands_gamemode_success_other(Translatable|string $param1, Translatable|string $param0) : Translatable{ + public static function commands_gamemode_success_other(Translatable|string $param0, Translatable|string $param1) : Translatable{ return new Translatable(KnownTranslationKeys::COMMANDS_GAMEMODE_SUCCESS_OTHER, [ - 1 => $param1, 0 => $param0, + 1 => $param1, ]); } From 0a58fd5472000cb6cddaddef50489661855a9da1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 12 Dec 2021 21:58:07 +0000 Subject: [PATCH 511/710] GeneratorManager: fixed addGenerator() being case-sensitive when overwrite=true this was caused by 083a1e1ff6b6ff5c0c1ba14250d2b026af103b90. This was discovered by a new PHPStan rule I'm working on, which disallows overwriting the values of parameter variables. During the refactor of this function to correct the error, another error appeared: Variable might not be defined. This is yet another excellent example of why mutability is bad. --- src/world/generator/GeneratorManager.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/world/generator/GeneratorManager.php b/src/world/generator/GeneratorManager.php index 0e29cc68b..f90c6ae4a 100644 --- a/src/world/generator/GeneratorManager.php +++ b/src/world/generator/GeneratorManager.php @@ -72,7 +72,8 @@ final class GeneratorManager{ public function addGenerator(string $class, string $name, \Closure $presetValidator, bool $overwrite = false) : void{ Utils::testValidInstance($class, Generator::class); - if(!$overwrite and isset($this->list[$name = strtolower($name)])){ + $name = strtolower($name); + if(!$overwrite and isset($this->list[$name])){ throw new \InvalidArgumentException("Alias \"$name\" is already assigned"); } From 178dcb71a9a1139527dbb9ff2229dbcd61735e5c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 12 Dec 2021 23:27:50 +0000 Subject: [PATCH 512/710] Release 4.0.2 --- changelogs/4.0.md | 18 ++++++++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 4fc8c4af4..2ba259372 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1547,3 +1547,21 @@ Released 9th December 2021. - `Config->save()` will no longer write empty data to the file when using JSON and the data fails to encode - an exception will be thrown instead. - `StringToItemParser` now returns the correct items for `bamboo`, `shulker_box`, `stone_slab`, `stone_stairs` and `tall_grass`. - `StringToItemParser` now recognizes `slime` and `slime_block` (these were previously missing). + +# 4.0.2 +Released 12th December 2021. + +## Fixes +### Core +- Fixed server crash when loading written books containing pages with invalid UTF-8 characters - the invalid characters are now scrubbed. +- Fixed server crash when root type of `plugin.yml` is valid, but not an array. +- Fixed ConsoleReader crash due OPcache ASLR issue - it's not clear what caused this, but OPcache is not needed in the subprocess anyway. +- Fixed backslashes getting stripped from unquoted command arguments - these were only supposed to be stripped from quoted arguments, to allow escaping of quotes. +- `build/generate-known-translation-apis.php` now sorts numerically-indexed arguments into ascending order, irrespective of the order they appear in the original string. + +### API +- `KnownTranslationKeys` and `KnownTranslationFactory` are now marked `@internal`. +- `ItemEntity` now clones the itemstack passed to its constructor, fixing various confusing mutability issues. +- `PlayerExperienceChangeEvent->setNewProgress()` now performs range checks. This fixes the root of a very old and confusing crash bug which took several years to identify the cause of. + - Note that the defective plugin(s) which caused this problem will still cause a server crash, but the plugin responsible will now get blamed correctly. +- `GeneratorManager->addGenerator()` now consistently converts the given alias to lowercase. Due to a bug, it previously didn't do this if the `$overwrite` parameter was set to `true`, causing a range of confusing bugs. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index d5cd1d7f1..1d0f10892 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.2"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 22bb1ce8e03dba57173debf0415390511d68e045 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 12 Dec 2021 23:27:54 +0000 Subject: [PATCH 513/710] 4.0.3 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 1d0f10892..dec840bca 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.2"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.3"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 3be8472ae237bfb5d0d6f4ce1a32a2fa688ba89c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 13 Dec 2021 12:11:49 +0000 Subject: [PATCH 514/710] MemoryManager: fixed dumping of uninitialized properties closes #4643 --- src/MemoryManager.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/MemoryManager.php b/src/MemoryManager.php index 020532f82..0967f7121 100644 --- a/src/MemoryManager.php +++ b/src/MemoryManager.php @@ -325,6 +325,9 @@ class MemoryManager{ if(!$property->isPublic()){ $property->setAccessible(true); } + if(!$property->isInitialized()){ + continue; + } $staticCount++; $staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize); @@ -448,6 +451,9 @@ class MemoryManager{ if(!$property->isPublic()){ $property->setAccessible(true); } + if(!$property->isInitialized($object)){ + continue; + } $info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize); } From f5bbd30dbb6bffcc5b15ba29bdf6f3c8130028fb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 13 Dec 2021 12:35:55 +0000 Subject: [PATCH 515/710] Fixed skins appearing black when using RTX resource packs, closes #4537 --- src/pocketmine/entity/Entity.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 39e1a28fc..22cae83dc 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -619,6 +619,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ $this->propertyManager->setFloat(self::DATA_SCALE, 1); $this->propertyManager->setFloat(self::DATA_BOUNDING_BOX_WIDTH, $this->width); $this->propertyManager->setFloat(self::DATA_BOUNDING_BOX_HEIGHT, $this->height); + $this->propertyManager->setFloat(self::DATA_COLOR, 0); $this->fireTicks = $this->namedtag->getShort("Fire", 0); if($this->isOnFire()){ From 89a766b7995a5135dcbf4e13dd4d81b88a2c70b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Dec 2021 21:39:44 +0000 Subject: [PATCH 516/710] Bump fgrosse/phpasn1 from 2.3.1 to 2.4.0 (#4644) Bumps [fgrosse/phpasn1](https://github.com/fgrosse/PHPASN1) from 2.3.1 to 2.4.0. - [Release notes](https://github.com/fgrosse/PHPASN1/releases) - [Changelog](https://github.com/fgrosse/PHPASN1/blob/master/CHANGELOG.md) - [Commits](https://github.com/fgrosse/PHPASN1/compare/v2.3.1...v2.4.0) --- updated-dependencies: - dependency-name: fgrosse/phpasn1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index b342d4dcd..0400953d1 100644 --- a/composer.lock +++ b/composer.lock @@ -123,24 +123,24 @@ }, { "name": "fgrosse/phpasn1", - "version": "v2.3.1", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/fgrosse/PHPASN1.git", - "reference": "6edcecb4df8b6881e79080d5e363dc8b90d4558c" + "reference": "eef488991d53e58e60c9554b09b1201ca5ba9296" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/6edcecb4df8b6881e79080d5e363dc8b90d4558c", - "reference": "6edcecb4df8b6881e79080d5e363dc8b90d4558c", + "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/eef488991d53e58e60c9554b09b1201ca5ba9296", + "reference": "eef488991d53e58e60c9554b09b1201ca5ba9296", "shasum": "" }, "require": { - "php": ">=7.0.0" + "php": "~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0" }, "require-dev": { "php-coveralls/php-coveralls": "~2.0", - "phpunit/phpunit": "^6.3 | ^7.0" + "phpunit/phpunit": "^6.3 || ^7.0 || ^8.0" }, "suggest": { "ext-bcmath": "BCmath is the fallback extension for big integer calculations", @@ -192,9 +192,9 @@ ], "support": { "issues": "https://github.com/fgrosse/PHPASN1/issues", - "source": "https://github.com/fgrosse/PHPASN1/tree/v2.3.1" + "source": "https://github.com/fgrosse/PHPASN1/tree/v2.4.0" }, - "time": "2021-12-09T20:59:31+00:00" + "time": "2021-12-11T12:41:06+00:00" }, { "name": "netresearch/jsonmapper", From c334e6dec7a11371295ea697b954a61701f6f0e1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 14 Dec 2021 00:31:44 +0000 Subject: [PATCH 517/710] Updated locale-data dependency --- composer.json | 2 +- composer.lock | 14 +++++++------- src/lang/KnownTranslationFactory.php | 6 ++++++ src/lang/KnownTranslationKeys.php | 1 + 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 415a36e95..c65948459 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", "pocketmine/errorhandler": "^0.3.0", - "pocketmine/locale-data": "^2.0.16", + "pocketmine/locale-data": "^2.1.0", "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", "pocketmine/math": "^0.4.0", diff --git a/composer.lock b/composer.lock index 0400953d1..fb65cd8e0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b515e7eebbf12a6251d2df817ce56dbc", + "content-hash": "6a1fde030a0133e4ff23047afab5727e", "packages": [ { "name": "adhocore/json-comment", @@ -535,16 +535,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.0.22", + "version": "2.1.25", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "181eb9d42653296e65d55a1bbba10e0dd76bbd61" + "reference": "0c810aaa24baffcccd57ca5bca16ca8f346c483c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/181eb9d42653296e65d55a1bbba10e0dd76bbd61", - "reference": "181eb9d42653296e65d55a1bbba10e0dd76bbd61", + "url": "https://api.github.com/repos/pmmp/Language/zipball/0c810aaa24baffcccd57ca5bca16ca8f346c483c", + "reference": "0c810aaa24baffcccd57ca5bca16ca8f346c483c", "shasum": "" }, "type": "library", @@ -552,9 +552,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.0.22" + "source": "https://github.com/pmmp/Language/tree/2.1.25" }, - "time": "2021-12-04T22:37:10+00:00" + "time": "2021-12-14T00:29:11+00:00" }, { "name": "pocketmine/log", diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 6aea89053..7b4a6adbd 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -917,6 +917,12 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::GAMEMODE_INFO, []); } + public static function gamemode_options(Translatable|string $param0) : Translatable{ + return new Translatable(KnownTranslationKeys::GAMEMODE_OPTIONS, [ + 0 => $param0, + ]); + } + public static function invalid_port() : Translatable{ return new Translatable(KnownTranslationKeys::INVALID_PORT, []); } diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 805f0a686..2174e9720 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -203,6 +203,7 @@ final class KnownTranslationKeys{ public const GAMEMODE_SPECTATOR = "gameMode.spectator"; public const GAMEMODE_SURVIVAL = "gameMode.survival"; public const GAMEMODE_INFO = "gamemode_info"; + public const GAMEMODE_OPTIONS = "gamemode_options"; public const INVALID_PORT = "invalid_port"; public const IP_CONFIRM = "ip_confirm"; public const IP_GET = "ip_get"; From 7e6bbcc393924cae39bf5e8da0de4a37684f362d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 14 Dec 2021 01:27:11 +0000 Subject: [PATCH 518/710] Sync composer deps --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index fb65cd8e0..1e11bf2e8 100644 --- a/composer.lock +++ b/composer.lock @@ -1833,16 +1833,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", - "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", "shasum": "" }, "require": { @@ -1894,9 +1894,9 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.14.0" + "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" }, - "time": "2021-09-10T09:02:12+00:00" + "time": "2021-12-08T12:19:24+00:00" }, { "name": "phpstan/phpstan", From 4ad8cb02a5bb99bbd89eed49c0f9c16f331e67a5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 14 Dec 2021 17:36:25 +0000 Subject: [PATCH 519/710] BlockIdentifier: ensure that the tile class given is valid --- src/block/BlockIdentifier.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/block/BlockIdentifier.php b/src/block/BlockIdentifier.php index 5ea45c90b..b69037ad0 100644 --- a/src/block/BlockIdentifier.php +++ b/src/block/BlockIdentifier.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\tile\Tile; +use pocketmine\utils\Utils; class BlockIdentifier{ @@ -40,6 +41,10 @@ class BlockIdentifier{ $this->blockId = $blockId; $this->variant = $variant; $this->itemId = $itemId; + + if($tileClass !== null){ + Utils::testValidInstance($tileClass, Tile::class); + } $this->tileClass = $tileClass; } From 45c4a9673ddd536db814a7b6bdfcfdc21d8d6ad5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 14 Dec 2021 19:03:42 +0000 Subject: [PATCH 520/710] Player: fixed arm swing animation not showing during attack cooldown of victim closes #4650 --- src/player/Player.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/player/Player.php b/src/player/Player.php index aab421014..d431f430e 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1667,13 +1667,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } $entity->attack($ev); + $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); $soundPos = $entity->getPosition()->add(0, $entity->size->getHeight() / 2, 0); if($ev->isCancelled()){ $this->getWorld()->addSound($soundPos, new EntityAttackNoDamageSound()); return false; } - $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); $this->getWorld()->addSound($soundPos, new EntityAttackSound()); if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0 and $entity instanceof Living){ From a09817864b0d05f7aadb32211e962b66045e7ebb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 14 Dec 2021 22:50:43 +0000 Subject: [PATCH 521/710] php-cs-fixer: add return_type_declaration space_before --- .php-cs-fixer.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 590f6ebd8..aa00fc033 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -69,6 +69,9 @@ return (new PhpCsFixer\Config) ], 'phpdoc_trim' => true, 'phpdoc_trim_consecutive_blank_line_separation' => true, + 'return_type_declaration' => [ + 'space_before' => 'one' + ], 'single_import_per_statement' => true, 'strict_param' => true, ]) From a41404bd8afb99bd0cafae25110e216af036a815 Mon Sep 17 00:00:00 2001 From: Matthew Jordan Date: Tue, 14 Dec 2021 16:56:22 -0600 Subject: [PATCH 522/710] Allow gamemode strings for gamemode property in server.properties (#4638) closes #2692 --- src/Server.php | 5 ++--- src/command/defaults/DefaultGamemodeCommand.php | 3 +-- src/wizard/SetupWizard.php | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Server.php b/src/Server.php index fc0be90af..bd2761ad7 100644 --- a/src/Server.php +++ b/src/Server.php @@ -36,7 +36,6 @@ use pocketmine\crafting\CraftingManager; use pocketmine\crafting\CraftingManagerFromDataHelper; use pocketmine\crash\CrashDump; use pocketmine\crash\CrashDumpRenderer; -use pocketmine\data\java\GameModeIdMap; use pocketmine\entity\EntityDataHelper; use pocketmine\entity\Location; use pocketmine\event\HandlerListManager; @@ -357,7 +356,7 @@ class Server{ } public function getGamemode() : GameMode{ - return GameModeIdMap::getInstance()->fromId($this->configGroup->getConfigInt("gamemode", 0)) ?? GameMode::SURVIVAL(); + return GameMode::fromString($this->configGroup->getConfigString("gamemode", GameMode::SURVIVAL()->name())) ?? GameMode::SURVIVAL(); } public function getForceGamemode() : bool{ @@ -804,7 +803,7 @@ class Server{ "enable-ipv6" => true, "white-list" => false, "max-players" => 20, - "gamemode" => 0, + "gamemode" => GameMode::SURVIVAL()->name(), "force-gamemode" => false, "hardcore" => false, "pvp" => true, diff --git a/src/command/defaults/DefaultGamemodeCommand.php b/src/command/defaults/DefaultGamemodeCommand.php index d2ae848ae..1f0b29aa3 100644 --- a/src/command/defaults/DefaultGamemodeCommand.php +++ b/src/command/defaults/DefaultGamemodeCommand.php @@ -25,7 +25,6 @@ namespace pocketmine\command\defaults; use pocketmine\command\CommandSender; use pocketmine\command\utils\InvalidCommandSyntaxException; -use pocketmine\data\java\GameModeIdMap; use pocketmine\lang\KnownTranslationFactory; use pocketmine\permission\DefaultPermissionNames; use pocketmine\player\GameMode; @@ -57,7 +56,7 @@ class DefaultGamemodeCommand extends VanillaCommand{ return true; } - $sender->getServer()->getConfigGroup()->setConfigInt("gamemode", GameModeIdMap::getInstance()->toId($gameMode)); + $sender->getServer()->getConfigGroup()->setConfigString("gamemode", $gameMode->name()); $sender->sendMessage(KnownTranslationFactory::commands_defaultgamemode_success($gameMode->getTranslatableName())); return true; } diff --git a/src/wizard/SetupWizard.php b/src/wizard/SetupWizard.php index 6dfb3b690..97bf2fd58 100644 --- a/src/wizard/SetupWizard.php +++ b/src/wizard/SetupWizard.php @@ -162,9 +162,9 @@ LICENSE; $this->message($this->lang->translate(KnownTranslationFactory::gamemode_info())); do{ - $gamemode = (int) $this->getInput($this->lang->translate(KnownTranslationFactory::default_gamemode()), (string) GameModeIdMap::getInstance()->toId(GameMode::SURVIVAL())); - }while($gamemode < 0 or $gamemode > 3); - $config->set("gamemode", $gamemode); + $gamemode = GameModeIdMap::getInstance()->fromId((int) $this->getInput($this->lang->translate(KnownTranslationFactory::default_gamemode()), (string) GameModeIdMap::getInstance()->toId(GameMode::SURVIVAL()))); + }while($gamemode === null); + $config->set("gamemode", $gamemode->name()); $config->set("max-players", (int) $this->getInput($this->lang->translate(KnownTranslationFactory::max_players()), (string) self::DEFAULT_PLAYERS)); From 7fb1669c6d547202bbfa47b206c6929719c930e2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 14 Dec 2021 23:14:39 +0000 Subject: [PATCH 523/710] php-cs-fixer: added binary_operator_spaces and unary_operator_spaces rules --- .php-cs-fixer.php | 4 ++++ src/pocketmine/entity/Entity.php | 8 +++---- src/pocketmine/level/format/io/ChunkUtils.php | 2 +- .../mcpe/protocol/AdventureSettingsPacket.php | 4 ++-- .../mcpe/protocol/AvailableCommandsPacket.php | 22 +++++++++---------- .../mcpe/protocol/LevelChunkPacket.php | 2 +- .../mcpe/protocol/UpdateBlockPacket.php | 6 ++--- src/pocketmine/utils/Config.php | 8 +++---- 8 files changed, 30 insertions(+), 26 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index aa00fc033..01a6e52c0 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -19,6 +19,9 @@ return (new PhpCsFixer\Config) 'array_syntax' => [ 'syntax' => 'short' ], + 'binary_operator_spaces' => [ + 'default' => 'single_space' + ], 'blank_line_after_namespace' => true, 'blank_line_after_opening_tag' => true, 'blank_line_before_statement' => [ @@ -74,6 +77,7 @@ return (new PhpCsFixer\Config) ], 'single_import_per_statement' => true, 'strict_param' => true, + 'unary_operator_spaces' => true, ]) ->setFinder($finder) ->setIndent("\t") diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 22cae83dc..927fc64cd 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -1230,10 +1230,10 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ $diffZ = $z - $floorZ; if(BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY, $floorZ)]){ - $westNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX - 1, $floorY, $floorZ)]; - $eastNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX + 1, $floorY, $floorZ)]; - $downNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY - 1, $floorZ)]; - $upNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY + 1, $floorZ)]; + $westNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX - 1, $floorY, $floorZ)]; + $eastNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX + 1, $floorY, $floorZ)]; + $downNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY - 1, $floorZ)]; + $upNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY + 1, $floorZ)]; $northNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY, $floorZ - 1)]; $southNonSolid = !BlockFactory::$solid[$this->level->getBlockIdAt($floorX, $floorY, $floorZ + 1)]; diff --git a/src/pocketmine/level/format/io/ChunkUtils.php b/src/pocketmine/level/format/io/ChunkUtils.php index 0bfb52fdc..98abf40fa 100644 --- a/src/pocketmine/level/format/io/ChunkUtils.php +++ b/src/pocketmine/level/format/io/ChunkUtils.php @@ -81,7 +81,7 @@ if(!extension_loaded('pocketmine_chunkutils')){ }else{ $i1 = ord($array[$j]); $i2 = ord($array[$j80]); - $result[$i] = chr(($i2 << 4) | ($i1 & 0x0f)); + $result[$i] = chr(($i2 << 4) | ($i1 & 0x0f)); $result[$i | 0x80] = chr(($i1 >> 4) | ($i2 & 0xf0)); } $i++; diff --git a/src/pocketmine/network/mcpe/protocol/AdventureSettingsPacket.php b/src/pocketmine/network/mcpe/protocol/AdventureSettingsPacket.php index 427784d32..49645974c 100644 --- a/src/pocketmine/network/mcpe/protocol/AdventureSettingsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AdventureSettingsPacket.php @@ -108,9 +108,9 @@ class AdventureSettingsPacket extends DataPacket{ */ public function setFlag(int $flag, bool $value){ if(($flag & self::BITFLAG_SECOND_SET) !== 0){ - $flagSet =& $this->flags2; + $flagSet = &$this->flags2; }else{ - $flagSet =& $this->flags; + $flagSet = &$this->flags; } if($value){ diff --git a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php index 5b2d4c3d9..40dad3338 100644 --- a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php @@ -48,27 +48,27 @@ class AvailableCommandsPacket extends DataPacket{ * Basic parameter types. These must be combined with the ARG_FLAG_VALID constant. * ARG_FLAG_VALID | (type const) */ - public const ARG_TYPE_INT = 0x01; - public const ARG_TYPE_FLOAT = 0x03; - public const ARG_TYPE_VALUE = 0x04; - public const ARG_TYPE_WILDCARD_INT = 0x05; - public const ARG_TYPE_OPERATOR = 0x06; - public const ARG_TYPE_TARGET = 0x07; + public const ARG_TYPE_INT = 0x01; + public const ARG_TYPE_FLOAT = 0x03; + public const ARG_TYPE_VALUE = 0x04; + public const ARG_TYPE_WILDCARD_INT = 0x05; + public const ARG_TYPE_OPERATOR = 0x06; + public const ARG_TYPE_TARGET = 0x07; public const ARG_TYPE_WILDCARD_TARGET = 0x08; public const ARG_TYPE_FILEPATH = 0x10; - public const ARG_TYPE_STRING = 0x20; + public const ARG_TYPE_STRING = 0x20; public const ARG_TYPE_POSITION = 0x28; - public const ARG_TYPE_MESSAGE = 0x2c; + public const ARG_TYPE_MESSAGE = 0x2c; - public const ARG_TYPE_RAWTEXT = 0x2e; + public const ARG_TYPE_RAWTEXT = 0x2e; - public const ARG_TYPE_JSON = 0x32; + public const ARG_TYPE_JSON = 0x32; - public const ARG_TYPE_COMMAND = 0x3f; + public const ARG_TYPE_COMMAND = 0x3f; /** * Enums are a little different: they are composed as follows: diff --git a/src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php b/src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php index 43c5ee894..e859a76bb 100644 --- a/src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php +++ b/src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php @@ -106,7 +106,7 @@ class LevelChunkPacket extends DataPacket/* implements ClientboundPacket*/{ $this->subChunkCount = $this->getUnsignedVarInt(); $this->cacheEnabled = $this->getBool(); if($this->cacheEnabled){ - for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ + for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ $this->usedBlobHashes[] = $this->getLLong(); } } diff --git a/src/pocketmine/network/mcpe/protocol/UpdateBlockPacket.php b/src/pocketmine/network/mcpe/protocol/UpdateBlockPacket.php index 9e7ca6c32..25d24dfdb 100644 --- a/src/pocketmine/network/mcpe/protocol/UpdateBlockPacket.php +++ b/src/pocketmine/network/mcpe/protocol/UpdateBlockPacket.php @@ -30,11 +30,11 @@ use pocketmine\network\mcpe\NetworkSession; class UpdateBlockPacket extends DataPacket{ public const NETWORK_ID = ProtocolInfo::UPDATE_BLOCK_PACKET; - public const FLAG_NONE = 0b0000; + public const FLAG_NONE = 0b0000; public const FLAG_NEIGHBORS = 0b0001; - public const FLAG_NETWORK = 0b0010; + public const FLAG_NETWORK = 0b0010; public const FLAG_NOGRAPHIC = 0b0100; - public const FLAG_PRIORITY = 0b1000; + public const FLAG_PRIORITY = 0b1000; public const FLAG_ALL = self::FLAG_NEIGHBORS | self::FLAG_NETWORK; public const FLAG_ALL_PRIORITY = self::FLAG_ALL | self::FLAG_PRIORITY; diff --git a/src/pocketmine/utils/Config.php b/src/pocketmine/utils/Config.php index cdeafbb9f..f38a0e2a3 100644 --- a/src/pocketmine/utils/Config.php +++ b/src/pocketmine/utils/Config.php @@ -368,14 +368,14 @@ class Config{ $this->config[$base] = []; } - $base =& $this->config[$base]; + $base = &$this->config[$base]; while(count($vars) > 0){ $baseKey = array_shift($vars); if(!isset($base[$baseKey])){ $base[$baseKey] = []; } - $base =& $base[$baseKey]; + $base = &$base[$baseKey]; } $base = $value; @@ -420,14 +420,14 @@ class Config{ $vars = explode(".", $key); - $currentNode =& $this->config; + $currentNode = &$this->config; while(count($vars) > 0){ $nodeName = array_shift($vars); if(isset($currentNode[$nodeName])){ if(count($vars) === 0){ //final node unset($currentNode[$nodeName]); }elseif(is_array($currentNode[$nodeName])){ - $currentNode =& $currentNode[$nodeName]; + $currentNode = &$currentNode[$nodeName]; } }else{ break; From 60938c8c9df4bf21d096f142c6579dfad92eb8c2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 00:59:10 +0000 Subject: [PATCH 524/710] Random: fixed nextSignedInt() not actually returning signed ints closes #4646 closes #4645 Impact assessment by core usage search and poggit suggests that the impact of this change will be close to zero. However, since it changes behaviour which plugins might be unknowingly relying on, it's going into 4.1 rather than a patch release. --- src/utils/Random.php | 2 +- tests/phpunit/utils/RandomTest.php | 43 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 tests/phpunit/utils/RandomTest.php diff --git a/src/utils/Random.php b/src/utils/Random.php index 81598ac24..3c7f6cb0d 100644 --- a/src/utils/Random.php +++ b/src/utils/Random.php @@ -94,7 +94,7 @@ class Random{ $this->z = $this->w; $this->w = ($this->w ^ (($this->w >> 19) & 0x7fffffff) ^ ($t ^ (($t >> 8) & 0x7fffffff))) & 0xffffffff; - return $this->w; + return Binary::signInt($this->w); } /** diff --git a/tests/phpunit/utils/RandomTest.php b/tests/phpunit/utils/RandomTest.php new file mode 100644 index 000000000..4c6f1fdf4 --- /dev/null +++ b/tests/phpunit/utils/RandomTest.php @@ -0,0 +1,43 @@ +nextSignedInt() < 0){ + $negatives = true; + break; + } + } + self::assertTrue($negatives); + } +} \ No newline at end of file From 4d37b79ff7f9d9452e988387f97919a9a1c4954e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 01:08:59 +0000 Subject: [PATCH 525/710] Server: fixed not being able to deop players whose names were added to ops.txt with uppercase letters in them same as iTXTech/Genisys#1204 why didn't anyone report this??? --- src/Server.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index f40667786..b776b20eb 100644 --- a/src/Server.php +++ b/src/Server.php @@ -694,7 +694,13 @@ class Server{ } public function removeOp(string $name) : void{ - $this->operators->remove(strtolower($name)); + $lowercaseName = strtolower($name); + foreach($this->operators->getAll() as $operatorName => $_){ + $operatorName = (string) $operatorName; + if($lowercaseName === strtolower($operatorName)){ + $this->operators->remove($operatorName); + } + } if(($player = $this->getPlayerExact($name)) !== null){ $player->unsetBasePermission(DefaultPermissions::ROOT_OPERATOR); From 79b510995342399cb03e213d16f18061b082bc4a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 01:40:29 +0000 Subject: [PATCH 526/710] Move some configuration constants to .. well .. constants --- src/Server.php | 26 ++++++++++++++++---------- src/wizard/SetupWizard.php | 7 ++++--- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/Server.php b/src/Server.php index bd2761ad7..a46b2b4ab 100644 --- a/src/Server.php +++ b/src/Server.php @@ -177,6 +177,12 @@ class Server{ public const BROADCAST_CHANNEL_ADMINISTRATIVE = "pocketmine.broadcast.admin"; public const BROADCAST_CHANNEL_USERS = "pocketmine.broadcast.user"; + public const DEFAULT_SERVER_NAME = VersionInfo::NAME . " Server"; + public const DEFAULT_MAX_PLAYERS = 20; + public const DEFAULT_PORT_IPV4 = 19132; + public const DEFAULT_PORT_IPV6 = 19133; + public const DEFAULT_VIEW_DISTANCE = 8; + private static ?Server $instance = null; private SleeperHandler $tickSleeper; @@ -323,15 +329,15 @@ class Server{ } public function getPort() : int{ - return $this->configGroup->getConfigInt("server-port", 19132); + return $this->configGroup->getConfigInt("server-port", self::DEFAULT_PORT_IPV4); } public function getPortV6() : int{ - return $this->configGroup->getConfigInt("server-portv6", 19133); + return $this->configGroup->getConfigInt("server-portv6", self::DEFAULT_PORT_IPV6); } public function getViewDistance() : int{ - return max(2, $this->configGroup->getConfigInt("view-distance", 8)); + return max(2, $this->configGroup->getConfigInt("view-distance", self::DEFAULT_VIEW_DISTANCE)); } /** @@ -379,7 +385,7 @@ class Server{ } public function getMotd() : string{ - return $this->configGroup->getConfigString("motd", VersionInfo::NAME . " Server"); + return $this->configGroup->getConfigString("motd", self::DEFAULT_SERVER_NAME); } public function getLoader() : \DynamicClassLoader{ @@ -797,12 +803,12 @@ class Server{ $this->configGroup = new ServerConfigGroup( new Config($pocketmineYmlPath, Config::YAML, []), new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES, [ - "motd" => VersionInfo::NAME . " Server", - "server-port" => 19132, - "server-portv6" => 19133, + "motd" => self::DEFAULT_SERVER_NAME, + "server-port" => self::DEFAULT_PORT_IPV4, + "server-portv6" => self::DEFAULT_PORT_IPV6, "enable-ipv6" => true, "white-list" => false, - "max-players" => 20, + "max-players" => self::DEFAULT_MAX_PLAYERS, "gamemode" => GameMode::SURVIVAL()->name(), "force-gamemode" => false, "hardcore" => false, @@ -814,7 +820,7 @@ class Server{ "level-type" => "DEFAULT", "enable-query" => true, "auto-save" => true, - "view-distance" => 8, + "view-distance" => self::DEFAULT_VIEW_DISTANCE, "xbox-auth" => true, "language" => "eng" ]) @@ -911,7 +917,7 @@ class Server{ $this->banByIP = new BanList($bannedIpsTxt); $this->banByIP->load(); - $this->maxPlayers = $this->configGroup->getConfigInt("max-players", 20); + $this->maxPlayers = $this->configGroup->getConfigInt("max-players", self::DEFAULT_MAX_PLAYERS); $this->onlineMode = $this->configGroup->getConfigBool("xbox-auth", true); if($this->onlineMode){ diff --git a/src/wizard/SetupWizard.php b/src/wizard/SetupWizard.php index 97bf2fd58..0a48b71d3 100644 --- a/src/wizard/SetupWizard.php +++ b/src/wizard/SetupWizard.php @@ -32,6 +32,7 @@ use pocketmine\lang\KnownTranslationFactory; use pocketmine\lang\Language; use pocketmine\lang\LanguageNotFoundException; use pocketmine\player\GameMode; +use pocketmine\Server; use pocketmine\utils\Config; use pocketmine\utils\Internet; use pocketmine\utils\InternetException; @@ -46,9 +47,9 @@ use const PHP_EOL; use const STDIN; class SetupWizard{ - public const DEFAULT_NAME = VersionInfo::NAME . " Server"; - public const DEFAULT_PORT = 19132; - public const DEFAULT_PLAYERS = 20; + public const DEFAULT_NAME = Server::DEFAULT_SERVER_NAME; + public const DEFAULT_PORT = Server::DEFAULT_PORT_IPV4; + public const DEFAULT_PLAYERS = Server::DEFAULT_MAX_PLAYERS; /** @var Language */ private $lang; From 5f8ebd81d72f759ef5fb3353a8d780e21af5e32f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 01:42:29 +0000 Subject: [PATCH 527/710] it's MAX view distance, not fixed --- src/Server.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Server.php b/src/Server.php index a46b2b4ab..5b55ffa6d 100644 --- a/src/Server.php +++ b/src/Server.php @@ -181,7 +181,7 @@ class Server{ public const DEFAULT_MAX_PLAYERS = 20; public const DEFAULT_PORT_IPV4 = 19132; public const DEFAULT_PORT_IPV6 = 19133; - public const DEFAULT_VIEW_DISTANCE = 8; + public const DEFAULT_MAX_VIEW_DISTANCE = 8; private static ?Server $instance = null; @@ -337,7 +337,7 @@ class Server{ } public function getViewDistance() : int{ - return max(2, $this->configGroup->getConfigInt("view-distance", self::DEFAULT_VIEW_DISTANCE)); + return max(2, $this->configGroup->getConfigInt("view-distance", self::DEFAULT_MAX_VIEW_DISTANCE)); } /** @@ -820,7 +820,7 @@ class Server{ "level-type" => "DEFAULT", "enable-query" => true, "auto-save" => true, - "view-distance" => self::DEFAULT_VIEW_DISTANCE, + "view-distance" => self::DEFAULT_MAX_VIEW_DISTANCE, "xbox-auth" => true, "language" => "eng" ]) From 6e67c7532a64b1c368091ebb32a65be6b8e73551 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 01:46:50 +0000 Subject: [PATCH 528/710] Bump default max render radius to 16 chunks It's 2021, this is making PM look bad to new users (as if we need something else to make PM look bad...) --- src/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server.php b/src/Server.php index 5b55ffa6d..2fcda6a93 100644 --- a/src/Server.php +++ b/src/Server.php @@ -181,7 +181,7 @@ class Server{ public const DEFAULT_MAX_PLAYERS = 20; public const DEFAULT_PORT_IPV4 = 19132; public const DEFAULT_PORT_IPV6 = 19133; - public const DEFAULT_MAX_VIEW_DISTANCE = 8; + public const DEFAULT_MAX_VIEW_DISTANCE = 16; private static ?Server $instance = null; From c04b00d09d3249599d96d76c66a7c1100b1857df Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 02:15:24 +0000 Subject: [PATCH 529/710] Updated Language to 2.2.0 --- composer.json | 2 +- composer.lock | 14 +++++++------- src/lang/KnownTranslationFactory.php | 12 ++++++++++++ src/lang/KnownTranslationKeys.php | 3 +++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index c65948459..f516b8fb7 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", "pocketmine/errorhandler": "^0.3.0", - "pocketmine/locale-data": "^2.1.0", + "pocketmine/locale-data": "^2.2.0", "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", "pocketmine/math": "^0.4.0", diff --git a/composer.lock b/composer.lock index 1e11bf2e8..4705ec16d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6a1fde030a0133e4ff23047afab5727e", + "content-hash": "c6ea83d1ae49200c45ab58fcff2ae1ac", "packages": [ { "name": "adhocore/json-comment", @@ -535,16 +535,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.1.25", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "0c810aaa24baffcccd57ca5bca16ca8f346c483c" + "reference": "dc88ad618a482e55b7c9fec162257efa62a67d6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/0c810aaa24baffcccd57ca5bca16ca8f346c483c", - "reference": "0c810aaa24baffcccd57ca5bca16ca8f346c483c", + "url": "https://api.github.com/repos/pmmp/Language/zipball/dc88ad618a482e55b7c9fec162257efa62a67d6f", + "reference": "dc88ad618a482e55b7c9fec162257efa62a67d6f", "shasum": "" }, "type": "library", @@ -552,9 +552,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.1.25" + "source": "https://github.com/pmmp/Language/tree/2.2.0" }, - "time": "2021-12-14T00:29:11+00:00" + "time": "2021-12-15T02:01:24+00:00" }, { "name": "pocketmine/log", diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 7b4a6adbd..6c1b2f556 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -2131,6 +2131,14 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::SERVER_PORT, []); } + public static function server_port_v4() : Translatable{ + return new Translatable(KnownTranslationKeys::SERVER_PORT_V4, []); + } + + public static function server_port_v6() : Translatable{ + return new Translatable(KnownTranslationKeys::SERVER_PORT_V6, []); + } + public static function server_properties() : Translatable{ return new Translatable(KnownTranslationKeys::SERVER_PROPERTIES, []); } @@ -2155,6 +2163,10 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::TILE_BED_TOOFAR, []); } + public static function view_distance() : Translatable{ + return new Translatable(KnownTranslationKeys::VIEW_DISTANCE, []); + } + public static function welcome_to_pocketmine(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::WELCOME_TO_POCKETMINE, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 2174e9720..95d9bbccd 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -443,12 +443,15 @@ final class KnownTranslationKeys{ public const QUERY_WARNING1 = "query_warning1"; public const QUERY_WARNING2 = "query_warning2"; public const SERVER_PORT = "server_port"; + public const SERVER_PORT_V4 = "server_port_v4"; + public const SERVER_PORT_V6 = "server_port_v6"; public const SERVER_PROPERTIES = "server_properties"; public const SETTING_UP_SERVER_NOW = "setting_up_server_now"; public const SKIP_INSTALLER = "skip_installer"; public const TILE_BED_NOSLEEP = "tile.bed.noSleep"; public const TILE_BED_OCCUPIED = "tile.bed.occupied"; public const TILE_BED_TOOFAR = "tile.bed.tooFar"; + public const VIEW_DISTANCE = "view_distance"; public const WELCOME_TO_POCKETMINE = "welcome_to_pocketmine"; public const WHITELIST_ENABLE = "whitelist_enable"; public const WHITELIST_INFO = "whitelist_info"; From 3aa34b59a51485739eea83e121d28214f35923b4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 02:22:04 +0000 Subject: [PATCH 530/710] Ask for IPv6 port in setup wizard --- src/wizard/SetupWizard.php | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/wizard/SetupWizard.php b/src/wizard/SetupWizard.php index 0a48b71d3..34b145077 100644 --- a/src/wizard/SetupWizard.php +++ b/src/wizard/SetupWizard.php @@ -31,6 +31,7 @@ use pocketmine\data\java\GameModeIdMap; use pocketmine\lang\KnownTranslationFactory; use pocketmine\lang\Language; use pocketmine\lang\LanguageNotFoundException; +use pocketmine\lang\Translatable; use pocketmine\player\GameMode; use pocketmine\Server; use pocketmine\utils\Config; @@ -141,6 +142,18 @@ LICENSE; $this->message($this->lang->translate(KnownTranslationFactory::server_properties())); } + private function askPort(Translatable $prompt, int $default) : int{ + while(true){ + $port = (int) $this->getInput($this->lang->translate($prompt), (string) $default); + if($port <= 0 or $port > 65535){ + $this->error($this->lang->translate(KnownTranslationFactory::invalid_port())); + continue; + } + + return $port; + } + } + private function generateBaseConfig() : void{ $config = new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES); @@ -149,16 +162,8 @@ LICENSE; $this->message($this->lang->translate(KnownTranslationFactory::port_warning())); - do{ - $port = (int) $this->getInput($this->lang->translate(KnownTranslationFactory::server_port()), (string) self::DEFAULT_PORT); - if($port <= 0 or $port > 65535){ - $this->error($this->lang->translate(KnownTranslationFactory::invalid_port())); - continue; - } - - break; - }while(true); - $config->set("server-port", $port); + $config->set("server-port", $this->askPort(KnownTranslationFactory::server_port_v4(), Server::DEFAULT_PORT_IPV4)); + $config->set("server-portv6", $this->askPort(KnownTranslationFactory::server_port_v6(), Server::DEFAULT_PORT_IPV6)); $this->message($this->lang->translate(KnownTranslationFactory::gamemode_info())); From 0da1810aaaf0d9774a6f1011c97a6f336815af1e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 03:12:26 +0000 Subject: [PATCH 531/710] Updated composer dependencies --- composer.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index 1e11bf2e8..4b23a3bb7 100644 --- a/composer.lock +++ b/composer.lock @@ -275,16 +275,16 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "7.0.0+bedrock-1.18.0", + "version": "7.1.0+bedrock-1.18.0", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "040a883a4abb8c9b93114d5278cb5fecc635da82" + "reference": "42f2a00634c17c346fd98c05b2daf29d1fbf5805" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/040a883a4abb8c9b93114d5278cb5fecc635da82", - "reference": "040a883a4abb8c9b93114d5278cb5fecc635da82", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/42f2a00634c17c346fd98c05b2daf29d1fbf5805", + "reference": "42f2a00634c17c346fd98c05b2daf29d1fbf5805", "shasum": "" }, "require": { @@ -316,9 +316,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/7.0.0+bedrock-1.18.0" + "source": "https://github.com/pmmp/BedrockProtocol/tree/7.1.0+bedrock-1.18.0" }, - "time": "2021-11-30T19:02:41+00:00" + "time": "2021-12-15T03:07:05+00:00" }, { "name": "pocketmine/binaryutils", @@ -535,16 +535,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.1.25", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "0c810aaa24baffcccd57ca5bca16ca8f346c483c" + "reference": "dc88ad618a482e55b7c9fec162257efa62a67d6f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/0c810aaa24baffcccd57ca5bca16ca8f346c483c", - "reference": "0c810aaa24baffcccd57ca5bca16ca8f346c483c", + "url": "https://api.github.com/repos/pmmp/Language/zipball/dc88ad618a482e55b7c9fec162257efa62a67d6f", + "reference": "dc88ad618a482e55b7c9fec162257efa62a67d6f", "shasum": "" }, "type": "library", @@ -552,9 +552,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.1.25" + "source": "https://github.com/pmmp/Language/tree/2.2.0" }, - "time": "2021-12-14T00:29:11+00:00" + "time": "2021-12-15T02:01:24+00:00" }, { "name": "pocketmine/log", From 6494375a53e1de091aac7fa6da320cddabe55f0e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 03:15:04 +0000 Subject: [PATCH 532/710] SetupWizard: ask for max view distance --- src/wizard/SetupWizard.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wizard/SetupWizard.php b/src/wizard/SetupWizard.php index 34b145077..a0261501d 100644 --- a/src/wizard/SetupWizard.php +++ b/src/wizard/SetupWizard.php @@ -174,6 +174,8 @@ LICENSE; $config->set("max-players", (int) $this->getInput($this->lang->translate(KnownTranslationFactory::max_players()), (string) self::DEFAULT_PLAYERS)); + $config->set("view-distance", (int) $this->getInput($this->lang->translate(KnownTranslationFactory::view_distance()), (string) Server::DEFAULT_MAX_VIEW_DISTANCE)); + $config->save(); } From 57e1509c3afecacaef0333b76f8b801e90ce788c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 03:24:13 +0000 Subject: [PATCH 533/710] Updated translation APIs --- src/lang/KnownTranslationFactory.php | 12 ++++++++++++ src/lang/KnownTranslationKeys.php | 3 +++ 2 files changed, 15 insertions(+) diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 7b4a6adbd..6c1b2f556 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -2131,6 +2131,14 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::SERVER_PORT, []); } + public static function server_port_v4() : Translatable{ + return new Translatable(KnownTranslationKeys::SERVER_PORT_V4, []); + } + + public static function server_port_v6() : Translatable{ + return new Translatable(KnownTranslationKeys::SERVER_PORT_V6, []); + } + public static function server_properties() : Translatable{ return new Translatable(KnownTranslationKeys::SERVER_PROPERTIES, []); } @@ -2155,6 +2163,10 @@ final class KnownTranslationFactory{ return new Translatable(KnownTranslationKeys::TILE_BED_TOOFAR, []); } + public static function view_distance() : Translatable{ + return new Translatable(KnownTranslationKeys::VIEW_DISTANCE, []); + } + public static function welcome_to_pocketmine(Translatable|string $param0) : Translatable{ return new Translatable(KnownTranslationKeys::WELCOME_TO_POCKETMINE, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 2174e9720..95d9bbccd 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -443,12 +443,15 @@ final class KnownTranslationKeys{ public const QUERY_WARNING1 = "query_warning1"; public const QUERY_WARNING2 = "query_warning2"; public const SERVER_PORT = "server_port"; + public const SERVER_PORT_V4 = "server_port_v4"; + public const SERVER_PORT_V6 = "server_port_v6"; public const SERVER_PROPERTIES = "server_properties"; public const SETTING_UP_SERVER_NOW = "setting_up_server_now"; public const SKIP_INSTALLER = "skip_installer"; public const TILE_BED_NOSLEEP = "tile.bed.noSleep"; public const TILE_BED_OCCUPIED = "tile.bed.occupied"; public const TILE_BED_TOOFAR = "tile.bed.tooFar"; + public const VIEW_DISTANCE = "view_distance"; public const WELCOME_TO_POCKETMINE = "welcome_to_pocketmine"; public const WHITELIST_ENABLE = "whitelist_enable"; public const WHITELIST_INFO = "whitelist_info"; From d487e43766c186ef35f8407b0b02babf556d1a8c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 04:01:40 +0000 Subject: [PATCH 534/710] InGamePacketHandler: fixed block breaking borked by enabling PlayerAuthInputPacket --- .../mcpe/handler/InGamePacketHandler.php | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index ac09d90ee..c8f244ff2 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -37,6 +37,7 @@ use pocketmine\inventory\transaction\TransactionValidationException; use pocketmine\item\VanillaItems; use pocketmine\item\WritableBook; use pocketmine\item\WrittenBook; +use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\StringTag; @@ -83,6 +84,7 @@ use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket; use pocketmine\network\mcpe\protocol\SubClientLoginPacket; use pocketmine\network\mcpe\protocol\TextPacket; use pocketmine\network\mcpe\protocol\types\ActorEvent; +use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds; use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\NetworkInventoryAction; @@ -92,6 +94,8 @@ use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset; use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData; use pocketmine\network\mcpe\protocol\types\PlayerAction; +use pocketmine\network\mcpe\protocol\types\PlayerBlockActionStopBreak; +use pocketmine\network\mcpe\protocol\types\PlayerBlockActionWithBlockInfo; use pocketmine\network\PacketHandlingException; use pocketmine\player\Player; use pocketmine\utils\AssumptionFailedError; @@ -182,7 +186,32 @@ class InGamePacketHandler extends PacketHandler{ //TODO: this packet has WAYYYYY more useful information that we're not using $this->player->handleMovement($newPos); - return true; + $packetHandled = true; + + $useItemTransaction = $packet->getItemInteractionData(); + if($useItemTransaction !== null && !$this->handleUseItemTransaction($useItemTransaction->getTransactionData())){ + $packetHandled = false; + $this->session->getLogger()->debug("Unhandled transaction in PlayerAuthInputPacket (type " . $useItemTransaction->getTransactionData()->getActionType() . ")"); + } + + $blockActions = $packet->getBlockActions(); + if($blockActions !== null){ + foreach($blockActions as $k => $blockAction){ + $actionHandled = false; + if($blockAction instanceof PlayerBlockActionStopBreak){ + $actionHandled = $this->handlePlayerActionFromData($blockAction->getActionType(), new BlockPosition(0, 0, 0), Facing::DOWN); + }elseif($blockAction instanceof PlayerBlockActionWithBlockInfo){ + $actionHandled = $this->handlePlayerActionFromData($blockAction->getActionType(), $blockAction->getBlockPosition(), $blockAction->getFace()); + } + + if(!$actionHandled){ + $packetHandled = false; + $this->session->getLogger()->debug("Unhandled player block action at offset $k in PlayerAuthInputPacket"); + } + } + } + + return $packetHandled; } public function handleLevelSoundEventPacketV1(LevelSoundEventPacketV1 $packet) : bool{ @@ -493,12 +522,16 @@ class InGamePacketHandler extends PacketHandler{ } public function handlePlayerAction(PlayerActionPacket $packet) : bool{ - $pos = new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ()); + return $this->handlePlayerActionFromData($packet->action, $packet->blockPosition, $packet->face); + } - switch($packet->action){ + private function handlePlayerActionFromData(int $action, BlockPosition $blockPosition, int $face) : bool{ + $pos = new Vector3($blockPosition->getX(), $blockPosition->getY(), $blockPosition->getZ()); + + switch($action){ case PlayerAction::START_BREAK: - if(!$this->player->attackBlock($pos, $packet->face)){ - $this->onFailedBlockAction($pos, $packet->face); + if(!$this->player->attackBlock($pos, $face)){ + $this->onFailedBlockAction($pos, $face); } break; @@ -540,7 +573,7 @@ class InGamePacketHandler extends PacketHandler{ case PlayerAction::STOP_GLIDE: break; //TODO case PlayerAction::CRACK_BREAK: - $this->player->continueBreakBlock($pos, $packet->face); + $this->player->continueBreakBlock($pos, $face); break; case PlayerAction::START_SWIMMING: break; //TODO @@ -553,7 +586,7 @@ class InGamePacketHandler extends PacketHandler{ //TODO: do we need to handle this? break; default: - $this->session->getLogger()->debug("Unhandled/unknown player action type " . $packet->action); + $this->session->getLogger()->debug("Unhandled/unknown player action type " . $action); return false; } From de82424fb2c84b022b3429fad98e790e0d7cab85 Mon Sep 17 00:00:00 2001 From: ShockedPlot7560 <66992287+ShockedPlot7560@users.noreply.github.com> Date: Wed, 15 Dec 2021 05:40:46 +0100 Subject: [PATCH 535/710] XpManager: add APIs to prevent owning Human from attracting XP orbs (#4623) Fixes #4589 The following API methods are added: - `XpManager->canAttractXpOrbs()` - `XpManager->setCanAttractXpOrbs()` Possible future scope: flip this on its head to allow spectator players to attract XP orbs, in case someone wants that for some reason ??? Co-authored-by: Dylan K. Taylor --- src/entity/ExperienceManager.php | 11 +++++++++++ src/entity/object/ExperienceOrb.php | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/entity/ExperienceManager.php b/src/entity/ExperienceManager.php index f79fdd95f..c91f9ffee 100644 --- a/src/entity/ExperienceManager.php +++ b/src/entity/ExperienceManager.php @@ -49,6 +49,9 @@ class ExperienceManager{ /** @var int */ private $totalXp = 0; + /** @var bool */ + private $canAttractXpOrbs = true; + /** @var int */ private $xpCooldown = 0; @@ -294,4 +297,12 @@ class ExperienceManager{ $this->xpCooldown = max(0, $this->xpCooldown - $tickDiff); } } + + public function canAttractXpOrbs() : bool{ + return $this->canAttractXpOrbs; + } + + public function setCanAttractXpOrbs(bool $v = true) : void{ + $this->canAttractXpOrbs = $v; + } } diff --git a/src/entity/object/ExperienceOrb.php b/src/entity/object/ExperienceOrb.php index 8011a6a47..ef26ffb0e 100644 --- a/src/entity/object/ExperienceOrb.php +++ b/src/entity/object/ExperienceOrb.php @@ -166,7 +166,7 @@ class ExperienceOrb extends Entity{ } $currentTarget = $this->getTargetPlayer(); - if($currentTarget !== null and (!$currentTarget->isAlive() or $currentTarget->location->distanceSquared($this->location) > self::MAX_TARGET_DISTANCE ** 2)){ + if($currentTarget !== null and (!$currentTarget->isAlive() or !$currentTarget->getXpManager()->canAttractXpOrbs() or $currentTarget->location->distanceSquared($this->location) > self::MAX_TARGET_DISTANCE ** 2)){ $currentTarget = null; } @@ -174,7 +174,7 @@ class ExperienceOrb extends Entity{ if($currentTarget === null){ $newTarget = $this->getWorld()->getNearestEntity($this->location, self::MAX_TARGET_DISTANCE, Human::class); - if($newTarget instanceof Human and !($newTarget instanceof Player and $newTarget->isSpectator())){ + if($newTarget instanceof Human and !($newTarget instanceof Player and $newTarget->isSpectator()) and $newTarget->getXpManager()->canAttractXpOrbs()){ $currentTarget = $newTarget; } } From 482bc462d3ad8815b5a1334f0304972c02ebc4c8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 15 Dec 2021 14:32:50 +0000 Subject: [PATCH 536/710] VersionString: Use multiplication instead of bitshift for version IDs this makes them more recognizable, and also fixes #4630. This is technically a BC break (behavioural change), but since nothing appears to use this functionality anyway except PM itself, I don't think it matters. --- src/utils/VersionString.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/VersionString.php b/src/utils/VersionString.php index 7dae029b5..095be3c2c 100644 --- a/src/utils/VersionString.php +++ b/src/utils/VersionString.php @@ -68,7 +68,7 @@ class VersionString{ } public function getNumber() : int{ - return (($this->major << 9) | ($this->minor << 5) | $this->patch); + return (($this->major * 1_000_000) + ($this->minor * 1_000) + $this->patch); } public function getBaseVersion() : string{ From e70f81a111d045471a04877ba73df67cdefa7d7c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Dec 2021 01:08:23 +0000 Subject: [PATCH 537/710] Updated pocketmine/nbt to 0.3.2 --- composer.json | 2 +- composer.lock | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index c65948459..5499bc07b 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", "pocketmine/math": "^0.4.0", - "pocketmine/nbt": "^0.3.0", + "pocketmine/nbt": "^0.3.2", "pocketmine/raklib": "^0.14.2", "pocketmine/raklib-ipc": "^0.1.0", "pocketmine/snooze": "^0.3.0", diff --git a/composer.lock b/composer.lock index 4b23a3bb7..525636c6c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6a1fde030a0133e4ff23047afab5727e", + "content-hash": "7e9247927fa23baf3e899811c8119f95", "packages": [ { "name": "adhocore/json-comment", @@ -684,16 +684,16 @@ }, { "name": "pocketmine/nbt", - "version": "0.3.1", + "version": "0.3.2", "source": { "type": "git", "url": "https://github.com/pmmp/NBT.git", - "reference": "f43db89b8216b772407cdcedd90147db8eef34bc" + "reference": "3e0d9ef6b6c5fb45e3745a121296e75631b3eefe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/NBT/zipball/f43db89b8216b772407cdcedd90147db8eef34bc", - "reference": "f43db89b8216b772407cdcedd90147db8eef34bc", + "url": "https://api.github.com/repos/pmmp/NBT/zipball/3e0d9ef6b6c5fb45e3745a121296e75631b3eefe", + "reference": "3e0d9ef6b6c5fb45e3745a121296e75631b3eefe", "shasum": "" }, "require": { @@ -702,10 +702,10 @@ "pocketmine/binaryutils": "^0.2.0" }, "require-dev": { - "irstea/phpunit-shim": "^9.5", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.99", - "phpstan/phpstan-strict-rules": "^0.12.4" + "phpstan/phpstan": "1.2.0", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5" }, "type": "library", "autoload": { @@ -720,9 +720,9 @@ "description": "PHP library for working with Named Binary Tags", "support": { "issues": "https://github.com/pmmp/NBT/issues", - "source": "https://github.com/pmmp/NBT/tree/0.3.1" + "source": "https://github.com/pmmp/NBT/tree/0.3.2" }, - "time": "2021-12-06T16:19:10+00:00" + "time": "2021-12-16T01:02:37+00:00" }, { "name": "pocketmine/raklib", From 2955a92837e2554bb2d13eee1df517bec4d7d7d0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Dec 2021 01:19:30 +0000 Subject: [PATCH 538/710] Updated pocketmine/nbt to 0.2.19 --- composer.json | 2 +- composer.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index ab792210b..9517df926 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "pocketmine/log": "^0.2.0", "pocketmine/log-pthreads": "^0.1.0", "pocketmine/math": "^0.2.0", - "pocketmine/nbt": "^0.2.18", + "pocketmine/nbt": "^0.2.19", "pocketmine/raklib": "^0.12.7", "pocketmine/snooze": "^0.1.0", "pocketmine/spl": "^0.4.0" diff --git a/composer.lock b/composer.lock index e948d9abf..ee5297b91 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2d144524b177c9e7f699ba7366c16354", + "content-hash": "03871ed11c5fe042f6417bceefe9bd4a", "packages": [ { "name": "adhocore/json-comment", @@ -322,16 +322,16 @@ }, { "name": "pocketmine/nbt", - "version": "0.2.18", + "version": "0.2.19", "source": { "type": "git", "url": "https://github.com/pmmp/NBT.git", - "reference": "9f82ca4d7f97fcd9a566e44b63c4f18a7657ae82" + "reference": "8567c65e8e099c2f7436cfea3d886b3dcd332283" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/NBT/zipball/9f82ca4d7f97fcd9a566e44b63c4f18a7657ae82", - "reference": "9f82ca4d7f97fcd9a566e44b63c4f18a7657ae82", + "url": "https://api.github.com/repos/pmmp/NBT/zipball/8567c65e8e099c2f7436cfea3d886b3dcd332283", + "reference": "8567c65e8e099c2f7436cfea3d886b3dcd332283", "shasum": "" }, "require": { @@ -343,7 +343,7 @@ "require-dev": { "irstea/phpunit-shim": "^7.5 || ^8.0", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.80", + "phpstan/phpstan": "0.12.85", "phpstan/phpstan-strict-rules": "^0.12.4" }, "type": "library", @@ -359,9 +359,9 @@ "description": "PHP library for working with Named Binary Tags", "support": { "issues": "https://github.com/pmmp/NBT/issues", - "source": "https://github.com/pmmp/NBT/tree/0.2.18" + "source": "https://github.com/pmmp/NBT/tree/0.2.19" }, - "time": "2021-03-11T00:09:04+00:00" + "time": "2021-12-16T01:15:41+00:00" }, { "name": "pocketmine/raklib", From 3d205c6e5f98bd2989166d80d3a662d432a5170b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Dec 2021 01:20:05 +0000 Subject: [PATCH 539/710] Updated transient dependency junk --- composer.lock | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/composer.lock b/composer.lock index ee5297b91..b6cbb4d18 100644 --- a/composer.lock +++ b/composer.lock @@ -618,16 +618,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.1", + "version": "v4.13.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd" + "reference": "210577fe3cf7badcc5814d99455df46564f3c077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd", - "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077", "shasum": "" }, "require": { @@ -668,9 +668,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" }, - "time": "2021-11-03T20:52:16+00:00" + "time": "2021-11-30T19:35:32+00:00" }, { "name": "phar-io/manifest", @@ -945,16 +945,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", - "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", "shasum": "" }, "require": { @@ -1006,9 +1006,9 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.14.0" + "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" }, - "time": "2021-09-10T09:02:12+00:00" + "time": "2021-12-08T12:19:24+00:00" }, { "name": "phpstan/phpstan", @@ -1182,16 +1182,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.9", + "version": "9.2.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b" + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", - "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687", + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687", "shasum": "" }, "require": { @@ -1247,7 +1247,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10" }, "funding": [ { @@ -1255,20 +1255,20 @@ "type": "github" } ], - "time": "2021-11-19T15:21:02+00:00" + "time": "2021-12-05T09:12:13+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.5", + "version": "3.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { @@ -1307,7 +1307,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" }, "funding": [ { @@ -1315,7 +1315,7 @@ "type": "github" } ], - "time": "2020-09-28T05:57:25+00:00" + "time": "2021-12-02T12:48:52+00:00" }, { "name": "phpunit/php-invoker", From 75a72786f903eaab8e65895f3a9e44c18b9a9fa8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Dec 2021 01:23:21 +0000 Subject: [PATCH 540/710] Release 3.26.4 --- changelogs/3.26.md | 5 +++++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/changelogs/3.26.md b/changelogs/3.26.md index 86a3a2d2e..35b840a98 100644 --- a/changelogs/3.26.md +++ b/changelogs/3.26.md @@ -21,3 +21,8 @@ Plugin developers should **only** update their required API to this version if y # 3.26.3 - `PlayerExperienceChangeEvent->setNewProgress()` now performs range checks. This fixes the root of a very old and confusing crash bug which took several years to identify the cause of. - Note that the defective plugin(s) which caused this problem will still cause a server crash, but the plugin responsible will now get blamed correctly. + +# 3.26.4 +- Fixed skins appearing black when using RTX resource packs. +- Fixed chunks containing furnaces in old worlds (pre-2017) being discarded as corrupted. + - This was caused by a strict corruption check detecting bad data created by a bug in PocketMine-MP that was fixed in 2017. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 31fcdcb9e..1f69ea55f 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,5 +34,5 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.26.4"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_CHANNEL = "pm3"; From 9979a64ad2f2ba37b48aca34190b6c5205196300 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Dec 2021 01:23:22 +0000 Subject: [PATCH 541/710] 3.26.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 1f69ea55f..ae075617b 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.26.4"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.26.5"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_CHANNEL = "pm3"; From 795ebd182461f96beeb47b067f7fe33e76bc9059 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Dec 2021 01:35:42 +0000 Subject: [PATCH 542/710] Release 4.0.3 --- changelogs/4.0.md | 11 +++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 2ba259372..9cd1d089f 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1565,3 +1565,14 @@ Released 12th December 2021. - `PlayerExperienceChangeEvent->setNewProgress()` now performs range checks. This fixes the root of a very old and confusing crash bug which took several years to identify the cause of. - Note that the defective plugin(s) which caused this problem will still cause a server crash, but the plugin responsible will now get blamed correctly. - `GeneratorManager->addGenerator()` now consistently converts the given alias to lowercase. Due to a bug, it previously didn't do this if the `$overwrite` parameter was set to `true`, causing a range of confusing bugs. + +# 4.0.3 +Released 16th December 2021. + +## Fixes +- Fixed `/dumpmemory` crashing when encountering uninitialized typed properties. +- Fixed all chunks containing furnaces being treated as corrupted in worlds older than 2017. + - This was caused by a strict corruption check detecting bad data created by a bug in PocketMine-MP that was fixed in 2017. +- Fixed player arm swing animation not being shown when attacks were cancelled by attack cooldown. +- Fixed being unable to use `/deop` to de-op a player whose name appeared in `ops.txt` with uppercase letters in it. +- Added a check for valid tile class in `BlockIdentifier`. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index dec840bca..5583ec51d 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.3"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; private function __construct(){ From e6e1bca6763d1e7f10b044c27476ca06693be7bb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Dec 2021 01:35:43 +0000 Subject: [PATCH 543/710] 4.0.4 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 5583ec51d..066bdb730 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.3"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.4"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From aa56c66a3c6c2b53f120372ea2550fff81f91a8d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Dec 2021 18:46:34 +0000 Subject: [PATCH 544/710] ProcessLoginTask: drop usage of no-op method this is no longer useful since 8.0. --- src/network/mcpe/auth/ProcessLoginTask.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/network/mcpe/auth/ProcessLoginTask.php b/src/network/mcpe/auth/ProcessLoginTask.php index c0e537c64..15cafe952 100644 --- a/src/network/mcpe/auth/ProcessLoginTask.php +++ b/src/network/mcpe/auth/ProcessLoginTask.php @@ -33,7 +33,6 @@ use function base64_decode; use function igbinary_serialize; use function igbinary_unserialize; use function openssl_error_string; -use function openssl_free_key; use function time; class ProcessLoginTask extends AsyncTask{ @@ -158,8 +157,6 @@ class ProcessLoginTask extends AsyncTask{ throw new VerifyLoginException($e->getMessage(), 0, $e); } - @openssl_free_key($signingKeyOpenSSL); - if($headers->x5u === self::MOJANG_ROOT_PUBLIC_KEY){ $this->authenticated = true; //we're signed into xbox live } From 1ab285f5731a585badb245b8fde6722c9ac9ab74 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 16 Dec 2021 18:47:50 +0000 Subject: [PATCH 545/710] PrepareEncryptionTask: remove usage of no-op function --- src/network/mcpe/encryption/PrepareEncryptionTask.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/network/mcpe/encryption/PrepareEncryptionTask.php b/src/network/mcpe/encryption/PrepareEncryptionTask.php index 75b3b1f1c..7b2bee0e8 100644 --- a/src/network/mcpe/encryption/PrepareEncryptionTask.php +++ b/src/network/mcpe/encryption/PrepareEncryptionTask.php @@ -29,7 +29,6 @@ use pocketmine\utils\AssumptionFailedError; use function igbinary_serialize; use function igbinary_unserialize; use function openssl_error_string; -use function openssl_free_key; use function openssl_pkey_get_details; use function openssl_pkey_new; use function random_bytes; @@ -78,9 +77,6 @@ class PrepareEncryptionTask extends AsyncTask{ $salt = random_bytes(16); $this->aesKey = EncryptionUtils::generateKey($sharedSecret, $salt); $this->handshakeJwt = EncryptionUtils::generateServerHandshakeJwt($serverPriv, $salt); - - @openssl_free_key($serverPriv); - @openssl_free_key($clientPub); } public function onCompletion() : void{ From fc3a6c6984a6f8334808df5e9033d7db2da36294 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Thu, 16 Dec 2021 23:36:34 +0000 Subject: [PATCH 546/710] Implemented fire spread (#4617) --- src/block/Fire.php | 64 +++++++++++++++++++++- tests/phpstan/configs/actual-problems.neon | 30 ++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/block/Fire.php b/src/block/Fire.php index 0e2410341..adf6209a3 100644 --- a/src/block/Fire.php +++ b/src/block/Fire.php @@ -33,6 +33,10 @@ use pocketmine\event\entity\EntityDamageByBlockEvent; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\item\Item; use pocketmine\math\Facing; +use pocketmine\world\format\Chunk; +use pocketmine\world\World; +use function intdiv; +use function max; use function min; use function mt_rand; @@ -139,7 +143,7 @@ class Fire extends Flowable{ if($canSpread){ $this->burnBlocksAround(); - //TODO: fire spread + $this->spreadFire(); } } @@ -189,6 +193,64 @@ class Fire extends Flowable{ } } + private function spreadFire() : void{ + $world = $this->position->getWorld(); + $difficultyChanceIncrease = $world->getDifficulty() * 7; + $ageDivisor = $this->age + 30; + + for($y = -1; $y <= 4; ++$y){ + $targetY = $y + (int) $this->position->y; + if($targetY < World::Y_MIN || $targetY >= World::Y_MAX){ + continue; + } + //Higher blocks have a lower chance of catching fire + $randomBound = 100 + ($y > 1 ? ($y - 1) * 100 : 0); + + for($z = -1; $z <= 1; ++$z){ + $targetZ = $z + (int) $this->position->z; + for($x = -1; $x <= 1; ++$x){ + if($x === 0 and $y === 0 and $z === 0){ + continue; + } + $targetX = $x + (int) $this->position->x; + if(!$world->isInWorld($targetX, $targetY, $targetZ)){ + continue; + } + + if(!$world->isChunkLoaded($targetX >> Chunk::COORD_BIT_SIZE, $targetZ >> Chunk::COORD_BIT_SIZE)){ + continue; + } + $block = $world->getBlockAt($targetX, $targetY, $targetZ); + if($block->getId() !== BlockLegacyIds::AIR){ + continue; + } + + //TODO: fire can't spread if it's raining in any horizontally adjacent block, or the current one + + $encouragement = 0; + foreach($block->position->sides() as $vector3){ + if($world->isInWorld($vector3->x, $vector3->y, $vector3->z)){ + $encouragement = max($encouragement, $world->getBlockAt($vector3->x, $vector3->y, $vector3->z)->getFlameEncouragement()); + } + } + + if($encouragement <= 0){ + continue; + } + + $maxChance = intdiv($encouragement + 40 + $difficultyChanceIncrease, $ageDivisor); + //TODO: max chance is lowered by half in humid biomes + + if($maxChance > 0 and mt_rand(0, $randomBound - 1) <= $maxChance){ + $new = clone $this; + $new->age = min(15, $this->age + (mt_rand(0, 4) >> 2)); + $this->spreadBlock($block, $new); + } + } + } + } + } + private function spreadBlock(Block $block, Block $newState) : bool{ $ev = new BlockSpreadEvent($block, $this, $newState); $ev->call(); diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index ae07a0bd9..77f3e5d77 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -165,6 +165,36 @@ parameters: count: 1 path: ../../../src/block/Farmland.php + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/block/Fire.php + + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/block/Fire.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/block/Fire.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/block/Fire.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/block/Fire.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:isInWorld\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/block/Fire.php + - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockAt\\(\\) expects int, float\\|int given\\.$#" count: 1 From 93caf72f34910d74eb9d3b849115bc5238022b42 Mon Sep 17 00:00:00 2001 From: Alexey Date: Fri, 17 Dec 2021 23:33:20 +0300 Subject: [PATCH 547/710] KickCommand: Add missing space closes #4660 closes #4661 --- src/command/defaults/KickCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/defaults/KickCommand.php b/src/command/defaults/KickCommand.php index a341ca64b..7952c522e 100644 --- a/src/command/defaults/KickCommand.php +++ b/src/command/defaults/KickCommand.php @@ -59,7 +59,7 @@ class KickCommand extends VanillaCommand{ $reason = trim(implode(" ", $args)); if(($player = $sender->getServer()->getPlayerByPrefix($name)) instanceof Player){ - $player->kick("Kicked by admin." . ($reason !== "" ? "Reason: " . $reason : "")); + $player->kick("Kicked by admin." . ($reason !== "" ? " Reason: " . $reason : "")); if($reason !== ""){ Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_kick_success_reason($player->getName(), $reason)); }else{ From e3614d1a825e4a8cb9ba4114b7265cb610280281 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 18 Dec 2021 22:38:45 +0000 Subject: [PATCH 548/710] Entity: fixed game performance issue with large scale entities this->size refers to the scaled height, but the client wants the base (unscaled) size in these properties. This caused immense lag when, for example, setting the scale of a player to 10, because their collision box would become 180 by 60, instead of the expected 18 by 6. --- src/entity/Entity.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index a431e3ecc..2dfaf13e4 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -1589,8 +1589,8 @@ abstract class Entity{ protected function syncNetworkData(EntityMetadataCollection $properties) : void{ $properties->setByte(EntityMetadataProperties::ALWAYS_SHOW_NAMETAG, $this->alwaysShowNameTag ? 1 : 0); - $properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_HEIGHT, $this->size->getHeight()); - $properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_WIDTH, $this->size->getWidth()); + $properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_HEIGHT, $this->size->getHeight() / $this->scale); + $properties->setFloat(EntityMetadataProperties::BOUNDING_BOX_WIDTH, $this->size->getWidth() / $this->scale); $properties->setFloat(EntityMetadataProperties::SCALE, $this->scale); $properties->setLong(EntityMetadataProperties::LEAD_HOLDER_EID, -1); $properties->setLong(EntityMetadataProperties::OWNER_EID, $this->ownerId ?? -1); From 44e8603a6d488a2ac0abfcecf1b0ed4db26ad224 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Dec 2021 00:52:53 +0000 Subject: [PATCH 549/710] InGamePacketHandler: fixed borked sneak/sprint after switch to PlayerAuthInputPacket closes #4659 --- .../mcpe/handler/InGamePacketHandler.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index c8f244ff2..52fc9e2e3 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -94,6 +94,7 @@ use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset; use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData; use pocketmine\network\mcpe\protocol\types\PlayerAction; +use pocketmine\network\mcpe\protocol\types\PlayerAuthInputFlags; use pocketmine\network\mcpe\protocol\types\PlayerBlockActionStopBreak; use pocketmine\network\mcpe\protocol\types\PlayerBlockActionWithBlockInfo; use pocketmine\network\PacketHandlingException; @@ -154,6 +155,15 @@ class InGamePacketHandler extends PacketHandler{ return false; } + private function resolveOnOffInputFlags(PlayerAuthInputPacket $packet, int $startFlag, int $stopFlag) : ?bool{ + $enabled = $packet->hasFlag($startFlag); + if($enabled !== $packet->hasFlag($stopFlag)){ + return $enabled; + } + //neither flag was set, or both were set + return null; + } + public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{ $rawPos = $packet->getPosition(); foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->getYaw(), $packet->getHeadYaw(), $packet->getPitch()] as $float){ @@ -183,6 +193,16 @@ class InGamePacketHandler extends PacketHandler{ // Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock $this->forceMoveSync = false; + $sneaking = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING); + if($sneaking !== null){ + $this->player->toggleSneak($sneaking); + } + $sprinting = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING); + if($sprinting !== null){ + $this->player->toggleSprint($sprinting); + } + //TODO: swimming, gliding + //TODO: this packet has WAYYYYY more useful information that we're not using $this->player->handleMovement($newPos); From 65dabefa3b8365ba6de374bc89fd17cb2747f963 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Dec 2021 16:49:54 +0000 Subject: [PATCH 550/710] Config: improve config loading and parsing error handling closes #4654 closes #3454 --- composer.json | 2 +- composer.lock | 16 ++++++------- src/utils/Config.php | 26 +++++++++++++++++---- src/utils/ConfigLoadException.php | 31 +++++++++++++++++++++++++ tests/phpstan/configs/phpstan-bugs.neon | 5 ++++ 5 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 src/utils/ConfigLoadException.php diff --git a/composer.json b/composer.json index c5486663d..57b20e903 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", - "pocketmine/errorhandler": "^0.3.0", + "pocketmine/errorhandler": "^0.4.0", "pocketmine/locale-data": "^2.2.0", "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", diff --git a/composer.lock b/composer.lock index e5dc6dffc..2b6a1be72 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "eff9aac3494dbd6798ed7bb62f962ae9", + "content-hash": "f830ed22b7f602d1b03f52118371d559", "packages": [ { "name": "adhocore/json-comment", @@ -497,23 +497,23 @@ }, { "name": "pocketmine/errorhandler", - "version": "0.3.0", + "version": "0.4.0", "source": { "type": "git", "url": "https://github.com/pmmp/ErrorHandler.git", - "reference": "ec742b209e8056bbe855069c4eff94c9734ea19b" + "reference": "5bb9e2b66551ef7383da85165b7e8a7cc9aa162a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/ErrorHandler/zipball/ec742b209e8056bbe855069c4eff94c9734ea19b", - "reference": "ec742b209e8056bbe855069c4eff94c9734ea19b", + "url": "https://api.github.com/repos/pmmp/ErrorHandler/zipball/5bb9e2b66551ef7383da85165b7e8a7cc9aa162a", + "reference": "5bb9e2b66551ef7383da85165b7e8a7cc9aa162a", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "0.12.75", + "phpstan/phpstan": "0.12.99", "phpstan/phpstan-strict-rules": "^0.12.2" }, "type": "library", @@ -529,9 +529,9 @@ "description": "Utilities to handle nasty PHP E_* errors in a usable way", "support": { "issues": "https://github.com/pmmp/ErrorHandler/issues", - "source": "https://github.com/pmmp/ErrorHandler/tree/0.3.0" + "source": "https://github.com/pmmp/ErrorHandler/tree/0.4.0" }, - "time": "2021-02-12T18:56:22+00:00" + "time": "2021-12-16T18:13:42+00:00" }, { "name": "pocketmine/locale-data", diff --git a/src/utils/Config.php b/src/utils/Config.php index 49f111728..78bd4c955 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\utils; +use pocketmine\errorhandler\ErrorToExceptionHandler; use Webmozart\PathUtil\Path; use function array_change_key_case; use function array_fill_keys; @@ -33,6 +34,7 @@ use function date; use function explode; use function file_exists; use function file_get_contents; +use function get_debug_type; use function implode; use function is_array; use function is_bool; @@ -167,20 +169,31 @@ class Config{ if($content === false){ throw new \RuntimeException("Unable to load config file"); } - $config = null; switch($this->type){ case Config::PROPERTIES: $config = self::parseProperties($content); break; case Config::JSON: - $config = json_decode($content, true); + try{ + $config = json_decode($content, true, flags: JSON_THROW_ON_ERROR); + }catch(\JsonException $e){ + throw ConfigLoadException::wrap($this->file, $e); + } break; case Config::YAML: $content = self::fixYAMLIndexes($content); - $config = yaml_parse($content); + try{ + $config = ErrorToExceptionHandler::trap(fn() => yaml_parse($content)); + }catch(\ErrorException $e){ + throw ConfigLoadException::wrap($this->file, $e); + } break; case Config::SERIALIZED: - $config = unserialize($content); + try{ + $config = ErrorToExceptionHandler::trap(fn() => unserialize($content)); + }catch(\ErrorException $e){ + throw ConfigLoadException::wrap($this->file, $e); + } break; case Config::ENUM: $config = array_fill_keys(self::parseList($content), true); @@ -188,7 +201,10 @@ class Config{ default: throw new \InvalidArgumentException("Invalid config type specified"); } - $this->config = is_array($config) ? $config : $default; + if(!is_array($config)){ + throw new ConfigLoadException("Failed to load config $this->file: Expected array for base type, but got " . get_debug_type($config)); + } + $this->config = $config; if($this->fillDefaults($default, $this->config) > 0){ $this->save(); } diff --git a/src/utils/ConfigLoadException.php b/src/utils/ConfigLoadException.php new file mode 100644 index 000000000..d5644859e --- /dev/null +++ b/src/utils/ConfigLoadException.php @@ -0,0 +1,31 @@ +getMessage(), 0, $e); + } +} \ No newline at end of file diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 0d98c3677..3ff25c7e8 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -35,6 +35,11 @@ parameters: count: 1 path: ../../../src/plugin/ScriptPluginLoader.php + - + message: "#^Dead catch \\- JsonException is never thrown in the try block\\.$#" + count: 1 + path: ../../../src/utils/Config.php + - message: "#^Strict comparison using \\=\\=\\= between string and false will always evaluate to false\\.$#" count: 1 From d41f933e7be7236a5a14f73ffb5849cf3135abe0 Mon Sep 17 00:00:00 2001 From: XenialDan Date: Sun, 19 Dec 2021 18:10:41 +0100 Subject: [PATCH 551/710] Implement swimming/gliding including AABB recalculation (#4446) - The following events have been added: - PlayerToggleGlideEvent - PlayerToggleSwimEvent - The following API methods have been added: - Entity->getSize() - Living->isSwimming() - Living->setSwimming() - Living->isGliding() - Living->setSwimming() - Player->toggleSwim() - Player->toggleGlide() --- src/entity/Entity.php | 16 +++++--- src/entity/Living.php | 37 +++++++++++++++++ src/event/player/PlayerToggleGlideEvent.php | 40 +++++++++++++++++++ src/event/player/PlayerToggleSwimEvent.php | 40 +++++++++++++++++++ .../mcpe/handler/InGamePacketHandler.php | 20 ++++++++-- src/player/Player.php | 22 ++++++++++ 6 files changed, 166 insertions(+), 9 deletions(-) create mode 100644 src/event/player/PlayerToggleGlideEvent.php create mode 100644 src/event/player/PlayerToggleSwimEvent.php diff --git a/src/entity/Entity.php b/src/entity/Entity.php index a431e3ecc..d492b77e0 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -304,12 +304,8 @@ abstract class Entity{ if($value <= 0){ throw new \InvalidArgumentException("Scale must be greater than 0"); } - $this->size = $this->getInitialSizeInfo()->scale($value); - $this->scale = $value; - - $this->recalculateBoundingBox(); - $this->networkPropertiesDirty = true; + $this->setSize($this->getInitialSizeInfo()->scale($value)); } public function getBoundingBox() : AxisAlignedBB{ @@ -329,6 +325,16 @@ abstract class Entity{ ); } + public function getSize() : EntitySizeInfo{ + return $this->size; + } + + protected function setSize(EntitySizeInfo $size) : void{ + $this->size = $size; + $this->recalculateBoundingBox(); + $this->networkPropertiesDirty = true; + } + public function isImmobile() : bool{ return $this->immobile; } diff --git a/src/entity/Living.php b/src/entity/Living.php index 401bd051d..a5b6101c9 100644 --- a/src/entity/Living.php +++ b/src/entity/Living.php @@ -116,6 +116,10 @@ abstract class Living extends Entity{ protected $sprinting = false; /** @var bool */ protected $sneaking = false; + /** @var bool */ + protected $gliding = false; + /** @var bool */ + protected $swimming = false; abstract public function getName() : string; @@ -227,6 +231,37 @@ abstract class Living extends Entity{ } } + public function isGliding() : bool{ + return $this->gliding; + } + + public function setGliding(bool $value = true) : void{ + $this->gliding = $value; + $this->networkPropertiesDirty = true; + $this->recalculateSize(); + } + + public function isSwimming() : bool{ + return $this->swimming; + } + + public function setSwimming(bool $value = true) : void{ + $this->swimming = $value; + $this->networkPropertiesDirty = true; + $this->recalculateSize(); + } + + private function recalculateSize() : void{ + $size = $this->getInitialSizeInfo(); + if($this->isSwimming() || $this->isGliding()){ + $width = $size->getWidth(); + //we don't actually know an appropriate eye height for a swimming mob, but 2/3 should be good enough. + $this->setSize((new EntitySizeInfo($width, $width, $width * 2 / 3))->scale($this->getScale())); + }else{ + $this->setSize($size->scale($this->getScale())); + } + } + public function getMovementSpeed() : float{ return $this->moveSpeedAttr->getValue(); } @@ -800,6 +835,8 @@ abstract class Living extends Entity{ $properties->setGenericFlag(EntityMetadataFlags::BREATHING, $this->breathing); $properties->setGenericFlag(EntityMetadataFlags::SNEAKING, $this->sneaking); $properties->setGenericFlag(EntityMetadataFlags::SPRINTING, $this->sprinting); + $properties->setGenericFlag(EntityMetadataFlags::GLIDING, $this->gliding); + $properties->setGenericFlag(EntityMetadataFlags::SWIMMING, $this->swimming); } protected function onDispose() : void{ diff --git a/src/event/player/PlayerToggleGlideEvent.php b/src/event/player/PlayerToggleGlideEvent.php new file mode 100644 index 000000000..c8baabd9f --- /dev/null +++ b/src/event/player/PlayerToggleGlideEvent.php @@ -0,0 +1,40 @@ +player = $player; + } + + public function isGliding() : bool{ + return $this->isGliding; + } +} diff --git a/src/event/player/PlayerToggleSwimEvent.php b/src/event/player/PlayerToggleSwimEvent.php new file mode 100644 index 000000000..382b3c687 --- /dev/null +++ b/src/event/player/PlayerToggleSwimEvent.php @@ -0,0 +1,40 @@ +player = $player; + } + + public function isSwimming() : bool{ + return $this->isSwimming; + } +} diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 52fc9e2e3..f63487ebf 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -590,16 +590,28 @@ class InGamePacketHandler extends PacketHandler{ } return true; case PlayerAction::START_GLIDE: + if(!$this->player->toggleGlide(true)){ + $this->player->sendData([$this->player]); + } + return true; case PlayerAction::STOP_GLIDE: - break; //TODO + if(!$this->player->toggleGlide(false)){ + $this->player->sendData([$this->player]); + } + return true; case PlayerAction::CRACK_BREAK: $this->player->continueBreakBlock($pos, $face); break; case PlayerAction::START_SWIMMING: - break; //TODO + if(!$this->player->toggleSwim(true)){ + $this->player->sendData([$this->player]); + } + return true; case PlayerAction::STOP_SWIMMING: - //TODO: handle this when it doesn't spam every damn tick (yet another spam bug!!) - break; + if(!$this->player->toggleSwim(false)){ + $this->player->sendData([$this->player]); + } + return true; case PlayerAction::INTERACT_BLOCK: //TODO: ignored (for now) break; case PlayerAction::CREATIVE_PLAYER_DESTROY_BLOCK: diff --git a/src/player/Player.php b/src/player/Player.php index bdbec0bb3..400a254c2 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -68,8 +68,10 @@ use pocketmine\event\player\PlayerMoveEvent; use pocketmine\event\player\PlayerQuitEvent; use pocketmine\event\player\PlayerRespawnEvent; use pocketmine\event\player\PlayerToggleFlightEvent; +use pocketmine\event\player\PlayerToggleGlideEvent; use pocketmine\event\player\PlayerToggleSneakEvent; use pocketmine\event\player\PlayerToggleSprintEvent; +use pocketmine\event\player\PlayerToggleSwimEvent; use pocketmine\event\player\PlayerTransferEvent; use pocketmine\form\Form; use pocketmine\form\FormValidationException; @@ -1768,6 +1770,26 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ return true; } + public function toggleGlide(bool $glide) : bool{ + $ev = new PlayerToggleGlideEvent($this, $glide); + $ev->call(); + if($ev->isCancelled()){ + return false; + } + $this->setGliding($glide); + return true; + } + + public function toggleSwim(bool $swimming) : bool{ + $ev = new PlayerToggleSwimEvent($this, $swimming); + $ev->call(); + if($ev->isCancelled()){ + return false; + } + $this->setSwimming($swimming); + return true; + } + public function emote(string $emoteId) : void{ $currentTick = $this->server->getTick(); if($currentTick - $this->lastEmoteTick > 5){ From 18e26d975bb4656a251f26fe1cc2fc14b4ae512d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 19 Dec 2021 17:31:47 +0000 Subject: [PATCH 552/710] Fixed swimming and gliding for PlayerAuthInputPacket --- src/network/mcpe/handler/InGamePacketHandler.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index f63487ebf..825da1a65 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -201,7 +201,14 @@ class InGamePacketHandler extends PacketHandler{ if($sprinting !== null){ $this->player->toggleSprint($sprinting); } - //TODO: swimming, gliding + $swimming = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING); + if($swimming !== null){ + $this->player->toggleSwim($swimming); + } + $gliding = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING); + if($gliding !== null){ + $this->player->toggleGlide($gliding); + } //TODO: this packet has WAYYYYY more useful information that we're not using $this->player->handleMovement($newPos); From 091673d8f1dd645e58dbdda50a541d89dc7277f4 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 24 Dec 2021 00:52:07 +0100 Subject: [PATCH 553/710] Fixed "You can only sleep at night" message (#4671) --- src/block/Bed.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/block/Bed.php b/src/block/Bed.php index fe419547a..731cf664e 100644 --- a/src/block/Bed.php +++ b/src/block/Bed.php @@ -145,7 +145,7 @@ class Bed extends Transparent{ $isNight = ($time >= World::TIME_NIGHT and $time < World::TIME_SUNRISE); if(!$isNight){ - $player->sendMessage(KnownTranslationFactory::tile_bed_tooFar()->prefix(TextFormat::GRAY)); + $player->sendMessage(KnownTranslationFactory::tile_bed_noSleep()->prefix(TextFormat::GRAY)); return true; } From b55aa78aec5b7eb09a22f11d72ff17d184ecf3b1 Mon Sep 17 00:00:00 2001 From: Duo Incure Date: Mon, 27 Dec 2021 15:33:02 +0000 Subject: [PATCH 554/710] Changelog: Replaced non-existent method (#4676) --- changelogs/4.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 9cd1d089f..541bc3826 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -496,7 +496,7 @@ However, if we add `src-namespace-prefix: pmmp\TesterPlugin` to the `plugin.yml` - `Human->onPickupXp()` -> `ExperienceManager->onPickupXp()` - `Human->resetXpCooldown()` -> `ExperienceManager->resetXpCooldown()` - The following API methods have been removed: - - `Human->getRawUniqueId()`: use `Human->getUniqueId()->toBinary()` instead + - `Human->getRawUniqueId()`: use `Human->getUniqueId()->getBytes()` instead - The following classes have been removed: - `Creature` - `Damageable` From 95b6cb21f2932e25f645f909ac9f011377f89a43 Mon Sep 17 00:00:00 2001 From: Dries C Date: Mon, 27 Dec 2021 17:36:59 +0100 Subject: [PATCH 555/710] Implement BlockMeltEvent (#4666) --- src/block/Ice.php | 7 ++++++- src/block/SnowLayer.php | 7 ++++++- src/event/block/BlockMeltEvent.php | 31 ++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/event/block/BlockMeltEvent.php diff --git a/src/block/Ice.php b/src/block/Ice.php index c1156fffa..f41426ead 100644 --- a/src/block/Ice.php +++ b/src/block/Ice.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\event\block\BlockMeltEvent; use pocketmine\item\enchantment\VanillaEnchantments; use pocketmine\item\Item; use pocketmine\player\Player; @@ -51,7 +52,11 @@ class Ice extends Transparent{ public function onRandomTick() : void{ if($this->position->getWorld()->getHighestAdjacentBlockLight($this->position->x, $this->position->y, $this->position->z) >= 12){ - $this->position->getWorld()->useBreakOn($this->position); + $ev = new BlockMeltEvent($this, VanillaBlocks::WATER()); + $ev->call(); + if(!$ev->isCancelled()){ + $this->position->getWorld()->setBlock($this->position, $ev->getNewState()); + } } } diff --git a/src/block/SnowLayer.php b/src/block/SnowLayer.php index c901e9d0c..4bea77df5 100644 --- a/src/block/SnowLayer.php +++ b/src/block/SnowLayer.php @@ -26,6 +26,7 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\Fallable; use pocketmine\block\utils\FallableTrait; +use pocketmine\event\block\BlockMeltEvent; use pocketmine\item\Item; use pocketmine\item\VanillaItems; use pocketmine\math\AxisAlignedBB; @@ -100,7 +101,11 @@ class SnowLayer extends Flowable implements Fallable{ public function onRandomTick() : void{ if($this->position->getWorld()->getBlockLightAt($this->position->x, $this->position->y, $this->position->z) >= 12){ - $this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR(), false); + $ev = new BlockMeltEvent($this, VanillaBlocks::AIR()); + $ev->call(); + if(!$ev->isCancelled()){ + $this->position->getWorld()->setBlock($this->position, $ev->getNewState()); + } } } diff --git a/src/event/block/BlockMeltEvent.php b/src/event/block/BlockMeltEvent.php new file mode 100644 index 000000000..a3b2f8fc7 --- /dev/null +++ b/src/event/block/BlockMeltEvent.php @@ -0,0 +1,31 @@ + Date: Mon, 27 Dec 2021 16:43:19 +0000 Subject: [PATCH 556/710] Bump phpunit/phpunit from 9.5.10 to 9.5.11 (#4675) Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.10 to 9.5.11. - [Release notes](https://github.com/sebastianbergmann/phpunit/releases) - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.10...9.5.11) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.lock b/composer.lock index 525636c6c..2a17a08cc 100644 --- a/composer.lock +++ b/composer.lock @@ -2388,16 +2388,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.10", + "version": "9.5.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a" + "reference": "2406855036db1102126125537adb1406f7242fdd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a", - "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2406855036db1102126125537adb1406f7242fdd", + "reference": "2406855036db1102126125537adb1406f7242fdd", "shasum": "" }, "require": { @@ -2475,11 +2475,11 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.11" }, "funding": [ { - "url": "https://phpunit.de/donate.html", + "url": "https://phpunit.de/sponsors.html", "type": "custom" }, { @@ -2487,7 +2487,7 @@ "type": "github" } ], - "time": "2021-09-25T07:38:51+00:00" + "time": "2021-12-25T07:07:57+00:00" }, { "name": "sebastian/cli-parser", From 0da29beb1dea02f241538886f0b730c0a64dc6c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Dec 2021 16:43:32 +0000 Subject: [PATCH 557/710] Bump pocketmine/locale-data from 2.2.0 to 2.2.1 (#4667) Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.2.0 to 2.2.1. - [Release notes](https://github.com/pmmp/Language/releases) - [Commits](https://github.com/pmmp/Language/compare/2.2.0...2.2.1) --- updated-dependencies: - dependency-name: pocketmine/locale-data dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 2a17a08cc..9cf41a544 100644 --- a/composer.lock +++ b/composer.lock @@ -535,16 +535,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.2.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "dc88ad618a482e55b7c9fec162257efa62a67d6f" + "reference": "9fdd36f0ac3a2dfe1acacbee8b23eb6615129701" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/dc88ad618a482e55b7c9fec162257efa62a67d6f", - "reference": "dc88ad618a482e55b7c9fec162257efa62a67d6f", + "url": "https://api.github.com/repos/pmmp/Language/zipball/9fdd36f0ac3a2dfe1acacbee8b23eb6615129701", + "reference": "9fdd36f0ac3a2dfe1acacbee8b23eb6615129701", "shasum": "" }, "type": "library", @@ -552,9 +552,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.2.0" + "source": "https://github.com/pmmp/Language/tree/2.2.1" }, - "time": "2021-12-15T02:01:24+00:00" + "time": "2021-12-17T23:42:12+00:00" }, { "name": "pocketmine/log", From 8943d8a2a7d13c6adcdc11346b461a55e8a88363 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 27 Dec 2021 16:50:46 +0000 Subject: [PATCH 558/710] Player: fixed maximum message size limits to match vanilla bugrock --- src/player/Player.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/player/Player.php b/src/player/Player.php index d431f430e..444c366d8 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -134,6 +134,7 @@ use function floor; use function get_class; use function is_int; use function max; +use function mb_strlen; use function microtime; use function min; use function preg_match; @@ -1320,7 +1321,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $message = TextFormat::clean($message, false); foreach(explode("\n", $message) as $messagePart){ - if(trim($messagePart) !== "" and strlen($messagePart) <= 255 and $this->messageCounter-- > 0){ + if(trim($messagePart) !== "" and mb_strlen($messagePart, 'UTF-8') <= 512 and $this->messageCounter-- > 0){ if(strpos($messagePart, './') === 0){ $messagePart = substr($messagePart, 1); } From 74ac0f58622361447f983f6688fe7c71104a869d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 27 Dec 2021 17:06:19 +0000 Subject: [PATCH 559/710] Player: move max chat length to constant --- src/player/Player.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/player/Player.php b/src/player/Player.php index 2dea72efc..44fa23a75 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -160,6 +160,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ private const MOVES_PER_TICK = 2; private const MOVE_BACKLOG_SIZE = 100 * self::MOVES_PER_TICK; //100 ticks backlog (5 seconds) + /** Max length of a chat message (UTF-8 codepoints, not bytes) */ + private const MAX_CHAT_CHAR_LENGTH = 512; + /** * Validates the given username. */ @@ -1335,7 +1338,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $message = TextFormat::clean($message, false); foreach(explode("\n", $message) as $messagePart){ - if(trim($messagePart) !== "" and mb_strlen($messagePart, 'UTF-8') <= 512 and $this->messageCounter-- > 0){ + if(trim($messagePart) !== "" and mb_strlen($messagePart, 'UTF-8') <= self::MAX_CHAT_CHAR_LENGTH and $this->messageCounter-- > 0){ if(strpos($messagePart, './') === 0){ $messagePart = substr($messagePart, 1); } From 87170ab0675d04363fe9d1111f8958aceb2a43e5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 27 Dec 2021 17:32:04 +0000 Subject: [PATCH 560/710] Player: move reach distances to constants --- src/player/Player.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/player/Player.php b/src/player/Player.php index 44fa23a75..d52bc82da 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -162,6 +162,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ /** Max length of a chat message (UTF-8 codepoints, not bytes) */ private const MAX_CHAT_CHAR_LENGTH = 512; + private const MAX_REACH_DISTANCE_CREATIVE = 13; + private const MAX_REACH_DISTANCE_SURVIVAL = 7; + private const MAX_REACH_DISTANCE_ENTITY_INTERACTION = 8; /** * Validates the given username. @@ -1592,7 +1595,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ public function breakBlock(Vector3 $pos) : bool{ $this->removeCurrentWindow(); - if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 7)){ + if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? self::MAX_REACH_DISTANCE_CREATIVE : self::MAX_REACH_DISTANCE_SURVIVAL)){ $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); $this->stopBreakBlock($pos); $item = $this->inventory->getItemInHand(); @@ -1622,7 +1625,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ public function interactBlock(Vector3 $pos, int $face, Vector3 $clickOffset) : bool{ $this->setUsingItem(false); - if($this->canInteract($pos->add(0.5, 0.5, 0.5), 13)){ + if($this->canInteract($pos->add(0.5, 0.5, 0.5), $this->isCreative() ? self::MAX_REACH_DISTANCE_CREATIVE : self::MAX_REACH_DISTANCE_SURVIVAL)){ $this->broadcastAnimation(new ArmSwingAnimation($this), $this->getViewers()); $item = $this->inventory->getItemInHand(); //this is a copy of the real item $oldItem = clone $item; @@ -1661,7 +1664,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $oldItem = clone $heldItem; $ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints()); - if(!$this->canInteract($entity->getLocation(), 8)){ + if(!$this->canInteract($entity->getLocation(), self::MAX_REACH_DISTANCE_ENTITY_INTERACTION)){ $this->logger->debug("Cancelled attack of entity " . $entity->getId() . " due to not currently being interactable"); $ev->cancel(); }elseif($this->isSpectator() or ($entity instanceof Player and !$this->server->getConfigGroup()->getConfigBool("pvp"))){ @@ -1726,7 +1729,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ public function interactEntity(Entity $entity, Vector3 $clickPos) : bool{ $ev = new PlayerEntityInteractEvent($this, $entity, $clickPos); - if(!$this->canInteract($entity->getLocation(), 8)){ + if(!$this->canInteract($entity->getLocation(), self::MAX_REACH_DISTANCE_ENTITY_INTERACTION)){ $this->logger->debug("Cancelled interaction with entity " . $entity->getId() . " due to not currently being interactable"); $ev->cancel(); } From 4aab0565c0510f97711bd6f2fa8a2ca4e4189b2c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 27 Dec 2021 18:11:55 +0000 Subject: [PATCH 561/710] ChunkCache: fixed corner case in cache restart on AsyncTask error the cache may have been destroyed since the task inception, leading to an exception being thrown. --- src/network/mcpe/cache/ChunkCache.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/network/mcpe/cache/ChunkCache.php b/src/network/mcpe/cache/ChunkCache.php index bf0ee4419..1eb02a118 100644 --- a/src/network/mcpe/cache/ChunkCache.php +++ b/src/network/mcpe/cache/ChunkCache.php @@ -128,10 +128,12 @@ class ChunkCache implements ChunkListener{ $chunk, $this->caches[$chunkHash], $this->compressor, - function() use ($chunkX, $chunkZ) : void{ + function() use ($chunkHash, $chunkX, $chunkZ) : void{ $this->world->getLogger()->error("Failed preparing chunk $chunkX $chunkZ, retrying"); - $this->restartPendingRequest($chunkX, $chunkZ); + if(isset($this->caches[$chunkHash])){ + $this->restartPendingRequest($chunkX, $chunkZ); + } } ) ); From d9c70cb176c25bd67f7cab384428d6a9165f4539 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 27 Dec 2021 21:54:32 +0000 Subject: [PATCH 562/710] start.cmd: prevent idiotic behaviour when paths contain characters such as brackets god I hate this shit so much --- start.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.cmd b/start.cmd index 747716ff8..b8ab12ef8 100644 --- a/start.cmd +++ b/start.cmd @@ -16,7 +16,7 @@ if exist bin\php\php.exe ( ) if "%PHP_BINARY%"=="" ( - echo Couldn't find a PHP binary in system PATH or %~dp0\bin\php + echo Couldn't find a PHP binary in system PATH or "%~dp0bin\php" echo Please refer to the installation instructions at https://doc.pmmp.io/en/rtfd/installation.html pause exit 1 From 38b6b39cb34882e7905dc23073a96418c05e6ce4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 15:26:34 +0000 Subject: [PATCH 563/710] Filesystem: workaround a stupid Windows issue in safeFilePutContents() occasionally Windows will randomly decide to deny us access to rename the file for no reason whatsoever. If this happens, we attempt an old-style copy and delete. If the rename failed for a legit reason, the copy and delete should also fail and generate an error message. If it was Windows being a spaz, it should work normally without errors. --- src/utils/Filesystem.php | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/utils/Filesystem.php b/src/utils/Filesystem.php index fd3eca26b..4b7420ead 100644 --- a/src/utils/Filesystem.php +++ b/src/utils/Filesystem.php @@ -265,12 +265,33 @@ final class Filesystem{ throw new \RuntimeException("Failed to write to temporary file $temporaryFileName (possibly out of free disk space)"); } + //TODO: the @ prevents us receiving the actual error message, but right now it's necessary since we can't assume + //that the error handler has been set :( $renameTemporaryFileResult = $context !== null ? - rename($temporaryFileName, $fileName, $context) : - rename($temporaryFileName, $fileName); - + @rename($temporaryFileName, $fileName, $context) : + @rename($temporaryFileName, $fileName); if(!$renameTemporaryFileResult){ - throw new \RuntimeException("Failed to move temporary file contents into target file"); + /* + * The following code works around a bug in Windows where rename() will periodically decide to give us a + * spurious "Access is denied (code: 5)" error. As far as I could determine, the fault comes from Windows + * itself, but since I couldn't reliably reproduce the issue it's very hard to debug. + * + * The following code can be used to test. Usually it will fail anywhere before 100,000 iterations. + * + * for($i = 0; $i < 10_000_000; ++$i){ + * file_put_contents('ops.txt.0.tmp', 'some data ' . $i, 0); + * if(!rename('ops.txt.0.tmp', 'ops.txt')){ + * throw new \Error("something weird happened"); + * } + * } + */ + $copyTemporaryFileResult = $context !== null ? + copy($temporaryFileName, $fileName, $context) : + copy($temporaryFileName, $fileName); + if(!$copyTemporaryFileResult){ + throw new \RuntimeException("Failed to move temporary file contents into target file"); + } + @unlink($temporaryFileName); } } } From 7124d44b929f599c2d33ec3dd262b4e7606ee93f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 17:24:49 +0000 Subject: [PATCH 564/710] Player: prevent PlayerToggle(Sprint|Sneak|Fly|Glide|Swim)Events from firing multiple times with the same value this happens with swimming due to bugs in the client. --- src/player/Player.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/player/Player.php b/src/player/Player.php index d52bc82da..a3531ba08 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1743,6 +1743,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function toggleSprint(bool $sprint) : bool{ + if($sprint === $this->sprinting){ + return true; + } $ev = new PlayerToggleSprintEvent($this, $sprint); $ev->call(); if($ev->isCancelled()){ @@ -1753,6 +1756,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function toggleSneak(bool $sneak) : bool{ + if($sneak === $this->sneaking){ + return true; + } $ev = new PlayerToggleSneakEvent($this, $sneak); $ev->call(); if($ev->isCancelled()){ @@ -1763,6 +1769,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function toggleFlight(bool $fly) : bool{ + if($fly === $this->flying){ + return true; + } $ev = new PlayerToggleFlightEvent($this, $fly); if(!$this->allowFlight){ $ev->cancel(); @@ -1778,6 +1787,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function toggleGlide(bool $glide) : bool{ + if($glide === $this->gliding){ + return true; + } $ev = new PlayerToggleGlideEvent($this, $glide); $ev->call(); if($ev->isCancelled()){ @@ -1788,6 +1800,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function toggleSwim(bool $swimming) : bool{ + if($swimming === $this->swimming){ + return true; + } $ev = new PlayerToggleSwimEvent($this, $swimming); $ev->call(); if($ev->isCancelled()){ From e102339637b5dfd9db2943442adcd6ca05e97afc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 17:29:19 +0000 Subject: [PATCH 565/710] InGamePacketHandler: remove dead code from PlayerActionPacket handling --- .../mcpe/handler/InGamePacketHandler.php | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 825da1a65..a538b06a1 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -576,49 +576,9 @@ class InGamePacketHandler extends PacketHandler{ case PlayerAction::JUMP: $this->player->jump(); return true; - case PlayerAction::START_SPRINT: - if(!$this->player->toggleSprint(true)){ - $this->player->sendData([$this->player]); - } - return true; - case PlayerAction::STOP_SPRINT: - if(!$this->player->toggleSprint(false)){ - $this->player->sendData([$this->player]); - } - return true; - case PlayerAction::START_SNEAK: - if(!$this->player->toggleSneak(true)){ - $this->player->sendData([$this->player]); - } - return true; - case PlayerAction::STOP_SNEAK: - if(!$this->player->toggleSneak(false)){ - $this->player->sendData([$this->player]); - } - return true; - case PlayerAction::START_GLIDE: - if(!$this->player->toggleGlide(true)){ - $this->player->sendData([$this->player]); - } - return true; - case PlayerAction::STOP_GLIDE: - if(!$this->player->toggleGlide(false)){ - $this->player->sendData([$this->player]); - } - return true; case PlayerAction::CRACK_BREAK: $this->player->continueBreakBlock($pos, $face); break; - case PlayerAction::START_SWIMMING: - if(!$this->player->toggleSwim(true)){ - $this->player->sendData([$this->player]); - } - return true; - case PlayerAction::STOP_SWIMMING: - if(!$this->player->toggleSwim(false)){ - $this->player->sendData([$this->player]); - } - return true; case PlayerAction::INTERACT_BLOCK: //TODO: ignored (for now) break; case PlayerAction::CREATIVE_PLAYER_DESTROY_BLOCK: From a1d217e12b208927c0ecfbaf89330ea0c5985ec7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 18:23:05 +0000 Subject: [PATCH 566/710] InGamePacketHandler: fixed missing synchronization of metadata when plugins cancel PlayerToggle*Event --- .../mcpe/handler/InGamePacketHandler.php | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index a538b06a1..636356247 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -194,20 +194,16 @@ class InGamePacketHandler extends PacketHandler{ $this->forceMoveSync = false; $sneaking = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING); - if($sneaking !== null){ - $this->player->toggleSneak($sneaking); - } $sprinting = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING); - if($sprinting !== null){ - $this->player->toggleSprint($sprinting); - } $swimming = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING); - if($swimming !== null){ - $this->player->toggleSwim($swimming); - } $gliding = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING); - if($gliding !== null){ - $this->player->toggleGlide($gliding); + $mismatch = + ($sneaking !== null && !$this->player->toggleSneak($sneaking)) | + ($sprinting !== null && !$this->player->toggleSprint($sprinting)) | + ($swimming !== null && !$this->player->toggleSwim($swimming)) | + ($gliding !== null && !$this->player->toggleGlide($gliding)); + if((bool) $mismatch){ + $this->player->sendData([$this->player]); } //TODO: this packet has WAYYYYY more useful information that we're not using From 0a0de018a53a7a800d019375a25d84af65c7824d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 18:28:22 +0000 Subject: [PATCH 567/710] InGamePacketHandler: fixed player jump handling --- src/network/mcpe/handler/InGamePacketHandler.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 636356247..862b3e3b0 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -206,6 +206,10 @@ class InGamePacketHandler extends PacketHandler{ $this->player->sendData([$this->player]); } + if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){ + $this->player->jump(); + } + //TODO: this packet has WAYYYYY more useful information that we're not using $this->player->handleMovement($newPos); @@ -569,9 +573,6 @@ class InGamePacketHandler extends PacketHandler{ case PlayerAction::STOP_SLEEPING: $this->player->stopSleep(); break; - case PlayerAction::JUMP: - $this->player->jump(); - return true; case PlayerAction::CRACK_BREAK: $this->player->continueBreakBlock($pos, $face); break; From d94578a4205b84965a544d8b50d9cbaf967b83f5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 18:32:53 +0000 Subject: [PATCH 568/710] Player: remove dead TODO comment --- src/player/Player.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/player/Player.php b/src/player/Player.php index a3531ba08..ab348d899 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1576,7 +1576,6 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ public function continueBreakBlock(Vector3 $pos, int $face) : void{ if($this->blockBreakHandler !== null and $this->blockBreakHandler->getBlockPos()->distanceSquared($pos) < 0.0001){ - //TODO: check the targeted block matches the one we're told to target $this->blockBreakHandler->setTargetedFace($face); } } From 5c994e4a24babd4b02136b27c04171a5a1bb6432 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 18:41:11 +0000 Subject: [PATCH 569/710] Player: removed an old hack for setFlying() feedback loop this is no longer a concern, since we now check if the sent state matches the current state before doing anything, at multiple layers. --- src/player/Player.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/player/Player.php b/src/player/Player.php index ab348d899..f8efbcba8 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1779,9 +1779,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if($ev->isCancelled()){ return false; } - //don't use setFlying() here, to avoid feedback loops - TODO: get rid of this hack - $this->flying = $fly; - $this->resetFallDistance(); + $this->setFlying($fly); return true; } From e0a6bc1d4af263daa86aadd2a5e206d3d7d9c243 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 20:13:07 +0000 Subject: [PATCH 570/710] Lava: remove useless code, closes #4678 --- src/block/Lava.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/block/Lava.php b/src/block/Lava.php index 06ee5fd81..729393193 100644 --- a/src/block/Lava.php +++ b/src/block/Lava.php @@ -91,8 +91,6 @@ class Lava extends Liquid{ } public function onEntityInside(Entity $entity) : bool{ - $entity->fallDistance *= 0.5; - $ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4); $entity->attack($ev); From 207f7ec30917a5238e6b07bf0da5d424cffdb88b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 20:22:16 +0000 Subject: [PATCH 571/710] Player: avoid unnecessary network updates on repeated calls to setAllowFLight(), setHasBlockCollision() and setAutoJump() --- src/player/Player.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/player/Player.php b/src/player/Player.php index f8efbcba8..41fa7acb7 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -396,8 +396,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function setAllowFlight(bool $value) : void{ - $this->allowFlight = $value; - $this->getNetworkSession()->syncAdventureSettings($this); + if($this->allowFlight !== $value){ + $this->allowFlight = $value; + $this->getNetworkSession()->syncAdventureSettings($this); + } } public function getAllowFlight() : bool{ @@ -405,8 +407,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function setHasBlockCollision(bool $value) : void{ - $this->blockCollision = $value; - $this->getNetworkSession()->syncAdventureSettings($this); + if($this->blockCollision !== $value){ + $this->blockCollision = $value; + $this->getNetworkSession()->syncAdventureSettings($this); + } } public function hasBlockCollision() : bool{ @@ -426,8 +430,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function setAutoJump(bool $value) : void{ - $this->autoJump = $value; - $this->getNetworkSession()->syncAdventureSettings($this); + if($this->autoJump !== $value){ + $this->autoJump = $value; + $this->getNetworkSession()->syncAdventureSettings($this); + } } public function hasAutoJump() : bool{ From 62afa2f28dbd5edcb62bc3a36760a8b3e0ae88c4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 29 Dec 2021 23:04:54 +0000 Subject: [PATCH 572/710] Entity: extract getBlocksIntersected() from getBlocksAroundWithEntityInsideActions() --- src/entity/Entity.php | 47 ++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index 06edc47e3..2f286bd82 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -1219,32 +1219,41 @@ abstract class Entity{ $this->onGround = ($wantedY != $dy and $wantedY < 0); } + /** + * Yields all the blocks whose full-cube areas are intersected by the entity's AABB. + * + * @phpstan-return \Generator + */ + protected function getBlocksIntersected(float $inset) : \Generator{ + $minX = (int) floor($this->boundingBox->minX + $inset); + $minY = (int) floor($this->boundingBox->minY + $inset); + $minZ = (int) floor($this->boundingBox->minZ + $inset); + $maxX = (int) floor($this->boundingBox->maxX - $inset); + $maxY = (int) floor($this->boundingBox->maxY - $inset); + $maxZ = (int) floor($this->boundingBox->maxZ - $inset); + + $world = $this->getWorld(); + + for($z = $minZ; $z <= $maxZ; ++$z){ + for($x = $minX; $x <= $maxX; ++$x){ + for($y = $minY; $y <= $maxY; ++$y){ + yield $world->getBlockAt($x, $y, $z); + } + } + } + } + /** * @return Block[] */ protected function getBlocksAroundWithEntityInsideActions() : array{ if($this->blocksAround === null){ - $inset = 0.001; //Offset against floating-point errors - - $minX = (int) floor($this->boundingBox->minX + $inset); - $minY = (int) floor($this->boundingBox->minY + $inset); - $minZ = (int) floor($this->boundingBox->minZ + $inset); - $maxX = (int) floor($this->boundingBox->maxX - $inset); - $maxY = (int) floor($this->boundingBox->maxY - $inset); - $maxZ = (int) floor($this->boundingBox->maxZ - $inset); - $this->blocksAround = []; - $world = $this->getWorld(); - - for($z = $minZ; $z <= $maxZ; ++$z){ - for($x = $minX; $x <= $maxX; ++$x){ - for($y = $minY; $y <= $maxY; ++$y){ - $block = $world->getBlockAt($x, $y, $z); - if($block->hasEntityCollision()){ - $this->blocksAround[] = $block; - } - } + $inset = 0.001; //Offset against floating-point errors + foreach($this->getBlocksIntersected($inset) as $block){ + if($block->hasEntityCollision()){ + $this->blocksAround[] = $block; } } } From 193a1b3f4efcda0faa95ba089feeffe62e9a4acb Mon Sep 17 00:00:00 2001 From: xxAROX Date: Fri, 31 Dec 2021 00:53:05 +0100 Subject: [PATCH 573/710] =?UTF-8?q?TextFormat:=20Added=20MINECOIN=5FGOLD?= =?UTF-8?q?=20(=C2=A7g)=20color=20code=20support=20(#4670)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/Terminal.php | 6 +++++- src/utils/TextFormat.php | 12 +++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/utils/Terminal.php b/src/utils/Terminal.php index 73e350a2c..46aeaccae 100644 --- a/src/utils/Terminal.php +++ b/src/utils/Terminal.php @@ -58,6 +58,7 @@ abstract class Terminal{ public static string $COLOR_LIGHT_PURPLE = ""; public static string $COLOR_YELLOW = ""; public static string $COLOR_WHITE = ""; + public static string $COLOR_MINECOIN_GOLD = ""; /** @var bool|null */ private static $formattingCodes = null; @@ -110,6 +111,7 @@ abstract class Terminal{ self::$COLOR_LIGHT_PURPLE = $color(207); self::$COLOR_YELLOW = $color(227); self::$COLOR_WHITE = $color(231); + self::$COLOR_MINECOIN_GOLD = $color(184); } protected static function getEscapeCodes() : void{ @@ -142,11 +144,12 @@ abstract class Terminal{ self::$COLOR_LIGHT_PURPLE = $colors >= 256 ? $setaf(207) : $setaf(13); self::$COLOR_YELLOW = $colors >= 256 ? $setaf(227) : $setaf(11); self::$COLOR_WHITE = $colors >= 256 ? $setaf(231) : $setaf(15); + self::$COLOR_MINECOIN_GOLD = $colors >= 256 ? $setaf(184) : $setaf(11); }else{ self::$COLOR_BLACK = self::$COLOR_DARK_GRAY = $setaf(0); self::$COLOR_RED = self::$COLOR_DARK_RED = $setaf(1); self::$COLOR_GREEN = self::$COLOR_DARK_GREEN = $setaf(2); - self::$COLOR_YELLOW = self::$COLOR_GOLD = $setaf(3); + self::$COLOR_YELLOW = self::$COLOR_GOLD = self::$COLOR_MINECOIN_GOLD = $setaf(3); self::$COLOR_BLUE = self::$COLOR_DARK_BLUE = $setaf(4); self::$COLOR_LIGHT_PURPLE = self::$COLOR_PURPLE = $setaf(5); self::$COLOR_AQUA = self::$COLOR_DARK_AQUA = $setaf(6); @@ -210,6 +213,7 @@ abstract class Terminal{ TextFormat::LIGHT_PURPLE => Terminal::$COLOR_LIGHT_PURPLE, TextFormat::YELLOW => Terminal::$COLOR_YELLOW, TextFormat::WHITE => Terminal::$COLOR_WHITE, + TextFormat::MINECOIN_GOLD => Terminal::$COLOR_MINECOIN_GOLD, default => $token, }; } diff --git a/src/utils/TextFormat.php b/src/utils/TextFormat.php index 66189078c..f784f5dd2 100644 --- a/src/utils/TextFormat.php +++ b/src/utils/TextFormat.php @@ -62,6 +62,7 @@ abstract class TextFormat{ public const LIGHT_PURPLE = TextFormat::ESCAPE . "d"; public const YELLOW = TextFormat::ESCAPE . "e"; public const WHITE = TextFormat::ESCAPE . "f"; + public const MINECOIN_GOLD = TextFormat::ESCAPE . "g"; public const COLORS = [ self::BLACK => self::BLACK, @@ -80,6 +81,7 @@ abstract class TextFormat{ self::LIGHT_PURPLE => self::LIGHT_PURPLE, self::YELLOW => self::YELLOW, self::WHITE => self::WHITE, + self::MINECOIN_GOLD => self::MINECOIN_GOLD, ]; public const OBFUSCATED = TextFormat::ESCAPE . "k"; @@ -128,7 +130,7 @@ abstract class TextFormat{ * @return string[] */ public static function tokenize(string $string) : array{ - $result = preg_split("/(" . TextFormat::ESCAPE . "[0-9a-fk-or])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + $result = preg_split("/(" . TextFormat::ESCAPE . "[0-9a-gk-or])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); if($result === false) throw self::makePcreError(); return $result; } @@ -142,7 +144,7 @@ abstract class TextFormat{ $string = mb_scrub($string, 'UTF-8'); $string = self::preg_replace("/[\x{E000}-\x{F8FF}]/u", "", $string); //remove unicode private-use-area characters (they might break the console) if($removeFormat){ - $string = str_replace(TextFormat::ESCAPE, "", self::preg_replace("/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "", $string)); + $string = str_replace(TextFormat::ESCAPE, "", self::preg_replace("/" . TextFormat::ESCAPE . "[0-9a-gk-or]/u", "", $string)); } return str_replace("\x1b", "", self::preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string)); } @@ -153,7 +155,7 @@ abstract class TextFormat{ * @param string $placeholder default "&" */ public static function colorize(string $string, string $placeholder = "&") : string{ - return self::preg_replace('/' . preg_quote($placeholder, "/") . '([0-9a-fk-or])/u', TextFormat::ESCAPE . '$1', $string); + return self::preg_replace('/' . preg_quote($placeholder, "/") . '([0-9a-gk-or])/u', TextFormat::ESCAPE . '$1', $string); } /** @@ -254,6 +256,10 @@ abstract class TextFormat{ $newString .= ""; ++$tokens; break; + case TextFormat::MINECOIN_GOLD: + $newString .= ""; + ++$tokens; + break; default: $newString .= $token; break; From 72f2c794abbbfa98301eda68ea3916a0845cc6c8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 31 Dec 2021 18:32:19 +0000 Subject: [PATCH 574/710] SimpleInventory: improved performance of setContents() avoid the overhead incurred by clear() and setItem(), because in internalSetContents(), we already have no listeners or viewers to talk to anyway, so this is just spamming shit into /dev/null. --- src/inventory/SimpleInventory.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/inventory/SimpleInventory.php b/src/inventory/SimpleInventory.php index f05b527a2..e27ccafb0 100644 --- a/src/inventory/SimpleInventory.php +++ b/src/inventory/SimpleInventory.php @@ -71,10 +71,10 @@ class SimpleInventory extends BaseInventory{ protected function internalSetContents(array $items) : void{ for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ - if(!isset($items[$i])){ - $this->clear($i); + if(!isset($items[$i]) || $items[$i]->isNull()){ + $this->slots[$i] = null; }else{ - $this->setItem($i, $items[$i]); + $this->slots[$i] = clone $items[$i]; } } } From 3c6146b5e095f3f8d7c77da3745a7c40b57863c2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 1 Jan 2022 15:05:32 +0000 Subject: [PATCH 575/710] ContainerTrait: avoid absurdly inefficient use of setItem() this substantially improves the performance of loading containers such as chests. --- src/block/tile/ContainerTrait.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/block/tile/ContainerTrait.php b/src/block/tile/ContainerTrait.php index ae8cc8ea7..f3dc42390 100644 --- a/src/block/tile/ContainerTrait.php +++ b/src/block/tile/ContainerTrait.php @@ -48,11 +48,14 @@ trait ContainerTrait{ $inventory = $this->getRealInventory(); $listeners = $inventory->getListeners()->toArray(); $inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization - $inventory->clearAll(); + + $newContents = []; /** @var CompoundTag $itemNBT */ foreach($inventoryTag as $itemNBT){ - $inventory->setItem($itemNBT->getByte("Slot"), Item::nbtDeserialize($itemNBT)); + $newContents[$itemNBT->getByte("Slot")] = Item::nbtDeserialize($itemNBT); } + $inventory->setContents($newContents); + $inventory->getListeners()->add(...$listeners); } From eedea38669f53f21101465d4e4e2da6f61804256 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 1 Jan 2022 15:26:42 +0000 Subject: [PATCH 576/710] Improve performance of loading player inventories --- src/entity/Human.php | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/entity/Human.php b/src/entity/Human.php index c82cee7f8..7aebc89c3 100644 --- a/src/entity/Human.php +++ b/src/entity/Human.php @@ -217,6 +217,19 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ $this->uuid = Uuid::uuid3(Uuid::NIL, ((string) $this->getId()) . $this->skin->getSkinData() . $this->getNameTag()); } + /** + * @param Item[] $items + * @phpstan-param array $items + */ + private static function populateInventoryFromListTag(Inventory $inventory, array $items) : void{ + $listeners = $inventory->getListeners()->toArray(); + $inventory->getListeners()->clear(); + + $inventory->setContents($items); + + $inventory->getListeners()->add(...$listeners); + } + protected function initEntity(CompoundTag $nbt) : void{ parent::initEntity($nbt); @@ -247,10 +260,8 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ $inventoryTag = $nbt->getListTag("Inventory"); if($inventoryTag !== null){ - $armorListeners = $this->armorInventory->getListeners()->toArray(); - $this->armorInventory->getListeners()->clear(); - $inventoryListeners = $this->inventory->getListeners()->toArray(); - $this->inventory->getListeners()->clear(); + $inventoryItems = []; + $armorInventoryItems = []; /** @var CompoundTag $item */ foreach($inventoryTag as $i => $item){ @@ -258,14 +269,14 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ if($slot >= 0 and $slot < 9){ //Hotbar //Old hotbar saving stuff, ignore it }elseif($slot >= 100 and $slot < 104){ //Armor - $this->armorInventory->setItem($slot - 100, Item::nbtDeserialize($item)); + $armorInventoryItems[$slot - 100] = Item::nbtDeserialize($item); }elseif($slot >= 9 and $slot < $this->inventory->getSize() + 9){ - $this->inventory->setItem($slot - 9, Item::nbtDeserialize($item)); + $inventoryItems[$slot - 9] = Item::nbtDeserialize($item); } } - $this->armorInventory->getListeners()->add(...$armorListeners); - $this->inventory->getListeners()->add(...$inventoryListeners); + self::populateInventoryFromListTag($this->inventory, $inventoryItems); + self::populateInventoryFromListTag($this->armorInventory, $armorInventoryItems); } $offHand = $nbt->getCompoundTag("OffHandItem"); if($offHand !== null){ @@ -279,10 +290,13 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ $enderChestInventoryTag = $nbt->getListTag("EnderChestInventory"); if($enderChestInventoryTag !== null){ + $enderChestInventoryItems = []; + /** @var CompoundTag $item */ foreach($enderChestInventoryTag as $i => $item){ - $this->enderInventory->setItem($item->getByte("Slot"), Item::nbtDeserialize($item)); + $enderChestInventoryItems[$item->getByte("Slot")] = Item::nbtDeserialize($item); } + self::populateInventoryFromListTag($this->enderInventory, $enderChestInventoryItems); } $this->inventory->setHeldItemIndex($nbt->getInt("SelectedInventorySlot", 0)); From 54d6b83fc2816dcdb00c8351425a42518515902e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 1 Jan 2022 15:39:46 +0000 Subject: [PATCH 577/710] Entity: pass the appropriate value for AFFECTED_BY_GRAVITY --- src/entity/Entity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entity/Entity.php b/src/entity/Entity.php index 2dfaf13e4..6576d902e 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -1599,7 +1599,7 @@ abstract class Entity{ $properties->setString(EntityMetadataProperties::SCORE_TAG, $this->scoreTag); $properties->setByte(EntityMetadataProperties::COLOR, 0); - $properties->setGenericFlag(EntityMetadataFlags::AFFECTED_BY_GRAVITY, true); + $properties->setGenericFlag(EntityMetadataFlags::AFFECTED_BY_GRAVITY, $this->gravityEnabled); $properties->setGenericFlag(EntityMetadataFlags::CAN_CLIMB, $this->canClimb); $properties->setGenericFlag(EntityMetadataFlags::CAN_SHOW_NAMETAG, $this->nameTagVisible); $properties->setGenericFlag(EntityMetadataFlags::HAS_COLLISION, true); From f486b5f4a7af17299c41104d59a4a790029c8ea2 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Sat, 1 Jan 2022 15:41:19 +0000 Subject: [PATCH 578/710] Player: fixed fall damage when sprinting down stairs (#4685) Due to the way positions are updated over the network, we only see the end result of a movement and not its preceding actions. In addition, we don't know for sure whether the MCPE collision checks work the same exact way as PM. TL;DR: It's possible for the client to capture and send a movement frame after they collided with a step and then already moved forward from it some distance, resulting in a weird arc pattern. This PR checks the range between the old and new positions for collision boxes to ensure that all possible areas are checked for detecting fall damage. This has been tested and successfully resolves various issues involving running down stairs: - missing sounds - random fall damage --- src/player/Player.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/player/Player.php b/src/player/Player.php index 444c366d8..f445b537d 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1081,6 +1081,10 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $bb->minY = $this->location->y - 0.2; $bb->maxY = $this->location->y + 0.2; + //we're already at the new position at this point; check if there are blocks we might have landed on between + //the old and new positions (running down stairs necessitates this) + $bb = $bb->addCoord(-$dx, -$dy, -$dz); + $this->onGround = $this->isCollided = count($this->getWorld()->getCollisionBlocks($bb, true)) > 0; } } From c8247786d73e5562058cac3346abe49dd6057992 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 1 Jan 2022 16:45:35 +0000 Subject: [PATCH 579/710] Player: check chat length check with strlen() before mb_strlen() mb_strlen() is O(n), whereas strlen() is O(1). If we receive very large chat messages (e.g. 2 MB), mb_strlen() will take a very long time to return a result (around 8ms on my machine). Since the max size of a UTF-8 character is 4 bytes (according to standard), we can use strlen() with 4x the char limit to gate it and prevent this from happening. --- src/player/Player.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/player/Player.php b/src/player/Player.php index f445b537d..8bd29325b 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1325,7 +1325,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $message = TextFormat::clean($message, false); foreach(explode("\n", $message) as $messagePart){ - if(trim($messagePart) !== "" and mb_strlen($messagePart, 'UTF-8') <= 512 and $this->messageCounter-- > 0){ + if(trim($messagePart) !== "" and strlen($messagePart) <= 512 * 4 and mb_strlen($messagePart, 'UTF-8') <= 512 and $this->messageCounter-- > 0){ if(strpos($messagePart, './') === 0){ $messagePart = substr($messagePart, 1); } From b903e90dc29abc5ef1c6845012fdaea7e19a75de Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 1 Jan 2022 16:50:02 +0000 Subject: [PATCH 580/710] Release 4.0.4 --- changelogs/4.0.md | 15 +++++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 541bc3826..211b825e8 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1576,3 +1576,18 @@ Released 16th December 2021. - Fixed player arm swing animation not being shown when attacks were cancelled by attack cooldown. - Fixed being unable to use `/deop` to de-op a player whose name appeared in `ops.txt` with uppercase letters in it. - Added a check for valid tile class in `BlockIdentifier`. + +# 4.0.4 +Released 1st January 2022. + +## General +- Improved performance of loading chests and other containers from world saves. +- Improved performance of loading player inventories from saved data. + +## Fixes +- Fixed a crash that could occur when a chunk failed to be prepared for chunk sending. +- Fixed fall damage when sprinting down stairs. +- Fixed message length limit for chat (now 512 instead of 255, and accounts for UTF-8). +- Fixed incorrect message being displayed when trying to sleep in a bed which is too far away. +- Fixed missing space between `Kicked by admin.` and `Reason` when using `/kick` to kick a player. +- Fixed client-side performance issue of entities with very large scale. \ No newline at end of file diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 066bdb730..c58b90020 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.4"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; private function __construct(){ From f62cfe8ae344fe0e2fbc8ccb3e78116d639270f3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 1 Jan 2022 16:50:03 +0000 Subject: [PATCH 581/710] 4.0.5 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index c58b90020..5cd6474d5 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.4"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.5"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From bcc0f1e733ab26479912a9c2df15a456055755bc Mon Sep 17 00:00:00 2001 From: Covered123 <58715544+JavierLeon9966@users.noreply.github.com> Date: Mon, 3 Jan 2022 16:11:32 -0300 Subject: [PATCH 582/710] Fixed desynchronization of hunger when cancelling food-related events (#4691) --- src/network/mcpe/handler/InGamePacketHandler.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index e4553c49b..b2fd157ad 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -27,6 +27,7 @@ use pocketmine\block\BaseSign; use pocketmine\block\ItemFrame; use pocketmine\block\utils\SignText; use pocketmine\entity\animation\ConsumingItemAnimation; +use pocketmine\entity\Attribute; use pocketmine\entity\InvalidSkinException; use pocketmine\event\player\PlayerEditBookEvent; use pocketmine\inventory\transaction\action\InventoryAction; @@ -371,6 +372,8 @@ class InGamePacketHandler extends PacketHandler{ case UseItemTransactionData::ACTION_CLICK_AIR: if($this->player->isUsingItem()){ if(!$this->player->consumeHeldItem()){ + $hungerAttr = $this->player->getAttributeMap()->get(Attribute::HUNGER) ?? throw new AssumptionFailedError(); + $hungerAttr->markSynchronized(false); $this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex()); } return true; From decd1da2d07990d04611a7844bcdd2886e28fa9e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 3 Jan 2022 19:32:30 +0000 Subject: [PATCH 583/710] BaseSign: remove dead TODO comment --- src/block/BaseSign.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/block/BaseSign.php b/src/block/BaseSign.php index 586eee6a1..42e6bf178 100644 --- a/src/block/BaseSign.php +++ b/src/block/BaseSign.php @@ -37,8 +37,6 @@ use function assert; use function strlen; abstract class BaseSign extends Transparent{ - //TODO: conditionally useless properties, find a way to fix - protected SignText $text; protected ?int $editorEntityRuntimeId = null; From e43e0189df0a4a2051edb6bf0514d9a9d353b1a1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 3 Jan 2022 20:20:32 +0000 Subject: [PATCH 584/710] InGamePacketHandler: do not pass bare integers from BookEditPacket directly into event while these currently happen to be identical, they may not be in the future. Really this should be represented by an enum. --- src/network/mcpe/handler/InGamePacketHandler.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index b2fd157ad..04e1c847b 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -762,7 +762,16 @@ class InGamePacketHandler extends PacketHandler{ return false; } - $event = new PlayerEditBookEvent($this->player, $oldBook, $newBook, $packet->type, $modifiedPages); + //for redundancy, in case of protocol changes, we don't want to pass these directly + $action = match($packet->type){ + BookEditPacket::TYPE_REPLACE_PAGE => PlayerEditBookEvent::ACTION_REPLACE_PAGE, + BookEditPacket::TYPE_ADD_PAGE => PlayerEditBookEvent::ACTION_ADD_PAGE, + BookEditPacket::TYPE_DELETE_PAGE => PlayerEditBookEvent::ACTION_DELETE_PAGE, + BookEditPacket::TYPE_SWAP_PAGES => PlayerEditBookEvent::ACTION_SWAP_PAGES, + BookEditPacket::TYPE_SIGN_BOOK => PlayerEditBookEvent::ACTION_SIGN_BOOK, + default => throw new AssumptionFailedError("We already filtered unknown types in the switch above") + }; + $event = new PlayerEditBookEvent($this->player, $oldBook, $newBook, $action, $modifiedPages); $event->call(); if($event->isCancelled()){ return true; From 0d595e43249d58efa99349e554d9b2f84dcda8a3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 4 Jan 2022 00:47:04 +0000 Subject: [PATCH 585/710] Update Language dependency --- composer.json | 2 +- composer.lock | 14 +++++++------- src/lang/KnownTranslationFactory.php | 20 ++++++++++++++++++++ src/lang/KnownTranslationKeys.php | 3 +++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 5499bc07b..123247351 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", "pocketmine/errorhandler": "^0.3.0", - "pocketmine/locale-data": "^2.1.0", + "pocketmine/locale-data": "~2.3.0", "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", "pocketmine/math": "^0.4.0", diff --git a/composer.lock b/composer.lock index 9cf41a544..34218ee55 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7e9247927fa23baf3e899811c8119f95", + "content-hash": "cc667d8c5a4aaf129708742d04830e76", "packages": [ { "name": "adhocore/json-comment", @@ -535,16 +535,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.2.1", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "9fdd36f0ac3a2dfe1acacbee8b23eb6615129701" + "reference": "a16e5899709387ff03db8bba7f903a15c7c0a9af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/9fdd36f0ac3a2dfe1acacbee8b23eb6615129701", - "reference": "9fdd36f0ac3a2dfe1acacbee8b23eb6615129701", + "url": "https://api.github.com/repos/pmmp/Language/zipball/a16e5899709387ff03db8bba7f903a15c7c0a9af", + "reference": "a16e5899709387ff03db8bba7f903a15c7c0a9af", "shasum": "" }, "type": "library", @@ -552,9 +552,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.2.1" + "source": "https://github.com/pmmp/Language/tree/2.3.0" }, - "time": "2021-12-17T23:42:12+00:00" + "time": "2022-01-04T00:42:11+00:00" }, { "name": "pocketmine/log", diff --git a/src/lang/KnownTranslationFactory.php b/src/lang/KnownTranslationFactory.php index 6c1b2f556..d3b262d79 100644 --- a/src/lang/KnownTranslationFactory.php +++ b/src/lang/KnownTranslationFactory.php @@ -1974,6 +1974,26 @@ final class KnownTranslationFactory{ ]); } + public static function pocketmine_server_obsolete_warning1(Translatable|string $param0, Translatable|string $param1) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_OBSOLETE_WARNING1, [ + 0 => $param0, + 1 => $param1, + ]); + } + + public static function pocketmine_server_obsolete_warning2(Translatable|string $param0, Translatable|string $param1) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_OBSOLETE_WARNING2, [ + 0 => $param0, + 1 => $param1, + ]); + } + + public static function pocketmine_server_obsolete_warning3(Translatable|string $param0) : Translatable{ + return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_OBSOLETE_WARNING3, [ + 0 => $param0, + ]); + } + public static function pocketmine_server_query_running(Translatable|string $param0, Translatable|string $param1) : Translatable{ return new Translatable(KnownTranslationKeys::POCKETMINE_SERVER_QUERY_RUNNING, [ 0 => $param0, diff --git a/src/lang/KnownTranslationKeys.php b/src/lang/KnownTranslationKeys.php index 95d9bbccd..1e488e2b8 100644 --- a/src/lang/KnownTranslationKeys.php +++ b/src/lang/KnownTranslationKeys.php @@ -406,6 +406,9 @@ final class KnownTranslationKeys{ public const POCKETMINE_SERVER_LICENSE = "pocketmine.server.license"; public const POCKETMINE_SERVER_NETWORKSTART = "pocketmine.server.networkStart"; public const POCKETMINE_SERVER_NETWORKSTARTFAILED = "pocketmine.server.networkStartFailed"; + public const POCKETMINE_SERVER_OBSOLETE_WARNING1 = "pocketmine.server.obsolete.warning1"; + public const POCKETMINE_SERVER_OBSOLETE_WARNING2 = "pocketmine.server.obsolete.warning2"; + public const POCKETMINE_SERVER_OBSOLETE_WARNING3 = "pocketmine.server.obsolete.warning3"; public const POCKETMINE_SERVER_QUERY_RUNNING = "pocketmine.server.query.running"; public const POCKETMINE_SERVER_START = "pocketmine.server.start"; public const POCKETMINE_SERVER_STARTFINISHED = "pocketmine.server.startFinished"; From 7bee72ef2d6ea91aee4aae68436befab7bc03a53 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 4 Jan 2022 00:54:09 +0000 Subject: [PATCH 586/710] Use ~ instead of ^ for constraints on BedrockData and BedrockProtocol I got these two mixed up - they are exactly the opposite of what I thought. ~ is the stricter operator. --- composer.json | 4 ++-- composer.lock | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 123247351..8c2f8902a 100644 --- a/composer.json +++ b/composer.json @@ -34,8 +34,8 @@ "adhocore/json-comment": "^1.1", "fgrosse/phpasn1": "^2.3", "netresearch/jsonmapper": "^4.0", - "pocketmine/bedrock-data": "^1.5.0+bedrock-1.18.0", - "pocketmine/bedrock-protocol": "^7.0.0+bedrock-1.18.0", + "pocketmine/bedrock-data": "~1.5.0+bedrock-1.18.0", + "pocketmine/bedrock-protocol": "~7.1.0+bedrock-1.18.0", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "^0.2.0", diff --git a/composer.lock b/composer.lock index 34218ee55..be9b3c6eb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cc667d8c5a4aaf129708742d04830e76", + "content-hash": "5dc75b1eaa0493544081f223d3e2304c", "packages": [ { "name": "adhocore/json-comment", From aeab19a6165fd7b8930564039d80a2a785735425 Mon Sep 17 00:00:00 2001 From: Covered123 <58715544+JavierLeon9966@users.noreply.github.com> Date: Tue, 4 Jan 2022 17:31:27 -0300 Subject: [PATCH 587/710] Fixed world spawn point not updating to players (#4699) closes #4383 --- src/world/World.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/world/World.php b/src/world/World.php index 6d3aa6712..be5e7c426 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2258,6 +2258,11 @@ class World implements ChunkManager{ $previousSpawn = $this->getSpawnLocation(); $this->provider->getWorldData()->setSpawn($pos); (new SpawnChangeEvent($this, $previousSpawn))->call(); + + $location = Position::fromObject($pos, $this); + foreach($this->players as $player){ + $player->getNetworkSession()->syncWorldSpawnPoint($location); + } } /** From 68f3399cfd784f95927da7e90c72be952fde284a Mon Sep 17 00:00:00 2001 From: Dylan T Date: Tue, 4 Jan 2022 20:39:02 +0000 Subject: [PATCH 588/710] Merge pull request from GHSA-p62j-hrxm-xcxf This checks the following things: - Validity of UTF-8 encoding of title, author, and page content - Maximum soft and hard lengths of title, author, and page content (soft limits may be bypassed by uncancelling PlayerEditBookEvent; hard limits may not be bypassed) - Maximum number of pages. Books with more than 50 pages may still be edited, but may not have new pages added. --- src/pocketmine/Player.php | 51 +++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 7721b4013..c4bcd651d 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -210,6 +210,7 @@ use function json_encode; use function json_last_error_msg; use function lcg_value; use function max; +use function mb_strlen; use function microtime; use function min; use function preg_match; @@ -217,6 +218,7 @@ use function round; use function spl_object_hash; use function sprintf; use function sqrt; +use function str_repeat; use function strlen; use function strpos; use function strtolower; @@ -3265,6 +3267,24 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ return true; } + /** + * @throws \UnexpectedValueException + */ + private function checkBookText(string $string, string $fieldName, int $softLimit, int $hardLimit, bool &$cancel) : string{ + if(strlen($string) > $hardLimit){ + throw new \UnexpectedValueException(sprintf("Book %s must be at most %d bytes, but have %d bytes", $fieldName, $hardLimit, strlen($string))); + } + + $result = TextFormat::clean($string, false); + //strlen() is O(1), mb_strlen() is O(n) + if(strlen($result) > $softLimit * 4 || mb_strlen($result, 'UTF-8') > $softLimit){ + $cancel = true; + $this->server->getLogger()->debug(sprintf("Cancelled book edit by %s due to %s exceeded soft limit of %d chars", $this->getName(), $fieldName, $softLimit)); + } + + return $result; + } + public function handleBookEdit(BookEditPacket $packet) : bool{ /** @var WritableBook $oldBook */ $oldBook = $this->inventory->getItem($packet->inventorySlot); @@ -3274,10 +3294,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $newBook = clone $oldBook; $modifiedPages = []; - + $cancel = false; switch($packet->type){ case BookEditPacket::TYPE_REPLACE_PAGE: - $newBook->setPageText($packet->pageNumber, $packet->text); + $text = self::checkBookText($packet->text, "page text", 256, 0x7fff, $cancel); + $newBook->setPageText($packet->pageNumber, $text); $modifiedPages[] = $packet->pageNumber; break; case BookEditPacket::TYPE_ADD_PAGE: @@ -3286,7 +3307,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ //TODO: the client can send insert-before actions on trailing client-side pages which cause odd behaviour on the server return false; } - $newBook->insertPage($packet->pageNumber, $packet->text); + $text = self::checkBookText($packet->text, "page text", 256, 0x7fff, $cancel); + $newBook->insertPage($packet->pageNumber, $text); $modifiedPages[] = $packet->pageNumber; break; case BookEditPacket::TYPE_DELETE_PAGE: @@ -3305,17 +3327,36 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $modifiedPages = [$packet->pageNumber, $packet->secondaryPageNumber]; break; case BookEditPacket::TYPE_SIGN_BOOK: + $title = self::checkBookText($packet->title, "title", 16, 0x7fff, $cancel); + //this one doesn't have a limit in vanilla, so we have to improvise + $author = self::checkBookText($packet->author, "author", 256, 0x7fff, $cancel); + /** @var WrittenBook $newBook */ $newBook = Item::get(Item::WRITTEN_BOOK, 0, 1, $newBook->getNamedTag()); - $newBook->setAuthor($packet->author); - $newBook->setTitle($packet->title); + $newBook->setAuthor($author); + $newBook->setTitle($title); $newBook->setGeneration(WrittenBook::GENERATION_ORIGINAL); break; default: return false; } + /* + * Plugins may have created books with more than 50 pages; we allow plugins to do this, but not players. + * Don't allow the page count to grow past 50, but allow deleting, swapping or altering text of existing pages. + */ + $oldPageCount = count($oldBook->getPages()); + $newPageCount = count($newBook->getPages()); + if(($newPageCount > $oldPageCount && $newPageCount > 50)){ + $this->server->getLogger()->debug("Cancelled book edit by " . $this->getName() . " due to adding too many pages (new page count would be $newPageCount)"); + $cancel = true; + } + $event = new PlayerEditBookEvent($this, $oldBook, $newBook, $packet->type, $modifiedPages); + if($cancel){ + $event->setCancelled(); + } + $event->call(); if($event->isCancelled()){ return true; From 3ed57ce49a6b5ea49ced6d9622af04cf35120d79 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Tue, 4 Jan 2022 20:39:02 +0000 Subject: [PATCH 589/710] Merge pull request from GHSA-p62j-hrxm-xcxf This checks the following things: - Validity of UTF-8 encoding of title, author, and page content - Maximum soft and hard lengths of title, author, and page content (soft limits may be bypassed by uncancelling PlayerEditBookEvent; hard limits may not be bypassed) - Maximum number of pages. Books with more than 50 pages may still be edited, but may not have new pages added. --- src/item/WritableBookPage.php | 17 +++++- src/item/WrittenBook.php | 9 +++ .../mcpe/handler/InGamePacketHandler.php | 56 +++++++++++++++++-- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/item/WritableBookPage.php b/src/item/WritableBookPage.php index 62ebbcf50..95d5a6258 100644 --- a/src/item/WritableBookPage.php +++ b/src/item/WritableBookPage.php @@ -23,17 +23,32 @@ declare(strict_types=1); namespace pocketmine\item; +use pocketmine\utils\Limits; use pocketmine\utils\Utils; +use function sprintf; +use function strlen; class WritableBookPage{ + public const PAGE_LENGTH_HARD_LIMIT_BYTES = Limits::INT16_MAX; + public const PHOTO_NAME_LENGTH_HARD_LIMIT_BYTES = Limits::INT16_MAX; /** @var string */ private $text; /** @var string */ private $photoName; + /** + * @throws \InvalidArgumentException + */ + private static function checkLength(string $string, string $name, int $maxLength) : void{ + if(strlen($string) > $maxLength){ + throw new \InvalidArgumentException(sprintf("$name must be at most %d bytes, but have %d bytes", $maxLength, strlen($string))); + } + } + public function __construct(string $text, string $photoName = ""){ - //TODO: data validation + self::checkLength($text, "Text", self::PAGE_LENGTH_HARD_LIMIT_BYTES); + self::checkLength($photoName, "Photo name", self::PHOTO_NAME_LENGTH_HARD_LIMIT_BYTES); Utils::checkUTF8($text); $this->text = $text; $this->photoName = $photoName; diff --git a/src/item/WrittenBook.php b/src/item/WrittenBook.php index f356b1cd6..88352cdd1 100644 --- a/src/item/WrittenBook.php +++ b/src/item/WrittenBook.php @@ -24,7 +24,10 @@ declare(strict_types=1); namespace pocketmine\item; use pocketmine\nbt\tag\CompoundTag; +use pocketmine\utils\Limits; use pocketmine\utils\Utils; +use function sprintf; +use function strlen; class WrittenBook extends WritableBookBase{ @@ -85,6 +88,9 @@ class WrittenBook extends WritableBookBase{ * @return $this */ public function setAuthor(string $authorName) : self{ + if(strlen($authorName) > Limits::INT16_MAX){ + throw new \InvalidArgumentException(sprintf("Author must be at most %d bytes, but have %d bytes", Limits::INT16_MAX, strlen($authorName))); + } Utils::checkUTF8($authorName); $this->author = $authorName; return $this; @@ -103,6 +109,9 @@ class WrittenBook extends WritableBookBase{ * @return $this */ public function setTitle(string $title) : self{ + if(strlen($title) > Limits::INT16_MAX){ + throw new \InvalidArgumentException(sprintf("Title must be at most %d bytes, but have %d bytes", Limits::INT16_MAX, strlen($title))); + } Utils::checkUTF8($title); $this->title = $title; return $this; diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 04e1c847b..cfa80738c 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -37,6 +37,7 @@ use pocketmine\inventory\transaction\TransactionException; use pocketmine\inventory\transaction\TransactionValidationException; use pocketmine\item\VanillaItems; use pocketmine\item\WritableBook; +use pocketmine\item\WritableBookPage; use pocketmine\item\WrittenBook; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; @@ -96,6 +97,8 @@ use pocketmine\network\mcpe\protocol\types\PlayerAction; use pocketmine\network\PacketHandlingException; use pocketmine\player\Player; use pocketmine\utils\AssumptionFailedError; +use pocketmine\utils\Limits; +use pocketmine\utils\TextFormat; use function array_push; use function base64_encode; use function count; @@ -107,8 +110,10 @@ use function json_decode; use function json_encode; use function json_last_error_msg; use function max; +use function mb_strlen; use function microtime; use function preg_match; +use function sprintf; use function strlen; use function strpos; use function substr; @@ -711,6 +716,24 @@ class InGamePacketHandler extends PacketHandler{ return false; //TODO } + /** + * @throws PacketHandlingException + */ + private function checkBookText(string $string, string $fieldName, int $softLimit, int $hardLimit, bool &$cancel) : string{ + if(strlen($string) > $hardLimit){ + throw new PacketHandlingException(sprintf("Book %s must be at most %d bytes, but have %d bytes", $fieldName, $hardLimit, strlen($string))); + } + + $result = TextFormat::clean($string, false); + //strlen() is O(1), mb_strlen() is O(n) + if(strlen($result) > $softLimit * 4 || mb_strlen($result, 'UTF-8') > $softLimit){ + $cancel = true; + $this->session->getLogger()->debug("Cancelled book edit due to $fieldName exceeded soft limit of $softLimit chars"); + } + + return $result; + } + public function handleBookEdit(BookEditPacket $packet) : bool{ //TODO: break this up into book API things $oldBook = $this->player->getInventory()->getItem($packet->inventorySlot); @@ -720,10 +743,11 @@ class InGamePacketHandler extends PacketHandler{ $newBook = clone $oldBook; $modifiedPages = []; - + $cancel = false; switch($packet->type){ case BookEditPacket::TYPE_REPLACE_PAGE: - $newBook->setPageText($packet->pageNumber, $packet->text); + $text = self::checkBookText($packet->text, "page text", 256, WritableBookPage::PAGE_LENGTH_HARD_LIMIT_BYTES, $cancel); + $newBook->setPageText($packet->pageNumber, $text); $modifiedPages[] = $packet->pageNumber; break; case BookEditPacket::TYPE_ADD_PAGE: @@ -732,7 +756,8 @@ class InGamePacketHandler extends PacketHandler{ //TODO: the client can send insert-before actions on trailing client-side pages which cause odd behaviour on the server return false; } - $newBook->insertPage($packet->pageNumber, $packet->text); + $text = self::checkBookText($packet->text, "page text", 256, WritableBookPage::PAGE_LENGTH_HARD_LIMIT_BYTES, $cancel); + $newBook->insertPage($packet->pageNumber, $text); $modifiedPages[] = $packet->pageNumber; break; case BookEditPacket::TYPE_DELETE_PAGE: @@ -751,11 +776,14 @@ class InGamePacketHandler extends PacketHandler{ $modifiedPages = [$packet->pageNumber, $packet->secondaryPageNumber]; break; case BookEditPacket::TYPE_SIGN_BOOK: - /** @var WrittenBook $newBook */ + $title = self::checkBookText($packet->title, "title", 16, Limits::INT16_MAX, $cancel); + //this one doesn't have a limit in vanilla, so we have to improvise + $author = self::checkBookText($packet->author, "author", 256, Limits::INT16_MAX, $cancel); + $newBook = VanillaItems::WRITTEN_BOOK() ->setPages($oldBook->getPages()) - ->setAuthor($packet->author) - ->setTitle($packet->title) + ->setAuthor($author) + ->setTitle($title) ->setGeneration(WrittenBook::GENERATION_ORIGINAL); break; default: @@ -771,7 +799,23 @@ class InGamePacketHandler extends PacketHandler{ BookEditPacket::TYPE_SIGN_BOOK => PlayerEditBookEvent::ACTION_SIGN_BOOK, default => throw new AssumptionFailedError("We already filtered unknown types in the switch above") }; + + /* + * Plugins may have created books with more than 50 pages; we allow plugins to do this, but not players. + * Don't allow the page count to grow past 50, but allow deleting, swapping or altering text of existing pages. + */ + $oldPageCount = count($oldBook->getPages()); + $newPageCount = count($newBook->getPages()); + if(($newPageCount > $oldPageCount && $newPageCount > 50)){ + $this->session->getLogger()->debug("Cancelled book edit due to adding too many pages (new page count would be $newPageCount)"); + $cancel = true; + } + $event = new PlayerEditBookEvent($this->player, $oldBook, $newBook, $action, $modifiedPages); + if($cancel){ + $event->cancel(); + } + $event->call(); if($event->isCancelled()){ return true; From 958a9dbf0fe3131ab60319c5a939f5dfbfe5dfbb Mon Sep 17 00:00:00 2001 From: Dylan T Date: Tue, 4 Jan 2022 20:40:55 +0000 Subject: [PATCH 590/710] Merge pull request from GHSA-c6fg-99pr-25m9 * Skin: impose length limits on skinID, geometryName and geometryData fields * Skin: remove extra newline --- src/pocketmine/entity/Skin.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/pocketmine/entity/Skin.php b/src/pocketmine/entity/Skin.php index 98d1fdc4e..4effa390b 100644 --- a/src/pocketmine/entity/Skin.php +++ b/src/pocketmine/entity/Skin.php @@ -28,6 +28,7 @@ use function implode; use function in_array; use function json_encode; use function strlen; +use const INT32_MAX; class Skin{ public const ACCEPTED_SKIN_SIZES = [ @@ -67,10 +68,20 @@ class Skin{ } } + private static function checkLength(string $string, string $name, int $maxLength) : void{ + if(strlen($string) > $maxLength){ + throw new InvalidSkinException("$name must be at most $maxLength bytes, but have " . strlen($string) . " bytes"); + } + } + /** * @throws InvalidSkinException */ public function validate() : void{ + self::checkLength($this->skinId, "Skin ID", 32767); + self::checkLength($this->geometryName, "Geometry name", 32767); + self::checkLength($this->geometryData, "Geometry data", INT32_MAX); + if($this->skinId === ""){ throw new InvalidSkinException("Skin ID must not be empty"); } From 6492cac5c10f9fa8443ceddd2191a7b65b73f601 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Tue, 4 Jan 2022 20:40:55 +0000 Subject: [PATCH 591/710] Merge pull request from GHSA-c6fg-99pr-25m9 --- src/entity/Skin.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/entity/Skin.php b/src/entity/Skin.php index 0542bd75a..68dfd6e7b 100644 --- a/src/entity/Skin.php +++ b/src/entity/Skin.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\entity; use Ahc\Json\Comment as CommentedJsonDecoder; +use pocketmine\utils\Limits; use function implode; use function in_array; use function json_encode; @@ -48,7 +49,17 @@ final class Skin{ /** @var string */ private $geometryData; + private static function checkLength(string $string, string $name, int $maxLength) : void{ + if(strlen($string) > $maxLength){ + throw new InvalidSkinException("$name must be at most $maxLength bytes, but have " . strlen($string) . " bytes"); + } + } + public function __construct(string $skinId, string $skinData, string $capeData = "", string $geometryName = "", string $geometryData = ""){ + self::checkLength($skinId, "Skin ID", Limits::INT16_MAX); + self::checkLength($geometryName, "Geometry name", Limits::INT16_MAX); + self::checkLength($geometryData, "Geometry data", Limits::INT32_MAX); + if($skinId === ""){ throw new InvalidSkinException("Skin ID must not be empty"); } From 8c4b8a90422566c262bb96c545fca9365f3a4226 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 4 Jan 2022 20:44:10 +0000 Subject: [PATCH 592/710] CS --- src/pocketmine/Player.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index c4bcd651d..1bf11b1d6 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -218,7 +218,6 @@ use function round; use function spl_object_hash; use function sprintf; use function sqrt; -use function str_repeat; use function strlen; use function strpos; use function strtolower; From a4af1609eaf42eff5effe04b08f2c1402d408f3d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 4 Jan 2022 20:47:31 +0000 Subject: [PATCH 593/710] Release 3.26.5 --- changelogs/3.26.md | 4 ++++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/changelogs/3.26.md b/changelogs/3.26.md index 35b840a98..102e68aad 100644 --- a/changelogs/3.26.md +++ b/changelogs/3.26.md @@ -26,3 +26,7 @@ Plugin developers should **only** update their required API to this version if y - Fixed skins appearing black when using RTX resource packs. - Fixed chunks containing furnaces in old worlds (pre-2017) being discarded as corrupted. - This was caused by a strict corruption check detecting bad data created by a bug in PocketMine-MP that was fixed in 2017. + +# 3.26.5 +- Fixed several denial-of-service attack vectors related to writable book text length and encoding. +- Fixed several denial-of-service attack vectors related to skin data field lengths. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index ae075617b..8effa492f 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -34,5 +34,5 @@ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.26.5"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_CHANNEL = "pm3"; From e8893dd91f340b48e2072ebbba8d16a4cbd1ea82 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 4 Jan 2022 20:47:31 +0000 Subject: [PATCH 594/710] 3.26.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 8effa492f..d2c0036be 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.26.5"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.26.6"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_CHANNEL = "pm3"; From e7d17eb4d327f6573ae702273e3838305844d2d6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 4 Jan 2022 20:51:36 +0000 Subject: [PATCH 595/710] Release 4.0.5 --- changelogs/4.0.md | 11 ++++++++++- src/VersionInfo.php | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 211b825e8..a12c11cd4 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1590,4 +1590,13 @@ Released 1st January 2022. - Fixed message length limit for chat (now 512 instead of 255, and accounts for UTF-8). - Fixed incorrect message being displayed when trying to sleep in a bed which is too far away. - Fixed missing space between `Kicked by admin.` and `Reason` when using `/kick` to kick a player. -- Fixed client-side performance issue of entities with very large scale. \ No newline at end of file +- Fixed client-side performance issue of entities with very large scale. + +# 4.0.5 +Released 4th January 2022. + +## Fixes +- Fixed several denial-of-service attack vectors related to writable book text length and encoding. +- Fixed several denial-of-service attack vectors related to skin data field lengths. +- Fixed food bar desync when cancelling `PlayerItemConsumeEvent` in a plugin. +- Fixed compass needles not updating when the world spawn is changed. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 5cd6474d5..65bfbab9c 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.5"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 35f205b476a3f44484ed026a8c97d38f03e30bf8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 4 Jan 2022 20:51:37 +0000 Subject: [PATCH 596/710] 4.0.6 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 65bfbab9c..366709e4b 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.5"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.6"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 230a3c98390f2c285359a0d6831582943f21d991 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Jan 2022 13:49:29 +0000 Subject: [PATCH 597/710] Bump phpstan/phpstan from 1.2.0 to 1.3.1 (#4702) Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.2.0 to 1.3.1. - [Release notes](https://github.com/phpstan/phpstan/releases) - [Changelog](https://github.com/phpstan/phpstan/blob/master/CHANGELOG.md) - [Commits](https://github.com/phpstan/phpstan/compare/1.2.0...1.3.1) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- composer.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 8c2f8902a..4b870b112 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,7 @@ "webmozart/path-util": "^2.3" }, "require-dev": { - "phpstan/phpstan": "1.2.0", + "phpstan/phpstan": "1.3.1", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index be9b3c6eb..69e9f4733 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5dc75b1eaa0493544081f223d3e2304c", + "content-hash": "21dbdd29be952db47b97d8f3c8752b98", "packages": [ { "name": "adhocore/json-comment", @@ -1900,16 +1900,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.2.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee" + "reference": "c3e7a5837829b3cd5907b895da73a4da084a9f8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cbe085f9fdead5b6d62e4c022ca52dc9427a10ee", - "reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c3e7a5837829b3cd5907b895da73a4da084a9f8f", + "reference": "c3e7a5837829b3cd5907b895da73a4da084a9f8f", "shasum": "" }, "require": { @@ -1925,7 +1925,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -1940,7 +1940,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.2.0" + "source": "https://github.com/phpstan/phpstan/tree/1.3.1" }, "funding": [ { @@ -1960,7 +1960,7 @@ "type": "tidelift" } ], - "time": "2021-11-18T14:09:01+00:00" + "time": "2022-01-04T17:12:37+00:00" }, { "name": "phpstan/phpstan-phpunit", From 86beeb82559c98558d2a97e92a431a6dc3851d6c Mon Sep 17 00:00:00 2001 From: Dylan T Date: Thu, 6 Jan 2022 17:11:03 +0000 Subject: [PATCH 598/710] readme: update badge links [ci skip] --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 402558916..4d376751c 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@

- CI - GitHub release (latest SemVer) + CI + GitHub release (latest SemVer) Docker image version (latest semver) Discord
- GitHub all releases - GitHub release (latest by SemVer) + GitHub all releases + GitHub release (latest by SemVer)

## Getting started From ffa8cf3ec3f298fa9dbfc9ab7dbb4d7724c11850 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 6 Jan 2022 22:42:16 +0000 Subject: [PATCH 599/710] Update to BedrockProtocol 7.3.0 --- composer.json | 2 +- composer.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 499171b9c..f3f680f7c 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "fgrosse/phpasn1": "^2.3", "netresearch/jsonmapper": "^4.0", "pocketmine/bedrock-data": "~1.5.0+bedrock-1.18.0", - "pocketmine/bedrock-protocol": "~7.1.0+bedrock-1.18.0", + "pocketmine/bedrock-protocol": "~7.3.0+bedrock-1.18.0", "pocketmine/binaryutils": "^0.2.1", "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "^0.2.0", diff --git a/composer.lock b/composer.lock index a564c59df..5786279f3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1e11dbe91c0a485cacf0b0a5bb1eeee3", + "content-hash": "5d3bf1dc144f66c995d677cae7de8b63", "packages": [ { "name": "adhocore/json-comment", @@ -275,16 +275,16 @@ }, { "name": "pocketmine/bedrock-protocol", - "version": "7.1.0+bedrock-1.18.0", + "version": "7.3.0+bedrock-1.18.0", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockProtocol.git", - "reference": "42f2a00634c17c346fd98c05b2daf29d1fbf5805" + "reference": "418b4dbaa6720b6c6c4385a4d321d9c0b3dbf14b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/42f2a00634c17c346fd98c05b2daf29d1fbf5805", - "reference": "42f2a00634c17c346fd98c05b2daf29d1fbf5805", + "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/418b4dbaa6720b6c6c4385a4d321d9c0b3dbf14b", + "reference": "418b4dbaa6720b6c6c4385a4d321d9c0b3dbf14b", "shasum": "" }, "require": { @@ -298,7 +298,7 @@ "ramsey/uuid": "^4.1" }, "require-dev": { - "phpstan/phpstan": "1.2.0", + "phpstan/phpstan": "1.3.1", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.5" @@ -316,9 +316,9 @@ "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "support": { "issues": "https://github.com/pmmp/BedrockProtocol/issues", - "source": "https://github.com/pmmp/BedrockProtocol/tree/7.1.0+bedrock-1.18.0" + "source": "https://github.com/pmmp/BedrockProtocol/tree/7.3.0+bedrock-1.18.0" }, - "time": "2021-12-15T03:07:05+00:00" + "time": "2022-01-06T20:44:27+00:00" }, { "name": "pocketmine/binaryutils", From 4f8a0bad25265947a40779d9dec30b842442d846 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 6 Jan 2022 23:54:54 +0000 Subject: [PATCH 600/710] RegistryTrait: avoid overwriting parameter variables --- src/utils/RegistryTrait.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/utils/RegistryTrait.php b/src/utils/RegistryTrait.php index 31c2116f1..185dfefb3 100644 --- a/src/utils/RegistryTrait.php +++ b/src/utils/RegistryTrait.php @@ -37,11 +37,11 @@ trait RegistryTrait{ * @throws \InvalidArgumentException */ private static function _registryRegister(string $name, object $member) : void{ - $name = mb_strtoupper($name); - if(isset(self::$members[$name])){ - throw new \InvalidArgumentException("\"$name\" is already reserved"); + $upperName = mb_strtoupper($name); + if(isset(self::$members[$upperName])){ + throw new \InvalidArgumentException("\"$upperName\" is already reserved"); } - self::$members[mb_strtoupper($name)] = $member; + self::$members[$upperName] = $member; } /** @@ -68,11 +68,11 @@ trait RegistryTrait{ */ private static function _registryFromString(string $name) : object{ self::checkInit(); - $name = mb_strtoupper($name); - if(!isset(self::$members[$name])){ - throw new \InvalidArgumentException("No such registry member: " . self::class . "::" . $name); + $upperName = mb_strtoupper($name); + if(!isset(self::$members[$upperName])){ + throw new \InvalidArgumentException("No such registry member: " . self::class . "::" . $upperName); } - return self::preprocessMember(self::$members[$name]); + return self::preprocessMember(self::$members[$upperName]); } protected static function preprocessMember(object $member) : object{ From 3e6c157217e82dcbc8584681b2ec8ef0c7e2d833 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Jan 2022 15:20:33 +0000 Subject: [PATCH 601/710] Bump phpstan/phpstan from 1.3.1 to 1.3.3 (#4712) Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.3.1 to 1.3.3. - [Release notes](https://github.com/phpstan/phpstan/releases) - [Changelog](https://github.com/phpstan/phpstan/blob/master/CHANGELOG.md) - [Commits](https://github.com/phpstan/phpstan/compare/1.3.1...1.3.3) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 4b870b112..8eecd762e 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,7 @@ "webmozart/path-util": "^2.3" }, "require-dev": { - "phpstan/phpstan": "1.3.1", + "phpstan/phpstan": "1.3.3", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index 69e9f4733..26d6b7dc6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "21dbdd29be952db47b97d8f3c8752b98", + "content-hash": "055bec16a9bbc839f4410d09b09f2703", "packages": [ { "name": "adhocore/json-comment", @@ -1900,16 +1900,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.3.1", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "c3e7a5837829b3cd5907b895da73a4da084a9f8f" + "reference": "151a51f6149855785fbd883e79768c0abc96b75f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c3e7a5837829b3cd5907b895da73a4da084a9f8f", - "reference": "c3e7a5837829b3cd5907b895da73a4da084a9f8f", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/151a51f6149855785fbd883e79768c0abc96b75f", + "reference": "151a51f6149855785fbd883e79768c0abc96b75f", "shasum": "" }, "require": { @@ -1940,7 +1940,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.3.1" + "source": "https://github.com/phpstan/phpstan/tree/1.3.3" }, "funding": [ { @@ -1960,7 +1960,7 @@ "type": "tidelift" } ], - "time": "2022-01-04T17:12:37+00:00" + "time": "2022-01-07T09:49:03+00:00" }, { "name": "phpstan/phpstan-phpunit", From ed2145b6a4f2228fd7114b19c0809bd3056e1202 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 20:12:21 +0000 Subject: [PATCH 602/710] php-cs-fixer: enforce EOF newlines --- .php-cs-fixer.php | 1 + src/pocketmine/entity/InvalidSkinException.php | 2 +- src/pocketmine/network/mcpe/protocol/types/PersonaSkinPiece.php | 2 +- .../network/mcpe/protocol/types/SubChunkPacketHeightMapInfo.php | 2 +- .../network/mcpe/protocol/types/SubChunkPacketHeightMapType.php | 2 +- .../network/mcpe/protocol/types/SubChunkRequestResult.php | 2 +- src/pocketmine/utils/SingletonTrait.php | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 01a6e52c0..6fb364510 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -75,6 +75,7 @@ return (new PhpCsFixer\Config) 'return_type_declaration' => [ 'space_before' => 'one' ], + 'single_blank_line_at_eof' => true, 'single_import_per_statement' => true, 'strict_param' => true, 'unary_operator_spaces' => true, diff --git a/src/pocketmine/entity/InvalidSkinException.php b/src/pocketmine/entity/InvalidSkinException.php index 65ad5cf17..43aef8f10 100644 --- a/src/pocketmine/entity/InvalidSkinException.php +++ b/src/pocketmine/entity/InvalidSkinException.php @@ -25,4 +25,4 @@ namespace pocketmine\entity; final class InvalidSkinException extends \InvalidArgumentException{ -} \ No newline at end of file +} diff --git a/src/pocketmine/network/mcpe/protocol/types/PersonaSkinPiece.php b/src/pocketmine/network/mcpe/protocol/types/PersonaSkinPiece.php index bb22a1350..a671201d9 100644 --- a/src/pocketmine/network/mcpe/protocol/types/PersonaSkinPiece.php +++ b/src/pocketmine/network/mcpe/protocol/types/PersonaSkinPiece.php @@ -74,4 +74,4 @@ final class PersonaSkinPiece{ public function getProductId() : string{ return $this->productId; } -} \ No newline at end of file +} diff --git a/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapInfo.php b/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapInfo.php index d8934d744..df5526337 100644 --- a/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapInfo.php +++ b/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapInfo.php @@ -86,4 +86,4 @@ class SubChunkPacketHeightMapInfo{ } return true; } -} \ No newline at end of file +} diff --git a/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapType.php b/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapType.php index 7b1d4105d..74c33213a 100644 --- a/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapType.php +++ b/src/pocketmine/network/mcpe/protocol/types/SubChunkPacketHeightMapType.php @@ -29,4 +29,4 @@ final class SubChunkPacketHeightMapType{ public const DATA = 1; public const ALL_TOO_HIGH = 2; public const ALL_TOO_LOW = 3; -} \ No newline at end of file +} diff --git a/src/pocketmine/network/mcpe/protocol/types/SubChunkRequestResult.php b/src/pocketmine/network/mcpe/protocol/types/SubChunkRequestResult.php index 7a52d319f..a36709dc4 100644 --- a/src/pocketmine/network/mcpe/protocol/types/SubChunkRequestResult.php +++ b/src/pocketmine/network/mcpe/protocol/types/SubChunkRequestResult.php @@ -31,4 +31,4 @@ final class SubChunkRequestResult{ public const WRONG_DIMENSION = 3; public const NULL_PLAYER = 4; public const Y_INDEX_OUT_OF_BOUNDS = 5; -} \ No newline at end of file +} diff --git a/src/pocketmine/utils/SingletonTrait.php b/src/pocketmine/utils/SingletonTrait.php index 99e30e41c..ee63cbb9c 100644 --- a/src/pocketmine/utils/SingletonTrait.php +++ b/src/pocketmine/utils/SingletonTrait.php @@ -45,4 +45,4 @@ trait SingletonTrait{ public static function reset() : void{ self::$instance = null; } -} \ No newline at end of file +} From 661848c5e7ab146b9028614da7638dd9e21f43f1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 20:39:43 +0000 Subject: [PATCH 603/710] fix more EOF newlines --- src/command/defaults/ClearCommand.php | 2 +- src/entity/animation/ItemEntityStackSizeChangeAnimation.php | 2 +- src/event/entity/ItemMergeEvent.php | 2 +- src/utils/ConfigLoadException.php | 2 +- tests/phpunit/utils/RandomTest.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/command/defaults/ClearCommand.php b/src/command/defaults/ClearCommand.php index e4a359432..472321135 100644 --- a/src/command/defaults/ClearCommand.php +++ b/src/command/defaults/ClearCommand.php @@ -171,4 +171,4 @@ class ClearCommand extends VanillaCommand{ } return $count; } -} \ No newline at end of file +} diff --git a/src/entity/animation/ItemEntityStackSizeChangeAnimation.php b/src/entity/animation/ItemEntityStackSizeChangeAnimation.php index 40dab0ab4..ecc943c8c 100644 --- a/src/entity/animation/ItemEntityStackSizeChangeAnimation.php +++ b/src/entity/animation/ItemEntityStackSizeChangeAnimation.php @@ -37,4 +37,4 @@ final class ItemEntityStackSizeChangeAnimation implements Animation{ public function encode() : array{ return [ActorEventPacket::create($this->itemEntity->getId(), ActorEvent::ITEM_ENTITY_MERGE, $this->newStackSize)]; } -} \ No newline at end of file +} diff --git a/src/event/entity/ItemMergeEvent.php b/src/event/entity/ItemMergeEvent.php index 061c61b87..4b8b7af7c 100644 --- a/src/event/entity/ItemMergeEvent.php +++ b/src/event/entity/ItemMergeEvent.php @@ -49,4 +49,4 @@ class ItemMergeEvent extends EntityEvent implements Cancellable{ return $this->target; } -} \ No newline at end of file +} diff --git a/src/utils/ConfigLoadException.php b/src/utils/ConfigLoadException.php index d5644859e..a4be1da3d 100644 --- a/src/utils/ConfigLoadException.php +++ b/src/utils/ConfigLoadException.php @@ -28,4 +28,4 @@ final class ConfigLoadException extends \RuntimeException{ public static function wrap(string $fileName, \Exception $e) : self{ return new self("Failed to parse config $fileName: " . $e->getMessage(), 0, $e); } -} \ No newline at end of file +} diff --git a/tests/phpunit/utils/RandomTest.php b/tests/phpunit/utils/RandomTest.php index 4c6f1fdf4..d8d803d20 100644 --- a/tests/phpunit/utils/RandomTest.php +++ b/tests/phpunit/utils/RandomTest.php @@ -40,4 +40,4 @@ class RandomTest extends TestCase{ } self::assertTrue($negatives); } -} \ No newline at end of file +} From 0bc578b8fc17a2cbc1bed5e1c6afc14121e45e0c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:03:19 +0000 Subject: [PATCH 604/710] Block: added getTypeId() --- src/block/Block.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/block/Block.php b/src/block/Block.php index 414d9b649..d49206f6c 100644 --- a/src/block/Block.php +++ b/src/block/Block.php @@ -166,13 +166,21 @@ class Block{ } /** - * Returns whether the given block has an equivalent type to this one. This compares base legacy ID and variant. + * Returns a type ID that identifies this type of block. This does not include information like facing, colour, + * powered/unpowered, etc. + */ + public function getTypeId() : int{ + return ($this->idInfo->getBlockId() << Block::INTERNAL_METADATA_BITS) | $this->idInfo->getVariant(); + } + + /** + * Returns whether the given block has an equivalent type to this one. This compares the type IDs. * * Note: This ignores additional IDs used to represent additional states. This means that, for example, a lit * furnace and unlit furnace are considered the same type. */ public function isSameType(Block $other) : bool{ - return $this->idInfo->getBlockId() === $other->idInfo->getBlockId() and $this->idInfo->getVariant() === $other->idInfo->getVariant(); + return $this->getTypeId() === $other->getTypeId(); } /** From 3faeb5a5568566bccc449855b54495f88473f7fc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:06:06 +0000 Subject: [PATCH 605/710] disable-block-ticking directive now supports names a la /give --- resources/pocketmine.yml | 4 +++- src/world/World.php | 25 ++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/resources/pocketmine.yml b/resources/pocketmine.yml index 2e8492624..7d0a337a7 100644 --- a/resources/pocketmine.yml +++ b/resources/pocketmine.yml @@ -128,7 +128,9 @@ chunk-ticking: blocks-per-subchunk-per-tick: 3 #IDs of blocks not to perform random ticking on. disable-block-ticking: - #- 2 # grass + #- grass + #- ice + #- fire chunk-generation: #Max. amount of chunks in the waiting queue to be populated diff --git a/src/world/World.php b/src/world/World.php index 777a2e1f4..19709e3ac 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -54,6 +54,7 @@ use pocketmine\event\world\WorldSaveEvent; use pocketmine\item\Item; use pocketmine\item\ItemUseResult; use pocketmine\item\LegacyStringToItemParser; +use pocketmine\item\StringToItemParser; use pocketmine\item\VanillaItems; use pocketmine\lang\KnownTranslationFactory; use pocketmine\math\AxisAlignedBB; @@ -95,7 +96,6 @@ use pocketmine\world\sound\BlockPlaceSound; use pocketmine\world\sound\Sound; use pocketmine\world\utils\SubChunkExplorer; use function abs; -use function array_fill_keys; use function array_filter; use function array_key_exists; use function array_map; @@ -118,6 +118,7 @@ use function morton2d_encode; use function morton3d_decode; use function morton3d_encode; use function mt_rand; +use function preg_match; use function spl_object_id; use function strtolower; use function trim; @@ -453,10 +454,28 @@ class World implements ChunkManager{ $this->tickedBlocksPerSubchunkPerTick = $cfg->getPropertyInt("chunk-ticking.blocks-per-subchunk-per-tick", self::DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK); $this->maxConcurrentChunkPopulationTasks = $cfg->getPropertyInt("chunk-generation.population-queue-size", 2); - $dontTickBlocks = array_fill_keys($cfg->getProperty("chunk-ticking.disable-block-ticking", []), true); + $dontTickBlocks = []; + $parser = StringToItemParser::getInstance(); + foreach($cfg->getProperty("chunk-ticking.disable-block-ticking", []) as $name){ + $name = (string) $name; + $item = $parser->parse($name); + if($item !== null){ + $block = $item->getBlock(); + }elseif(preg_match("/^-?\d+$/", $name) === 1){ + $block = BlockFactory::getInstance()->get((int) $name, 0); + }else{ + //TODO: we probably ought to log an error here + continue; + } + + if($block->getId() !== BlockLegacyIds::AIR){ + $dontTickBlocks[$block->getTypeId()] = $name; + } + } foreach(BlockFactory::getInstance()->getAllKnownStates() as $state){ - if(!isset($dontTickBlocks[$state->getId()]) and $state->ticksRandomly()){ + $dontTickName = $dontTickBlocks[$state->getTypeId()] ?? null; + if($dontTickName === null && !$state->ticksRandomly()){ $this->randomTickBlocks[$state->getFullId()] = true; } } From c267e7b3c23ee1ad924d1bc7b5cda9128cad7140 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:15:05 +0000 Subject: [PATCH 606/710] Call BlockMeltEvent when frosted ice melts --- src/block/FrostedIce.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/block/FrostedIce.php b/src/block/FrostedIce.php index 269832d49..3f7c0ef10 100644 --- a/src/block/FrostedIce.php +++ b/src/block/FrostedIce.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; +use pocketmine\event\block\BlockMeltEvent; use function mt_rand; class FrostedIce extends Ice{ @@ -105,7 +106,11 @@ class FrostedIce extends Ice{ */ private function tryMelt() : bool{ if($this->age >= 3){ - $this->position->getWorld()->useBreakOn($this->position); + $ev = new BlockMeltEvent($this, VanillaBlocks::WATER()); + $ev->call(); + if(!$ev->isCancelled()){ + $this->position->getWorld()->setBlock($this->position, $ev->getNewState()); + } return true; } From 4f4aa624794c76f0f2cd31b37276b70c789ba923 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:19:08 +0000 Subject: [PATCH 607/710] ConcretePowder: call BlockFormEvent when coming in contact with water --- src/block/ConcretePowder.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/block/ConcretePowder.php b/src/block/ConcretePowder.php index b3c4c51ea..6503faf72 100644 --- a/src/block/ConcretePowder.php +++ b/src/block/ConcretePowder.php @@ -27,6 +27,7 @@ use pocketmine\block\utils\ColorInMetadataTrait; use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\Fallable; use pocketmine\block\utils\FallableTrait; +use pocketmine\event\block\BlockFormEvent; use pocketmine\math\Facing; class ConcretePowder extends Opaque implements Fallable{ @@ -42,7 +43,11 @@ class ConcretePowder extends Opaque implements Fallable{ public function onNearbyBlockChange() : void{ if(($block = $this->checkAdjacentWater()) !== null){ - $this->position->getWorld()->setBlock($this->position, $block); + $ev = new BlockFormEvent($this, $block); + $ev->call(); + if(!$ev->isCancelled()){ + $this->position->getWorld()->setBlock($this->position, $ev->getNewState()); + } }else{ $this->startFalling(); } From 5128bc02bb1bff2185547c1eff7a7b80d72cbe6b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:32:44 +0000 Subject: [PATCH 608/710] Reduce code duplication between BaseCoral and CoralBlock --- src/block/BaseCoral.php | 21 ++------------ src/block/CoralBlock.php | 21 ++------------ src/block/utils/CoralTypeTrait.php | 46 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 38 deletions(-) create mode 100644 src/block/utils/CoralTypeTrait.php diff --git a/src/block/BaseCoral.php b/src/block/BaseCoral.php index f3b37988a..71b1a5880 100644 --- a/src/block/BaseCoral.php +++ b/src/block/BaseCoral.php @@ -24,34 +24,17 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\CoralType; +use pocketmine\block\utils\CoralTypeTrait; use pocketmine\item\Item; abstract class BaseCoral extends Transparent{ - - protected CoralType $coralType; - protected bool $dead = false; + use CoralTypeTrait; public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){ parent::__construct($idInfo, $name, $breakInfo); $this->coralType = CoralType::TUBE(); } - public function getCoralType() : CoralType{ return $this->coralType; } - - /** @return $this */ - public function setCoralType(CoralType $coralType) : self{ - $this->coralType = $coralType; - return $this; - } - - public function isDead() : bool{ return $this->dead; } - - /** @return $this */ - public function setDead(bool $dead) : self{ - $this->dead = $dead; - return $this; - } - public function onNearbyBlockChange() : void{ if(!$this->dead){ $world = $this->position->getWorld(); diff --git a/src/block/CoralBlock.php b/src/block/CoralBlock.php index 5399e5804..f06172be5 100644 --- a/src/block/CoralBlock.php +++ b/src/block/CoralBlock.php @@ -24,15 +24,14 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\CoralType; +use pocketmine\block\utils\CoralTypeTrait; use pocketmine\block\utils\InvalidBlockStateException; use pocketmine\data\bedrock\CoralTypeIdMap; use pocketmine\item\Item; use function mt_rand; final class CoralBlock extends Opaque{ - - private CoralType $coralType; - private bool $dead = false; + use CoralTypeTrait; public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){ $this->coralType = CoralType::TUBE(); @@ -60,22 +59,6 @@ final class CoralBlock extends Opaque{ return 0b1111; } - public function getCoralType() : CoralType{ return $this->coralType; } - - /** @return $this */ - public function setCoralType(CoralType $coralType) : self{ - $this->coralType = $coralType; - return $this; - } - - public function isDead() : bool{ return $this->dead; } - - /** @return $this */ - public function setDead(bool $dead) : self{ - $this->dead = $dead; - return $this; - } - public function onNearbyBlockChange() : void{ if(!$this->dead){ $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(40, 200)); diff --git a/src/block/utils/CoralTypeTrait.php b/src/block/utils/CoralTypeTrait.php new file mode 100644 index 000000000..33a37bc55 --- /dev/null +++ b/src/block/utils/CoralTypeTrait.php @@ -0,0 +1,46 @@ +coralType; } + + /** @return $this */ + public function setCoralType(CoralType $coralType) : self{ + $this->coralType = $coralType; + return $this; + } + + public function isDead() : bool{ return $this->dead; } + + /** @return $this */ + public function setDead(bool $dead) : self{ + $this->dead = $dead; + return $this; + } +} From 51f2a78dcf6b5ce39d9ee41089b72a58c5039fee Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:36:49 +0000 Subject: [PATCH 609/710] World: break random tick blocks initializing out of constructor and fix a variable clobber by foreach as a side effect --- src/world/World.php | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 19709e3ac..89dfa9a4c 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -71,6 +71,7 @@ use pocketmine\promise\Promise; use pocketmine\promise\PromiseResolver; use pocketmine\scheduler\AsyncPool; use pocketmine\Server; +use pocketmine\ServerConfigGroup; use pocketmine\timings\Timings; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Limits; @@ -454,6 +455,23 @@ class World implements ChunkManager{ $this->tickedBlocksPerSubchunkPerTick = $cfg->getPropertyInt("chunk-ticking.blocks-per-subchunk-per-tick", self::DEFAULT_TICKED_BLOCKS_PER_SUBCHUNK_PER_TICK); $this->maxConcurrentChunkPopulationTasks = $cfg->getPropertyInt("chunk-generation.population-queue-size", 2); + $this->initRandomTickBlocksFromConfig($cfg); + + $this->timings = new WorldTimings($this); + + $this->workerPool->addWorkerStartHook($workerStartHook = function(int $workerId) : void{ + if(array_key_exists($workerId, $this->generatorRegisteredWorkers)){ + $this->logger->debug("Worker $workerId with previously registered generator restarted, flagging as unregistered"); + unset($this->generatorRegisteredWorkers[$workerId]); + } + }); + $workerPool = $this->workerPool; + $this->addOnUnloadCallback(static function() use ($workerPool, $workerStartHook) : void{ + $workerPool->removeWorkerStartHook($workerStartHook); + }); + } + + private function initRandomTickBlocksFromConfig(ServerConfigGroup $cfg) : void{ $dontTickBlocks = []; $parser = StringToItemParser::getInstance(); foreach($cfg->getProperty("chunk-ticking.disable-block-ticking", []) as $name){ @@ -479,19 +497,6 @@ class World implements ChunkManager{ $this->randomTickBlocks[$state->getFullId()] = true; } } - - $this->timings = new WorldTimings($this); - - $this->workerPool->addWorkerStartHook($workerStartHook = function(int $workerId) : void{ - if(array_key_exists($workerId, $this->generatorRegisteredWorkers)){ - $this->logger->debug("Worker $workerId with previously registered generator restarted, flagging as unregistered"); - unset($this->generatorRegisteredWorkers[$workerId]); - } - }); - $workerPool = $this->workerPool; - $this->addOnUnloadCallback(static function() use ($workerPool, $workerStartHook) : void{ - $workerPool->removeWorkerStartHook($workerStartHook); - }); } public function getTickRateTime() : float{ From dbbbc4f9c9ccac0da67327bb794353f29b9bb1ba Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:39:19 +0000 Subject: [PATCH 610/710] updated phpstan baseline --- tests/phpstan/configs/actual-problems.neon | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 77f3e5d77..b76a07a28 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -1040,6 +1040,11 @@ parameters: count: 1 path: ../../../src/world/Explosion.php + - + message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: ../../../src/world/World.php + - message: "#^Cannot access offset 'data' on array\\{priority\\: int, data\\: pocketmine\\\\math\\\\Vector3\\}\\|int\\|pocketmine\\\\math\\\\Vector3\\.$#" count: 1 @@ -1051,7 +1056,7 @@ parameters: path: ../../../src/world/World.php - - message: "#^Parameter \\#1 \\$keys of function array_fill_keys expects array, mixed given\\.$#" + message: "#^Cannot cast mixed to string\\.$#" count: 1 path: ../../../src/world/World.php From af81f80cf3bb53e427c726f42ca7bb6232d25ee0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:45:35 +0000 Subject: [PATCH 611/710] Updated PHPStan --- composer.json | 2 +- composer.lock | 57 +++++++++++++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/composer.json b/composer.json index 9517df926..4c8b68e82 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,7 @@ "pocketmine/spl": "^0.4.0" }, "require-dev": { - "phpstan/phpstan": "1.2.0", + "phpstan/phpstan": "1.3.3", "phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.2" diff --git a/composer.lock b/composer.lock index b6cbb4d18..f3dbc58ba 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "03871ed11c5fe042f6417bceefe9bd4a", + "content-hash": "9fe058549206174b6c62b2a41685083c", "packages": [ { "name": "adhocore/json-comment", @@ -895,16 +895,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.5.1", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae" + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/a12f7e301eb7258bb68acd89d4aefa05c2906cae", - "reference": "a12f7e301eb7258bb68acd89d4aefa05c2906cae", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706", + "reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706", "shasum": "" }, "require": { @@ -939,9 +939,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.5.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0" }, - "time": "2021-10-02T14:08:47+00:00" + "time": "2022-01-04T19:58:01+00:00" }, { "name": "phpspec/prophecy", @@ -1012,16 +1012,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.2.0", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee" + "reference": "151a51f6149855785fbd883e79768c0abc96b75f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cbe085f9fdead5b6d62e4c022ca52dc9427a10ee", - "reference": "cbe085f9fdead5b6d62e4c022ca52dc9427a10ee", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/151a51f6149855785fbd883e79768c0abc96b75f", + "reference": "151a51f6149855785fbd883e79768c0abc96b75f", "shasum": "" }, "require": { @@ -1037,7 +1037,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -1052,7 +1052,7 @@ "description": "PHPStan - PHP Static Analysis Tool", "support": { "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.2.0" + "source": "https://github.com/phpstan/phpstan/tree/1.3.3" }, "funding": [ { @@ -1072,7 +1072,7 @@ "type": "tidelift" } ], - "time": "2021-11-18T14:09:01+00:00" + "time": "2022-01-07T09:49:03+00:00" }, { "name": "phpstan/phpstan-phpunit", @@ -1500,16 +1500,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.10", + "version": "9.5.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a" + "reference": "2406855036db1102126125537adb1406f7242fdd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a", - "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2406855036db1102126125537adb1406f7242fdd", + "reference": "2406855036db1102126125537adb1406f7242fdd", "shasum": "" }, "require": { @@ -1587,11 +1587,11 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.11" }, "funding": [ { - "url": "https://phpunit.de/donate.html", + "url": "https://phpunit.de/sponsors.html", "type": "custom" }, { @@ -1599,7 +1599,7 @@ "type": "github" } ], - "time": "2021-09-25T07:38:51+00:00" + "time": "2021-12-25T07:07:57+00:00" }, { "name": "sebastian/cli-parser", @@ -2567,21 +2567,24 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "30885182c981ab175d4d034db0f6f469898070ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, @@ -2626,7 +2629,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0" }, "funding": [ { @@ -2642,7 +2645,7 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-10-20T20:35:02+00:00" }, { "name": "theseer/tokenizer", From bee2aba813cae19070880c1e9aad762b207a8a4a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:46:35 +0000 Subject: [PATCH 612/710] Updated PHPStan baseline --- tests/phpstan/configs/actual-problems.neon | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 59203a8d5..7ee1e46ed 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -3745,11 +3745,6 @@ parameters: count: 2 path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - - message: "#^Parameter \\#2 \\$code of class pocketmine\\\\resourcepacks\\\\ResourcePackException constructor expects int, mixed given\\.$#" - count: 1 - path: ../../../src/pocketmine/resourcepacks/ZippedResourcePack.php - - message: "#^Parameter \\#2 \\$length of function fread expects int\\<0, max\\>, int given\\.$#" count: 1 From b4e1871899e0ebfd2a30ba77024e10952acea470 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 21:49:49 +0000 Subject: [PATCH 613/710] Updated PHPStan baseline --- tests/phpstan/configs/actual-problems.neon | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 5776a837b..ed666daf4 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -830,11 +830,6 @@ parameters: count: 1 path: ../../../src/plugin/PluginDescription.php - - - message: "#^Parameter \\#1 \\$plugin of method pocketmine\\\\plugin\\\\PluginDescription\\:\\:loadMap\\(\\) expects array, mixed given\\.$#" - count: 1 - path: ../../../src/plugin/PluginDescription.php - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, mixed given\\.$#" count: 1 @@ -900,11 +895,6 @@ parameters: count: 2 path: ../../../src/resourcepacks/ZippedResourcePack.php - - - message: "#^Parameter \\#2 \\$code of class pocketmine\\\\resourcepacks\\\\ResourcePackException constructor expects int, mixed given\\.$#" - count: 1 - path: ../../../src/resourcepacks/ZippedResourcePack.php - - message: "#^Parameter \\#2 \\$length of function fread expects int\\<0, max\\>, int given\\.$#" count: 1 @@ -1055,11 +1045,6 @@ parameters: count: 1 path: ../../../src/utils/Utils.php - - - message: "#^Part \\$errno \\(mixed\\) of encapsed string cannot be cast to string\\.$#" - count: 1 - path: ../../../src/utils/Utils.php - - message: "#^Cannot call method getFullBlock\\(\\) on pocketmine\\\\world\\\\format\\\\SubChunk\\|null\\.$#" count: 1 From 0a5b146189b9e60e9074570fed42671e5e62e4bb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 7 Jan 2022 22:38:00 +0000 Subject: [PATCH 614/710] substr() returns an empty string instead of false in 8.0 an empty string will pass through preg_match_all() without any harmful effects, so we don't need to check for it. --- src/utils/Utils.php | 3 --- tests/phpstan/configs/phpstan-bugs.neon | 5 ----- 2 files changed, 8 deletions(-) diff --git a/src/utils/Utils.php b/src/utils/Utils.php index d761f772f..ee41ea837 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -503,9 +503,6 @@ final class Utils{ */ public static function parseDocComment(string $docComment) : array{ $rawDocComment = substr($docComment, 3, -2); //remove the opening and closing markers - if($rawDocComment === false){ //usually empty doc comment, but this is safer and statically analysable - return []; - } preg_match_all('/(*ANYCRLF)^[\t ]*(?:\* )?@([a-zA-Z\-]+)(?:[\t ]+(.+?))?[\t ]*$/m', $rawDocComment, $matches); return array_combine($matches[1], $matches[2]); diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 0d98c3677..6ca48d1b5 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -35,11 +35,6 @@ parameters: count: 1 path: ../../../src/plugin/ScriptPluginLoader.php - - - message: "#^Strict comparison using \\=\\=\\= between string and false will always evaluate to false\\.$#" - count: 1 - path: ../../../src/utils/Utils.php - - message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#" count: 2 From a323fb7bb5c643f82196ad3b43f28765052e3c61 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 9 Jan 2022 16:22:59 +0000 Subject: [PATCH 615/710] Updated pocketmine/errorhandler to 0.6.0 --- composer.json | 2 +- composer.lock | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 829c660e9..ca1bc66ef 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", - "pocketmine/errorhandler": "^0.4.0", + "pocketmine/errorhandler": "^0.6.0", "pocketmine/locale-data": "~2.3.0", "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", diff --git a/composer.lock b/composer.lock index 9a8b02923..abc8478df 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "934b70469f9dcb4c9697f69e6c4a9ec5", + "content-hash": "292d4bf59374d46e1ae84272f0abd522", "packages": [ { "name": "adhocore/json-comment", @@ -497,24 +497,25 @@ }, { "name": "pocketmine/errorhandler", - "version": "0.4.0", + "version": "0.6.0", "source": { "type": "git", "url": "https://github.com/pmmp/ErrorHandler.git", - "reference": "5bb9e2b66551ef7383da85165b7e8a7cc9aa162a" + "reference": "dae214a04348b911e8219ebf125ff1c5589cc878" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/ErrorHandler/zipball/5bb9e2b66551ef7383da85165b7e8a7cc9aa162a", - "reference": "5bb9e2b66551ef7383da85165b7e8a7cc9aa162a", + "url": "https://api.github.com/repos/pmmp/ErrorHandler/zipball/dae214a04348b911e8219ebf125ff1c5589cc878", + "reference": "dae214a04348b911e8219ebf125ff1c5589cc878", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^8.0" }, "require-dev": { "phpstan/phpstan": "0.12.99", - "phpstan/phpstan-strict-rules": "^0.12.2" + "phpstan/phpstan-strict-rules": "^0.12.2", + "phpunit/phpunit": "^9.5" }, "type": "library", "autoload": { @@ -529,9 +530,9 @@ "description": "Utilities to handle nasty PHP E_* errors in a usable way", "support": { "issues": "https://github.com/pmmp/ErrorHandler/issues", - "source": "https://github.com/pmmp/ErrorHandler/tree/0.4.0" + "source": "https://github.com/pmmp/ErrorHandler/tree/0.6.0" }, - "time": "2021-12-16T18:13:42+00:00" + "time": "2022-01-08T21:05:46+00:00" }, { "name": "pocketmine/locale-data", From fd880d8465a24b147a98a93038855a030aea5f1e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 9 Jan 2022 16:26:42 +0000 Subject: [PATCH 616/710] Filesystem: Use ErrorToExceptionHandler to improve error output --- src/utils/Filesystem.php | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/utils/Filesystem.php b/src/utils/Filesystem.php index d1795b805..574338035 100644 --- a/src/utils/Filesystem.php +++ b/src/utils/Filesystem.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\utils; +use pocketmine\errorhandler\ErrorToExceptionHandler; use Webmozart\PathUtil\Path; use function copy; use function dirname; @@ -111,8 +112,12 @@ final class Filesystem{ //if the parent dir doesn't exist, the user most likely made a mistake throw new \RuntimeException("The parent directory of $destination does not exist, or is not a directory"); } - if(!@mkdir($destination) && !is_dir($destination)){ - throw new \RuntimeException("Failed to create output directory $destination (permission denied?)"); + try{ + ErrorToExceptionHandler::trap(fn() => mkdir($destination)); + }catch(\ErrorException $e){ + if(!is_dir($destination)){ + throw new \RuntimeException("Failed to create output directory $destination: " . $e->getMessage()); + } } } self::recursiveCopyInternal($origin, $destination); @@ -263,8 +268,6 @@ final class Filesystem{ throw new \RuntimeException("Failed to write to temporary file $temporaryFileName (possibly out of free disk space)"); } - //TODO: the @ prevents us receiving the actual error message, but right now it's necessary since we can't assume - //that the error handler has been set :( $renameTemporaryFileResult = $context !== null ? @rename($temporaryFileName, $fileName, $context) : @rename($temporaryFileName, $fileName); @@ -283,11 +286,13 @@ final class Filesystem{ * } * } */ - $copyTemporaryFileResult = $context !== null ? - copy($temporaryFileName, $fileName, $context) : - copy($temporaryFileName, $fileName); - if(!$copyTemporaryFileResult){ - throw new \RuntimeException("Failed to move temporary file contents into target file"); + try{ + ErrorToExceptionHandler::trap(fn() => $context !== null ? + copy($temporaryFileName, $fileName, $context) : + copy($temporaryFileName, $fileName) + ); + }catch(\ErrorException $copyException){ + throw new \RuntimeException("Failed to move temporary file contents into target file: " . $copyException->getMessage(), 0, $copyException); } @unlink($temporaryFileName); } From a5c0958adf9bcc1a4419767ce8f2db3c29bfc99a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 9 Jan 2022 16:33:31 +0000 Subject: [PATCH 617/710] Filesystem::safeFilePutContents() now consistently throws RuntimeException in all expected failure cases unexpected cases may still throw ErrorException (such as undefined variables) but we don't want to capture those. --- src/Server.php | 2 +- src/utils/Filesystem.php | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Server.php b/src/Server.php index 9c8102354..48ff55861 100644 --- a/src/Server.php +++ b/src/Server.php @@ -545,7 +545,7 @@ class Server{ $contents = Utils::assumeNotFalse(zlib_encode($nbt->write(new TreeRoot($ev->getSaveData())), ZLIB_ENCODING_GZIP), "zlib_encode() failed unexpectedly"); try{ Filesystem::safeFilePutContents($this->getPlayerDataPath($name), $contents); - }catch(\RuntimeException | \ErrorException $e){ + }catch(\RuntimeException $e){ $this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage()))); $this->logger->logException($e); } diff --git a/src/utils/Filesystem.php b/src/utils/Filesystem.php index 574338035..9545bad1a 100644 --- a/src/utils/Filesystem.php +++ b/src/utils/Filesystem.php @@ -27,7 +27,6 @@ use pocketmine\errorhandler\ErrorToExceptionHandler; use Webmozart\PathUtil\Path; use function copy; use function dirname; -use function disk_free_space; use function fclose; use function fflush; use function file_exists; @@ -236,6 +235,8 @@ final class Filesystem{ * new contents. * * @param resource|null $context Context to pass to file_put_contents + * + * @throws \RuntimeException if the operation failed for any reason */ public static function safeFilePutContents(string $fileName, string $contents, int $flags = 0, $context = null) : void{ $directory = dirname($fileName); @@ -253,19 +254,16 @@ final class Filesystem{ $counter++; }while(is_dir($temporaryFileName)); - $writeTemporaryFileResult = $context !== null ? - file_put_contents($temporaryFileName, $contents, $flags, $context) : - file_put_contents($temporaryFileName, $contents, $flags); - - if($writeTemporaryFileResult !== strlen($contents)){ + try{ + ErrorToExceptionHandler::trap(fn() => $context !== null ? + file_put_contents($temporaryFileName, $contents, $flags, $context) : + file_put_contents($temporaryFileName, $contents, $flags) + ); + }catch(\ErrorException $filePutContentsException){ $context !== null ? @unlink($temporaryFileName, $context) : @unlink($temporaryFileName); - $diskSpace = disk_free_space($directory); - if($diskSpace !== false && $diskSpace < strlen($contents)){ - throw new \RuntimeException("Failed to write to temporary file $temporaryFileName (out of free disk space)"); - } - throw new \RuntimeException("Failed to write to temporary file $temporaryFileName (possibly out of free disk space)"); + throw new \RuntimeException("Failed to write to temporary file $temporaryFileName: " . $filePutContentsException->getMessage(), 0, $filePutContentsException); } $renameTemporaryFileResult = $context !== null ? From 58e1e7bd6ffbf4eb950e45308d36617b26d58105 Mon Sep 17 00:00:00 2001 From: Jack Honour Date: Mon, 10 Jan 2022 15:12:37 +0000 Subject: [PATCH 618/710] Worker: fixed missing AsyncTask import for documentation (#4719) OCD from f5c9c02e09f54b53ed4c495c8a0000b54930ccef --- src/thread/Worker.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/thread/Worker.php b/src/thread/Worker.php index e710787cc..e504165ff 100644 --- a/src/thread/Worker.php +++ b/src/thread/Worker.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\thread; +use pocketmine\scheduler\AsyncTask; use const PTHREADS_INHERIT_NONE; /** From d1726aa20c68a4b683282ab8a55fa8dac4a76042 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 10 Jan 2022 21:41:37 +0000 Subject: [PATCH 619/710] CS: use fully_qualified_strict_types --- .php-cs-fixer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 9734cddb0..35102be7d 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -36,6 +36,7 @@ return (new PhpCsFixer\Config) ], 'declare_strict_types' => true, 'elseif' => true, + 'fully_qualified_strict_types' => true, 'global_namespace_import' => [ 'import_constants' => true, 'import_functions' => true, From 248cc0ef4994037c0844da27be0d837d009f3c79 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 10 Jan 2022 22:06:07 +0000 Subject: [PATCH 620/710] actions: colorize diff output on CS failure --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fb2b8214e..1c4b38176 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -201,4 +201,4 @@ jobs: tools: php-cs-fixer:3.2 - name: Run PHP-CS-Fixer - run: php-cs-fixer fix --dry-run --diff + run: php-cs-fixer fix --dry-run --diff --ansi From 8a65fd273a31106c1a35a93e0f3c4fc6ec5bce11 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 10 Jan 2022 22:29:38 +0000 Subject: [PATCH 621/710] Updated RakLib to 0.14.3 --- composer.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index fa50aa545..8851d1095 100644 --- a/composer.lock +++ b/composer.lock @@ -726,16 +726,16 @@ }, { "name": "pocketmine/raklib", - "version": "0.14.2", + "version": "0.14.3", "source": { "type": "git", "url": "https://github.com/pmmp/RakLib.git", - "reference": "e3a861187470e1facc6625040128f447ebbcbaec" + "reference": "4798576fec0364266dce23b368a7fec5e5de7927" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/RakLib/zipball/e3a861187470e1facc6625040128f447ebbcbaec", - "reference": "e3a861187470e1facc6625040128f447ebbcbaec", + "url": "https://api.github.com/repos/pmmp/RakLib/zipball/4798576fec0364266dce23b368a7fec5e5de7927", + "reference": "4798576fec0364266dce23b368a7fec5e5de7927", "shasum": "" }, "require": { @@ -747,8 +747,8 @@ "pocketmine/log": "^0.3.0 || ^0.4.0" }, "require-dev": { - "phpstan/phpstan": "0.12.99", - "phpstan/phpstan-strict-rules": "^0.12.2" + "phpstan/phpstan": "1.3.3", + "phpstan/phpstan-strict-rules": "^1.0" }, "type": "library", "autoload": { @@ -763,9 +763,9 @@ "description": "A RakNet server implementation written in PHP", "support": { "issues": "https://github.com/pmmp/RakLib/issues", - "source": "https://github.com/pmmp/RakLib/tree/0.14.2" + "source": "https://github.com/pmmp/RakLib/tree/0.14.3" }, - "time": "2021-10-04T20:39:11+00:00" + "time": "2022-01-10T21:29:48+00:00" }, { "name": "pocketmine/raklib-ipc", From d34f4b28b3ed526708876b562ac5cd948f8d87e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 14:21:32 +0000 Subject: [PATCH 622/710] Bump pocketmine/binaryutils from 0.2.3 to 0.2.4 (#4726) Bumps [pocketmine/binaryutils](https://github.com/pmmp/BinaryUtils) from 0.2.3 to 0.2.4. - [Release notes](https://github.com/pmmp/BinaryUtils/releases) - [Commits](https://github.com/pmmp/BinaryUtils/compare/0.2.3...0.2.4) --- updated-dependencies: - dependency-name: pocketmine/binaryutils dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index 8851d1095..392eff4ed 100644 --- a/composer.lock +++ b/composer.lock @@ -322,16 +322,16 @@ }, { "name": "pocketmine/binaryutils", - "version": "0.2.3", + "version": "0.2.4", "source": { "type": "git", "url": "https://github.com/pmmp/BinaryUtils.git", - "reference": "dc94786fc6c30012b1892f548dbb8a8c9c0a8cd9" + "reference": "5ac7eea91afbad8dc498f5ce34ce6297d5e6ea9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/dc94786fc6c30012b1892f548dbb8a8c9c0a8cd9", - "reference": "dc94786fc6c30012b1892f548dbb8a8c9c0a8cd9", + "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/5ac7eea91afbad8dc498f5ce34ce6297d5e6ea9a", + "reference": "5ac7eea91afbad8dc498f5ce34ce6297d5e6ea9a", "shasum": "" }, "require": { @@ -340,7 +340,7 @@ }, "require-dev": { "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "1.2.0", + "phpstan/phpstan": "1.3.0", "phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-strict-rules": "^1.0.0", "phpunit/phpunit": "^9.5" @@ -358,9 +358,9 @@ "description": "Classes and methods for conveniently handling binary data", "support": { "issues": "https://github.com/pmmp/BinaryUtils/issues", - "source": "https://github.com/pmmp/BinaryUtils/tree/0.2.3" + "source": "https://github.com/pmmp/BinaryUtils/tree/0.2.4" }, - "time": "2021-12-04T20:56:05+00:00" + "time": "2022-01-12T18:06:33+00:00" }, { "name": "pocketmine/callback-validator", @@ -3544,5 +3544,5 @@ "platform-overrides": { "php": "8.0.0" }, - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.2.0" } From f126479c37ff00a717a828f5271cf8e821d12d6c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 13 Jan 2022 21:21:02 +0000 Subject: [PATCH 623/710] InGamePacketHandler: check the validity of facing values given by the client --- src/network/mcpe/handler/InGamePacketHandler.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index cfa80738c..947e29042 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -39,6 +39,7 @@ use pocketmine\item\VanillaItems; use pocketmine\item\WritableBook; use pocketmine\item\WritableBookPage; use pocketmine\item\WrittenBook; +use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\StringTag; @@ -104,6 +105,7 @@ use function base64_encode; use function count; use function fmod; use function implode; +use function in_array; use function is_infinite; use function is_nan; use function json_decode; @@ -361,6 +363,8 @@ class InGamePacketHandler extends PacketHandler{ } //TODO: end hack for client spam bug + self::validateFacing($data->getFace()); + $blockPos = $data->getBlockPosition(); $vBlockPos = new Vector3($blockPos->getX(), $blockPos->getY(), $blockPos->getZ()); if(!$this->player->interactBlock($vBlockPos, $data->getFace(), $clickPos)){ @@ -392,6 +396,15 @@ class InGamePacketHandler extends PacketHandler{ return false; } + /** + * @throws PacketHandlingException + */ + private static function validateFacing(int $facing) : void{ + if(!in_array($facing, Facing::ALL, true)){ + throw new PacketHandlingException("Invalid facing value $facing"); + } + } + /** * Internal function used to execute rollbacks when an action fails on a block. */ @@ -504,6 +517,7 @@ class InGamePacketHandler extends PacketHandler{ switch($packet->action){ case PlayerAction::START_BREAK: + self::validateFacing($packet->face); if(!$this->player->attackBlock($pos, $packet->face)){ $this->onFailedBlockAction($pos, $packet->face); } @@ -547,6 +561,7 @@ class InGamePacketHandler extends PacketHandler{ case PlayerAction::STOP_GLIDE: break; //TODO case PlayerAction::CRACK_BREAK: + self::validateFacing($packet->face); $this->player->continueBreakBlock($pos, $packet->face); break; case PlayerAction::START_SWIMMING: From 097347284285726615507e4b98f76a00e3046815 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 13 Jan 2022 21:23:23 +0000 Subject: [PATCH 624/710] actions: bump to 8.0.14 --- .github/workflows/main.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1c4b38176..274fdcdcf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: image: [ubuntu-20.04] - php: [8.0.11] + php: [8.0.14] steps: - name: Build and prepare PHP cache @@ -31,7 +31,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [8.0.11] + php: [8.0.14] steps: - uses: actions/checkout@v2 @@ -69,7 +69,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [8.0.11] + php: [8.0.14] steps: - uses: actions/checkout@v2 @@ -107,7 +107,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [8.0.11] + php: [8.0.14] steps: - uses: actions/checkout@v2 @@ -147,7 +147,7 @@ jobs: fail-fast: false matrix: image: [ubuntu-20.04] - php: [8.0.11] + php: [8.0.14] steps: - uses: actions/checkout@v2 From 0ccb47fb07881cf7252da5c8a4717810703b89bd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 13 Jan 2022 21:46:06 +0000 Subject: [PATCH 625/710] make-release: trap more errors --- build/make-release.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/build/make-release.php b/build/make-release.php index e3a3dad81..d3428d3c1 100644 --- a/build/make-release.php +++ b/build/make-release.php @@ -75,6 +75,14 @@ const ACCEPTED_OPTS = [ "channel" => "Release channel to post this build into" ]; +function systemWrapper(string $command, string $errorMessage) : void{ + system($command, $result); + if($result !== 0){ + echo "error: $errorMessage; aborting\n"; + exit(1); + } +} + function main() : void{ $filteredOpts = []; foreach(Utils::stringifyKeys(getopt("", ["current:", "next:", "channel:", "help"])) as $optName => $optValue){ @@ -115,7 +123,7 @@ function main() : void{ echo "$currentVer will be published on release channel \"$channel\".\n"; echo "please add appropriate notes to the changelog and press enter..."; fgets(STDIN); - system('git add "' . dirname(__DIR__) . '/changelogs"'); + systemWrapper('git add "' . dirname(__DIR__) . '/changelogs"', "failed to stage changelog changes"); system('git diff --cached --quiet "' . dirname(__DIR__) . '/changelogs"', $result); if($result === 0){ echo "error: no changelog changes detected; aborting\n"; @@ -123,14 +131,15 @@ function main() : void{ } $versionInfoPath = dirname(__DIR__) . '/src/VersionInfo.php'; replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel); - system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"'); - system('git tag ' . $currentVer->getBaseVersion()); + systemWrapper('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"', "failed to create release commit"); + systemWrapper('git tag ' . $currentVer->getBaseVersion(), "failed to create release tag"); + replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel); - system('git add "' . $versionInfoPath . '"'); - system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"'); + systemWrapper('git add "' . $versionInfoPath . '"', "failed to stage changes for post-release commit"); + systemWrapper('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"', "failed to create post-release commit"); echo "pushing changes in 5 seconds\n"; sleep(5); - system('git push origin HEAD ' . $currentVer->getBaseVersion()); + systemWrapper('git push origin HEAD ' . $currentVer->getBaseVersion(), "failed to push changes to remote"); } main(); From f7d25f251e431aace3ca835918b661583d32e6e7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 13 Jan 2022 21:46:30 +0000 Subject: [PATCH 626/710] Release 4.0.6 --- changelogs/4.0.md | 7 +++++++ src/VersionInfo.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index a12c11cd4..0cd3c2a25 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1600,3 +1600,10 @@ Released 4th January 2022. - Fixed several denial-of-service attack vectors related to skin data field lengths. - Fixed food bar desync when cancelling `PlayerItemConsumeEvent` in a plugin. - Fixed compass needles not updating when the world spawn is changed. + +# 4.0.6 +Released 13th January 2022. + +## Fixes +- Fixed server crash on invalid facing values provided by the client when placing or breaking blocks. +- Fixed documentation link to AsyncTask in Worker. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 366709e4b..b1acadb58 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.6"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 9d061e86afc9cc88518e28feb6ad312f76fa43ed Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 13 Jan 2022 21:46:30 +0000 Subject: [PATCH 627/710] 4.0.7 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index b1acadb58..44e0baf24 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.6"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.7"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 6679c53e56f4d23a96e41998d9e8dcacc1300cfa Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 15 Jan 2022 16:41:27 +0000 Subject: [PATCH 628/710] BrewingStand: fixed collision box --- src/block/BrewingStand.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/block/BrewingStand.php b/src/block/BrewingStand.php index 8d631453f..87f8d3c1f 100644 --- a/src/block/BrewingStand.php +++ b/src/block/BrewingStand.php @@ -26,6 +26,9 @@ namespace pocketmine\block; use pocketmine\block\tile\BrewingStand as TileBrewingStand; use pocketmine\block\utils\BrewingStandSlot; use pocketmine\item\Item; +use pocketmine\math\Axis; +use pocketmine\math\AxisAlignedBB; +use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; use function array_key_exists; @@ -67,6 +70,19 @@ class BrewingStand extends Transparent{ return 0b111; } + protected function recalculateCollisionBoxes() : array{ + return [ + //bottom slab part - in PC this is also inset on X/Z by 1/16, but Bedrock sucks + AxisAlignedBB::one()->trim(Facing::UP, 7 / 8), + + //center post + AxisAlignedBB::one() + ->squash(Axis::X, 7 / 16) + ->squash(Axis::Z, 7 / 16) + ->trim(Facing::UP, 1 / 8) + ]; + } + public function hasSlot(BrewingStandSlot $slot) : bool{ return array_key_exists($slot->id(), $this->slots); } From 1366c49f1f6a51b238b0a29e1d0d503ba5860c0e Mon Sep 17 00:00:00 2001 From: ipad54 <63200545+ipad54@users.noreply.github.com> Date: Sun, 16 Jan 2022 00:21:29 +0300 Subject: [PATCH 629/710] Implemented Lectern (#4708) Co-authored-by: Covered123 <58715544+JavierLeon9966@users.noreply.github.com> Co-authored-by: Dylan K. Taylor --- src/block/BlockFactory.php | 3 +- src/block/Lectern.php | 127 ++++++++++++++++++ src/block/VanillaBlocks.php | 2 + src/block/tile/Lectern.php | 87 ++++++++++++ src/block/tile/TileFactory.php | 2 +- src/item/StringToItemParser.php | 1 + .../mcpe/handler/InGamePacketHandler.php | 32 +++++ .../block_factory_consistency_check.json | 2 +- 8 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 src/block/Lectern.php create mode 100644 src/block/tile/Lectern.php diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index 2cda5bcdd..4c13ce994 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -43,6 +43,7 @@ use pocketmine\block\tile\FlowerPot as TileFlowerPot; use pocketmine\block\tile\Hopper as TileHopper; use pocketmine\block\tile\ItemFrame as TileItemFrame; use pocketmine\block\tile\Jukebox as TileJukebox; +use pocketmine\block\tile\Lectern as TileLectern; use pocketmine\block\tile\MonsterSpawner as TileMonsterSpawner; use pocketmine\block\tile\NormalFurnace as TileNormalFurnace; use pocketmine\block\tile\Note as TileNote; @@ -253,6 +254,7 @@ class BlockFactory{ $this->registerAllMeta(new Opaque(new BID(Ids::LAPIS_BLOCK, 0), "Lapis Lazuli Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel()))); $this->registerAllMeta(new LapisOre(new BID(Ids::LAPIS_ORE, 0), "Lapis Lazuli Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel()))); $this->registerAllMeta(new Lava(new BIDFlattened(Ids::FLOWING_LAVA, [Ids::STILL_LAVA], 0), "Lava", BlockBreakInfo::indestructible(500.0))); + $this->registerAllMeta(new Lectern(new BID(Ids::LECTERN, 0, ItemIds::LECTERN, TileLectern::class), "Lectern", new BlockBreakInfo(2.0, BlockToolType::AXE))); $this->registerAllMeta(new Lever(new BID(Ids::LEVER, 0), "Lever", new BlockBreakInfo(0.5))); $this->registerAllMeta(new Loom(new BID(Ids::LOOM, 0), "Loom", new BlockBreakInfo(2.5, BlockToolType::AXE))); $this->registerAllMeta(new Magma(new BID(Ids::MAGMA, 0), "Magma Block", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); @@ -612,7 +614,6 @@ class BlockFactory{ //TODO: minecraft:jigsaw //TODO: minecraft:kelp //TODO: minecraft:lava_cauldron - //TODO: minecraft:lectern //TODO: minecraft:movingBlock //TODO: minecraft:observer //TODO: minecraft:piston diff --git a/src/block/Lectern.php b/src/block/Lectern.php new file mode 100644 index 000000000..bda8fa620 --- /dev/null +++ b/src/block/Lectern.php @@ -0,0 +1,127 @@ +facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta); + } + + public function writeStateToMeta() : int{ + return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing); + } + + public function readStateFromWorld() : void{ + parent::readStateFromWorld(); + $tile = $this->position->getWorld()->getTile($this->position); + if($tile instanceof TileLectern){ + $this->viewedPage = $tile->getViewedPage(); + $this->book = $tile->getBook(); + } + } + + public function writeStateToWorld() : void{ + parent::writeStateToWorld(); + $tile = $this->position->getWorld()->getTile($this->position); + if($tile instanceof TileLectern){ + $tile->setViewedPage($this->viewedPage); + $tile->setBook($this->book); + } + } + + public function getStateBitmask() : int{ + return 0b11; + } + + public function getFlammability() : int{ + return 30; + } + + public function getDrops(Item $item) : array{ + $drops = parent::getDrops($item); + if($this->book !== null){ + $drops[] = clone $this->book; + } + + return $drops; + } + + protected function recalculateCollisionBoxes() : array{ + return [AxisAlignedBB::one()->trim(Facing::UP, 0.1)]; + } + + public function getViewedPage() : int{ + return $this->viewedPage; + } + + /** @return $this */ + public function setViewedPage(int $viewedPage) : self{ + $this->viewedPage = $viewedPage; + return $this; + } + + public function getBook() : ?WritableBookBase{ + return $this->book !== null ? clone $this->book : null; + } + + /** @return $this */ + public function setBook(?WritableBookBase $book) : self{ + $this->book = $book !== null && !$book->isNull() ? (clone $book)->setCount(1) : null; + $this->viewedPage = 0; + return $this; + } + + public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ + if($this->book === null && $item instanceof WritableBookBase){ + $this->position->getWorld()->setBlock($this->position, $this->setBook($item)); + $item->pop(); + } + return true; + } + + public function onAttack(Item $item, int $face, ?Player $player = null) : bool{ + if($this->book !== null){ + $this->position->getWorld()->dropItem($this->position->up(), $this->book); + $this->position->getWorld()->setBlock($this->position, $this->setBook(null)); + } + return false; + } +} diff --git a/src/block/VanillaBlocks.php b/src/block/VanillaBlocks.php index f9ec337a4..7d1c4a1e6 100644 --- a/src/block/VanillaBlocks.php +++ b/src/block/VanillaBlocks.php @@ -363,6 +363,7 @@ use pocketmine\utils\CloningRegistryTrait; * @method static LapisOre LAPIS_LAZULI_ORE() * @method static DoubleTallGrass LARGE_FERN() * @method static Lava LAVA() + * @method static Lectern LECTERN() * @method static Opaque LEGACY_STONECUTTER() * @method static Lever LEVER() * @method static GlazedTerracotta LIGHT_BLUE_GLAZED_TERRACOTTA() @@ -924,6 +925,7 @@ final class VanillaBlocks{ self::register("lapis_lazuli_ore", $factory->get(21, 0)); self::register("large_fern", $factory->get(175, 3)); self::register("lava", $factory->get(10, 0)); + self::register("lectern", $factory->get(449, 0)); self::register("legacy_stonecutter", $factory->get(245, 0)); self::register("lever", $factory->get(69, 0)); self::register("light_blue_glazed_terracotta", $factory->get(223, 2)); diff --git a/src/block/tile/Lectern.php b/src/block/tile/Lectern.php new file mode 100644 index 000000000..00e4a1072 --- /dev/null +++ b/src/block/tile/Lectern.php @@ -0,0 +1,87 @@ +viewedPage = $nbt->getInt(self::TAG_PAGE, 0); + if(($itemTag = $nbt->getCompoundTag(self::TAG_BOOK)) !== null){ + $book = Item::nbtDeserialize($itemTag); + if($book instanceof WritableBookBase && !$book->isNull()){ + $this->book = $book; + } + } + } + + protected function writeSaveData(CompoundTag $nbt) : void{ + $nbt->setByte(self::TAG_HAS_BOOK, $this->book !== null ? 1 : 0); + $nbt->setInt(self::TAG_PAGE, $this->viewedPage); + if($this->book !== null){ + $nbt->setTag(self::TAG_BOOK, $this->book->nbtSerialize()); + $nbt->setInt(self::TAG_TOTAL_PAGES, count($this->book->getPages())); + } + } + + public function getViewedPage() : int{ + return $this->viewedPage; + } + + public function setViewedPage(int $viewedPage) : void{ + $this->viewedPage = $viewedPage; + } + + public function getBook() : ?WritableBookBase{ + return $this->book !== null ? clone $this->book : null; + } + + public function setBook(?WritableBookBase $book) : void{ + $this->book = $book !== null && !$book->isNull() ? clone $book : null; + } + + protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ + $nbt->setByte(self::TAG_HAS_BOOK, $this->book !== null ? 1 : 0); + $nbt->setInt(self::TAG_PAGE, $this->viewedPage); + if($this->book !== null){ + $nbt->setTag(self::TAG_BOOK, $this->book->nbtSerialize()); + $nbt->setInt(self::TAG_TOTAL_PAGES, count($this->book->getPages())); + } + } +} diff --git a/src/block/tile/TileFactory.php b/src/block/tile/TileFactory.php index f8a6db746..10c09ad55 100644 --- a/src/block/tile/TileFactory.php +++ b/src/block/tile/TileFactory.php @@ -67,6 +67,7 @@ final class TileFactory{ $this->register(Hopper::class, ["Hopper", "minecraft:hopper"]); $this->register(ItemFrame::class, ["ItemFrame"]); //this is an entity in PC $this->register(Jukebox::class, ["Jukebox", "RecordPlayer", "minecraft:jukebox"]); + $this->register(Lectern::class, ["Lectern", "minecraft:lectern"]); $this->register(MonsterSpawner::class, ["MobSpawner", "minecraft:mob_spawner"]); $this->register(Note::class, ["Music", "minecraft:noteblock"]); $this->register(ShulkerBox::class, ["ShulkerBox", "minecraft:shulker_box"]); @@ -85,7 +86,6 @@ final class TileFactory{ //TODO: EndGateway //TODO: EndPortal //TODO: JigsawBlock - //TODO: Lectern //TODO: MovingBlock //TODO: NetherReactor //TODO: PistonArm diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index e2ae03a97..843beae49 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -628,6 +628,7 @@ final class StringToItemParser extends StringToTParser{ $result->registerBlock("leave2", fn() => VanillaBlocks::ACACIA_LEAVES()); $result->registerBlock("leaves", fn() => VanillaBlocks::OAK_LEAVES()); $result->registerBlock("leaves2", fn() => VanillaBlocks::ACACIA_LEAVES()); + $result->registerBlock("lectern", fn() => VanillaBlocks::LECTERN()); $result->registerBlock("legacy_stonecutter", fn() => VanillaBlocks::LEGACY_STONECUTTER()); $result->registerBlock("lever", fn() => VanillaBlocks::LEVER()); $result->registerBlock("light_blue_glazed_terracotta", fn() => VanillaBlocks::LIGHT_BLUE_GLAZED_TERRACOTTA()); diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 19f050a99..b6b86f2ca 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe\handler; use pocketmine\block\BaseSign; use pocketmine\block\ItemFrame; +use pocketmine\block\Lectern; use pocketmine\block\utils\SignText; use pocketmine\entity\animation\ConsumingItemAnimation; use pocketmine\entity\Attribute; @@ -65,6 +66,7 @@ use pocketmine\network\mcpe\protocol\InteractPacket; use pocketmine\network\mcpe\protocol\InventoryTransactionPacket; use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket; use pocketmine\network\mcpe\protocol\LabTablePacket; +use pocketmine\network\mcpe\protocol\LecternUpdatePacket; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\network\mcpe\protocol\LevelSoundEventPacketV1; use pocketmine\network\mcpe\protocol\MapInfoRequestPacket; @@ -104,6 +106,7 @@ use pocketmine\player\Player; use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\Limits; use pocketmine\utils\TextFormat; +use pocketmine\world\format\Chunk; use function array_push; use function base64_encode; use function count; @@ -926,6 +929,35 @@ class InGamePacketHandler extends PacketHandler{ return false; //TODO } + public function handleLecternUpdate(LecternUpdatePacket $packet) : bool{ + if($packet->dropBook){ + //Drop book is handled with an interact event on use item transaction + return true; + } + + $pos = $packet->blockPosition; + $chunkX = $pos->getX() >> Chunk::COORD_BIT_SIZE; + $chunkZ = $pos->getZ() >> Chunk::COORD_BIT_SIZE; + $world = $this->player->getWorld(); + if(!$world->isChunkLoaded($chunkX, $chunkZ) || $world->isChunkLocked($chunkX, $chunkZ)){ + return false; + } + + $lectern = $world->getBlockAt($pos->getX(), $pos->getY(), $pos->getZ()); + if($lectern instanceof Lectern && $this->player->canInteract($lectern->getPosition(), 15)){ + if($lectern->getViewedPage() === $packet->page){ + return true; + } + $book = $lectern->getBook(); + if($book !== null && count($book->getPages()) === $packet->totalPages && $packet->page >= 0 && $packet->page < $packet->totalPages){ + $world->setBlock($lectern->getPosition(), $lectern->setViewedPage($packet->page)); + return true; + } + } + + return false; + } + public function handleNetworkStackLatency(NetworkStackLatencyPacket $packet) : bool{ return true; //TODO: implement this properly - this is here to silence debug spam from MCPE dev builds } diff --git a/tests/phpunit/block/block_factory_consistency_check.json b/tests/phpunit/block/block_factory_consistency_check.json index 932d526a4..108153dc4 100644 --- a/tests/phpunit/block/block_factory_consistency_check.json +++ b/tests/phpunit/block/block_factory_consistency_check.json @@ -1 +1 @@ -{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7296":"Fletching Table","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"23":16,"24":16,"25":16,"26":16,"27":16,"28":16,"29":16,"30":16,"31":16,"33":32,"34":32,"35":32,"36":32,"37":32,"38":32,"39":32,"40":32,"41":32,"42":32,"43":32,"44":32,"45":32,"46":32,"47":32,"50":48,"51":48,"52":48,"53":48,"54":48,"55":48,"56":48,"57":48,"58":48,"59":48,"60":48,"61":48,"62":48,"63":48,"65":64,"66":64,"67":64,"68":64,"69":64,"70":64,"71":64,"72":64,"73":64,"74":64,"75":64,"76":64,"77":64,"78":64,"79":64,"86":80,"87":80,"88":80,"89":80,"90":80,"91":80,"92":80,"93":80,"94":80,"95":80,"102":96,"103":96,"110":96,"111":96,"114":112,"115":112,"116":112,"117":112,"118":112,"119":112,"120":112,"121":112,"122":112,"123":112,"124":112,"125":112,"126":112,"127":112,"194":192,"195":192,"196":192,"197":192,"198":192,"199":192,"200":192,"201":192,"202":192,"203":192,"204":192,"205":192,"206":192,"207":192,"209":208,"210":208,"211":208,"212":208,"213":208,"214":208,"215":208,"216":208,"217":208,"218":208,"219":208,"220":208,"221":208,"222":208,"223":208,"225":224,"226":224,"227":224,"228":224,"229":224,"230":224,"231":224,"232":224,"233":224,"234":224,"235":224,"236":224,"237":224,"238":224,"239":224,"241":240,"242":240,"243":240,"244":240,"245":240,"246":240,"247":240,"248":240,"249":240,"250":240,"251":240,"252":240,"253":240,"254":240,"255":240,"257":256,"258":256,"259":256,"260":256,"261":256,"262":256,"263":256,"264":256,"265":256,"266":256,"267":256,"268":256,"269":256,"270":256,"271":256,"284":7472,"285":7473,"286":7474,"287":7475,"306":304,"307":304,"308":304,"309":304,"310":304,"311":304,"312":304,"313":304,"314":304,"315":304,"316":304,"317":304,"318":304,"319":304,"321":320,"322":320,"323":320,"324":320,"325":320,"326":320,"327":320,"328":320,"329":320,"330":320,"331":320,"332":320,"333":320,"334":320,"335":320,"337":336,"338":336,"339":336,"340":336,"341":336,"342":336,"343":336,"344":336,"345":336,"346":336,"347":336,"348":336,"349":336,"350":336,"351":336,"353":352,"354":352,"355":352,"356":352,"357":352,"358":352,"359":352,"360":352,"361":352,"362":352,"363":352,"364":352,"365":352,"366":352,"367":352,"388":384,"389":384,"390":384,"391":384,"392":384,"393":384,"394":384,"395":384,"396":384,"397":384,"398":384,"399":384,"401":400,"402":400,"403":400,"404":400,"405":400,"406":400,"407":400,"408":400,"409":400,"410":400,"411":400,"412":400,"413":400,"414":400,"415":400,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"481":480,"482":480,"483":480,"484":480,"485":480,"486":480,"487":480,"488":480,"489":480,"490":480,"491":480,"492":480,"493":480,"494":480,"495":480,"496":498,"499":498,"500":498,"501":498,"502":498,"503":498,"504":498,"505":498,"506":498,"507":498,"508":498,"509":498,"510":498,"511":498,"513":512,"514":512,"515":512,"516":512,"517":512,"518":512,"519":512,"520":512,"521":512,"522":512,"523":512,"524":512,"525":512,"526":512,"527":512,"577":576,"578":576,"579":576,"580":576,"581":576,"582":576,"583":576,"584":576,"585":576,"586":576,"587":576,"588":576,"589":576,"590":576,"591":576,"593":592,"594":592,"595":592,"596":592,"597":592,"598":592,"599":592,"600":592,"601":592,"602":592,"603":592,"604":592,"605":592,"606":592,"607":592,"619":608,"620":608,"621":608,"622":608,"623":608,"625":624,"626":624,"627":624,"628":624,"629":624,"630":624,"631":624,"632":624,"633":624,"634":624,"635":624,"636":624,"637":624,"638":624,"639":624,"641":640,"642":640,"643":640,"644":640,"645":640,"646":640,"647":640,"648":640,"649":640,"650":640,"651":640,"652":640,"653":640,"654":640,"655":640,"657":656,"658":656,"659":656,"660":656,"661":656,"662":656,"663":656,"664":656,"665":656,"666":656,"667":656,"668":656,"669":656,"670":656,"671":656,"673":672,"674":672,"675":672,"676":672,"677":672,"678":672,"679":672,"680":672,"681":672,"682":672,"683":672,"684":672,"685":672,"686":672,"687":672,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"721":720,"722":720,"723":720,"724":720,"725":720,"726":720,"727":720,"728":720,"729":720,"730":720,"731":720,"732":720,"733":720,"734":720,"735":720,"740":736,"741":736,"742":736,"743":736,"744":736,"745":736,"746":736,"747":736,"748":736,"749":736,"750":736,"751":736,"753":752,"754":752,"755":752,"756":752,"757":752,"758":752,"759":752,"760":752,"761":752,"762":752,"763":752,"764":752,"765":752,"766":752,"767":752,"769":768,"770":768,"771":768,"772":768,"773":768,"774":768,"775":768,"776":768,"777":768,"778":768,"779":768,"780":768,"781":768,"782":768,"783":768,"785":784,"786":784,"787":784,"788":784,"789":784,"790":784,"791":784,"792":784,"793":784,"794":784,"795":784,"796":784,"797":784,"798":784,"799":784,"800":805,"806":805,"807":805,"808":805,"809":805,"810":805,"811":805,"812":805,"813":805,"814":805,"815":805,"833":832,"834":832,"835":832,"836":832,"837":832,"838":832,"839":832,"840":832,"841":832,"842":832,"843":832,"844":832,"845":832,"846":832,"847":832,"856":851,"857":851,"858":851,"859":851,"860":851,"861":851,"862":851,"863":851,"864":866,"865":866,"870":866,"871":866,"872":866,"873":866,"874":866,"875":866,"876":866,"877":866,"878":866,"879":866,"897":896,"898":896,"899":896,"900":896,"901":896,"902":896,"903":896,"904":896,"905":896,"906":896,"907":896,"908":896,"909":896,"910":896,"911":896,"913":912,"914":912,"915":912,"916":912,"917":912,"918":912,"919":912,"920":912,"921":912,"922":912,"923":912,"924":912,"925":912,"926":912,"927":912,"929":928,"930":928,"931":928,"932":928,"933":928,"934":928,"935":928,"936":928,"937":928,"938":928,"939":928,"940":928,"941":928,"942":928,"943":928,"952":944,"953":944,"954":944,"955":944,"956":944,"957":944,"958":944,"959":944,"968":960,"969":960,"970":960,"971":960,"972":960,"973":960,"974":960,"975":960,"976":978,"977":978,"982":978,"983":978,"984":978,"985":978,"986":978,"987":978,"988":978,"989":978,"990":978,"991":978,"992":978,"993":978,"998":978,"999":978,"1000":978,"1001":978,"1002":978,"1003":978,"1004":978,"1005":978,"1006":978,"1007":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1048":1042,"1049":1042,"1050":1042,"1051":1042,"1052":1042,"1053":1042,"1054":1042,"1055":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1080":1075,"1081":1075,"1082":1075,"1083":1075,"1084":1075,"1085":1075,"1086":1075,"1087":1075,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1096":1090,"1097":1090,"1098":1090,"1099":1090,"1100":1090,"1101":1090,"1102":1090,"1103":1090,"1122":1120,"1123":1120,"1124":1120,"1125":1120,"1126":1120,"1127":1120,"1128":1120,"1129":1120,"1130":1120,"1131":1120,"1132":1120,"1133":1120,"1134":1120,"1135":1120,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1154":1152,"1155":1152,"1156":1152,"1157":1152,"1158":1152,"1159":1152,"1160":1152,"1161":1152,"1162":1152,"1163":1152,"1164":1152,"1165":1152,"1166":1152,"1167":1152,"1169":1168,"1170":1168,"1171":1168,"1172":1168,"1173":1168,"1174":1168,"1175":1168,"1176":1168,"1177":1168,"1178":1168,"1179":1168,"1180":1168,"1181":1168,"1182":1168,"1183":1168,"1185":1168,"1186":1168,"1187":1168,"1188":1168,"1189":1168,"1190":1168,"1191":1168,"1192":1168,"1193":1168,"1194":1168,"1195":1168,"1196":1168,"1197":1168,"1198":1168,"1199":1168,"1200":1221,"1206":1221,"1207":1221,"1208":1221,"1209":1221,"1210":1221,"1211":1221,"1212":1221,"1213":1221,"1214":1221,"1215":1221,"1216":1221,"1222":1221,"1223":1221,"1224":1221,"1225":1221,"1226":1221,"1227":1221,"1228":1221,"1229":1221,"1230":1221,"1231":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1256":1248,"1257":1248,"1258":1248,"1259":1248,"1260":1248,"1261":1248,"1262":1248,"1263":1248,"1265":1264,"1266":1264,"1267":1264,"1268":1264,"1269":1264,"1270":1264,"1271":1264,"1272":1264,"1273":1264,"1274":1264,"1275":1264,"1276":1264,"1277":1264,"1278":1264,"1279":1264,"1281":1280,"1282":1280,"1283":1280,"1284":1280,"1285":1280,"1286":1280,"1287":1280,"1288":1280,"1289":1280,"1290":1280,"1291":1280,"1292":1280,"1293":1280,"1294":1280,"1295":1280,"1313":1312,"1314":1312,"1315":1312,"1316":1312,"1317":1312,"1318":1312,"1319":1312,"1320":1312,"1321":1312,"1322":1312,"1323":1312,"1324":1312,"1325":1312,"1326":1312,"1327":1312,"1345":1344,"1346":1344,"1347":1344,"1348":1344,"1349":1344,"1350":1344,"1351":1344,"1352":1344,"1353":1344,"1354":1344,"1355":1344,"1356":1344,"1357":1344,"1358":1344,"1359":1344,"1366":1360,"1367":1360,"1368":1360,"1369":1360,"1370":1360,"1371":1360,"1372":1360,"1373":1360,"1374":1360,"1375":1360,"1377":1376,"1378":1376,"1379":1376,"1380":1376,"1381":1376,"1382":1376,"1383":1376,"1384":1376,"1385":1376,"1386":1376,"1387":1376,"1388":1376,"1389":1376,"1390":1376,"1391":1376,"1393":1392,"1394":1392,"1395":1392,"1396":1392,"1397":1392,"1398":1392,"1399":1392,"1400":1392,"1401":1392,"1402":1392,"1403":1392,"1404":1392,"1405":1392,"1406":1392,"1407":1392,"1409":1408,"1410":1408,"1411":1408,"1412":1408,"1413":1408,"1414":1408,"1415":1408,"1416":1408,"1417":1408,"1418":1408,"1419":1408,"1420":1408,"1421":1408,"1422":1408,"1423":1408,"1425":1424,"1426":1424,"1427":1424,"1428":1424,"1429":1424,"1430":1424,"1431":1424,"1432":1424,"1433":1424,"1434":1424,"1435":1424,"1436":1424,"1437":1424,"1438":1424,"1439":1424,"1440":1441,"1443":1441,"1444":1441,"1445":1441,"1446":1441,"1447":1441,"1448":1441,"1449":1441,"1450":1441,"1451":1441,"1452":1441,"1453":1441,"1454":1441,"1455":1441,"1460":1458,"1461":1458,"1462":1458,"1463":1458,"1464":1458,"1465":1458,"1466":1458,"1467":1458,"1468":1458,"1469":1458,"1470":1458,"1471":1458,"1479":1472,"1480":1472,"1481":1472,"1482":1472,"1483":1472,"1484":1472,"1485":1472,"1486":1472,"1487":1472,"1521":1520,"1522":1520,"1523":1520,"1524":1520,"1525":1520,"1526":1520,"1527":1520,"1528":1520,"1529":1520,"1530":1520,"1531":1520,"1532":1520,"1533":1520,"1534":1520,"1535":1520,"1558":1552,"1559":1552,"1560":1552,"1561":1552,"1562":1552,"1563":1552,"1564":1552,"1565":1552,"1566":1552,"1567":1552,"1572":1568,"1573":1568,"1574":1568,"1575":1568,"1576":1568,"1577":1568,"1578":1568,"1579":1568,"1580":1568,"1581":1568,"1582":1568,"1583":1568,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"1617":1616,"1618":1616,"1619":1616,"1620":1616,"1621":1616,"1622":1616,"1623":1616,"1624":1616,"1625":1616,"1626":1616,"1627":1616,"1628":1616,"1629":1616,"1630":1616,"1631":1616,"1633":1632,"1634":1632,"1635":1632,"1636":1632,"1637":1632,"1638":1632,"1639":1632,"1640":1632,"1641":1632,"1642":1632,"1643":1632,"1644":1632,"1645":1632,"1646":1632,"1647":1632,"1649":1648,"1650":1648,"1651":1648,"1652":1648,"1653":1648,"1654":1648,"1655":1648,"1656":1648,"1657":1648,"1658":1648,"1659":1648,"1660":1648,"1661":1648,"1662":1648,"1663":1648,"1672":1664,"1673":1664,"1674":1664,"1675":1664,"1676":1664,"1677":1664,"1678":1664,"1679":1664,"1688":1680,"1689":1680,"1690":1680,"1691":1680,"1692":1680,"1693":1680,"1694":1680,"1695":1680,"1736":1731,"1737":1731,"1738":1731,"1739":1731,"1740":1731,"1741":1731,"1742":1731,"1743":1731,"1752":1747,"1753":1747,"1754":1747,"1755":1747,"1756":1747,"1757":1747,"1758":1747,"1759":1747,"1761":1760,"1762":1760,"1763":1760,"1764":1760,"1765":1760,"1766":1760,"1767":1760,"1768":1760,"1769":1760,"1770":1760,"1771":1760,"1772":1760,"1773":1760,"1774":1760,"1775":1760,"1777":1776,"1778":1776,"1779":1776,"1780":1776,"1781":1776,"1782":1776,"1783":1776,"1784":1776,"1785":1776,"1786":1776,"1787":1776,"1788":1776,"1789":1776,"1790":1776,"1791":1776,"1793":1792,"1794":1792,"1795":1792,"1796":1792,"1797":1792,"1798":1792,"1799":1792,"1800":1792,"1801":1792,"1802":1792,"1803":1792,"1804":1792,"1805":1792,"1806":1792,"1807":1792,"1809":1808,"1810":1808,"1811":1808,"1812":1808,"1813":1808,"1814":1808,"1815":1808,"1816":1808,"1817":1808,"1818":1808,"1819":1808,"1820":1808,"1821":1808,"1822":1808,"1823":1808,"1832":1827,"1833":1827,"1834":1827,"1835":1827,"1836":1827,"1837":1827,"1838":1827,"1839":1827,"1844":1840,"1845":1840,"1846":1840,"1847":1840,"1848":1840,"1849":1840,"1850":1840,"1851":1840,"1852":1840,"1853":1840,"1854":1840,"1855":1840,"1857":1856,"1858":1856,"1859":1856,"1860":1856,"1861":1856,"1862":1856,"1863":1856,"1864":1856,"1865":1856,"1866":1856,"1867":1856,"1868":1856,"1869":1856,"1870":1856,"1871":1856,"1880":1872,"1881":1872,"1882":1872,"1883":1872,"1884":1872,"1885":1872,"1886":1872,"1887":1872,"1928":1922,"1929":1922,"1930":1922,"1931":1922,"1932":1922,"1933":1922,"1934":1922,"1935":1922,"1937":1936,"1938":1936,"1939":1936,"1940":1936,"1941":1936,"1942":1936,"1943":1936,"1944":1936,"1945":1936,"1946":1936,"1947":1936,"1948":1936,"1949":1936,"1950":1936,"1951":1936,"1953":1952,"1954":1952,"1955":1952,"1956":1952,"1957":1952,"1958":1952,"1959":1952,"1960":1952,"1961":1952,"1962":1952,"1963":1952,"1964":1952,"1965":1952,"1966":1952,"1967":1952,"1969":1968,"1970":1968,"1971":1968,"1972":1968,"1973":1968,"1974":1968,"1975":1968,"1976":1968,"1977":1968,"1978":1968,"1979":1968,"1980":1968,"1981":1968,"1982":1968,"1983":1968,"1985":1968,"1986":1968,"1987":1968,"1988":1968,"1989":1968,"1990":1968,"1991":1968,"1992":1968,"1993":1968,"1994":1968,"1995":1968,"1996":1968,"1997":1968,"1998":1968,"1999":1968,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2056":2051,"2057":2051,"2058":2051,"2059":2051,"2060":2051,"2061":2051,"2062":2051,"2063":2051,"2065":2064,"2066":2064,"2067":2064,"2068":2064,"2069":2064,"2070":2064,"2071":2064,"2072":2064,"2073":2064,"2074":2064,"2075":2064,"2076":2064,"2077":2064,"2078":2064,"2079":2064,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2088":2082,"2089":2082,"2090":2082,"2091":2082,"2092":2082,"2093":2082,"2094":2082,"2095":2082,"2129":2128,"2130":2128,"2131":2128,"2132":2128,"2133":2128,"2134":2128,"2135":2128,"2136":2128,"2137":2128,"2138":2128,"2139":2128,"2140":2128,"2141":2128,"2142":2128,"2143":2128,"2152":2147,"2153":2147,"2154":2147,"2155":2147,"2156":2147,"2157":2147,"2158":2147,"2159":2147,"2168":2163,"2169":2163,"2170":2163,"2171":2163,"2172":2163,"2173":2163,"2174":2163,"2175":2163,"2184":2179,"2185":2179,"2186":2179,"2187":2179,"2188":2179,"2189":2179,"2190":2179,"2191":2179,"2209":2208,"2210":2208,"2211":2208,"2212":2208,"2213":2208,"2214":2208,"2215":2208,"2216":2208,"2217":2208,"2218":2208,"2219":2208,"2220":2208,"2221":2208,"2222":2208,"2223":2208,"2238":2224,"2239":2224,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2264":2256,"2265":2256,"2266":2256,"2267":2256,"2268":2256,"2269":2256,"2270":2256,"2271":2256,"2280":2272,"2281":2272,"2282":2272,"2283":2272,"2284":2272,"2285":2272,"2286":2272,"2287":2272,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2344":2338,"2345":2338,"2346":2338,"2347":2338,"2348":2338,"2349":2338,"2350":2338,"2351":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2433":2432,"2434":2432,"2435":2432,"2436":2432,"2437":2432,"2438":2432,"2439":2432,"2440":2432,"2441":2432,"2442":2432,"2443":2432,"2444":2432,"2445":2432,"2446":2432,"2447":2432,"2449":2448,"2450":2448,"2451":2448,"2452":2448,"2453":2448,"2454":2448,"2455":2448,"2456":2448,"2457":2448,"2458":2448,"2459":2448,"2460":2448,"2461":2448,"2462":2448,"2463":2448,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2484":2480,"2487":2480,"2488":2480,"2491":2480,"2492":2480,"2493":2481,"2494":2482,"2495":2480,"2504":2499,"2505":2499,"2506":2499,"2507":2499,"2508":2499,"2509":2499,"2510":2499,"2511":2499,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2578":288,"2579":288,"2582":288,"2583":288,"2586":288,"2587":288,"2590":288,"2591":288,"2604":7476,"2605":7477,"2616":2611,"2617":2611,"2618":2611,"2619":2611,"2620":2611,"2621":2611,"2622":2611,"2623":2611,"2632":2627,"2633":2627,"2634":2627,"2635":2627,"2636":2627,"2637":2627,"2638":2627,"2639":2627,"2641":2640,"2642":2640,"2643":2640,"2644":2640,"2645":2640,"2646":2640,"2647":2640,"2648":2640,"2649":2640,"2650":2640,"2651":2640,"2652":2640,"2653":2640,"2654":2640,"2655":2640,"2691":2688,"2692":2688,"2693":2688,"2694":2688,"2695":2688,"2696":2688,"2697":2688,"2698":2688,"2699":2688,"2700":2688,"2701":2688,"2702":2688,"2703":2688,"2705":2704,"2706":2704,"2707":2704,"2708":2704,"2709":2704,"2710":2704,"2711":2704,"2712":2704,"2713":2704,"2714":2704,"2715":2704,"2716":2704,"2717":2704,"2718":2704,"2719":2704,"2721":2720,"2722":2720,"2723":2720,"2725":2720,"2726":2720,"2727":2720,"2729":2720,"2730":2720,"2731":2720,"2732":2720,"2733":2720,"2734":2720,"2735":2720,"2753":2752,"2754":2752,"2755":2752,"2756":2752,"2757":2752,"2758":2752,"2759":2752,"2760":2752,"2761":2752,"2762":2752,"2763":2752,"2764":2752,"2765":2752,"2766":2752,"2767":2752,"2769":2768,"2770":2768,"2771":2768,"2772":2768,"2773":2768,"2774":2768,"2775":2768,"2776":2768,"2777":2768,"2778":2768,"2779":2768,"2780":2768,"2781":2768,"2782":2768,"2783":2768,"2785":2784,"2786":2784,"2787":2784,"2788":2784,"2789":2784,"2790":2784,"2791":2784,"2792":2784,"2793":2784,"2794":2784,"2795":2784,"2796":2784,"2797":2784,"2798":2784,"2799":2784,"2806":2800,"2807":2800,"2814":2800,"2815":2800,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2840":2834,"2841":2834,"2842":2834,"2843":2834,"2844":2834,"2845":2834,"2846":2834,"2847":2834,"2868":2864,"2869":2864,"2870":2864,"2871":2864,"2872":2864,"2873":2864,"2874":2864,"2875":2864,"2876":2864,"2877":2864,"2878":2864,"2879":2864,"2888":2883,"2889":2883,"2890":2883,"2891":2883,"2892":2883,"2893":2883,"2894":2883,"2895":2883,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3041":3040,"3042":3040,"3043":3040,"3044":3040,"3045":3040,"3046":3040,"3047":3040,"3048":3040,"3049":3040,"3050":3040,"3051":3040,"3052":3040,"3053":3040,"3054":3040,"3055":3040,"3073":3072,"3074":3072,"3075":3072,"3076":3072,"3077":3072,"3078":3072,"3079":3072,"3080":3072,"3081":3072,"3082":3072,"3083":3072,"3084":3072,"3085":3072,"3086":3072,"3087":3072,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3169":3168,"3170":3168,"3171":3168,"3172":3168,"3173":3168,"3174":3168,"3175":3168,"3176":3168,"3177":3168,"3178":3168,"3179":3168,"3180":3168,"3181":3168,"3182":3168,"3183":3168,"3192":3187,"3193":3187,"3194":3187,"3195":3187,"3196":3187,"3197":3187,"3198":3187,"3199":3187,"3217":3216,"3219":3216,"3220":3216,"3221":3216,"3223":3216,"3224":3216,"3225":3216,"3227":3216,"3228":3216,"3229":3216,"3230":3218,"3231":3216,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3256":3251,"3257":3251,"3258":3251,"3259":3251,"3260":3251,"3261":3251,"3262":3251,"3263":3251,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3281":3280,"3282":3280,"3283":3280,"3284":3280,"3285":3280,"3286":3280,"3287":3280,"3288":3280,"3289":3280,"3290":3280,"3291":3280,"3292":3280,"3293":3280,"3294":3280,"3295":3280,"3297":3296,"3298":3296,"3299":3296,"3300":3296,"3301":3296,"3302":3296,"3303":3296,"3304":3296,"3305":3296,"3306":3296,"3307":3296,"3308":3296,"3309":3296,"3310":3296,"3311":3296,"3316":3312,"3317":3312,"3318":3312,"3319":3312,"3320":3312,"3321":3312,"3322":3312,"3323":3312,"3324":3312,"3325":3312,"3326":3312,"3327":3312,"3334":3328,"3335":3328,"3336":3328,"3337":3328,"3338":3328,"3339":3328,"3340":3328,"3341":3328,"3342":3328,"3343":3328,"3409":3408,"3410":3408,"3411":3408,"3412":3408,"3413":3408,"3414":3408,"3415":3408,"3416":3408,"3417":3408,"3418":3408,"3419":3408,"3420":3408,"3421":3408,"3422":3408,"3423":3408,"3425":3424,"3426":3424,"3427":3424,"3428":3424,"3429":3424,"3430":3424,"3431":3424,"3432":3424,"3433":3424,"3434":3424,"3435":3424,"3436":3424,"3437":3424,"3438":3424,"3439":3424,"3441":3440,"3442":3440,"3443":3440,"3444":3440,"3445":3440,"3446":3440,"3447":3440,"3448":3440,"3449":3440,"3450":3440,"3451":3440,"3452":3440,"3453":3440,"3454":3440,"3455":3440,"3457":3456,"3458":3456,"3459":3456,"3461":3456,"3462":3456,"3463":3456,"3465":3456,"3466":3456,"3467":3456,"3468":3456,"3469":3456,"3470":3456,"3471":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3512":3506,"3513":3506,"3514":3506,"3515":3506,"3516":3506,"3517":3506,"3518":3506,"3519":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3528":3522,"3529":3522,"3530":3522,"3531":3522,"3532":3522,"3533":3522,"3534":3522,"3535":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3544":3538,"3545":3538,"3546":3538,"3547":3538,"3548":3538,"3549":3538,"3550":3538,"3551":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3560":3554,"3561":3554,"3562":3554,"3563":3554,"3564":3554,"3565":3554,"3566":3554,"3567":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3576":3570,"3577":3570,"3578":3570,"3579":3570,"3580":3570,"3581":3570,"3582":3570,"3583":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3592":3586,"3593":3586,"3594":3586,"3595":3586,"3596":3586,"3597":3586,"3598":3586,"3599":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3608":3602,"3609":3602,"3610":3602,"3611":3602,"3612":3602,"3613":3602,"3614":3602,"3615":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3624":3618,"3625":3618,"3626":3618,"3627":3618,"3628":3618,"3629":3618,"3630":3618,"3631":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3640":3634,"3641":3634,"3642":3634,"3643":3634,"3644":3634,"3645":3634,"3646":3634,"3647":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3656":3650,"3657":3650,"3658":3650,"3659":3650,"3660":3650,"3661":3650,"3662":3650,"3663":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3672":3666,"3673":3666,"3674":3666,"3675":3666,"3676":3666,"3677":3666,"3678":3666,"3679":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3704":3698,"3705":3698,"3706":3698,"3707":3698,"3708":3698,"3709":3698,"3710":3698,"3711":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3720":3714,"3721":3714,"3722":3714,"3723":3714,"3724":3714,"3725":3714,"3726":3714,"3727":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3736":3730,"3737":3730,"3738":3730,"3739":3730,"3740":3730,"3741":3730,"3742":3730,"3743":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3752":3746,"3753":3746,"3754":3746,"3755":3746,"3756":3746,"3757":3746,"3758":3746,"3759":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3768":3762,"3769":3762,"3770":3762,"3771":3762,"3772":3762,"3773":3762,"3774":3762,"3775":3762,"3824":3829,"3830":3829,"3831":3829,"3832":3829,"3833":3829,"3834":3829,"3835":3829,"3836":3829,"3837":3829,"3838":3829,"3839":3829,"3889":3888,"3890":3888,"3891":3888,"3892":3888,"3893":3888,"3894":3888,"3895":3888,"3896":3888,"3897":3888,"3898":3888,"3899":3888,"3900":3888,"3901":3888,"3902":3888,"3903":3888,"3912":3904,"3913":3904,"3914":3904,"3915":3904,"3916":3904,"3917":3904,"3918":3904,"3919":3904,"3921":3920,"3922":3920,"3923":3920,"3924":3920,"3925":3920,"3926":3920,"3927":3920,"3928":3920,"3929":3920,"3930":3920,"3931":3920,"3932":3920,"3933":3920,"3934":3920,"3935":3920,"3937":3936,"3938":3936,"3939":3936,"3940":3936,"3941":3936,"3942":3936,"3943":3936,"3944":3936,"3945":3936,"3946":3936,"3947":3936,"3948":3936,"3949":3936,"3950":3936,"3951":3936,"3955":3952,"3956":3952,"3957":3952,"3958":3952,"3959":3952,"3960":3952,"3961":3952,"3962":3952,"3963":3952,"3964":3952,"3965":3952,"3966":3952,"3967":3952,"3969":3968,"3970":3968,"3971":3968,"3972":3968,"3973":3968,"3974":3968,"3975":3968,"3976":3968,"3977":3968,"3978":3968,"3979":3968,"3980":3968,"3981":3968,"3982":3968,"3983":3968,"3985":3984,"3986":3984,"3987":3984,"3988":3984,"3989":3984,"3990":3984,"3991":3984,"3992":3984,"3993":3984,"3994":3984,"3995":3984,"3996":3984,"3997":3984,"3998":3984,"3999":3984,"4049":4048,"4050":4048,"4051":4048,"4052":4048,"4053":4048,"4054":4048,"4055":4048,"4056":4048,"4057":4048,"4058":4048,"4059":4048,"4060":4048,"4061":4048,"4062":4048,"4063":4048,"4081":4080,"4082":4080,"4083":4080,"4084":4080,"4085":4080,"4086":4080,"4087":4080,"4088":4080,"4089":4080,"4090":4080,"4091":4080,"4092":4080,"4093":4080,"4094":4080,"4095":4080,"4120":4115,"4121":4115,"4122":4115,"4123":4115,"4124":4115,"4125":4115,"4126":4115,"4127":4115,"4136":4131,"4137":4131,"4138":4131,"4139":4131,"4140":4131,"4141":4131,"4142":4131,"4143":4131,"4152":4147,"4153":4147,"4154":4147,"4155":4147,"4156":4147,"4157":4147,"4158":4147,"4159":4147,"4163":4160,"4164":4160,"4165":4160,"4166":4160,"4167":4160,"4168":4160,"4169":4160,"4170":4160,"4171":4160,"4172":4160,"4173":4160,"4174":4160,"4175":4160,"4179":4176,"4180":4176,"4181":4176,"4182":4176,"4183":4176,"4184":4176,"4185":4176,"4186":4176,"4187":4176,"4188":4176,"4189":4176,"4190":4176,"4191":4176,"4195":4192,"4196":4192,"4197":4192,"4198":4192,"4199":4192,"4200":4192,"4201":4192,"4202":4192,"4203":4192,"4204":4192,"4205":4192,"4206":4192,"4207":4192,"4211":4208,"4212":4208,"4213":4208,"4214":4208,"4215":4208,"4216":4208,"4217":4208,"4218":4208,"4219":4208,"4220":4208,"4221":4208,"4222":4208,"4223":4208,"4227":4224,"4228":4224,"4229":4224,"4230":4224,"4231":4224,"4232":4224,"4233":4224,"4234":4224,"4235":4224,"4236":4224,"4237":4224,"4238":4224,"4239":4224,"4243":4240,"4244":4240,"4245":4240,"4246":4240,"4247":4240,"4248":4240,"4249":4240,"4250":4240,"4251":4240,"4252":4240,"4253":4240,"4254":4240,"4255":4240,"4257":4256,"4258":4256,"4259":4256,"4260":4256,"4261":4256,"4262":4256,"4263":4256,"4264":4256,"4265":4256,"4266":4256,"4267":4256,"4268":4256,"4269":4256,"4270":4256,"4271":4256,"4273":4272,"4274":4272,"4275":4272,"4276":4272,"4277":4272,"4278":4272,"4279":4272,"4280":4272,"4281":4272,"4282":4272,"4283":4272,"4284":4272,"4285":4272,"4286":4272,"4287":4272,"4289":4288,"4290":4288,"4291":4288,"4292":4288,"4293":4288,"4294":4288,"4295":4288,"4296":4288,"4297":4288,"4298":4288,"4299":4288,"4300":4288,"4301":4288,"4302":4288,"4303":4288,"4305":4304,"4306":4304,"4307":4304,"4308":4304,"4309":4304,"4310":4304,"4311":4304,"4312":4304,"4313":4304,"4314":4304,"4315":4304,"4316":4304,"4317":4304,"4318":4304,"4319":4304,"4321":4320,"4322":4320,"4323":4320,"4324":4320,"4325":4320,"4326":4320,"4327":4320,"4328":4320,"4329":4320,"4330":4320,"4331":4320,"4332":4320,"4333":4320,"4334":4320,"4335":4320,"4337":4336,"4338":4336,"4339":4336,"4340":4336,"4341":4336,"4342":4336,"4343":4336,"4344":4336,"4345":4336,"4346":4336,"4347":4336,"4348":4336,"4349":4336,"4350":4336,"4351":4336,"4353":4352,"4354":4352,"4355":4352,"4356":4352,"4357":4352,"4358":4352,"4359":4352,"4360":4352,"4361":4352,"4362":4352,"4363":4352,"4364":4352,"4365":4352,"4366":4352,"4367":4352,"4369":4368,"4370":4368,"4371":4368,"4372":4368,"4373":4368,"4374":4368,"4375":4368,"4376":4368,"4377":4368,"4378":4368,"4379":4368,"4380":4368,"4381":4368,"4382":4368,"4383":4368,"4385":4384,"4386":4384,"4387":4384,"4388":4384,"4389":4384,"4390":4384,"4391":4384,"4392":4384,"4393":4384,"4394":4384,"4395":4384,"4396":4384,"4397":4384,"4398":4384,"4399":4384,"4401":4400,"4402":4400,"4403":4400,"4404":4400,"4405":4400,"4406":4400,"4407":4400,"4408":4400,"4409":4400,"4410":4400,"4411":4400,"4412":4400,"4413":4400,"4414":4400,"4415":4400,"4417":4416,"4418":4416,"4419":4416,"4420":4416,"4421":4416,"4422":4416,"4423":4416,"4424":4416,"4425":4416,"4426":4416,"4427":4416,"4428":4416,"4429":4416,"4430":4416,"4431":4416,"4433":4432,"4434":4432,"4435":4432,"4436":4432,"4437":4432,"4438":4432,"4439":4432,"4440":4432,"4441":4432,"4442":4432,"4443":4432,"4444":4432,"4445":4432,"4446":4432,"4447":4432,"4449":4448,"4450":4448,"4451":4448,"4452":4448,"4453":4448,"4454":4448,"4455":4448,"4456":4448,"4457":4448,"4458":4448,"4459":4448,"4460":4448,"4461":4448,"4462":4448,"4463":4448,"4465":4464,"4466":4464,"4467":4464,"4468":4464,"4469":4464,"4470":4464,"4471":4464,"4472":4464,"4473":4464,"4474":4464,"4475":4464,"4476":4464,"4477":4464,"4478":4464,"4479":4464,"4481":4480,"4482":4480,"4483":4480,"4484":4480,"4485":4480,"4486":4480,"4487":4480,"4488":4480,"4489":4480,"4490":4480,"4491":4480,"4492":4480,"4493":4480,"4494":4480,"4495":4480,"4497":4496,"4498":4496,"4499":4496,"4500":4496,"4501":4496,"4502":4496,"4503":4496,"4504":4496,"4505":4496,"4506":4496,"4507":4496,"4508":4496,"4509":4496,"4510":4496,"4511":4496,"4513":4512,"4514":4512,"4515":4512,"4516":4512,"4517":4512,"4518":4512,"4519":4512,"4520":4512,"4521":4512,"4522":4512,"4523":4512,"4524":4512,"4525":4512,"4526":4512,"4527":4512,"4529":4528,"4530":4528,"4531":4528,"4532":4528,"4533":4528,"4534":4528,"4535":4528,"4536":4528,"4537":4528,"4538":4528,"4539":4528,"4540":4528,"4541":4528,"4542":4528,"4543":4528,"4545":4544,"4546":4544,"4547":4544,"4548":4544,"4549":4544,"4550":4544,"4551":4544,"4552":4544,"4553":4544,"4554":4544,"4555":4544,"4556":4544,"4557":4544,"4558":4544,"4559":4544,"4561":4560,"4562":4560,"4563":4560,"4564":4560,"4565":4560,"4566":4560,"4567":4560,"4568":4560,"4569":4560,"4570":4560,"4571":4560,"4572":4560,"4573":4560,"4574":4560,"4575":4560,"4577":4576,"4578":4576,"4579":4576,"4580":4576,"4581":4576,"4582":4576,"4583":4576,"4584":4576,"4585":4576,"4586":4576,"4587":4576,"4588":4576,"4589":4576,"4590":4576,"4591":4576,"4593":4592,"4594":4592,"4595":4592,"4596":4592,"4597":4592,"4598":4592,"4599":4592,"4600":4592,"4601":4592,"4602":4592,"4603":4592,"4604":4592,"4605":4592,"4606":4592,"4607":4592,"4609":4608,"4610":4608,"4611":4608,"4612":4608,"4613":4608,"4614":4608,"4615":4608,"4616":4608,"4617":4608,"4618":4608,"4619":4608,"4620":4608,"4621":4608,"4622":4608,"4623":4608,"4625":4624,"4626":4624,"4627":4624,"4628":4624,"4629":4624,"4630":4624,"4631":4624,"4632":4624,"4633":4624,"4634":4624,"4635":4624,"4636":4624,"4637":4624,"4638":4624,"4639":4624,"4641":4640,"4642":4640,"4643":4640,"4644":4640,"4645":4640,"4646":4640,"4647":4640,"4648":4640,"4649":4640,"4650":4640,"4651":4640,"4652":4640,"4653":4640,"4654":4640,"4655":4640,"4657":4656,"4658":4656,"4659":4656,"4660":4656,"4661":4656,"4662":4656,"4663":4656,"4664":4656,"4665":4656,"4666":4656,"4667":4656,"4668":4656,"4669":4656,"4670":4656,"4671":4656,"4673":4672,"4674":4672,"4675":4672,"4676":4672,"4677":4672,"4678":4672,"4679":4672,"4680":4672,"4681":4672,"4682":4672,"4683":4672,"4684":4672,"4685":4672,"4686":4672,"4687":4672,"4689":4688,"4690":4688,"4691":4688,"4692":4688,"4693":4688,"4694":4688,"4695":4688,"4696":4688,"4697":4688,"4698":4688,"4699":4688,"4700":4688,"4701":4688,"4702":4688,"4703":4688,"4705":4704,"4706":4704,"4707":4704,"4708":4704,"4709":4704,"4710":4704,"4711":4704,"4712":4704,"4713":4704,"4714":4704,"4715":4704,"4716":4704,"4717":4704,"4718":4704,"4719":4704,"4721":4720,"4722":4720,"4723":4720,"4724":4720,"4725":4720,"4726":4720,"4727":4720,"4728":4720,"4729":4720,"4730":4720,"4731":4720,"4732":4720,"4733":4720,"4734":4720,"4735":4720,"4737":4736,"4738":4736,"4739":4736,"4740":4736,"4741":4736,"4742":4736,"4743":4736,"4744":4736,"4745":4736,"4746":4736,"4747":4736,"4748":4736,"4749":4736,"4750":4736,"4751":4736,"4753":4752,"4754":4752,"4755":4752,"4756":4752,"4757":4752,"4758":4752,"4759":4752,"4760":4752,"4761":4752,"4762":4752,"4763":4752,"4764":4752,"4765":4752,"4766":4752,"4767":4752,"4769":4768,"4770":4768,"4771":4768,"4772":4768,"4773":4768,"4774":4768,"4775":4768,"4776":4768,"4777":4768,"4778":4768,"4779":4768,"4780":4768,"4781":4768,"4782":4768,"4783":4768,"4785":4784,"4786":4784,"4787":4784,"4788":4784,"4789":4784,"4790":4784,"4791":4784,"4792":4784,"4793":4784,"4794":4784,"4795":4784,"4796":4784,"4797":4784,"4798":4784,"4799":4784,"4801":4800,"4802":4800,"4803":4800,"4804":4800,"4805":4800,"4806":4800,"4807":4800,"4808":4800,"4809":4800,"4810":4800,"4811":4800,"4812":4800,"4813":4800,"4814":4800,"4815":4800,"4817":4816,"4818":4816,"4819":4816,"4820":4816,"4821":4816,"4822":4816,"4823":4816,"4824":4816,"4825":4816,"4826":4816,"4827":4816,"4828":4816,"4829":4816,"4830":4816,"4831":4816,"4833":4832,"4834":4832,"4835":4832,"4836":4832,"4837":4832,"4838":4832,"4839":4832,"4840":4832,"4841":4832,"4842":4832,"4843":4832,"4844":4832,"4845":4832,"4846":4832,"4847":4832,"4849":4848,"4850":4848,"4851":4848,"4852":4848,"4853":4848,"4854":4848,"4855":4848,"4856":4848,"4857":4848,"4858":4848,"4859":4848,"4860":4848,"4861":4848,"4862":4848,"4863":4848,"4865":4864,"4866":4864,"4867":4864,"4868":4864,"4869":4864,"4870":4864,"4871":4864,"4872":4864,"4873":4864,"4874":4864,"4875":4864,"4876":4864,"4877":4864,"4878":4864,"4879":4864,"4881":4880,"4882":4880,"4883":4880,"4884":4880,"4885":4880,"4886":4880,"4887":4880,"4888":4880,"4889":4880,"4890":4880,"4891":4880,"4892":4880,"4893":4880,"4894":4880,"4895":4880,"4897":4896,"4898":4896,"4899":4896,"4900":4896,"4901":4896,"4902":4896,"4903":4896,"4904":4896,"4905":4896,"4906":4896,"4907":4896,"4908":4896,"4909":4896,"4910":4896,"4911":4896,"4913":4912,"4914":4912,"4915":4912,"4916":4912,"4917":4912,"4918":4912,"4919":4912,"4920":4912,"4921":4912,"4922":4912,"4923":4912,"4924":4912,"4925":4912,"4926":4912,"4927":4912,"4929":4928,"4930":4928,"4931":4928,"4932":4928,"4933":4928,"4934":4928,"4935":4928,"4936":4928,"4937":4928,"4938":4928,"4939":4928,"4940":4928,"4941":4928,"4942":4928,"4943":4928,"4945":4944,"4946":4944,"4947":4944,"4948":4944,"4949":4944,"4950":4944,"4951":4944,"4952":4944,"4953":4944,"4954":4944,"4955":4944,"4956":4944,"4957":4944,"4958":4944,"4959":4944,"4961":4960,"4962":4960,"4963":4960,"4964":4960,"4965":4960,"4966":4960,"4967":4960,"4968":4960,"4969":4960,"4970":4960,"4971":4960,"4972":4960,"4973":4960,"4974":4960,"4975":4960,"4977":4976,"4978":4976,"4979":4976,"4980":4976,"4981":4976,"4982":4976,"4983":4976,"4984":4976,"4985":4976,"4986":4976,"4987":4976,"4988":4976,"4989":4976,"4990":4976,"4991":4976,"4993":4992,"4994":4992,"4995":4992,"4996":4992,"4997":4992,"4998":4992,"4999":4992,"5000":4992,"5001":4992,"5002":4992,"5003":4992,"5004":4992,"5005":4992,"5006":4992,"5007":4992,"5009":5008,"5010":5008,"5011":5008,"5012":5008,"5013":5008,"5014":5008,"5015":5008,"5016":5008,"5017":5008,"5018":5008,"5019":5008,"5020":5008,"5021":5008,"5022":5008,"5023":5008,"5025":5024,"5026":5024,"5027":5024,"5028":5024,"5029":5024,"5030":5024,"5031":5024,"5032":5024,"5033":5024,"5034":5024,"5035":5024,"5036":5024,"5037":5024,"5038":5024,"5039":5024,"5041":5040,"5042":5040,"5043":5040,"5044":5040,"5045":5040,"5046":5040,"5047":5040,"5048":5040,"5049":5040,"5050":5040,"5051":5040,"5052":5040,"5053":5040,"5054":5040,"5055":5040,"5057":5056,"5058":5056,"5059":5056,"5060":5056,"5061":5056,"5062":5056,"5063":5056,"5064":5056,"5065":5056,"5066":5056,"5067":5056,"5068":5056,"5069":5056,"5070":5056,"5071":5056,"5073":5072,"5074":5072,"5075":5072,"5076":5072,"5077":5072,"5078":5072,"5079":5072,"5080":5072,"5081":5072,"5082":5072,"5083":5072,"5084":5072,"5085":5072,"5086":5072,"5087":5072,"5089":5088,"5090":5088,"5091":5088,"5092":5088,"5093":5088,"5094":5088,"5095":5088,"5096":5088,"5097":5088,"5098":5088,"5099":5088,"5100":5088,"5101":5088,"5102":5088,"5103":5088,"5105":5104,"5106":5104,"5107":5104,"5108":5104,"5109":5104,"5110":5104,"5111":5104,"5112":5104,"5113":5104,"5114":5104,"5115":5104,"5116":5104,"5117":5104,"5118":5104,"5119":5104,"5121":5120,"5122":5120,"5123":5120,"5124":5120,"5125":5120,"5126":5120,"5127":5120,"5128":5120,"5129":5120,"5130":5120,"5131":5120,"5132":5120,"5133":5120,"5134":5120,"5135":5120,"5137":5136,"5138":5136,"5139":5136,"5140":5136,"5141":5136,"5142":5136,"5143":5136,"5144":5136,"5145":5136,"5146":5136,"5147":5136,"5148":5136,"5149":5136,"5150":5136,"5151":5136,"5153":5152,"5154":5152,"5155":5152,"5156":5152,"5157":5152,"5158":5152,"5159":5152,"5160":5152,"5161":5152,"5162":5152,"5163":5152,"5164":5152,"5165":5152,"5166":5152,"5167":5152,"5169":5168,"5170":5168,"5171":5168,"5172":5168,"5173":5168,"5174":5168,"5175":5168,"5176":5168,"5177":5168,"5178":5168,"5179":5168,"5180":5168,"5181":5168,"5182":5168,"5183":5168,"5185":5184,"5186":5184,"5187":5184,"5188":5184,"5189":5184,"5190":5184,"5191":5184,"5192":5184,"5193":5184,"5194":5184,"5195":5184,"5196":5184,"5197":5184,"5198":5184,"5199":5184,"5201":5200,"5202":5200,"5203":5200,"5204":5200,"5205":5200,"5206":5200,"5207":5200,"5208":5200,"5209":5200,"5210":5200,"5211":5200,"5212":5200,"5213":5200,"5214":5200,"5215":5200,"5217":5216,"5218":5216,"5219":5216,"5220":5216,"5221":5216,"5222":5216,"5223":5216,"5224":5216,"5225":5216,"5226":5216,"5227":5216,"5228":5216,"5229":5216,"5230":5216,"5231":5216,"5233":5232,"5234":5232,"5235":5232,"5236":5232,"5237":5232,"5238":5232,"5239":5232,"5240":5232,"5241":5232,"5242":5232,"5243":5232,"5244":5232,"5245":5232,"5246":5232,"5247":5232,"5249":5248,"5250":5248,"5251":5248,"5252":5248,"5253":5248,"5254":5248,"5255":5248,"5256":5248,"5257":5248,"5258":5248,"5259":5248,"5260":5248,"5261":5248,"5262":5248,"5263":5248,"5265":5264,"5266":5264,"5267":5264,"5268":5264,"5269":5264,"5270":5264,"5271":5264,"5272":5264,"5273":5264,"5274":5264,"5275":5264,"5276":5264,"5277":5264,"5278":5264,"5279":5264,"5281":5280,"5282":5280,"5283":5280,"5284":5280,"5285":5280,"5286":5280,"5287":5280,"5288":5280,"5289":5280,"5290":5280,"5291":5280,"5292":5280,"5293":5280,"5294":5280,"5295":5280,"5297":5296,"5298":5296,"5299":5296,"5300":5296,"5301":5296,"5302":5296,"5303":5296,"5304":5296,"5305":5296,"5306":5296,"5307":5296,"5308":5296,"5309":5296,"5310":5296,"5311":5296,"5313":5312,"5314":5312,"5315":5312,"5316":5312,"5317":5312,"5318":5312,"5319":5312,"5320":5312,"5321":5312,"5322":5312,"5323":5312,"5324":5312,"5325":5312,"5326":5312,"5327":5312,"5329":5328,"5330":5328,"5331":5328,"5332":5328,"5333":5328,"5334":5328,"5335":5328,"5336":5328,"5337":5328,"5338":5328,"5339":5328,"5340":5328,"5341":5328,"5342":5328,"5343":5328,"5345":5344,"5346":5344,"5347":5344,"5348":5344,"5349":5344,"5350":5344,"5351":5344,"5352":5344,"5353":5344,"5354":5344,"5355":5344,"5356":5344,"5357":5344,"5358":5344,"5359":5344,"5361":5360,"5362":5360,"5363":5360,"5364":5360,"5365":5360,"5366":5360,"5367":5360,"5368":5360,"5369":5360,"5370":5360,"5371":5360,"5372":5360,"5373":5360,"5374":5360,"5375":5360,"5377":5376,"5378":5376,"5379":5376,"5380":5376,"5381":5376,"5382":5376,"5383":5376,"5384":5376,"5385":5376,"5386":5376,"5387":5376,"5388":5376,"5389":5376,"5390":5376,"5391":5376,"5393":5392,"5394":5392,"5395":5392,"5396":5392,"5397":5392,"5398":5392,"5399":5392,"5400":5392,"5401":5392,"5402":5392,"5403":5392,"5404":5392,"5405":5392,"5406":5392,"5407":5392,"5409":5408,"5410":5408,"5411":5408,"5412":5408,"5413":5408,"5414":5408,"5415":5408,"5416":5408,"5417":5408,"5418":5408,"5419":5408,"5420":5408,"5421":5408,"5422":5408,"5423":5408,"5425":5424,"5426":5424,"5427":5424,"5428":5424,"5429":5424,"5430":5424,"5431":5424,"5432":5424,"5433":5424,"5434":5424,"5435":5424,"5436":5424,"5437":5424,"5438":5424,"5439":5424,"5441":5440,"5442":5440,"5443":5440,"5444":5440,"5445":5440,"5446":5440,"5447":5440,"5448":5440,"5449":5440,"5450":5440,"5451":5440,"5452":5440,"5453":5440,"5454":5440,"5455":5440,"5457":5456,"5458":5456,"5459":5456,"5460":5456,"5461":5456,"5462":5456,"5463":5456,"5464":5456,"5465":5456,"5466":5456,"5467":5456,"5468":5456,"5469":5456,"5470":5456,"5471":5456,"5473":5472,"5474":5472,"5475":5472,"5476":5472,"5477":5472,"5478":5472,"5479":5472,"5480":5472,"5481":5472,"5482":5472,"5483":5472,"5484":5472,"5485":5472,"5486":5472,"5487":5472,"5489":5488,"5490":5488,"5491":5488,"5492":5488,"5493":5488,"5494":5488,"5495":5488,"5496":5488,"5497":5488,"5498":5488,"5499":5488,"5500":5488,"5501":5488,"5502":5488,"5503":5488,"5505":5504,"5506":5504,"5507":5504,"5508":5504,"5509":5504,"5510":5504,"5511":5504,"5512":5504,"5513":5504,"5514":5504,"5515":5504,"5516":5504,"5517":5504,"5518":5504,"5519":5504,"5521":5520,"5522":5520,"5523":5520,"5524":5520,"5525":5520,"5526":5520,"5527":5520,"5528":5520,"5529":5520,"5530":5520,"5531":5520,"5532":5520,"5533":5520,"5534":5520,"5535":5520,"5537":5536,"5538":5536,"5539":5536,"5540":5536,"5541":5536,"5542":5536,"5543":5536,"5544":5536,"5545":5536,"5546":5536,"5547":5536,"5548":5536,"5549":5536,"5550":5536,"5551":5536,"5553":5552,"5554":5552,"5555":5552,"5556":5552,"5557":5552,"5558":5552,"5559":5552,"5560":5552,"5561":5552,"5562":5552,"5563":5552,"5564":5552,"5565":5552,"5566":5552,"5567":5552,"5569":5568,"5570":5568,"5571":5568,"5572":5568,"5573":5568,"5574":5568,"5575":5568,"5576":5568,"5577":5568,"5578":5568,"5579":5568,"5580":5568,"5581":5568,"5582":5568,"5583":5568,"5585":5584,"5586":5584,"5587":5584,"5588":5584,"5589":5584,"5590":5584,"5591":5584,"5592":5584,"5593":5584,"5594":5584,"5595":5584,"5596":5584,"5597":5584,"5598":5584,"5599":5584,"5601":5600,"5602":5600,"5603":5600,"5604":5600,"5605":5600,"5606":5600,"5607":5600,"5608":5600,"5609":5600,"5610":5600,"5611":5600,"5612":5600,"5613":5600,"5614":5600,"5615":5600,"5617":5616,"5618":5616,"5619":5616,"5620":5616,"5621":5616,"5622":5616,"5623":5616,"5624":5616,"5625":5616,"5626":5616,"5627":5616,"5628":5616,"5629":5616,"5630":5616,"5631":5616,"5633":5632,"5634":5632,"5635":5632,"5636":5632,"5637":5632,"5638":5632,"5639":5632,"5640":5632,"5641":5632,"5642":5632,"5643":5632,"5644":5632,"5645":5632,"5646":5632,"5647":5632,"5649":5648,"5650":5648,"5651":5648,"5652":5648,"5653":5648,"5654":5648,"5655":5648,"5656":5648,"5657":5648,"5658":5648,"5659":5648,"5660":5648,"5661":5648,"5662":5648,"5663":5648,"5665":5664,"5666":5664,"5667":5664,"5668":5664,"5669":5664,"5670":5664,"5671":5664,"5672":5664,"5673":5664,"5674":5664,"5675":5664,"5676":5664,"5677":5664,"5678":5664,"5679":5664,"5681":5680,"5682":5680,"5683":5680,"5684":5680,"5685":5680,"5686":5680,"5687":5680,"5688":5680,"5689":5680,"5690":5680,"5691":5680,"5692":5680,"5693":5680,"5694":5680,"5695":5680,"5697":5696,"5698":5696,"5699":5696,"5700":5696,"5701":5696,"5702":5696,"5703":5696,"5704":5696,"5705":5696,"5706":5696,"5707":5696,"5708":5696,"5709":5696,"5710":5696,"5711":5696,"5713":5712,"5714":5712,"5715":5712,"5716":5712,"5717":5712,"5718":5712,"5719":5712,"5720":5712,"5721":5712,"5722":5712,"5723":5712,"5724":5712,"5725":5712,"5726":5712,"5727":5712,"5729":5728,"5730":5728,"5731":5728,"5732":5728,"5733":5728,"5734":5728,"5735":5728,"5736":5728,"5737":5728,"5738":5728,"5739":5728,"5740":5728,"5741":5728,"5742":5728,"5743":5728,"5745":5744,"5746":5744,"5747":5744,"5748":5744,"5749":5744,"5750":5744,"5751":5744,"5752":5744,"5753":5744,"5754":5744,"5755":5744,"5756":5744,"5757":5744,"5758":5744,"5759":5744,"5761":5760,"5762":5760,"5763":5760,"5764":5760,"5765":5760,"5766":5760,"5767":5760,"5768":5760,"5769":5760,"5770":5760,"5771":5760,"5772":5760,"5773":5760,"5774":5760,"5775":5760,"5777":5776,"5778":5776,"5779":5776,"5780":5776,"5781":5776,"5782":5776,"5783":5776,"5784":5776,"5785":5776,"5786":5776,"5787":5776,"5788":5776,"5789":5776,"5790":5776,"5791":5776,"5793":5792,"5794":5792,"5795":5792,"5796":5792,"5797":5792,"5798":5792,"5799":5792,"5800":5792,"5801":5792,"5802":5792,"5803":5792,"5804":5792,"5805":5792,"5806":5792,"5807":5792,"5809":5808,"5810":5808,"5811":5808,"5812":5808,"5813":5808,"5814":5808,"5815":5808,"5816":5808,"5817":5808,"5818":5808,"5819":5808,"5820":5808,"5821":5808,"5822":5808,"5823":5808,"5825":5824,"5826":5824,"5827":5824,"5828":5824,"5829":5824,"5830":5824,"5831":5824,"5832":5824,"5833":5824,"5834":5824,"5835":5824,"5836":5824,"5837":5824,"5838":5824,"5839":5824,"5841":5840,"5842":5840,"5843":5840,"5844":5840,"5845":5840,"5846":5840,"5847":5840,"5848":5840,"5849":5840,"5850":5840,"5851":5840,"5852":5840,"5853":5840,"5854":5840,"5855":5840,"5857":5856,"5858":5856,"5859":5856,"5860":5856,"5861":5856,"5862":5856,"5863":5856,"5864":5856,"5865":5856,"5866":5856,"5867":5856,"5868":5856,"5869":5856,"5870":5856,"5871":5856,"5873":5872,"5874":5872,"5875":5872,"5876":5872,"5877":5872,"5878":5872,"5879":5872,"5880":5872,"5881":5872,"5882":5872,"5883":5872,"5884":5872,"5885":5872,"5886":5872,"5887":5872,"5889":5888,"5890":5888,"5891":5888,"5892":5888,"5893":5888,"5894":5888,"5895":5888,"5896":5888,"5897":5888,"5898":5888,"5899":5888,"5900":5888,"5901":5888,"5902":5888,"5903":5888,"5905":5904,"5906":5904,"5907":5904,"5908":5904,"5909":5904,"5910":5904,"5911":5904,"5912":5904,"5913":5904,"5914":5904,"5915":5904,"5916":5904,"5917":5904,"5918":5904,"5919":5904,"5921":5920,"5922":5920,"5923":5920,"5924":5920,"5925":5920,"5926":5920,"5927":5920,"5928":5920,"5929":5920,"5930":5920,"5931":5920,"5932":5920,"5933":5920,"5934":5920,"5935":5920,"5937":5936,"5938":5936,"5939":5936,"5940":5936,"5941":5936,"5942":5936,"5943":5936,"5944":5936,"5945":5936,"5946":5936,"5947":5936,"5948":5936,"5949":5936,"5950":5936,"5951":5936,"5953":5952,"5954":5952,"5955":5952,"5956":5952,"5957":5952,"5958":5952,"5959":5952,"5960":5952,"5961":5952,"5962":5952,"5963":5952,"5964":5952,"5965":5952,"5966":5952,"5967":5952,"5969":5968,"5970":5968,"5971":5968,"5972":5968,"5973":5968,"5974":5968,"5975":5968,"5976":5968,"5977":5968,"5978":5968,"5979":5968,"5980":5968,"5981":5968,"5982":5968,"5983":5968,"5985":5984,"5986":5984,"5987":5984,"5988":5984,"5989":5984,"5990":5984,"5991":5984,"5992":5984,"5993":5984,"5994":5984,"5995":5984,"5996":5984,"5997":5984,"5998":5984,"5999":5984,"6001":6000,"6002":6000,"6003":6000,"6004":6000,"6005":6000,"6006":6000,"6007":6000,"6008":6000,"6009":6000,"6010":6000,"6011":6000,"6012":6000,"6013":6000,"6014":6000,"6015":6000,"6017":6016,"6018":6016,"6019":6016,"6020":6016,"6021":6016,"6022":6016,"6023":6016,"6024":6016,"6025":6016,"6026":6016,"6027":6016,"6028":6016,"6029":6016,"6030":6016,"6031":6016,"6033":6032,"6034":6032,"6035":6032,"6036":6032,"6037":6032,"6038":6032,"6039":6032,"6040":6032,"6041":6032,"6042":6032,"6043":6032,"6044":6032,"6045":6032,"6046":6032,"6047":6032,"6049":6048,"6050":6048,"6051":6048,"6052":6048,"6053":6048,"6054":6048,"6055":6048,"6056":6048,"6057":6048,"6058":6048,"6059":6048,"6060":6048,"6061":6048,"6062":6048,"6063":6048,"6065":6064,"6066":6064,"6067":6064,"6068":6064,"6069":6064,"6070":6064,"6071":6064,"6072":6064,"6073":6064,"6074":6064,"6075":6064,"6076":6064,"6077":6064,"6078":6064,"6079":6064,"6081":6080,"6082":6080,"6083":6080,"6084":6080,"6085":6080,"6086":6080,"6087":6080,"6088":6080,"6089":6080,"6090":6080,"6091":6080,"6092":6080,"6093":6080,"6094":6080,"6095":6080,"6097":6096,"6098":6096,"6099":6096,"6100":6096,"6101":6096,"6102":6096,"6103":6096,"6104":6096,"6105":6096,"6106":6096,"6107":6096,"6108":6096,"6109":6096,"6110":6096,"6111":6096,"6113":6112,"6114":6112,"6115":6112,"6116":6112,"6117":6112,"6118":6112,"6119":6112,"6120":6112,"6121":6112,"6122":6112,"6123":6112,"6124":6112,"6125":6112,"6126":6112,"6127":6112,"6129":6128,"6130":6128,"6131":6128,"6132":6128,"6133":6128,"6134":6128,"6135":6128,"6136":6128,"6137":6128,"6138":6128,"6139":6128,"6140":6128,"6141":6128,"6142":6128,"6143":6128,"6145":6144,"6146":6144,"6147":6144,"6148":6144,"6149":6144,"6150":6144,"6151":6144,"6152":6144,"6153":6144,"6154":6144,"6155":6144,"6156":6144,"6157":6144,"6158":6144,"6159":6144,"6181":6176,"6182":6176,"6183":6176,"6184":6176,"6185":6176,"6186":6176,"6187":6176,"6188":6176,"6189":6176,"6190":6176,"6191":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6305":6304,"6306":6304,"6307":6304,"6308":6304,"6309":6304,"6310":6304,"6311":6304,"6312":6304,"6313":6304,"6314":6304,"6315":6304,"6316":6304,"6317":6304,"6318":6304,"6319":6304,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6482":6480,"6483":6480,"6484":6480,"6485":6480,"6486":6480,"6487":6480,"6488":6480,"6489":6480,"6490":6480,"6491":6480,"6492":6480,"6493":6480,"6494":6480,"6495":6480,"6498":6496,"6499":6496,"6500":6496,"6501":6496,"6502":6496,"6503":6496,"6504":6496,"6505":6496,"6506":6496,"6507":6496,"6508":6496,"6509":6496,"6510":6496,"6511":6496,"6514":6512,"6515":6512,"6516":6512,"6517":6512,"6518":6512,"6519":6512,"6520":6512,"6521":6512,"6522":6512,"6523":6512,"6524":6512,"6525":6512,"6526":6512,"6527":6512,"6530":6528,"6531":6528,"6532":6528,"6533":6528,"6534":6528,"6535":6528,"6536":6528,"6537":6528,"6538":6528,"6539":6528,"6540":6528,"6541":6528,"6542":6528,"6543":6528,"6546":6544,"6547":6544,"6548":6544,"6549":6544,"6550":6544,"6551":6544,"6552":6544,"6553":6544,"6554":6544,"6555":6544,"6556":6544,"6557":6544,"6558":6544,"6559":6544,"6564":6562,"6565":6562,"6566":6562,"6567":6562,"6568":6562,"6569":6562,"6570":6562,"6571":6562,"6572":6562,"6573":6562,"6574":6562,"6575":6562,"6584":6580,"6585":6580,"6586":6580,"6587":6580,"6588":6580,"6589":6580,"6590":6580,"6591":6580,"6657":6656,"6658":6656,"6659":6656,"6660":6656,"6661":6656,"6662":6656,"6663":6656,"6664":6656,"6665":6656,"6666":6656,"6667":6656,"6668":6656,"6669":6656,"6670":6656,"6671":6656,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6705":6704,"6706":6704,"6707":6704,"6708":6704,"6709":6704,"6710":6704,"6711":6704,"6713":6704,"6714":6704,"6715":6704,"6716":6704,"6717":6704,"6718":6704,"6719":6704,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6792":6787,"6793":6787,"6794":6787,"6795":6787,"6796":6787,"6797":6787,"6798":6787,"6799":6787,"6808":6803,"6809":6803,"6810":6803,"6811":6803,"6812":6803,"6813":6803,"6814":6803,"6815":6803,"6824":6819,"6825":6819,"6826":6819,"6827":6819,"6828":6819,"6829":6819,"6830":6819,"6831":6819,"6840":6835,"6841":6835,"6842":6835,"6843":6835,"6844":6835,"6845":6835,"6846":6835,"6847":6835,"6856":6851,"6857":6851,"6858":6851,"6859":6851,"6860":6851,"6861":6851,"6862":6851,"6863":6851,"6872":6867,"6873":6867,"6874":6867,"6875":6867,"6876":6867,"6877":6867,"6878":6867,"6879":6867,"6888":6883,"6889":6883,"6890":6883,"6891":6883,"6892":6883,"6893":6883,"6894":6883,"6895":6883,"6904":6899,"6905":6899,"6906":6899,"6907":6899,"6908":6899,"6909":6899,"6910":6899,"6911":6899,"6920":6915,"6921":6915,"6922":6915,"6923":6915,"6924":6915,"6925":6915,"6926":6915,"6927":6915,"6936":6931,"6937":6931,"6938":6931,"6939":6931,"6940":6931,"6941":6931,"6942":6931,"6943":6931,"6952":6947,"6953":6947,"6954":6947,"6955":6947,"6956":6947,"6957":6947,"6958":6947,"6959":6947,"6968":6963,"6969":6963,"6970":6963,"6971":6963,"6972":6963,"6973":6963,"6974":6963,"6975":6963,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7000":6994,"7001":6994,"7002":6994,"7003":6994,"7004":6994,"7005":6994,"7006":6994,"7007":6994,"7009":7008,"7010":7008,"7011":7008,"7012":7008,"7013":7008,"7014":7008,"7015":7008,"7016":7008,"7017":7008,"7018":7008,"7019":7008,"7020":7008,"7021":7008,"7022":7008,"7023":7008,"7032":7027,"7033":7027,"7034":7027,"7035":7027,"7036":7027,"7037":7027,"7038":7027,"7039":7027,"7048":7043,"7049":7043,"7050":7043,"7051":7043,"7052":7043,"7053":7043,"7054":7043,"7055":7043,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7080":7074,"7081":7074,"7082":7074,"7083":7074,"7084":7074,"7085":7074,"7086":7074,"7087":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7112":7106,"7113":7106,"7114":7106,"7115":7106,"7116":7106,"7117":7106,"7118":7106,"7119":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7144":7138,"7145":7138,"7146":7138,"7147":7138,"7148":7138,"7149":7138,"7150":7138,"7151":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7176":7170,"7177":7170,"7178":7170,"7179":7170,"7180":7170,"7181":7170,"7182":7170,"7183":7170,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7224":7218,"7225":7218,"7226":7218,"7227":7218,"7228":7218,"7229":7218,"7230":7218,"7231":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7256":7250,"7257":7250,"7258":7250,"7259":7250,"7260":7250,"7261":7250,"7262":7250,"7263":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7272":7250,"7273":7250,"7274":7250,"7275":7250,"7276":7250,"7277":7250,"7278":7250,"7279":7250,"7297":7296,"7298":7296,"7299":7296,"7300":7296,"7301":7296,"7302":7296,"7303":7296,"7304":7296,"7305":7296,"7306":7296,"7307":7296,"7308":7296,"7309":7296,"7310":7296,"7311":7296,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7348":7346,"7349":7346,"7350":7346,"7351":7346,"7352":7346,"7353":7346,"7354":7346,"7355":7346,"7356":7346,"7357":7346,"7358":7346,"7359":7346,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7400":7392,"7401":7392,"7402":7392,"7403":7392,"7404":7392,"7405":7392,"7406":7392,"7407":7392,"7410":7408,"7411":7408,"7412":7408,"7413":7408,"7414":7408,"7415":7408,"7416":7408,"7417":7408,"7418":7408,"7419":7408,"7420":7408,"7421":7408,"7422":7408,"7423":7408,"7478":7472,"7479":7472,"7486":7472,"7487":7472,"7504":7218,"7505":7218,"7510":7218,"7511":7218,"7512":7218,"7513":7218,"7514":7218,"7515":7218,"7516":7218,"7517":7218,"7518":7218,"7519":7218}} \ No newline at end of file +{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7184":"Lectern","7185":"Lectern","7186":"Lectern","7187":"Lectern","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7296":"Fletching Table","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"23":16,"24":16,"25":16,"26":16,"27":16,"28":16,"29":16,"30":16,"31":16,"33":32,"34":32,"35":32,"36":32,"37":32,"38":32,"39":32,"40":32,"41":32,"42":32,"43":32,"44":32,"45":32,"46":32,"47":32,"50":48,"51":48,"52":48,"53":48,"54":48,"55":48,"56":48,"57":48,"58":48,"59":48,"60":48,"61":48,"62":48,"63":48,"65":64,"66":64,"67":64,"68":64,"69":64,"70":64,"71":64,"72":64,"73":64,"74":64,"75":64,"76":64,"77":64,"78":64,"79":64,"86":80,"87":80,"88":80,"89":80,"90":80,"91":80,"92":80,"93":80,"94":80,"95":80,"102":96,"103":96,"110":96,"111":96,"114":112,"115":112,"116":112,"117":112,"118":112,"119":112,"120":112,"121":112,"122":112,"123":112,"124":112,"125":112,"126":112,"127":112,"194":192,"195":192,"196":192,"197":192,"198":192,"199":192,"200":192,"201":192,"202":192,"203":192,"204":192,"205":192,"206":192,"207":192,"209":208,"210":208,"211":208,"212":208,"213":208,"214":208,"215":208,"216":208,"217":208,"218":208,"219":208,"220":208,"221":208,"222":208,"223":208,"225":224,"226":224,"227":224,"228":224,"229":224,"230":224,"231":224,"232":224,"233":224,"234":224,"235":224,"236":224,"237":224,"238":224,"239":224,"241":240,"242":240,"243":240,"244":240,"245":240,"246":240,"247":240,"248":240,"249":240,"250":240,"251":240,"252":240,"253":240,"254":240,"255":240,"257":256,"258":256,"259":256,"260":256,"261":256,"262":256,"263":256,"264":256,"265":256,"266":256,"267":256,"268":256,"269":256,"270":256,"271":256,"284":7472,"285":7473,"286":7474,"287":7475,"306":304,"307":304,"308":304,"309":304,"310":304,"311":304,"312":304,"313":304,"314":304,"315":304,"316":304,"317":304,"318":304,"319":304,"321":320,"322":320,"323":320,"324":320,"325":320,"326":320,"327":320,"328":320,"329":320,"330":320,"331":320,"332":320,"333":320,"334":320,"335":320,"337":336,"338":336,"339":336,"340":336,"341":336,"342":336,"343":336,"344":336,"345":336,"346":336,"347":336,"348":336,"349":336,"350":336,"351":336,"353":352,"354":352,"355":352,"356":352,"357":352,"358":352,"359":352,"360":352,"361":352,"362":352,"363":352,"364":352,"365":352,"366":352,"367":352,"388":384,"389":384,"390":384,"391":384,"392":384,"393":384,"394":384,"395":384,"396":384,"397":384,"398":384,"399":384,"401":400,"402":400,"403":400,"404":400,"405":400,"406":400,"407":400,"408":400,"409":400,"410":400,"411":400,"412":400,"413":400,"414":400,"415":400,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"481":480,"482":480,"483":480,"484":480,"485":480,"486":480,"487":480,"488":480,"489":480,"490":480,"491":480,"492":480,"493":480,"494":480,"495":480,"496":498,"499":498,"500":498,"501":498,"502":498,"503":498,"504":498,"505":498,"506":498,"507":498,"508":498,"509":498,"510":498,"511":498,"513":512,"514":512,"515":512,"516":512,"517":512,"518":512,"519":512,"520":512,"521":512,"522":512,"523":512,"524":512,"525":512,"526":512,"527":512,"577":576,"578":576,"579":576,"580":576,"581":576,"582":576,"583":576,"584":576,"585":576,"586":576,"587":576,"588":576,"589":576,"590":576,"591":576,"593":592,"594":592,"595":592,"596":592,"597":592,"598":592,"599":592,"600":592,"601":592,"602":592,"603":592,"604":592,"605":592,"606":592,"607":592,"619":608,"620":608,"621":608,"622":608,"623":608,"625":624,"626":624,"627":624,"628":624,"629":624,"630":624,"631":624,"632":624,"633":624,"634":624,"635":624,"636":624,"637":624,"638":624,"639":624,"641":640,"642":640,"643":640,"644":640,"645":640,"646":640,"647":640,"648":640,"649":640,"650":640,"651":640,"652":640,"653":640,"654":640,"655":640,"657":656,"658":656,"659":656,"660":656,"661":656,"662":656,"663":656,"664":656,"665":656,"666":656,"667":656,"668":656,"669":656,"670":656,"671":656,"673":672,"674":672,"675":672,"676":672,"677":672,"678":672,"679":672,"680":672,"681":672,"682":672,"683":672,"684":672,"685":672,"686":672,"687":672,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"721":720,"722":720,"723":720,"724":720,"725":720,"726":720,"727":720,"728":720,"729":720,"730":720,"731":720,"732":720,"733":720,"734":720,"735":720,"740":736,"741":736,"742":736,"743":736,"744":736,"745":736,"746":736,"747":736,"748":736,"749":736,"750":736,"751":736,"753":752,"754":752,"755":752,"756":752,"757":752,"758":752,"759":752,"760":752,"761":752,"762":752,"763":752,"764":752,"765":752,"766":752,"767":752,"769":768,"770":768,"771":768,"772":768,"773":768,"774":768,"775":768,"776":768,"777":768,"778":768,"779":768,"780":768,"781":768,"782":768,"783":768,"785":784,"786":784,"787":784,"788":784,"789":784,"790":784,"791":784,"792":784,"793":784,"794":784,"795":784,"796":784,"797":784,"798":784,"799":784,"800":805,"806":805,"807":805,"808":805,"809":805,"810":805,"811":805,"812":805,"813":805,"814":805,"815":805,"833":832,"834":832,"835":832,"836":832,"837":832,"838":832,"839":832,"840":832,"841":832,"842":832,"843":832,"844":832,"845":832,"846":832,"847":832,"856":851,"857":851,"858":851,"859":851,"860":851,"861":851,"862":851,"863":851,"864":866,"865":866,"870":866,"871":866,"872":866,"873":866,"874":866,"875":866,"876":866,"877":866,"878":866,"879":866,"897":896,"898":896,"899":896,"900":896,"901":896,"902":896,"903":896,"904":896,"905":896,"906":896,"907":896,"908":896,"909":896,"910":896,"911":896,"913":912,"914":912,"915":912,"916":912,"917":912,"918":912,"919":912,"920":912,"921":912,"922":912,"923":912,"924":912,"925":912,"926":912,"927":912,"929":928,"930":928,"931":928,"932":928,"933":928,"934":928,"935":928,"936":928,"937":928,"938":928,"939":928,"940":928,"941":928,"942":928,"943":928,"952":944,"953":944,"954":944,"955":944,"956":944,"957":944,"958":944,"959":944,"968":960,"969":960,"970":960,"971":960,"972":960,"973":960,"974":960,"975":960,"976":978,"977":978,"982":978,"983":978,"984":978,"985":978,"986":978,"987":978,"988":978,"989":978,"990":978,"991":978,"992":978,"993":978,"998":978,"999":978,"1000":978,"1001":978,"1002":978,"1003":978,"1004":978,"1005":978,"1006":978,"1007":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1048":1042,"1049":1042,"1050":1042,"1051":1042,"1052":1042,"1053":1042,"1054":1042,"1055":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1080":1075,"1081":1075,"1082":1075,"1083":1075,"1084":1075,"1085":1075,"1086":1075,"1087":1075,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1096":1090,"1097":1090,"1098":1090,"1099":1090,"1100":1090,"1101":1090,"1102":1090,"1103":1090,"1122":1120,"1123":1120,"1124":1120,"1125":1120,"1126":1120,"1127":1120,"1128":1120,"1129":1120,"1130":1120,"1131":1120,"1132":1120,"1133":1120,"1134":1120,"1135":1120,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1154":1152,"1155":1152,"1156":1152,"1157":1152,"1158":1152,"1159":1152,"1160":1152,"1161":1152,"1162":1152,"1163":1152,"1164":1152,"1165":1152,"1166":1152,"1167":1152,"1169":1168,"1170":1168,"1171":1168,"1172":1168,"1173":1168,"1174":1168,"1175":1168,"1176":1168,"1177":1168,"1178":1168,"1179":1168,"1180":1168,"1181":1168,"1182":1168,"1183":1168,"1185":1168,"1186":1168,"1187":1168,"1188":1168,"1189":1168,"1190":1168,"1191":1168,"1192":1168,"1193":1168,"1194":1168,"1195":1168,"1196":1168,"1197":1168,"1198":1168,"1199":1168,"1200":1221,"1206":1221,"1207":1221,"1208":1221,"1209":1221,"1210":1221,"1211":1221,"1212":1221,"1213":1221,"1214":1221,"1215":1221,"1216":1221,"1222":1221,"1223":1221,"1224":1221,"1225":1221,"1226":1221,"1227":1221,"1228":1221,"1229":1221,"1230":1221,"1231":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1256":1248,"1257":1248,"1258":1248,"1259":1248,"1260":1248,"1261":1248,"1262":1248,"1263":1248,"1265":1264,"1266":1264,"1267":1264,"1268":1264,"1269":1264,"1270":1264,"1271":1264,"1272":1264,"1273":1264,"1274":1264,"1275":1264,"1276":1264,"1277":1264,"1278":1264,"1279":1264,"1281":1280,"1282":1280,"1283":1280,"1284":1280,"1285":1280,"1286":1280,"1287":1280,"1288":1280,"1289":1280,"1290":1280,"1291":1280,"1292":1280,"1293":1280,"1294":1280,"1295":1280,"1313":1312,"1314":1312,"1315":1312,"1316":1312,"1317":1312,"1318":1312,"1319":1312,"1320":1312,"1321":1312,"1322":1312,"1323":1312,"1324":1312,"1325":1312,"1326":1312,"1327":1312,"1345":1344,"1346":1344,"1347":1344,"1348":1344,"1349":1344,"1350":1344,"1351":1344,"1352":1344,"1353":1344,"1354":1344,"1355":1344,"1356":1344,"1357":1344,"1358":1344,"1359":1344,"1366":1360,"1367":1360,"1368":1360,"1369":1360,"1370":1360,"1371":1360,"1372":1360,"1373":1360,"1374":1360,"1375":1360,"1377":1376,"1378":1376,"1379":1376,"1380":1376,"1381":1376,"1382":1376,"1383":1376,"1384":1376,"1385":1376,"1386":1376,"1387":1376,"1388":1376,"1389":1376,"1390":1376,"1391":1376,"1393":1392,"1394":1392,"1395":1392,"1396":1392,"1397":1392,"1398":1392,"1399":1392,"1400":1392,"1401":1392,"1402":1392,"1403":1392,"1404":1392,"1405":1392,"1406":1392,"1407":1392,"1409":1408,"1410":1408,"1411":1408,"1412":1408,"1413":1408,"1414":1408,"1415":1408,"1416":1408,"1417":1408,"1418":1408,"1419":1408,"1420":1408,"1421":1408,"1422":1408,"1423":1408,"1425":1424,"1426":1424,"1427":1424,"1428":1424,"1429":1424,"1430":1424,"1431":1424,"1432":1424,"1433":1424,"1434":1424,"1435":1424,"1436":1424,"1437":1424,"1438":1424,"1439":1424,"1440":1441,"1443":1441,"1444":1441,"1445":1441,"1446":1441,"1447":1441,"1448":1441,"1449":1441,"1450":1441,"1451":1441,"1452":1441,"1453":1441,"1454":1441,"1455":1441,"1460":1458,"1461":1458,"1462":1458,"1463":1458,"1464":1458,"1465":1458,"1466":1458,"1467":1458,"1468":1458,"1469":1458,"1470":1458,"1471":1458,"1479":1472,"1480":1472,"1481":1472,"1482":1472,"1483":1472,"1484":1472,"1485":1472,"1486":1472,"1487":1472,"1521":1520,"1522":1520,"1523":1520,"1524":1520,"1525":1520,"1526":1520,"1527":1520,"1528":1520,"1529":1520,"1530":1520,"1531":1520,"1532":1520,"1533":1520,"1534":1520,"1535":1520,"1558":1552,"1559":1552,"1560":1552,"1561":1552,"1562":1552,"1563":1552,"1564":1552,"1565":1552,"1566":1552,"1567":1552,"1572":1568,"1573":1568,"1574":1568,"1575":1568,"1576":1568,"1577":1568,"1578":1568,"1579":1568,"1580":1568,"1581":1568,"1582":1568,"1583":1568,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"1617":1616,"1618":1616,"1619":1616,"1620":1616,"1621":1616,"1622":1616,"1623":1616,"1624":1616,"1625":1616,"1626":1616,"1627":1616,"1628":1616,"1629":1616,"1630":1616,"1631":1616,"1633":1632,"1634":1632,"1635":1632,"1636":1632,"1637":1632,"1638":1632,"1639":1632,"1640":1632,"1641":1632,"1642":1632,"1643":1632,"1644":1632,"1645":1632,"1646":1632,"1647":1632,"1649":1648,"1650":1648,"1651":1648,"1652":1648,"1653":1648,"1654":1648,"1655":1648,"1656":1648,"1657":1648,"1658":1648,"1659":1648,"1660":1648,"1661":1648,"1662":1648,"1663":1648,"1672":1664,"1673":1664,"1674":1664,"1675":1664,"1676":1664,"1677":1664,"1678":1664,"1679":1664,"1688":1680,"1689":1680,"1690":1680,"1691":1680,"1692":1680,"1693":1680,"1694":1680,"1695":1680,"1736":1731,"1737":1731,"1738":1731,"1739":1731,"1740":1731,"1741":1731,"1742":1731,"1743":1731,"1752":1747,"1753":1747,"1754":1747,"1755":1747,"1756":1747,"1757":1747,"1758":1747,"1759":1747,"1761":1760,"1762":1760,"1763":1760,"1764":1760,"1765":1760,"1766":1760,"1767":1760,"1768":1760,"1769":1760,"1770":1760,"1771":1760,"1772":1760,"1773":1760,"1774":1760,"1775":1760,"1777":1776,"1778":1776,"1779":1776,"1780":1776,"1781":1776,"1782":1776,"1783":1776,"1784":1776,"1785":1776,"1786":1776,"1787":1776,"1788":1776,"1789":1776,"1790":1776,"1791":1776,"1793":1792,"1794":1792,"1795":1792,"1796":1792,"1797":1792,"1798":1792,"1799":1792,"1800":1792,"1801":1792,"1802":1792,"1803":1792,"1804":1792,"1805":1792,"1806":1792,"1807":1792,"1809":1808,"1810":1808,"1811":1808,"1812":1808,"1813":1808,"1814":1808,"1815":1808,"1816":1808,"1817":1808,"1818":1808,"1819":1808,"1820":1808,"1821":1808,"1822":1808,"1823":1808,"1832":1827,"1833":1827,"1834":1827,"1835":1827,"1836":1827,"1837":1827,"1838":1827,"1839":1827,"1844":1840,"1845":1840,"1846":1840,"1847":1840,"1848":1840,"1849":1840,"1850":1840,"1851":1840,"1852":1840,"1853":1840,"1854":1840,"1855":1840,"1857":1856,"1858":1856,"1859":1856,"1860":1856,"1861":1856,"1862":1856,"1863":1856,"1864":1856,"1865":1856,"1866":1856,"1867":1856,"1868":1856,"1869":1856,"1870":1856,"1871":1856,"1880":1872,"1881":1872,"1882":1872,"1883":1872,"1884":1872,"1885":1872,"1886":1872,"1887":1872,"1928":1922,"1929":1922,"1930":1922,"1931":1922,"1932":1922,"1933":1922,"1934":1922,"1935":1922,"1937":1936,"1938":1936,"1939":1936,"1940":1936,"1941":1936,"1942":1936,"1943":1936,"1944":1936,"1945":1936,"1946":1936,"1947":1936,"1948":1936,"1949":1936,"1950":1936,"1951":1936,"1953":1952,"1954":1952,"1955":1952,"1956":1952,"1957":1952,"1958":1952,"1959":1952,"1960":1952,"1961":1952,"1962":1952,"1963":1952,"1964":1952,"1965":1952,"1966":1952,"1967":1952,"1969":1968,"1970":1968,"1971":1968,"1972":1968,"1973":1968,"1974":1968,"1975":1968,"1976":1968,"1977":1968,"1978":1968,"1979":1968,"1980":1968,"1981":1968,"1982":1968,"1983":1968,"1985":1968,"1986":1968,"1987":1968,"1988":1968,"1989":1968,"1990":1968,"1991":1968,"1992":1968,"1993":1968,"1994":1968,"1995":1968,"1996":1968,"1997":1968,"1998":1968,"1999":1968,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2056":2051,"2057":2051,"2058":2051,"2059":2051,"2060":2051,"2061":2051,"2062":2051,"2063":2051,"2065":2064,"2066":2064,"2067":2064,"2068":2064,"2069":2064,"2070":2064,"2071":2064,"2072":2064,"2073":2064,"2074":2064,"2075":2064,"2076":2064,"2077":2064,"2078":2064,"2079":2064,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2088":2082,"2089":2082,"2090":2082,"2091":2082,"2092":2082,"2093":2082,"2094":2082,"2095":2082,"2129":2128,"2130":2128,"2131":2128,"2132":2128,"2133":2128,"2134":2128,"2135":2128,"2136":2128,"2137":2128,"2138":2128,"2139":2128,"2140":2128,"2141":2128,"2142":2128,"2143":2128,"2152":2147,"2153":2147,"2154":2147,"2155":2147,"2156":2147,"2157":2147,"2158":2147,"2159":2147,"2168":2163,"2169":2163,"2170":2163,"2171":2163,"2172":2163,"2173":2163,"2174":2163,"2175":2163,"2184":2179,"2185":2179,"2186":2179,"2187":2179,"2188":2179,"2189":2179,"2190":2179,"2191":2179,"2209":2208,"2210":2208,"2211":2208,"2212":2208,"2213":2208,"2214":2208,"2215":2208,"2216":2208,"2217":2208,"2218":2208,"2219":2208,"2220":2208,"2221":2208,"2222":2208,"2223":2208,"2238":2224,"2239":2224,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2264":2256,"2265":2256,"2266":2256,"2267":2256,"2268":2256,"2269":2256,"2270":2256,"2271":2256,"2280":2272,"2281":2272,"2282":2272,"2283":2272,"2284":2272,"2285":2272,"2286":2272,"2287":2272,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2344":2338,"2345":2338,"2346":2338,"2347":2338,"2348":2338,"2349":2338,"2350":2338,"2351":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2433":2432,"2434":2432,"2435":2432,"2436":2432,"2437":2432,"2438":2432,"2439":2432,"2440":2432,"2441":2432,"2442":2432,"2443":2432,"2444":2432,"2445":2432,"2446":2432,"2447":2432,"2449":2448,"2450":2448,"2451":2448,"2452":2448,"2453":2448,"2454":2448,"2455":2448,"2456":2448,"2457":2448,"2458":2448,"2459":2448,"2460":2448,"2461":2448,"2462":2448,"2463":2448,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2484":2480,"2487":2480,"2488":2480,"2491":2480,"2492":2480,"2493":2481,"2494":2482,"2495":2480,"2504":2499,"2505":2499,"2506":2499,"2507":2499,"2508":2499,"2509":2499,"2510":2499,"2511":2499,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2578":288,"2579":288,"2582":288,"2583":288,"2586":288,"2587":288,"2590":288,"2591":288,"2604":7476,"2605":7477,"2616":2611,"2617":2611,"2618":2611,"2619":2611,"2620":2611,"2621":2611,"2622":2611,"2623":2611,"2632":2627,"2633":2627,"2634":2627,"2635":2627,"2636":2627,"2637":2627,"2638":2627,"2639":2627,"2641":2640,"2642":2640,"2643":2640,"2644":2640,"2645":2640,"2646":2640,"2647":2640,"2648":2640,"2649":2640,"2650":2640,"2651":2640,"2652":2640,"2653":2640,"2654":2640,"2655":2640,"2691":2688,"2692":2688,"2693":2688,"2694":2688,"2695":2688,"2696":2688,"2697":2688,"2698":2688,"2699":2688,"2700":2688,"2701":2688,"2702":2688,"2703":2688,"2705":2704,"2706":2704,"2707":2704,"2708":2704,"2709":2704,"2710":2704,"2711":2704,"2712":2704,"2713":2704,"2714":2704,"2715":2704,"2716":2704,"2717":2704,"2718":2704,"2719":2704,"2721":2720,"2722":2720,"2723":2720,"2725":2720,"2726":2720,"2727":2720,"2729":2720,"2730":2720,"2731":2720,"2732":2720,"2733":2720,"2734":2720,"2735":2720,"2753":2752,"2754":2752,"2755":2752,"2756":2752,"2757":2752,"2758":2752,"2759":2752,"2760":2752,"2761":2752,"2762":2752,"2763":2752,"2764":2752,"2765":2752,"2766":2752,"2767":2752,"2769":2768,"2770":2768,"2771":2768,"2772":2768,"2773":2768,"2774":2768,"2775":2768,"2776":2768,"2777":2768,"2778":2768,"2779":2768,"2780":2768,"2781":2768,"2782":2768,"2783":2768,"2785":2784,"2786":2784,"2787":2784,"2788":2784,"2789":2784,"2790":2784,"2791":2784,"2792":2784,"2793":2784,"2794":2784,"2795":2784,"2796":2784,"2797":2784,"2798":2784,"2799":2784,"2806":2800,"2807":2800,"2814":2800,"2815":2800,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2840":2834,"2841":2834,"2842":2834,"2843":2834,"2844":2834,"2845":2834,"2846":2834,"2847":2834,"2868":2864,"2869":2864,"2870":2864,"2871":2864,"2872":2864,"2873":2864,"2874":2864,"2875":2864,"2876":2864,"2877":2864,"2878":2864,"2879":2864,"2888":2883,"2889":2883,"2890":2883,"2891":2883,"2892":2883,"2893":2883,"2894":2883,"2895":2883,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3041":3040,"3042":3040,"3043":3040,"3044":3040,"3045":3040,"3046":3040,"3047":3040,"3048":3040,"3049":3040,"3050":3040,"3051":3040,"3052":3040,"3053":3040,"3054":3040,"3055":3040,"3073":3072,"3074":3072,"3075":3072,"3076":3072,"3077":3072,"3078":3072,"3079":3072,"3080":3072,"3081":3072,"3082":3072,"3083":3072,"3084":3072,"3085":3072,"3086":3072,"3087":3072,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3169":3168,"3170":3168,"3171":3168,"3172":3168,"3173":3168,"3174":3168,"3175":3168,"3176":3168,"3177":3168,"3178":3168,"3179":3168,"3180":3168,"3181":3168,"3182":3168,"3183":3168,"3192":3187,"3193":3187,"3194":3187,"3195":3187,"3196":3187,"3197":3187,"3198":3187,"3199":3187,"3217":3216,"3219":3216,"3220":3216,"3221":3216,"3223":3216,"3224":3216,"3225":3216,"3227":3216,"3228":3216,"3229":3216,"3230":3218,"3231":3216,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3256":3251,"3257":3251,"3258":3251,"3259":3251,"3260":3251,"3261":3251,"3262":3251,"3263":3251,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3281":3280,"3282":3280,"3283":3280,"3284":3280,"3285":3280,"3286":3280,"3287":3280,"3288":3280,"3289":3280,"3290":3280,"3291":3280,"3292":3280,"3293":3280,"3294":3280,"3295":3280,"3297":3296,"3298":3296,"3299":3296,"3300":3296,"3301":3296,"3302":3296,"3303":3296,"3304":3296,"3305":3296,"3306":3296,"3307":3296,"3308":3296,"3309":3296,"3310":3296,"3311":3296,"3316":3312,"3317":3312,"3318":3312,"3319":3312,"3320":3312,"3321":3312,"3322":3312,"3323":3312,"3324":3312,"3325":3312,"3326":3312,"3327":3312,"3334":3328,"3335":3328,"3336":3328,"3337":3328,"3338":3328,"3339":3328,"3340":3328,"3341":3328,"3342":3328,"3343":3328,"3409":3408,"3410":3408,"3411":3408,"3412":3408,"3413":3408,"3414":3408,"3415":3408,"3416":3408,"3417":3408,"3418":3408,"3419":3408,"3420":3408,"3421":3408,"3422":3408,"3423":3408,"3425":3424,"3426":3424,"3427":3424,"3428":3424,"3429":3424,"3430":3424,"3431":3424,"3432":3424,"3433":3424,"3434":3424,"3435":3424,"3436":3424,"3437":3424,"3438":3424,"3439":3424,"3441":3440,"3442":3440,"3443":3440,"3444":3440,"3445":3440,"3446":3440,"3447":3440,"3448":3440,"3449":3440,"3450":3440,"3451":3440,"3452":3440,"3453":3440,"3454":3440,"3455":3440,"3457":3456,"3458":3456,"3459":3456,"3461":3456,"3462":3456,"3463":3456,"3465":3456,"3466":3456,"3467":3456,"3468":3456,"3469":3456,"3470":3456,"3471":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3512":3506,"3513":3506,"3514":3506,"3515":3506,"3516":3506,"3517":3506,"3518":3506,"3519":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3528":3522,"3529":3522,"3530":3522,"3531":3522,"3532":3522,"3533":3522,"3534":3522,"3535":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3544":3538,"3545":3538,"3546":3538,"3547":3538,"3548":3538,"3549":3538,"3550":3538,"3551":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3560":3554,"3561":3554,"3562":3554,"3563":3554,"3564":3554,"3565":3554,"3566":3554,"3567":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3576":3570,"3577":3570,"3578":3570,"3579":3570,"3580":3570,"3581":3570,"3582":3570,"3583":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3592":3586,"3593":3586,"3594":3586,"3595":3586,"3596":3586,"3597":3586,"3598":3586,"3599":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3608":3602,"3609":3602,"3610":3602,"3611":3602,"3612":3602,"3613":3602,"3614":3602,"3615":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3624":3618,"3625":3618,"3626":3618,"3627":3618,"3628":3618,"3629":3618,"3630":3618,"3631":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3640":3634,"3641":3634,"3642":3634,"3643":3634,"3644":3634,"3645":3634,"3646":3634,"3647":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3656":3650,"3657":3650,"3658":3650,"3659":3650,"3660":3650,"3661":3650,"3662":3650,"3663":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3672":3666,"3673":3666,"3674":3666,"3675":3666,"3676":3666,"3677":3666,"3678":3666,"3679":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3704":3698,"3705":3698,"3706":3698,"3707":3698,"3708":3698,"3709":3698,"3710":3698,"3711":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3720":3714,"3721":3714,"3722":3714,"3723":3714,"3724":3714,"3725":3714,"3726":3714,"3727":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3736":3730,"3737":3730,"3738":3730,"3739":3730,"3740":3730,"3741":3730,"3742":3730,"3743":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3752":3746,"3753":3746,"3754":3746,"3755":3746,"3756":3746,"3757":3746,"3758":3746,"3759":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3768":3762,"3769":3762,"3770":3762,"3771":3762,"3772":3762,"3773":3762,"3774":3762,"3775":3762,"3824":3829,"3830":3829,"3831":3829,"3832":3829,"3833":3829,"3834":3829,"3835":3829,"3836":3829,"3837":3829,"3838":3829,"3839":3829,"3889":3888,"3890":3888,"3891":3888,"3892":3888,"3893":3888,"3894":3888,"3895":3888,"3896":3888,"3897":3888,"3898":3888,"3899":3888,"3900":3888,"3901":3888,"3902":3888,"3903":3888,"3912":3904,"3913":3904,"3914":3904,"3915":3904,"3916":3904,"3917":3904,"3918":3904,"3919":3904,"3921":3920,"3922":3920,"3923":3920,"3924":3920,"3925":3920,"3926":3920,"3927":3920,"3928":3920,"3929":3920,"3930":3920,"3931":3920,"3932":3920,"3933":3920,"3934":3920,"3935":3920,"3937":3936,"3938":3936,"3939":3936,"3940":3936,"3941":3936,"3942":3936,"3943":3936,"3944":3936,"3945":3936,"3946":3936,"3947":3936,"3948":3936,"3949":3936,"3950":3936,"3951":3936,"3955":3952,"3956":3952,"3957":3952,"3958":3952,"3959":3952,"3960":3952,"3961":3952,"3962":3952,"3963":3952,"3964":3952,"3965":3952,"3966":3952,"3967":3952,"3969":3968,"3970":3968,"3971":3968,"3972":3968,"3973":3968,"3974":3968,"3975":3968,"3976":3968,"3977":3968,"3978":3968,"3979":3968,"3980":3968,"3981":3968,"3982":3968,"3983":3968,"3985":3984,"3986":3984,"3987":3984,"3988":3984,"3989":3984,"3990":3984,"3991":3984,"3992":3984,"3993":3984,"3994":3984,"3995":3984,"3996":3984,"3997":3984,"3998":3984,"3999":3984,"4049":4048,"4050":4048,"4051":4048,"4052":4048,"4053":4048,"4054":4048,"4055":4048,"4056":4048,"4057":4048,"4058":4048,"4059":4048,"4060":4048,"4061":4048,"4062":4048,"4063":4048,"4081":4080,"4082":4080,"4083":4080,"4084":4080,"4085":4080,"4086":4080,"4087":4080,"4088":4080,"4089":4080,"4090":4080,"4091":4080,"4092":4080,"4093":4080,"4094":4080,"4095":4080,"4120":4115,"4121":4115,"4122":4115,"4123":4115,"4124":4115,"4125":4115,"4126":4115,"4127":4115,"4136":4131,"4137":4131,"4138":4131,"4139":4131,"4140":4131,"4141":4131,"4142":4131,"4143":4131,"4152":4147,"4153":4147,"4154":4147,"4155":4147,"4156":4147,"4157":4147,"4158":4147,"4159":4147,"4163":4160,"4164":4160,"4165":4160,"4166":4160,"4167":4160,"4168":4160,"4169":4160,"4170":4160,"4171":4160,"4172":4160,"4173":4160,"4174":4160,"4175":4160,"4179":4176,"4180":4176,"4181":4176,"4182":4176,"4183":4176,"4184":4176,"4185":4176,"4186":4176,"4187":4176,"4188":4176,"4189":4176,"4190":4176,"4191":4176,"4195":4192,"4196":4192,"4197":4192,"4198":4192,"4199":4192,"4200":4192,"4201":4192,"4202":4192,"4203":4192,"4204":4192,"4205":4192,"4206":4192,"4207":4192,"4211":4208,"4212":4208,"4213":4208,"4214":4208,"4215":4208,"4216":4208,"4217":4208,"4218":4208,"4219":4208,"4220":4208,"4221":4208,"4222":4208,"4223":4208,"4227":4224,"4228":4224,"4229":4224,"4230":4224,"4231":4224,"4232":4224,"4233":4224,"4234":4224,"4235":4224,"4236":4224,"4237":4224,"4238":4224,"4239":4224,"4243":4240,"4244":4240,"4245":4240,"4246":4240,"4247":4240,"4248":4240,"4249":4240,"4250":4240,"4251":4240,"4252":4240,"4253":4240,"4254":4240,"4255":4240,"4257":4256,"4258":4256,"4259":4256,"4260":4256,"4261":4256,"4262":4256,"4263":4256,"4264":4256,"4265":4256,"4266":4256,"4267":4256,"4268":4256,"4269":4256,"4270":4256,"4271":4256,"4273":4272,"4274":4272,"4275":4272,"4276":4272,"4277":4272,"4278":4272,"4279":4272,"4280":4272,"4281":4272,"4282":4272,"4283":4272,"4284":4272,"4285":4272,"4286":4272,"4287":4272,"4289":4288,"4290":4288,"4291":4288,"4292":4288,"4293":4288,"4294":4288,"4295":4288,"4296":4288,"4297":4288,"4298":4288,"4299":4288,"4300":4288,"4301":4288,"4302":4288,"4303":4288,"4305":4304,"4306":4304,"4307":4304,"4308":4304,"4309":4304,"4310":4304,"4311":4304,"4312":4304,"4313":4304,"4314":4304,"4315":4304,"4316":4304,"4317":4304,"4318":4304,"4319":4304,"4321":4320,"4322":4320,"4323":4320,"4324":4320,"4325":4320,"4326":4320,"4327":4320,"4328":4320,"4329":4320,"4330":4320,"4331":4320,"4332":4320,"4333":4320,"4334":4320,"4335":4320,"4337":4336,"4338":4336,"4339":4336,"4340":4336,"4341":4336,"4342":4336,"4343":4336,"4344":4336,"4345":4336,"4346":4336,"4347":4336,"4348":4336,"4349":4336,"4350":4336,"4351":4336,"4353":4352,"4354":4352,"4355":4352,"4356":4352,"4357":4352,"4358":4352,"4359":4352,"4360":4352,"4361":4352,"4362":4352,"4363":4352,"4364":4352,"4365":4352,"4366":4352,"4367":4352,"4369":4368,"4370":4368,"4371":4368,"4372":4368,"4373":4368,"4374":4368,"4375":4368,"4376":4368,"4377":4368,"4378":4368,"4379":4368,"4380":4368,"4381":4368,"4382":4368,"4383":4368,"4385":4384,"4386":4384,"4387":4384,"4388":4384,"4389":4384,"4390":4384,"4391":4384,"4392":4384,"4393":4384,"4394":4384,"4395":4384,"4396":4384,"4397":4384,"4398":4384,"4399":4384,"4401":4400,"4402":4400,"4403":4400,"4404":4400,"4405":4400,"4406":4400,"4407":4400,"4408":4400,"4409":4400,"4410":4400,"4411":4400,"4412":4400,"4413":4400,"4414":4400,"4415":4400,"4417":4416,"4418":4416,"4419":4416,"4420":4416,"4421":4416,"4422":4416,"4423":4416,"4424":4416,"4425":4416,"4426":4416,"4427":4416,"4428":4416,"4429":4416,"4430":4416,"4431":4416,"4433":4432,"4434":4432,"4435":4432,"4436":4432,"4437":4432,"4438":4432,"4439":4432,"4440":4432,"4441":4432,"4442":4432,"4443":4432,"4444":4432,"4445":4432,"4446":4432,"4447":4432,"4449":4448,"4450":4448,"4451":4448,"4452":4448,"4453":4448,"4454":4448,"4455":4448,"4456":4448,"4457":4448,"4458":4448,"4459":4448,"4460":4448,"4461":4448,"4462":4448,"4463":4448,"4465":4464,"4466":4464,"4467":4464,"4468":4464,"4469":4464,"4470":4464,"4471":4464,"4472":4464,"4473":4464,"4474":4464,"4475":4464,"4476":4464,"4477":4464,"4478":4464,"4479":4464,"4481":4480,"4482":4480,"4483":4480,"4484":4480,"4485":4480,"4486":4480,"4487":4480,"4488":4480,"4489":4480,"4490":4480,"4491":4480,"4492":4480,"4493":4480,"4494":4480,"4495":4480,"4497":4496,"4498":4496,"4499":4496,"4500":4496,"4501":4496,"4502":4496,"4503":4496,"4504":4496,"4505":4496,"4506":4496,"4507":4496,"4508":4496,"4509":4496,"4510":4496,"4511":4496,"4513":4512,"4514":4512,"4515":4512,"4516":4512,"4517":4512,"4518":4512,"4519":4512,"4520":4512,"4521":4512,"4522":4512,"4523":4512,"4524":4512,"4525":4512,"4526":4512,"4527":4512,"4529":4528,"4530":4528,"4531":4528,"4532":4528,"4533":4528,"4534":4528,"4535":4528,"4536":4528,"4537":4528,"4538":4528,"4539":4528,"4540":4528,"4541":4528,"4542":4528,"4543":4528,"4545":4544,"4546":4544,"4547":4544,"4548":4544,"4549":4544,"4550":4544,"4551":4544,"4552":4544,"4553":4544,"4554":4544,"4555":4544,"4556":4544,"4557":4544,"4558":4544,"4559":4544,"4561":4560,"4562":4560,"4563":4560,"4564":4560,"4565":4560,"4566":4560,"4567":4560,"4568":4560,"4569":4560,"4570":4560,"4571":4560,"4572":4560,"4573":4560,"4574":4560,"4575":4560,"4577":4576,"4578":4576,"4579":4576,"4580":4576,"4581":4576,"4582":4576,"4583":4576,"4584":4576,"4585":4576,"4586":4576,"4587":4576,"4588":4576,"4589":4576,"4590":4576,"4591":4576,"4593":4592,"4594":4592,"4595":4592,"4596":4592,"4597":4592,"4598":4592,"4599":4592,"4600":4592,"4601":4592,"4602":4592,"4603":4592,"4604":4592,"4605":4592,"4606":4592,"4607":4592,"4609":4608,"4610":4608,"4611":4608,"4612":4608,"4613":4608,"4614":4608,"4615":4608,"4616":4608,"4617":4608,"4618":4608,"4619":4608,"4620":4608,"4621":4608,"4622":4608,"4623":4608,"4625":4624,"4626":4624,"4627":4624,"4628":4624,"4629":4624,"4630":4624,"4631":4624,"4632":4624,"4633":4624,"4634":4624,"4635":4624,"4636":4624,"4637":4624,"4638":4624,"4639":4624,"4641":4640,"4642":4640,"4643":4640,"4644":4640,"4645":4640,"4646":4640,"4647":4640,"4648":4640,"4649":4640,"4650":4640,"4651":4640,"4652":4640,"4653":4640,"4654":4640,"4655":4640,"4657":4656,"4658":4656,"4659":4656,"4660":4656,"4661":4656,"4662":4656,"4663":4656,"4664":4656,"4665":4656,"4666":4656,"4667":4656,"4668":4656,"4669":4656,"4670":4656,"4671":4656,"4673":4672,"4674":4672,"4675":4672,"4676":4672,"4677":4672,"4678":4672,"4679":4672,"4680":4672,"4681":4672,"4682":4672,"4683":4672,"4684":4672,"4685":4672,"4686":4672,"4687":4672,"4689":4688,"4690":4688,"4691":4688,"4692":4688,"4693":4688,"4694":4688,"4695":4688,"4696":4688,"4697":4688,"4698":4688,"4699":4688,"4700":4688,"4701":4688,"4702":4688,"4703":4688,"4705":4704,"4706":4704,"4707":4704,"4708":4704,"4709":4704,"4710":4704,"4711":4704,"4712":4704,"4713":4704,"4714":4704,"4715":4704,"4716":4704,"4717":4704,"4718":4704,"4719":4704,"4721":4720,"4722":4720,"4723":4720,"4724":4720,"4725":4720,"4726":4720,"4727":4720,"4728":4720,"4729":4720,"4730":4720,"4731":4720,"4732":4720,"4733":4720,"4734":4720,"4735":4720,"4737":4736,"4738":4736,"4739":4736,"4740":4736,"4741":4736,"4742":4736,"4743":4736,"4744":4736,"4745":4736,"4746":4736,"4747":4736,"4748":4736,"4749":4736,"4750":4736,"4751":4736,"4753":4752,"4754":4752,"4755":4752,"4756":4752,"4757":4752,"4758":4752,"4759":4752,"4760":4752,"4761":4752,"4762":4752,"4763":4752,"4764":4752,"4765":4752,"4766":4752,"4767":4752,"4769":4768,"4770":4768,"4771":4768,"4772":4768,"4773":4768,"4774":4768,"4775":4768,"4776":4768,"4777":4768,"4778":4768,"4779":4768,"4780":4768,"4781":4768,"4782":4768,"4783":4768,"4785":4784,"4786":4784,"4787":4784,"4788":4784,"4789":4784,"4790":4784,"4791":4784,"4792":4784,"4793":4784,"4794":4784,"4795":4784,"4796":4784,"4797":4784,"4798":4784,"4799":4784,"4801":4800,"4802":4800,"4803":4800,"4804":4800,"4805":4800,"4806":4800,"4807":4800,"4808":4800,"4809":4800,"4810":4800,"4811":4800,"4812":4800,"4813":4800,"4814":4800,"4815":4800,"4817":4816,"4818":4816,"4819":4816,"4820":4816,"4821":4816,"4822":4816,"4823":4816,"4824":4816,"4825":4816,"4826":4816,"4827":4816,"4828":4816,"4829":4816,"4830":4816,"4831":4816,"4833":4832,"4834":4832,"4835":4832,"4836":4832,"4837":4832,"4838":4832,"4839":4832,"4840":4832,"4841":4832,"4842":4832,"4843":4832,"4844":4832,"4845":4832,"4846":4832,"4847":4832,"4849":4848,"4850":4848,"4851":4848,"4852":4848,"4853":4848,"4854":4848,"4855":4848,"4856":4848,"4857":4848,"4858":4848,"4859":4848,"4860":4848,"4861":4848,"4862":4848,"4863":4848,"4865":4864,"4866":4864,"4867":4864,"4868":4864,"4869":4864,"4870":4864,"4871":4864,"4872":4864,"4873":4864,"4874":4864,"4875":4864,"4876":4864,"4877":4864,"4878":4864,"4879":4864,"4881":4880,"4882":4880,"4883":4880,"4884":4880,"4885":4880,"4886":4880,"4887":4880,"4888":4880,"4889":4880,"4890":4880,"4891":4880,"4892":4880,"4893":4880,"4894":4880,"4895":4880,"4897":4896,"4898":4896,"4899":4896,"4900":4896,"4901":4896,"4902":4896,"4903":4896,"4904":4896,"4905":4896,"4906":4896,"4907":4896,"4908":4896,"4909":4896,"4910":4896,"4911":4896,"4913":4912,"4914":4912,"4915":4912,"4916":4912,"4917":4912,"4918":4912,"4919":4912,"4920":4912,"4921":4912,"4922":4912,"4923":4912,"4924":4912,"4925":4912,"4926":4912,"4927":4912,"4929":4928,"4930":4928,"4931":4928,"4932":4928,"4933":4928,"4934":4928,"4935":4928,"4936":4928,"4937":4928,"4938":4928,"4939":4928,"4940":4928,"4941":4928,"4942":4928,"4943":4928,"4945":4944,"4946":4944,"4947":4944,"4948":4944,"4949":4944,"4950":4944,"4951":4944,"4952":4944,"4953":4944,"4954":4944,"4955":4944,"4956":4944,"4957":4944,"4958":4944,"4959":4944,"4961":4960,"4962":4960,"4963":4960,"4964":4960,"4965":4960,"4966":4960,"4967":4960,"4968":4960,"4969":4960,"4970":4960,"4971":4960,"4972":4960,"4973":4960,"4974":4960,"4975":4960,"4977":4976,"4978":4976,"4979":4976,"4980":4976,"4981":4976,"4982":4976,"4983":4976,"4984":4976,"4985":4976,"4986":4976,"4987":4976,"4988":4976,"4989":4976,"4990":4976,"4991":4976,"4993":4992,"4994":4992,"4995":4992,"4996":4992,"4997":4992,"4998":4992,"4999":4992,"5000":4992,"5001":4992,"5002":4992,"5003":4992,"5004":4992,"5005":4992,"5006":4992,"5007":4992,"5009":5008,"5010":5008,"5011":5008,"5012":5008,"5013":5008,"5014":5008,"5015":5008,"5016":5008,"5017":5008,"5018":5008,"5019":5008,"5020":5008,"5021":5008,"5022":5008,"5023":5008,"5025":5024,"5026":5024,"5027":5024,"5028":5024,"5029":5024,"5030":5024,"5031":5024,"5032":5024,"5033":5024,"5034":5024,"5035":5024,"5036":5024,"5037":5024,"5038":5024,"5039":5024,"5041":5040,"5042":5040,"5043":5040,"5044":5040,"5045":5040,"5046":5040,"5047":5040,"5048":5040,"5049":5040,"5050":5040,"5051":5040,"5052":5040,"5053":5040,"5054":5040,"5055":5040,"5057":5056,"5058":5056,"5059":5056,"5060":5056,"5061":5056,"5062":5056,"5063":5056,"5064":5056,"5065":5056,"5066":5056,"5067":5056,"5068":5056,"5069":5056,"5070":5056,"5071":5056,"5073":5072,"5074":5072,"5075":5072,"5076":5072,"5077":5072,"5078":5072,"5079":5072,"5080":5072,"5081":5072,"5082":5072,"5083":5072,"5084":5072,"5085":5072,"5086":5072,"5087":5072,"5089":5088,"5090":5088,"5091":5088,"5092":5088,"5093":5088,"5094":5088,"5095":5088,"5096":5088,"5097":5088,"5098":5088,"5099":5088,"5100":5088,"5101":5088,"5102":5088,"5103":5088,"5105":5104,"5106":5104,"5107":5104,"5108":5104,"5109":5104,"5110":5104,"5111":5104,"5112":5104,"5113":5104,"5114":5104,"5115":5104,"5116":5104,"5117":5104,"5118":5104,"5119":5104,"5121":5120,"5122":5120,"5123":5120,"5124":5120,"5125":5120,"5126":5120,"5127":5120,"5128":5120,"5129":5120,"5130":5120,"5131":5120,"5132":5120,"5133":5120,"5134":5120,"5135":5120,"5137":5136,"5138":5136,"5139":5136,"5140":5136,"5141":5136,"5142":5136,"5143":5136,"5144":5136,"5145":5136,"5146":5136,"5147":5136,"5148":5136,"5149":5136,"5150":5136,"5151":5136,"5153":5152,"5154":5152,"5155":5152,"5156":5152,"5157":5152,"5158":5152,"5159":5152,"5160":5152,"5161":5152,"5162":5152,"5163":5152,"5164":5152,"5165":5152,"5166":5152,"5167":5152,"5169":5168,"5170":5168,"5171":5168,"5172":5168,"5173":5168,"5174":5168,"5175":5168,"5176":5168,"5177":5168,"5178":5168,"5179":5168,"5180":5168,"5181":5168,"5182":5168,"5183":5168,"5185":5184,"5186":5184,"5187":5184,"5188":5184,"5189":5184,"5190":5184,"5191":5184,"5192":5184,"5193":5184,"5194":5184,"5195":5184,"5196":5184,"5197":5184,"5198":5184,"5199":5184,"5201":5200,"5202":5200,"5203":5200,"5204":5200,"5205":5200,"5206":5200,"5207":5200,"5208":5200,"5209":5200,"5210":5200,"5211":5200,"5212":5200,"5213":5200,"5214":5200,"5215":5200,"5217":5216,"5218":5216,"5219":5216,"5220":5216,"5221":5216,"5222":5216,"5223":5216,"5224":5216,"5225":5216,"5226":5216,"5227":5216,"5228":5216,"5229":5216,"5230":5216,"5231":5216,"5233":5232,"5234":5232,"5235":5232,"5236":5232,"5237":5232,"5238":5232,"5239":5232,"5240":5232,"5241":5232,"5242":5232,"5243":5232,"5244":5232,"5245":5232,"5246":5232,"5247":5232,"5249":5248,"5250":5248,"5251":5248,"5252":5248,"5253":5248,"5254":5248,"5255":5248,"5256":5248,"5257":5248,"5258":5248,"5259":5248,"5260":5248,"5261":5248,"5262":5248,"5263":5248,"5265":5264,"5266":5264,"5267":5264,"5268":5264,"5269":5264,"5270":5264,"5271":5264,"5272":5264,"5273":5264,"5274":5264,"5275":5264,"5276":5264,"5277":5264,"5278":5264,"5279":5264,"5281":5280,"5282":5280,"5283":5280,"5284":5280,"5285":5280,"5286":5280,"5287":5280,"5288":5280,"5289":5280,"5290":5280,"5291":5280,"5292":5280,"5293":5280,"5294":5280,"5295":5280,"5297":5296,"5298":5296,"5299":5296,"5300":5296,"5301":5296,"5302":5296,"5303":5296,"5304":5296,"5305":5296,"5306":5296,"5307":5296,"5308":5296,"5309":5296,"5310":5296,"5311":5296,"5313":5312,"5314":5312,"5315":5312,"5316":5312,"5317":5312,"5318":5312,"5319":5312,"5320":5312,"5321":5312,"5322":5312,"5323":5312,"5324":5312,"5325":5312,"5326":5312,"5327":5312,"5329":5328,"5330":5328,"5331":5328,"5332":5328,"5333":5328,"5334":5328,"5335":5328,"5336":5328,"5337":5328,"5338":5328,"5339":5328,"5340":5328,"5341":5328,"5342":5328,"5343":5328,"5345":5344,"5346":5344,"5347":5344,"5348":5344,"5349":5344,"5350":5344,"5351":5344,"5352":5344,"5353":5344,"5354":5344,"5355":5344,"5356":5344,"5357":5344,"5358":5344,"5359":5344,"5361":5360,"5362":5360,"5363":5360,"5364":5360,"5365":5360,"5366":5360,"5367":5360,"5368":5360,"5369":5360,"5370":5360,"5371":5360,"5372":5360,"5373":5360,"5374":5360,"5375":5360,"5377":5376,"5378":5376,"5379":5376,"5380":5376,"5381":5376,"5382":5376,"5383":5376,"5384":5376,"5385":5376,"5386":5376,"5387":5376,"5388":5376,"5389":5376,"5390":5376,"5391":5376,"5393":5392,"5394":5392,"5395":5392,"5396":5392,"5397":5392,"5398":5392,"5399":5392,"5400":5392,"5401":5392,"5402":5392,"5403":5392,"5404":5392,"5405":5392,"5406":5392,"5407":5392,"5409":5408,"5410":5408,"5411":5408,"5412":5408,"5413":5408,"5414":5408,"5415":5408,"5416":5408,"5417":5408,"5418":5408,"5419":5408,"5420":5408,"5421":5408,"5422":5408,"5423":5408,"5425":5424,"5426":5424,"5427":5424,"5428":5424,"5429":5424,"5430":5424,"5431":5424,"5432":5424,"5433":5424,"5434":5424,"5435":5424,"5436":5424,"5437":5424,"5438":5424,"5439":5424,"5441":5440,"5442":5440,"5443":5440,"5444":5440,"5445":5440,"5446":5440,"5447":5440,"5448":5440,"5449":5440,"5450":5440,"5451":5440,"5452":5440,"5453":5440,"5454":5440,"5455":5440,"5457":5456,"5458":5456,"5459":5456,"5460":5456,"5461":5456,"5462":5456,"5463":5456,"5464":5456,"5465":5456,"5466":5456,"5467":5456,"5468":5456,"5469":5456,"5470":5456,"5471":5456,"5473":5472,"5474":5472,"5475":5472,"5476":5472,"5477":5472,"5478":5472,"5479":5472,"5480":5472,"5481":5472,"5482":5472,"5483":5472,"5484":5472,"5485":5472,"5486":5472,"5487":5472,"5489":5488,"5490":5488,"5491":5488,"5492":5488,"5493":5488,"5494":5488,"5495":5488,"5496":5488,"5497":5488,"5498":5488,"5499":5488,"5500":5488,"5501":5488,"5502":5488,"5503":5488,"5505":5504,"5506":5504,"5507":5504,"5508":5504,"5509":5504,"5510":5504,"5511":5504,"5512":5504,"5513":5504,"5514":5504,"5515":5504,"5516":5504,"5517":5504,"5518":5504,"5519":5504,"5521":5520,"5522":5520,"5523":5520,"5524":5520,"5525":5520,"5526":5520,"5527":5520,"5528":5520,"5529":5520,"5530":5520,"5531":5520,"5532":5520,"5533":5520,"5534":5520,"5535":5520,"5537":5536,"5538":5536,"5539":5536,"5540":5536,"5541":5536,"5542":5536,"5543":5536,"5544":5536,"5545":5536,"5546":5536,"5547":5536,"5548":5536,"5549":5536,"5550":5536,"5551":5536,"5553":5552,"5554":5552,"5555":5552,"5556":5552,"5557":5552,"5558":5552,"5559":5552,"5560":5552,"5561":5552,"5562":5552,"5563":5552,"5564":5552,"5565":5552,"5566":5552,"5567":5552,"5569":5568,"5570":5568,"5571":5568,"5572":5568,"5573":5568,"5574":5568,"5575":5568,"5576":5568,"5577":5568,"5578":5568,"5579":5568,"5580":5568,"5581":5568,"5582":5568,"5583":5568,"5585":5584,"5586":5584,"5587":5584,"5588":5584,"5589":5584,"5590":5584,"5591":5584,"5592":5584,"5593":5584,"5594":5584,"5595":5584,"5596":5584,"5597":5584,"5598":5584,"5599":5584,"5601":5600,"5602":5600,"5603":5600,"5604":5600,"5605":5600,"5606":5600,"5607":5600,"5608":5600,"5609":5600,"5610":5600,"5611":5600,"5612":5600,"5613":5600,"5614":5600,"5615":5600,"5617":5616,"5618":5616,"5619":5616,"5620":5616,"5621":5616,"5622":5616,"5623":5616,"5624":5616,"5625":5616,"5626":5616,"5627":5616,"5628":5616,"5629":5616,"5630":5616,"5631":5616,"5633":5632,"5634":5632,"5635":5632,"5636":5632,"5637":5632,"5638":5632,"5639":5632,"5640":5632,"5641":5632,"5642":5632,"5643":5632,"5644":5632,"5645":5632,"5646":5632,"5647":5632,"5649":5648,"5650":5648,"5651":5648,"5652":5648,"5653":5648,"5654":5648,"5655":5648,"5656":5648,"5657":5648,"5658":5648,"5659":5648,"5660":5648,"5661":5648,"5662":5648,"5663":5648,"5665":5664,"5666":5664,"5667":5664,"5668":5664,"5669":5664,"5670":5664,"5671":5664,"5672":5664,"5673":5664,"5674":5664,"5675":5664,"5676":5664,"5677":5664,"5678":5664,"5679":5664,"5681":5680,"5682":5680,"5683":5680,"5684":5680,"5685":5680,"5686":5680,"5687":5680,"5688":5680,"5689":5680,"5690":5680,"5691":5680,"5692":5680,"5693":5680,"5694":5680,"5695":5680,"5697":5696,"5698":5696,"5699":5696,"5700":5696,"5701":5696,"5702":5696,"5703":5696,"5704":5696,"5705":5696,"5706":5696,"5707":5696,"5708":5696,"5709":5696,"5710":5696,"5711":5696,"5713":5712,"5714":5712,"5715":5712,"5716":5712,"5717":5712,"5718":5712,"5719":5712,"5720":5712,"5721":5712,"5722":5712,"5723":5712,"5724":5712,"5725":5712,"5726":5712,"5727":5712,"5729":5728,"5730":5728,"5731":5728,"5732":5728,"5733":5728,"5734":5728,"5735":5728,"5736":5728,"5737":5728,"5738":5728,"5739":5728,"5740":5728,"5741":5728,"5742":5728,"5743":5728,"5745":5744,"5746":5744,"5747":5744,"5748":5744,"5749":5744,"5750":5744,"5751":5744,"5752":5744,"5753":5744,"5754":5744,"5755":5744,"5756":5744,"5757":5744,"5758":5744,"5759":5744,"5761":5760,"5762":5760,"5763":5760,"5764":5760,"5765":5760,"5766":5760,"5767":5760,"5768":5760,"5769":5760,"5770":5760,"5771":5760,"5772":5760,"5773":5760,"5774":5760,"5775":5760,"5777":5776,"5778":5776,"5779":5776,"5780":5776,"5781":5776,"5782":5776,"5783":5776,"5784":5776,"5785":5776,"5786":5776,"5787":5776,"5788":5776,"5789":5776,"5790":5776,"5791":5776,"5793":5792,"5794":5792,"5795":5792,"5796":5792,"5797":5792,"5798":5792,"5799":5792,"5800":5792,"5801":5792,"5802":5792,"5803":5792,"5804":5792,"5805":5792,"5806":5792,"5807":5792,"5809":5808,"5810":5808,"5811":5808,"5812":5808,"5813":5808,"5814":5808,"5815":5808,"5816":5808,"5817":5808,"5818":5808,"5819":5808,"5820":5808,"5821":5808,"5822":5808,"5823":5808,"5825":5824,"5826":5824,"5827":5824,"5828":5824,"5829":5824,"5830":5824,"5831":5824,"5832":5824,"5833":5824,"5834":5824,"5835":5824,"5836":5824,"5837":5824,"5838":5824,"5839":5824,"5841":5840,"5842":5840,"5843":5840,"5844":5840,"5845":5840,"5846":5840,"5847":5840,"5848":5840,"5849":5840,"5850":5840,"5851":5840,"5852":5840,"5853":5840,"5854":5840,"5855":5840,"5857":5856,"5858":5856,"5859":5856,"5860":5856,"5861":5856,"5862":5856,"5863":5856,"5864":5856,"5865":5856,"5866":5856,"5867":5856,"5868":5856,"5869":5856,"5870":5856,"5871":5856,"5873":5872,"5874":5872,"5875":5872,"5876":5872,"5877":5872,"5878":5872,"5879":5872,"5880":5872,"5881":5872,"5882":5872,"5883":5872,"5884":5872,"5885":5872,"5886":5872,"5887":5872,"5889":5888,"5890":5888,"5891":5888,"5892":5888,"5893":5888,"5894":5888,"5895":5888,"5896":5888,"5897":5888,"5898":5888,"5899":5888,"5900":5888,"5901":5888,"5902":5888,"5903":5888,"5905":5904,"5906":5904,"5907":5904,"5908":5904,"5909":5904,"5910":5904,"5911":5904,"5912":5904,"5913":5904,"5914":5904,"5915":5904,"5916":5904,"5917":5904,"5918":5904,"5919":5904,"5921":5920,"5922":5920,"5923":5920,"5924":5920,"5925":5920,"5926":5920,"5927":5920,"5928":5920,"5929":5920,"5930":5920,"5931":5920,"5932":5920,"5933":5920,"5934":5920,"5935":5920,"5937":5936,"5938":5936,"5939":5936,"5940":5936,"5941":5936,"5942":5936,"5943":5936,"5944":5936,"5945":5936,"5946":5936,"5947":5936,"5948":5936,"5949":5936,"5950":5936,"5951":5936,"5953":5952,"5954":5952,"5955":5952,"5956":5952,"5957":5952,"5958":5952,"5959":5952,"5960":5952,"5961":5952,"5962":5952,"5963":5952,"5964":5952,"5965":5952,"5966":5952,"5967":5952,"5969":5968,"5970":5968,"5971":5968,"5972":5968,"5973":5968,"5974":5968,"5975":5968,"5976":5968,"5977":5968,"5978":5968,"5979":5968,"5980":5968,"5981":5968,"5982":5968,"5983":5968,"5985":5984,"5986":5984,"5987":5984,"5988":5984,"5989":5984,"5990":5984,"5991":5984,"5992":5984,"5993":5984,"5994":5984,"5995":5984,"5996":5984,"5997":5984,"5998":5984,"5999":5984,"6001":6000,"6002":6000,"6003":6000,"6004":6000,"6005":6000,"6006":6000,"6007":6000,"6008":6000,"6009":6000,"6010":6000,"6011":6000,"6012":6000,"6013":6000,"6014":6000,"6015":6000,"6017":6016,"6018":6016,"6019":6016,"6020":6016,"6021":6016,"6022":6016,"6023":6016,"6024":6016,"6025":6016,"6026":6016,"6027":6016,"6028":6016,"6029":6016,"6030":6016,"6031":6016,"6033":6032,"6034":6032,"6035":6032,"6036":6032,"6037":6032,"6038":6032,"6039":6032,"6040":6032,"6041":6032,"6042":6032,"6043":6032,"6044":6032,"6045":6032,"6046":6032,"6047":6032,"6049":6048,"6050":6048,"6051":6048,"6052":6048,"6053":6048,"6054":6048,"6055":6048,"6056":6048,"6057":6048,"6058":6048,"6059":6048,"6060":6048,"6061":6048,"6062":6048,"6063":6048,"6065":6064,"6066":6064,"6067":6064,"6068":6064,"6069":6064,"6070":6064,"6071":6064,"6072":6064,"6073":6064,"6074":6064,"6075":6064,"6076":6064,"6077":6064,"6078":6064,"6079":6064,"6081":6080,"6082":6080,"6083":6080,"6084":6080,"6085":6080,"6086":6080,"6087":6080,"6088":6080,"6089":6080,"6090":6080,"6091":6080,"6092":6080,"6093":6080,"6094":6080,"6095":6080,"6097":6096,"6098":6096,"6099":6096,"6100":6096,"6101":6096,"6102":6096,"6103":6096,"6104":6096,"6105":6096,"6106":6096,"6107":6096,"6108":6096,"6109":6096,"6110":6096,"6111":6096,"6113":6112,"6114":6112,"6115":6112,"6116":6112,"6117":6112,"6118":6112,"6119":6112,"6120":6112,"6121":6112,"6122":6112,"6123":6112,"6124":6112,"6125":6112,"6126":6112,"6127":6112,"6129":6128,"6130":6128,"6131":6128,"6132":6128,"6133":6128,"6134":6128,"6135":6128,"6136":6128,"6137":6128,"6138":6128,"6139":6128,"6140":6128,"6141":6128,"6142":6128,"6143":6128,"6145":6144,"6146":6144,"6147":6144,"6148":6144,"6149":6144,"6150":6144,"6151":6144,"6152":6144,"6153":6144,"6154":6144,"6155":6144,"6156":6144,"6157":6144,"6158":6144,"6159":6144,"6181":6176,"6182":6176,"6183":6176,"6184":6176,"6185":6176,"6186":6176,"6187":6176,"6188":6176,"6189":6176,"6190":6176,"6191":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6305":6304,"6306":6304,"6307":6304,"6308":6304,"6309":6304,"6310":6304,"6311":6304,"6312":6304,"6313":6304,"6314":6304,"6315":6304,"6316":6304,"6317":6304,"6318":6304,"6319":6304,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6482":6480,"6483":6480,"6484":6480,"6485":6480,"6486":6480,"6487":6480,"6488":6480,"6489":6480,"6490":6480,"6491":6480,"6492":6480,"6493":6480,"6494":6480,"6495":6480,"6498":6496,"6499":6496,"6500":6496,"6501":6496,"6502":6496,"6503":6496,"6504":6496,"6505":6496,"6506":6496,"6507":6496,"6508":6496,"6509":6496,"6510":6496,"6511":6496,"6514":6512,"6515":6512,"6516":6512,"6517":6512,"6518":6512,"6519":6512,"6520":6512,"6521":6512,"6522":6512,"6523":6512,"6524":6512,"6525":6512,"6526":6512,"6527":6512,"6530":6528,"6531":6528,"6532":6528,"6533":6528,"6534":6528,"6535":6528,"6536":6528,"6537":6528,"6538":6528,"6539":6528,"6540":6528,"6541":6528,"6542":6528,"6543":6528,"6546":6544,"6547":6544,"6548":6544,"6549":6544,"6550":6544,"6551":6544,"6552":6544,"6553":6544,"6554":6544,"6555":6544,"6556":6544,"6557":6544,"6558":6544,"6559":6544,"6564":6562,"6565":6562,"6566":6562,"6567":6562,"6568":6562,"6569":6562,"6570":6562,"6571":6562,"6572":6562,"6573":6562,"6574":6562,"6575":6562,"6584":6580,"6585":6580,"6586":6580,"6587":6580,"6588":6580,"6589":6580,"6590":6580,"6591":6580,"6657":6656,"6658":6656,"6659":6656,"6660":6656,"6661":6656,"6662":6656,"6663":6656,"6664":6656,"6665":6656,"6666":6656,"6667":6656,"6668":6656,"6669":6656,"6670":6656,"6671":6656,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6705":6704,"6706":6704,"6707":6704,"6708":6704,"6709":6704,"6710":6704,"6711":6704,"6713":6704,"6714":6704,"6715":6704,"6716":6704,"6717":6704,"6718":6704,"6719":6704,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6792":6787,"6793":6787,"6794":6787,"6795":6787,"6796":6787,"6797":6787,"6798":6787,"6799":6787,"6808":6803,"6809":6803,"6810":6803,"6811":6803,"6812":6803,"6813":6803,"6814":6803,"6815":6803,"6824":6819,"6825":6819,"6826":6819,"6827":6819,"6828":6819,"6829":6819,"6830":6819,"6831":6819,"6840":6835,"6841":6835,"6842":6835,"6843":6835,"6844":6835,"6845":6835,"6846":6835,"6847":6835,"6856":6851,"6857":6851,"6858":6851,"6859":6851,"6860":6851,"6861":6851,"6862":6851,"6863":6851,"6872":6867,"6873":6867,"6874":6867,"6875":6867,"6876":6867,"6877":6867,"6878":6867,"6879":6867,"6888":6883,"6889":6883,"6890":6883,"6891":6883,"6892":6883,"6893":6883,"6894":6883,"6895":6883,"6904":6899,"6905":6899,"6906":6899,"6907":6899,"6908":6899,"6909":6899,"6910":6899,"6911":6899,"6920":6915,"6921":6915,"6922":6915,"6923":6915,"6924":6915,"6925":6915,"6926":6915,"6927":6915,"6936":6931,"6937":6931,"6938":6931,"6939":6931,"6940":6931,"6941":6931,"6942":6931,"6943":6931,"6952":6947,"6953":6947,"6954":6947,"6955":6947,"6956":6947,"6957":6947,"6958":6947,"6959":6947,"6968":6963,"6969":6963,"6970":6963,"6971":6963,"6972":6963,"6973":6963,"6974":6963,"6975":6963,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7000":6994,"7001":6994,"7002":6994,"7003":6994,"7004":6994,"7005":6994,"7006":6994,"7007":6994,"7009":7008,"7010":7008,"7011":7008,"7012":7008,"7013":7008,"7014":7008,"7015":7008,"7016":7008,"7017":7008,"7018":7008,"7019":7008,"7020":7008,"7021":7008,"7022":7008,"7023":7008,"7032":7027,"7033":7027,"7034":7027,"7035":7027,"7036":7027,"7037":7027,"7038":7027,"7039":7027,"7048":7043,"7049":7043,"7050":7043,"7051":7043,"7052":7043,"7053":7043,"7054":7043,"7055":7043,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7080":7074,"7081":7074,"7082":7074,"7083":7074,"7084":7074,"7085":7074,"7086":7074,"7087":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7112":7106,"7113":7106,"7114":7106,"7115":7106,"7116":7106,"7117":7106,"7118":7106,"7119":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7144":7138,"7145":7138,"7146":7138,"7147":7138,"7148":7138,"7149":7138,"7150":7138,"7151":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7176":7170,"7177":7170,"7178":7170,"7179":7170,"7180":7170,"7181":7170,"7182":7170,"7183":7170,"7188":7186,"7189":7186,"7190":7186,"7191":7186,"7192":7186,"7193":7186,"7194":7186,"7195":7186,"7196":7186,"7197":7186,"7198":7186,"7199":7186,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7224":7218,"7225":7218,"7226":7218,"7227":7218,"7228":7218,"7229":7218,"7230":7218,"7231":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7256":7250,"7257":7250,"7258":7250,"7259":7250,"7260":7250,"7261":7250,"7262":7250,"7263":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7272":7250,"7273":7250,"7274":7250,"7275":7250,"7276":7250,"7277":7250,"7278":7250,"7279":7250,"7297":7296,"7298":7296,"7299":7296,"7300":7296,"7301":7296,"7302":7296,"7303":7296,"7304":7296,"7305":7296,"7306":7296,"7307":7296,"7308":7296,"7309":7296,"7310":7296,"7311":7296,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7348":7346,"7349":7346,"7350":7346,"7351":7346,"7352":7346,"7353":7346,"7354":7346,"7355":7346,"7356":7346,"7357":7346,"7358":7346,"7359":7346,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7400":7392,"7401":7392,"7402":7392,"7403":7392,"7404":7392,"7405":7392,"7406":7392,"7407":7392,"7410":7408,"7411":7408,"7412":7408,"7413":7408,"7414":7408,"7415":7408,"7416":7408,"7417":7408,"7418":7408,"7419":7408,"7420":7408,"7421":7408,"7422":7408,"7423":7408,"7478":7472,"7479":7472,"7486":7472,"7487":7472,"7504":7218,"7505":7218,"7510":7218,"7511":7218,"7512":7218,"7513":7218,"7514":7218,"7515":7218,"7516":7218,"7517":7218,"7518":7218,"7519":7218}} \ No newline at end of file From 42d07c74d71aa741de2338b3d5c5e7fa3790f451 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 15 Jan 2022 22:12:42 +0000 Subject: [PATCH 630/710] added missing redstone power flag logic --- src/block/BlockLegacyMetadata.php | 2 + src/block/Lectern.php | 42 +++++++++++++++++-- .../mcpe/handler/InGamePacketHandler.php | 10 ++--- .../block_factory_consistency_check.json | 2 +- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/block/BlockLegacyMetadata.php b/src/block/BlockLegacyMetadata.php index c9faa5ce7..5078654ab 100644 --- a/src/block/BlockLegacyMetadata.php +++ b/src/block/BlockLegacyMetadata.php @@ -142,6 +142,8 @@ final class BlockLegacyMetadata{ public const LEAVES_FLAG_NO_DECAY = 0x04; public const LEAVES_FLAG_CHECK_DECAY = 0x08; + public const LECTERN_FLAG_POWERED = 0x04; + public const LEVER_FLAG_POWERED = 0x08; public const LIQUID_FLAG_FALLING = 0x08; diff --git a/src/block/Lectern.php b/src/block/Lectern.php index bda8fa620..11e9f2653 100644 --- a/src/block/Lectern.php +++ b/src/block/Lectern.php @@ -40,13 +40,15 @@ class Lectern extends Transparent{ protected int $viewedPage = 0; protected ?WritableBookBase $book = null; + protected bool $producingSignal = false; public function readStateFromData(int $id, int $stateMeta) : void{ - $this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta); + $this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03); + $this->producingSignal = ($stateMeta & BlockLegacyMetadata::LECTERN_FLAG_POWERED) !== 0; } public function writeStateToMeta() : int{ - return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing); + return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) | ($this->producingSignal ? BlockLegacyMetadata::LECTERN_FLAG_POWERED : 0); } public function readStateFromWorld() : void{ @@ -68,7 +70,7 @@ class Lectern extends Transparent{ } public function getStateBitmask() : int{ - return 0b11; + return 0b111; } public function getFlammability() : int{ @@ -88,6 +90,14 @@ class Lectern extends Transparent{ return [AxisAlignedBB::one()->trim(Facing::UP, 0.1)]; } + public function isProducingSignal() : bool{ return $this->producingSignal; } + + /** @return $this */ + public function setProducingSignal(bool $producingSignal) : self{ + $this->producingSignal = $producingSignal; + return $this; + } + public function getViewedPage() : int{ return $this->viewedPage; } @@ -124,4 +134,30 @@ class Lectern extends Transparent{ } return false; } + + public function onPageTurn(int $newPage) : bool{ + if($newPage === $this->viewedPage){ + return true; + } + if($this->book === null || $newPage >= count($this->book->getPages()) || $newPage < 0){ + return false; + } + + $this->viewedPage = $newPage; + if(!$this->producingSignal){ + $this->producingSignal = true; + $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); + } + + $this->position->getWorld()->setBlock($this->position, $this); + + return true; + } + + public function onScheduledUpdate() : void{ + if($this->producingSignal){ + $this->producingSignal = false; + $this->position->getWorld()->setBlock($this->position, $this); + } + } } diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index b6b86f2ca..bed549378 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -945,14 +945,10 @@ class InGamePacketHandler extends PacketHandler{ $lectern = $world->getBlockAt($pos->getX(), $pos->getY(), $pos->getZ()); if($lectern instanceof Lectern && $this->player->canInteract($lectern->getPosition(), 15)){ - if($lectern->getViewedPage() === $packet->page){ - return true; - } - $book = $lectern->getBook(); - if($book !== null && count($book->getPages()) === $packet->totalPages && $packet->page >= 0 && $packet->page < $packet->totalPages){ - $world->setBlock($lectern->getPosition(), $lectern->setViewedPage($packet->page)); - return true; + if(!$lectern->onPageTurn($packet->page)){ + $this->onFailedBlockAction($lectern->getPosition(), null); } + return true; } return false; diff --git a/tests/phpunit/block/block_factory_consistency_check.json b/tests/phpunit/block/block_factory_consistency_check.json index 108153dc4..25cc92200 100644 --- a/tests/phpunit/block/block_factory_consistency_check.json +++ b/tests/phpunit/block/block_factory_consistency_check.json @@ -1 +1 @@ -{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7184":"Lectern","7185":"Lectern","7186":"Lectern","7187":"Lectern","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7296":"Fletching Table","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"23":16,"24":16,"25":16,"26":16,"27":16,"28":16,"29":16,"30":16,"31":16,"33":32,"34":32,"35":32,"36":32,"37":32,"38":32,"39":32,"40":32,"41":32,"42":32,"43":32,"44":32,"45":32,"46":32,"47":32,"50":48,"51":48,"52":48,"53":48,"54":48,"55":48,"56":48,"57":48,"58":48,"59":48,"60":48,"61":48,"62":48,"63":48,"65":64,"66":64,"67":64,"68":64,"69":64,"70":64,"71":64,"72":64,"73":64,"74":64,"75":64,"76":64,"77":64,"78":64,"79":64,"86":80,"87":80,"88":80,"89":80,"90":80,"91":80,"92":80,"93":80,"94":80,"95":80,"102":96,"103":96,"110":96,"111":96,"114":112,"115":112,"116":112,"117":112,"118":112,"119":112,"120":112,"121":112,"122":112,"123":112,"124":112,"125":112,"126":112,"127":112,"194":192,"195":192,"196":192,"197":192,"198":192,"199":192,"200":192,"201":192,"202":192,"203":192,"204":192,"205":192,"206":192,"207":192,"209":208,"210":208,"211":208,"212":208,"213":208,"214":208,"215":208,"216":208,"217":208,"218":208,"219":208,"220":208,"221":208,"222":208,"223":208,"225":224,"226":224,"227":224,"228":224,"229":224,"230":224,"231":224,"232":224,"233":224,"234":224,"235":224,"236":224,"237":224,"238":224,"239":224,"241":240,"242":240,"243":240,"244":240,"245":240,"246":240,"247":240,"248":240,"249":240,"250":240,"251":240,"252":240,"253":240,"254":240,"255":240,"257":256,"258":256,"259":256,"260":256,"261":256,"262":256,"263":256,"264":256,"265":256,"266":256,"267":256,"268":256,"269":256,"270":256,"271":256,"284":7472,"285":7473,"286":7474,"287":7475,"306":304,"307":304,"308":304,"309":304,"310":304,"311":304,"312":304,"313":304,"314":304,"315":304,"316":304,"317":304,"318":304,"319":304,"321":320,"322":320,"323":320,"324":320,"325":320,"326":320,"327":320,"328":320,"329":320,"330":320,"331":320,"332":320,"333":320,"334":320,"335":320,"337":336,"338":336,"339":336,"340":336,"341":336,"342":336,"343":336,"344":336,"345":336,"346":336,"347":336,"348":336,"349":336,"350":336,"351":336,"353":352,"354":352,"355":352,"356":352,"357":352,"358":352,"359":352,"360":352,"361":352,"362":352,"363":352,"364":352,"365":352,"366":352,"367":352,"388":384,"389":384,"390":384,"391":384,"392":384,"393":384,"394":384,"395":384,"396":384,"397":384,"398":384,"399":384,"401":400,"402":400,"403":400,"404":400,"405":400,"406":400,"407":400,"408":400,"409":400,"410":400,"411":400,"412":400,"413":400,"414":400,"415":400,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"481":480,"482":480,"483":480,"484":480,"485":480,"486":480,"487":480,"488":480,"489":480,"490":480,"491":480,"492":480,"493":480,"494":480,"495":480,"496":498,"499":498,"500":498,"501":498,"502":498,"503":498,"504":498,"505":498,"506":498,"507":498,"508":498,"509":498,"510":498,"511":498,"513":512,"514":512,"515":512,"516":512,"517":512,"518":512,"519":512,"520":512,"521":512,"522":512,"523":512,"524":512,"525":512,"526":512,"527":512,"577":576,"578":576,"579":576,"580":576,"581":576,"582":576,"583":576,"584":576,"585":576,"586":576,"587":576,"588":576,"589":576,"590":576,"591":576,"593":592,"594":592,"595":592,"596":592,"597":592,"598":592,"599":592,"600":592,"601":592,"602":592,"603":592,"604":592,"605":592,"606":592,"607":592,"619":608,"620":608,"621":608,"622":608,"623":608,"625":624,"626":624,"627":624,"628":624,"629":624,"630":624,"631":624,"632":624,"633":624,"634":624,"635":624,"636":624,"637":624,"638":624,"639":624,"641":640,"642":640,"643":640,"644":640,"645":640,"646":640,"647":640,"648":640,"649":640,"650":640,"651":640,"652":640,"653":640,"654":640,"655":640,"657":656,"658":656,"659":656,"660":656,"661":656,"662":656,"663":656,"664":656,"665":656,"666":656,"667":656,"668":656,"669":656,"670":656,"671":656,"673":672,"674":672,"675":672,"676":672,"677":672,"678":672,"679":672,"680":672,"681":672,"682":672,"683":672,"684":672,"685":672,"686":672,"687":672,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"721":720,"722":720,"723":720,"724":720,"725":720,"726":720,"727":720,"728":720,"729":720,"730":720,"731":720,"732":720,"733":720,"734":720,"735":720,"740":736,"741":736,"742":736,"743":736,"744":736,"745":736,"746":736,"747":736,"748":736,"749":736,"750":736,"751":736,"753":752,"754":752,"755":752,"756":752,"757":752,"758":752,"759":752,"760":752,"761":752,"762":752,"763":752,"764":752,"765":752,"766":752,"767":752,"769":768,"770":768,"771":768,"772":768,"773":768,"774":768,"775":768,"776":768,"777":768,"778":768,"779":768,"780":768,"781":768,"782":768,"783":768,"785":784,"786":784,"787":784,"788":784,"789":784,"790":784,"791":784,"792":784,"793":784,"794":784,"795":784,"796":784,"797":784,"798":784,"799":784,"800":805,"806":805,"807":805,"808":805,"809":805,"810":805,"811":805,"812":805,"813":805,"814":805,"815":805,"833":832,"834":832,"835":832,"836":832,"837":832,"838":832,"839":832,"840":832,"841":832,"842":832,"843":832,"844":832,"845":832,"846":832,"847":832,"856":851,"857":851,"858":851,"859":851,"860":851,"861":851,"862":851,"863":851,"864":866,"865":866,"870":866,"871":866,"872":866,"873":866,"874":866,"875":866,"876":866,"877":866,"878":866,"879":866,"897":896,"898":896,"899":896,"900":896,"901":896,"902":896,"903":896,"904":896,"905":896,"906":896,"907":896,"908":896,"909":896,"910":896,"911":896,"913":912,"914":912,"915":912,"916":912,"917":912,"918":912,"919":912,"920":912,"921":912,"922":912,"923":912,"924":912,"925":912,"926":912,"927":912,"929":928,"930":928,"931":928,"932":928,"933":928,"934":928,"935":928,"936":928,"937":928,"938":928,"939":928,"940":928,"941":928,"942":928,"943":928,"952":944,"953":944,"954":944,"955":944,"956":944,"957":944,"958":944,"959":944,"968":960,"969":960,"970":960,"971":960,"972":960,"973":960,"974":960,"975":960,"976":978,"977":978,"982":978,"983":978,"984":978,"985":978,"986":978,"987":978,"988":978,"989":978,"990":978,"991":978,"992":978,"993":978,"998":978,"999":978,"1000":978,"1001":978,"1002":978,"1003":978,"1004":978,"1005":978,"1006":978,"1007":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1048":1042,"1049":1042,"1050":1042,"1051":1042,"1052":1042,"1053":1042,"1054":1042,"1055":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1080":1075,"1081":1075,"1082":1075,"1083":1075,"1084":1075,"1085":1075,"1086":1075,"1087":1075,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1096":1090,"1097":1090,"1098":1090,"1099":1090,"1100":1090,"1101":1090,"1102":1090,"1103":1090,"1122":1120,"1123":1120,"1124":1120,"1125":1120,"1126":1120,"1127":1120,"1128":1120,"1129":1120,"1130":1120,"1131":1120,"1132":1120,"1133":1120,"1134":1120,"1135":1120,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1154":1152,"1155":1152,"1156":1152,"1157":1152,"1158":1152,"1159":1152,"1160":1152,"1161":1152,"1162":1152,"1163":1152,"1164":1152,"1165":1152,"1166":1152,"1167":1152,"1169":1168,"1170":1168,"1171":1168,"1172":1168,"1173":1168,"1174":1168,"1175":1168,"1176":1168,"1177":1168,"1178":1168,"1179":1168,"1180":1168,"1181":1168,"1182":1168,"1183":1168,"1185":1168,"1186":1168,"1187":1168,"1188":1168,"1189":1168,"1190":1168,"1191":1168,"1192":1168,"1193":1168,"1194":1168,"1195":1168,"1196":1168,"1197":1168,"1198":1168,"1199":1168,"1200":1221,"1206":1221,"1207":1221,"1208":1221,"1209":1221,"1210":1221,"1211":1221,"1212":1221,"1213":1221,"1214":1221,"1215":1221,"1216":1221,"1222":1221,"1223":1221,"1224":1221,"1225":1221,"1226":1221,"1227":1221,"1228":1221,"1229":1221,"1230":1221,"1231":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1256":1248,"1257":1248,"1258":1248,"1259":1248,"1260":1248,"1261":1248,"1262":1248,"1263":1248,"1265":1264,"1266":1264,"1267":1264,"1268":1264,"1269":1264,"1270":1264,"1271":1264,"1272":1264,"1273":1264,"1274":1264,"1275":1264,"1276":1264,"1277":1264,"1278":1264,"1279":1264,"1281":1280,"1282":1280,"1283":1280,"1284":1280,"1285":1280,"1286":1280,"1287":1280,"1288":1280,"1289":1280,"1290":1280,"1291":1280,"1292":1280,"1293":1280,"1294":1280,"1295":1280,"1313":1312,"1314":1312,"1315":1312,"1316":1312,"1317":1312,"1318":1312,"1319":1312,"1320":1312,"1321":1312,"1322":1312,"1323":1312,"1324":1312,"1325":1312,"1326":1312,"1327":1312,"1345":1344,"1346":1344,"1347":1344,"1348":1344,"1349":1344,"1350":1344,"1351":1344,"1352":1344,"1353":1344,"1354":1344,"1355":1344,"1356":1344,"1357":1344,"1358":1344,"1359":1344,"1366":1360,"1367":1360,"1368":1360,"1369":1360,"1370":1360,"1371":1360,"1372":1360,"1373":1360,"1374":1360,"1375":1360,"1377":1376,"1378":1376,"1379":1376,"1380":1376,"1381":1376,"1382":1376,"1383":1376,"1384":1376,"1385":1376,"1386":1376,"1387":1376,"1388":1376,"1389":1376,"1390":1376,"1391":1376,"1393":1392,"1394":1392,"1395":1392,"1396":1392,"1397":1392,"1398":1392,"1399":1392,"1400":1392,"1401":1392,"1402":1392,"1403":1392,"1404":1392,"1405":1392,"1406":1392,"1407":1392,"1409":1408,"1410":1408,"1411":1408,"1412":1408,"1413":1408,"1414":1408,"1415":1408,"1416":1408,"1417":1408,"1418":1408,"1419":1408,"1420":1408,"1421":1408,"1422":1408,"1423":1408,"1425":1424,"1426":1424,"1427":1424,"1428":1424,"1429":1424,"1430":1424,"1431":1424,"1432":1424,"1433":1424,"1434":1424,"1435":1424,"1436":1424,"1437":1424,"1438":1424,"1439":1424,"1440":1441,"1443":1441,"1444":1441,"1445":1441,"1446":1441,"1447":1441,"1448":1441,"1449":1441,"1450":1441,"1451":1441,"1452":1441,"1453":1441,"1454":1441,"1455":1441,"1460":1458,"1461":1458,"1462":1458,"1463":1458,"1464":1458,"1465":1458,"1466":1458,"1467":1458,"1468":1458,"1469":1458,"1470":1458,"1471":1458,"1479":1472,"1480":1472,"1481":1472,"1482":1472,"1483":1472,"1484":1472,"1485":1472,"1486":1472,"1487":1472,"1521":1520,"1522":1520,"1523":1520,"1524":1520,"1525":1520,"1526":1520,"1527":1520,"1528":1520,"1529":1520,"1530":1520,"1531":1520,"1532":1520,"1533":1520,"1534":1520,"1535":1520,"1558":1552,"1559":1552,"1560":1552,"1561":1552,"1562":1552,"1563":1552,"1564":1552,"1565":1552,"1566":1552,"1567":1552,"1572":1568,"1573":1568,"1574":1568,"1575":1568,"1576":1568,"1577":1568,"1578":1568,"1579":1568,"1580":1568,"1581":1568,"1582":1568,"1583":1568,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"1617":1616,"1618":1616,"1619":1616,"1620":1616,"1621":1616,"1622":1616,"1623":1616,"1624":1616,"1625":1616,"1626":1616,"1627":1616,"1628":1616,"1629":1616,"1630":1616,"1631":1616,"1633":1632,"1634":1632,"1635":1632,"1636":1632,"1637":1632,"1638":1632,"1639":1632,"1640":1632,"1641":1632,"1642":1632,"1643":1632,"1644":1632,"1645":1632,"1646":1632,"1647":1632,"1649":1648,"1650":1648,"1651":1648,"1652":1648,"1653":1648,"1654":1648,"1655":1648,"1656":1648,"1657":1648,"1658":1648,"1659":1648,"1660":1648,"1661":1648,"1662":1648,"1663":1648,"1672":1664,"1673":1664,"1674":1664,"1675":1664,"1676":1664,"1677":1664,"1678":1664,"1679":1664,"1688":1680,"1689":1680,"1690":1680,"1691":1680,"1692":1680,"1693":1680,"1694":1680,"1695":1680,"1736":1731,"1737":1731,"1738":1731,"1739":1731,"1740":1731,"1741":1731,"1742":1731,"1743":1731,"1752":1747,"1753":1747,"1754":1747,"1755":1747,"1756":1747,"1757":1747,"1758":1747,"1759":1747,"1761":1760,"1762":1760,"1763":1760,"1764":1760,"1765":1760,"1766":1760,"1767":1760,"1768":1760,"1769":1760,"1770":1760,"1771":1760,"1772":1760,"1773":1760,"1774":1760,"1775":1760,"1777":1776,"1778":1776,"1779":1776,"1780":1776,"1781":1776,"1782":1776,"1783":1776,"1784":1776,"1785":1776,"1786":1776,"1787":1776,"1788":1776,"1789":1776,"1790":1776,"1791":1776,"1793":1792,"1794":1792,"1795":1792,"1796":1792,"1797":1792,"1798":1792,"1799":1792,"1800":1792,"1801":1792,"1802":1792,"1803":1792,"1804":1792,"1805":1792,"1806":1792,"1807":1792,"1809":1808,"1810":1808,"1811":1808,"1812":1808,"1813":1808,"1814":1808,"1815":1808,"1816":1808,"1817":1808,"1818":1808,"1819":1808,"1820":1808,"1821":1808,"1822":1808,"1823":1808,"1832":1827,"1833":1827,"1834":1827,"1835":1827,"1836":1827,"1837":1827,"1838":1827,"1839":1827,"1844":1840,"1845":1840,"1846":1840,"1847":1840,"1848":1840,"1849":1840,"1850":1840,"1851":1840,"1852":1840,"1853":1840,"1854":1840,"1855":1840,"1857":1856,"1858":1856,"1859":1856,"1860":1856,"1861":1856,"1862":1856,"1863":1856,"1864":1856,"1865":1856,"1866":1856,"1867":1856,"1868":1856,"1869":1856,"1870":1856,"1871":1856,"1880":1872,"1881":1872,"1882":1872,"1883":1872,"1884":1872,"1885":1872,"1886":1872,"1887":1872,"1928":1922,"1929":1922,"1930":1922,"1931":1922,"1932":1922,"1933":1922,"1934":1922,"1935":1922,"1937":1936,"1938":1936,"1939":1936,"1940":1936,"1941":1936,"1942":1936,"1943":1936,"1944":1936,"1945":1936,"1946":1936,"1947":1936,"1948":1936,"1949":1936,"1950":1936,"1951":1936,"1953":1952,"1954":1952,"1955":1952,"1956":1952,"1957":1952,"1958":1952,"1959":1952,"1960":1952,"1961":1952,"1962":1952,"1963":1952,"1964":1952,"1965":1952,"1966":1952,"1967":1952,"1969":1968,"1970":1968,"1971":1968,"1972":1968,"1973":1968,"1974":1968,"1975":1968,"1976":1968,"1977":1968,"1978":1968,"1979":1968,"1980":1968,"1981":1968,"1982":1968,"1983":1968,"1985":1968,"1986":1968,"1987":1968,"1988":1968,"1989":1968,"1990":1968,"1991":1968,"1992":1968,"1993":1968,"1994":1968,"1995":1968,"1996":1968,"1997":1968,"1998":1968,"1999":1968,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2056":2051,"2057":2051,"2058":2051,"2059":2051,"2060":2051,"2061":2051,"2062":2051,"2063":2051,"2065":2064,"2066":2064,"2067":2064,"2068":2064,"2069":2064,"2070":2064,"2071":2064,"2072":2064,"2073":2064,"2074":2064,"2075":2064,"2076":2064,"2077":2064,"2078":2064,"2079":2064,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2088":2082,"2089":2082,"2090":2082,"2091":2082,"2092":2082,"2093":2082,"2094":2082,"2095":2082,"2129":2128,"2130":2128,"2131":2128,"2132":2128,"2133":2128,"2134":2128,"2135":2128,"2136":2128,"2137":2128,"2138":2128,"2139":2128,"2140":2128,"2141":2128,"2142":2128,"2143":2128,"2152":2147,"2153":2147,"2154":2147,"2155":2147,"2156":2147,"2157":2147,"2158":2147,"2159":2147,"2168":2163,"2169":2163,"2170":2163,"2171":2163,"2172":2163,"2173":2163,"2174":2163,"2175":2163,"2184":2179,"2185":2179,"2186":2179,"2187":2179,"2188":2179,"2189":2179,"2190":2179,"2191":2179,"2209":2208,"2210":2208,"2211":2208,"2212":2208,"2213":2208,"2214":2208,"2215":2208,"2216":2208,"2217":2208,"2218":2208,"2219":2208,"2220":2208,"2221":2208,"2222":2208,"2223":2208,"2238":2224,"2239":2224,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2264":2256,"2265":2256,"2266":2256,"2267":2256,"2268":2256,"2269":2256,"2270":2256,"2271":2256,"2280":2272,"2281":2272,"2282":2272,"2283":2272,"2284":2272,"2285":2272,"2286":2272,"2287":2272,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2344":2338,"2345":2338,"2346":2338,"2347":2338,"2348":2338,"2349":2338,"2350":2338,"2351":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2433":2432,"2434":2432,"2435":2432,"2436":2432,"2437":2432,"2438":2432,"2439":2432,"2440":2432,"2441":2432,"2442":2432,"2443":2432,"2444":2432,"2445":2432,"2446":2432,"2447":2432,"2449":2448,"2450":2448,"2451":2448,"2452":2448,"2453":2448,"2454":2448,"2455":2448,"2456":2448,"2457":2448,"2458":2448,"2459":2448,"2460":2448,"2461":2448,"2462":2448,"2463":2448,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2484":2480,"2487":2480,"2488":2480,"2491":2480,"2492":2480,"2493":2481,"2494":2482,"2495":2480,"2504":2499,"2505":2499,"2506":2499,"2507":2499,"2508":2499,"2509":2499,"2510":2499,"2511":2499,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2578":288,"2579":288,"2582":288,"2583":288,"2586":288,"2587":288,"2590":288,"2591":288,"2604":7476,"2605":7477,"2616":2611,"2617":2611,"2618":2611,"2619":2611,"2620":2611,"2621":2611,"2622":2611,"2623":2611,"2632":2627,"2633":2627,"2634":2627,"2635":2627,"2636":2627,"2637":2627,"2638":2627,"2639":2627,"2641":2640,"2642":2640,"2643":2640,"2644":2640,"2645":2640,"2646":2640,"2647":2640,"2648":2640,"2649":2640,"2650":2640,"2651":2640,"2652":2640,"2653":2640,"2654":2640,"2655":2640,"2691":2688,"2692":2688,"2693":2688,"2694":2688,"2695":2688,"2696":2688,"2697":2688,"2698":2688,"2699":2688,"2700":2688,"2701":2688,"2702":2688,"2703":2688,"2705":2704,"2706":2704,"2707":2704,"2708":2704,"2709":2704,"2710":2704,"2711":2704,"2712":2704,"2713":2704,"2714":2704,"2715":2704,"2716":2704,"2717":2704,"2718":2704,"2719":2704,"2721":2720,"2722":2720,"2723":2720,"2725":2720,"2726":2720,"2727":2720,"2729":2720,"2730":2720,"2731":2720,"2732":2720,"2733":2720,"2734":2720,"2735":2720,"2753":2752,"2754":2752,"2755":2752,"2756":2752,"2757":2752,"2758":2752,"2759":2752,"2760":2752,"2761":2752,"2762":2752,"2763":2752,"2764":2752,"2765":2752,"2766":2752,"2767":2752,"2769":2768,"2770":2768,"2771":2768,"2772":2768,"2773":2768,"2774":2768,"2775":2768,"2776":2768,"2777":2768,"2778":2768,"2779":2768,"2780":2768,"2781":2768,"2782":2768,"2783":2768,"2785":2784,"2786":2784,"2787":2784,"2788":2784,"2789":2784,"2790":2784,"2791":2784,"2792":2784,"2793":2784,"2794":2784,"2795":2784,"2796":2784,"2797":2784,"2798":2784,"2799":2784,"2806":2800,"2807":2800,"2814":2800,"2815":2800,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2840":2834,"2841":2834,"2842":2834,"2843":2834,"2844":2834,"2845":2834,"2846":2834,"2847":2834,"2868":2864,"2869":2864,"2870":2864,"2871":2864,"2872":2864,"2873":2864,"2874":2864,"2875":2864,"2876":2864,"2877":2864,"2878":2864,"2879":2864,"2888":2883,"2889":2883,"2890":2883,"2891":2883,"2892":2883,"2893":2883,"2894":2883,"2895":2883,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3041":3040,"3042":3040,"3043":3040,"3044":3040,"3045":3040,"3046":3040,"3047":3040,"3048":3040,"3049":3040,"3050":3040,"3051":3040,"3052":3040,"3053":3040,"3054":3040,"3055":3040,"3073":3072,"3074":3072,"3075":3072,"3076":3072,"3077":3072,"3078":3072,"3079":3072,"3080":3072,"3081":3072,"3082":3072,"3083":3072,"3084":3072,"3085":3072,"3086":3072,"3087":3072,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3169":3168,"3170":3168,"3171":3168,"3172":3168,"3173":3168,"3174":3168,"3175":3168,"3176":3168,"3177":3168,"3178":3168,"3179":3168,"3180":3168,"3181":3168,"3182":3168,"3183":3168,"3192":3187,"3193":3187,"3194":3187,"3195":3187,"3196":3187,"3197":3187,"3198":3187,"3199":3187,"3217":3216,"3219":3216,"3220":3216,"3221":3216,"3223":3216,"3224":3216,"3225":3216,"3227":3216,"3228":3216,"3229":3216,"3230":3218,"3231":3216,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3256":3251,"3257":3251,"3258":3251,"3259":3251,"3260":3251,"3261":3251,"3262":3251,"3263":3251,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3281":3280,"3282":3280,"3283":3280,"3284":3280,"3285":3280,"3286":3280,"3287":3280,"3288":3280,"3289":3280,"3290":3280,"3291":3280,"3292":3280,"3293":3280,"3294":3280,"3295":3280,"3297":3296,"3298":3296,"3299":3296,"3300":3296,"3301":3296,"3302":3296,"3303":3296,"3304":3296,"3305":3296,"3306":3296,"3307":3296,"3308":3296,"3309":3296,"3310":3296,"3311":3296,"3316":3312,"3317":3312,"3318":3312,"3319":3312,"3320":3312,"3321":3312,"3322":3312,"3323":3312,"3324":3312,"3325":3312,"3326":3312,"3327":3312,"3334":3328,"3335":3328,"3336":3328,"3337":3328,"3338":3328,"3339":3328,"3340":3328,"3341":3328,"3342":3328,"3343":3328,"3409":3408,"3410":3408,"3411":3408,"3412":3408,"3413":3408,"3414":3408,"3415":3408,"3416":3408,"3417":3408,"3418":3408,"3419":3408,"3420":3408,"3421":3408,"3422":3408,"3423":3408,"3425":3424,"3426":3424,"3427":3424,"3428":3424,"3429":3424,"3430":3424,"3431":3424,"3432":3424,"3433":3424,"3434":3424,"3435":3424,"3436":3424,"3437":3424,"3438":3424,"3439":3424,"3441":3440,"3442":3440,"3443":3440,"3444":3440,"3445":3440,"3446":3440,"3447":3440,"3448":3440,"3449":3440,"3450":3440,"3451":3440,"3452":3440,"3453":3440,"3454":3440,"3455":3440,"3457":3456,"3458":3456,"3459":3456,"3461":3456,"3462":3456,"3463":3456,"3465":3456,"3466":3456,"3467":3456,"3468":3456,"3469":3456,"3470":3456,"3471":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3512":3506,"3513":3506,"3514":3506,"3515":3506,"3516":3506,"3517":3506,"3518":3506,"3519":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3528":3522,"3529":3522,"3530":3522,"3531":3522,"3532":3522,"3533":3522,"3534":3522,"3535":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3544":3538,"3545":3538,"3546":3538,"3547":3538,"3548":3538,"3549":3538,"3550":3538,"3551":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3560":3554,"3561":3554,"3562":3554,"3563":3554,"3564":3554,"3565":3554,"3566":3554,"3567":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3576":3570,"3577":3570,"3578":3570,"3579":3570,"3580":3570,"3581":3570,"3582":3570,"3583":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3592":3586,"3593":3586,"3594":3586,"3595":3586,"3596":3586,"3597":3586,"3598":3586,"3599":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3608":3602,"3609":3602,"3610":3602,"3611":3602,"3612":3602,"3613":3602,"3614":3602,"3615":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3624":3618,"3625":3618,"3626":3618,"3627":3618,"3628":3618,"3629":3618,"3630":3618,"3631":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3640":3634,"3641":3634,"3642":3634,"3643":3634,"3644":3634,"3645":3634,"3646":3634,"3647":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3656":3650,"3657":3650,"3658":3650,"3659":3650,"3660":3650,"3661":3650,"3662":3650,"3663":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3672":3666,"3673":3666,"3674":3666,"3675":3666,"3676":3666,"3677":3666,"3678":3666,"3679":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3704":3698,"3705":3698,"3706":3698,"3707":3698,"3708":3698,"3709":3698,"3710":3698,"3711":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3720":3714,"3721":3714,"3722":3714,"3723":3714,"3724":3714,"3725":3714,"3726":3714,"3727":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3736":3730,"3737":3730,"3738":3730,"3739":3730,"3740":3730,"3741":3730,"3742":3730,"3743":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3752":3746,"3753":3746,"3754":3746,"3755":3746,"3756":3746,"3757":3746,"3758":3746,"3759":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3768":3762,"3769":3762,"3770":3762,"3771":3762,"3772":3762,"3773":3762,"3774":3762,"3775":3762,"3824":3829,"3830":3829,"3831":3829,"3832":3829,"3833":3829,"3834":3829,"3835":3829,"3836":3829,"3837":3829,"3838":3829,"3839":3829,"3889":3888,"3890":3888,"3891":3888,"3892":3888,"3893":3888,"3894":3888,"3895":3888,"3896":3888,"3897":3888,"3898":3888,"3899":3888,"3900":3888,"3901":3888,"3902":3888,"3903":3888,"3912":3904,"3913":3904,"3914":3904,"3915":3904,"3916":3904,"3917":3904,"3918":3904,"3919":3904,"3921":3920,"3922":3920,"3923":3920,"3924":3920,"3925":3920,"3926":3920,"3927":3920,"3928":3920,"3929":3920,"3930":3920,"3931":3920,"3932":3920,"3933":3920,"3934":3920,"3935":3920,"3937":3936,"3938":3936,"3939":3936,"3940":3936,"3941":3936,"3942":3936,"3943":3936,"3944":3936,"3945":3936,"3946":3936,"3947":3936,"3948":3936,"3949":3936,"3950":3936,"3951":3936,"3955":3952,"3956":3952,"3957":3952,"3958":3952,"3959":3952,"3960":3952,"3961":3952,"3962":3952,"3963":3952,"3964":3952,"3965":3952,"3966":3952,"3967":3952,"3969":3968,"3970":3968,"3971":3968,"3972":3968,"3973":3968,"3974":3968,"3975":3968,"3976":3968,"3977":3968,"3978":3968,"3979":3968,"3980":3968,"3981":3968,"3982":3968,"3983":3968,"3985":3984,"3986":3984,"3987":3984,"3988":3984,"3989":3984,"3990":3984,"3991":3984,"3992":3984,"3993":3984,"3994":3984,"3995":3984,"3996":3984,"3997":3984,"3998":3984,"3999":3984,"4049":4048,"4050":4048,"4051":4048,"4052":4048,"4053":4048,"4054":4048,"4055":4048,"4056":4048,"4057":4048,"4058":4048,"4059":4048,"4060":4048,"4061":4048,"4062":4048,"4063":4048,"4081":4080,"4082":4080,"4083":4080,"4084":4080,"4085":4080,"4086":4080,"4087":4080,"4088":4080,"4089":4080,"4090":4080,"4091":4080,"4092":4080,"4093":4080,"4094":4080,"4095":4080,"4120":4115,"4121":4115,"4122":4115,"4123":4115,"4124":4115,"4125":4115,"4126":4115,"4127":4115,"4136":4131,"4137":4131,"4138":4131,"4139":4131,"4140":4131,"4141":4131,"4142":4131,"4143":4131,"4152":4147,"4153":4147,"4154":4147,"4155":4147,"4156":4147,"4157":4147,"4158":4147,"4159":4147,"4163":4160,"4164":4160,"4165":4160,"4166":4160,"4167":4160,"4168":4160,"4169":4160,"4170":4160,"4171":4160,"4172":4160,"4173":4160,"4174":4160,"4175":4160,"4179":4176,"4180":4176,"4181":4176,"4182":4176,"4183":4176,"4184":4176,"4185":4176,"4186":4176,"4187":4176,"4188":4176,"4189":4176,"4190":4176,"4191":4176,"4195":4192,"4196":4192,"4197":4192,"4198":4192,"4199":4192,"4200":4192,"4201":4192,"4202":4192,"4203":4192,"4204":4192,"4205":4192,"4206":4192,"4207":4192,"4211":4208,"4212":4208,"4213":4208,"4214":4208,"4215":4208,"4216":4208,"4217":4208,"4218":4208,"4219":4208,"4220":4208,"4221":4208,"4222":4208,"4223":4208,"4227":4224,"4228":4224,"4229":4224,"4230":4224,"4231":4224,"4232":4224,"4233":4224,"4234":4224,"4235":4224,"4236":4224,"4237":4224,"4238":4224,"4239":4224,"4243":4240,"4244":4240,"4245":4240,"4246":4240,"4247":4240,"4248":4240,"4249":4240,"4250":4240,"4251":4240,"4252":4240,"4253":4240,"4254":4240,"4255":4240,"4257":4256,"4258":4256,"4259":4256,"4260":4256,"4261":4256,"4262":4256,"4263":4256,"4264":4256,"4265":4256,"4266":4256,"4267":4256,"4268":4256,"4269":4256,"4270":4256,"4271":4256,"4273":4272,"4274":4272,"4275":4272,"4276":4272,"4277":4272,"4278":4272,"4279":4272,"4280":4272,"4281":4272,"4282":4272,"4283":4272,"4284":4272,"4285":4272,"4286":4272,"4287":4272,"4289":4288,"4290":4288,"4291":4288,"4292":4288,"4293":4288,"4294":4288,"4295":4288,"4296":4288,"4297":4288,"4298":4288,"4299":4288,"4300":4288,"4301":4288,"4302":4288,"4303":4288,"4305":4304,"4306":4304,"4307":4304,"4308":4304,"4309":4304,"4310":4304,"4311":4304,"4312":4304,"4313":4304,"4314":4304,"4315":4304,"4316":4304,"4317":4304,"4318":4304,"4319":4304,"4321":4320,"4322":4320,"4323":4320,"4324":4320,"4325":4320,"4326":4320,"4327":4320,"4328":4320,"4329":4320,"4330":4320,"4331":4320,"4332":4320,"4333":4320,"4334":4320,"4335":4320,"4337":4336,"4338":4336,"4339":4336,"4340":4336,"4341":4336,"4342":4336,"4343":4336,"4344":4336,"4345":4336,"4346":4336,"4347":4336,"4348":4336,"4349":4336,"4350":4336,"4351":4336,"4353":4352,"4354":4352,"4355":4352,"4356":4352,"4357":4352,"4358":4352,"4359":4352,"4360":4352,"4361":4352,"4362":4352,"4363":4352,"4364":4352,"4365":4352,"4366":4352,"4367":4352,"4369":4368,"4370":4368,"4371":4368,"4372":4368,"4373":4368,"4374":4368,"4375":4368,"4376":4368,"4377":4368,"4378":4368,"4379":4368,"4380":4368,"4381":4368,"4382":4368,"4383":4368,"4385":4384,"4386":4384,"4387":4384,"4388":4384,"4389":4384,"4390":4384,"4391":4384,"4392":4384,"4393":4384,"4394":4384,"4395":4384,"4396":4384,"4397":4384,"4398":4384,"4399":4384,"4401":4400,"4402":4400,"4403":4400,"4404":4400,"4405":4400,"4406":4400,"4407":4400,"4408":4400,"4409":4400,"4410":4400,"4411":4400,"4412":4400,"4413":4400,"4414":4400,"4415":4400,"4417":4416,"4418":4416,"4419":4416,"4420":4416,"4421":4416,"4422":4416,"4423":4416,"4424":4416,"4425":4416,"4426":4416,"4427":4416,"4428":4416,"4429":4416,"4430":4416,"4431":4416,"4433":4432,"4434":4432,"4435":4432,"4436":4432,"4437":4432,"4438":4432,"4439":4432,"4440":4432,"4441":4432,"4442":4432,"4443":4432,"4444":4432,"4445":4432,"4446":4432,"4447":4432,"4449":4448,"4450":4448,"4451":4448,"4452":4448,"4453":4448,"4454":4448,"4455":4448,"4456":4448,"4457":4448,"4458":4448,"4459":4448,"4460":4448,"4461":4448,"4462":4448,"4463":4448,"4465":4464,"4466":4464,"4467":4464,"4468":4464,"4469":4464,"4470":4464,"4471":4464,"4472":4464,"4473":4464,"4474":4464,"4475":4464,"4476":4464,"4477":4464,"4478":4464,"4479":4464,"4481":4480,"4482":4480,"4483":4480,"4484":4480,"4485":4480,"4486":4480,"4487":4480,"4488":4480,"4489":4480,"4490":4480,"4491":4480,"4492":4480,"4493":4480,"4494":4480,"4495":4480,"4497":4496,"4498":4496,"4499":4496,"4500":4496,"4501":4496,"4502":4496,"4503":4496,"4504":4496,"4505":4496,"4506":4496,"4507":4496,"4508":4496,"4509":4496,"4510":4496,"4511":4496,"4513":4512,"4514":4512,"4515":4512,"4516":4512,"4517":4512,"4518":4512,"4519":4512,"4520":4512,"4521":4512,"4522":4512,"4523":4512,"4524":4512,"4525":4512,"4526":4512,"4527":4512,"4529":4528,"4530":4528,"4531":4528,"4532":4528,"4533":4528,"4534":4528,"4535":4528,"4536":4528,"4537":4528,"4538":4528,"4539":4528,"4540":4528,"4541":4528,"4542":4528,"4543":4528,"4545":4544,"4546":4544,"4547":4544,"4548":4544,"4549":4544,"4550":4544,"4551":4544,"4552":4544,"4553":4544,"4554":4544,"4555":4544,"4556":4544,"4557":4544,"4558":4544,"4559":4544,"4561":4560,"4562":4560,"4563":4560,"4564":4560,"4565":4560,"4566":4560,"4567":4560,"4568":4560,"4569":4560,"4570":4560,"4571":4560,"4572":4560,"4573":4560,"4574":4560,"4575":4560,"4577":4576,"4578":4576,"4579":4576,"4580":4576,"4581":4576,"4582":4576,"4583":4576,"4584":4576,"4585":4576,"4586":4576,"4587":4576,"4588":4576,"4589":4576,"4590":4576,"4591":4576,"4593":4592,"4594":4592,"4595":4592,"4596":4592,"4597":4592,"4598":4592,"4599":4592,"4600":4592,"4601":4592,"4602":4592,"4603":4592,"4604":4592,"4605":4592,"4606":4592,"4607":4592,"4609":4608,"4610":4608,"4611":4608,"4612":4608,"4613":4608,"4614":4608,"4615":4608,"4616":4608,"4617":4608,"4618":4608,"4619":4608,"4620":4608,"4621":4608,"4622":4608,"4623":4608,"4625":4624,"4626":4624,"4627":4624,"4628":4624,"4629":4624,"4630":4624,"4631":4624,"4632":4624,"4633":4624,"4634":4624,"4635":4624,"4636":4624,"4637":4624,"4638":4624,"4639":4624,"4641":4640,"4642":4640,"4643":4640,"4644":4640,"4645":4640,"4646":4640,"4647":4640,"4648":4640,"4649":4640,"4650":4640,"4651":4640,"4652":4640,"4653":4640,"4654":4640,"4655":4640,"4657":4656,"4658":4656,"4659":4656,"4660":4656,"4661":4656,"4662":4656,"4663":4656,"4664":4656,"4665":4656,"4666":4656,"4667":4656,"4668":4656,"4669":4656,"4670":4656,"4671":4656,"4673":4672,"4674":4672,"4675":4672,"4676":4672,"4677":4672,"4678":4672,"4679":4672,"4680":4672,"4681":4672,"4682":4672,"4683":4672,"4684":4672,"4685":4672,"4686":4672,"4687":4672,"4689":4688,"4690":4688,"4691":4688,"4692":4688,"4693":4688,"4694":4688,"4695":4688,"4696":4688,"4697":4688,"4698":4688,"4699":4688,"4700":4688,"4701":4688,"4702":4688,"4703":4688,"4705":4704,"4706":4704,"4707":4704,"4708":4704,"4709":4704,"4710":4704,"4711":4704,"4712":4704,"4713":4704,"4714":4704,"4715":4704,"4716":4704,"4717":4704,"4718":4704,"4719":4704,"4721":4720,"4722":4720,"4723":4720,"4724":4720,"4725":4720,"4726":4720,"4727":4720,"4728":4720,"4729":4720,"4730":4720,"4731":4720,"4732":4720,"4733":4720,"4734":4720,"4735":4720,"4737":4736,"4738":4736,"4739":4736,"4740":4736,"4741":4736,"4742":4736,"4743":4736,"4744":4736,"4745":4736,"4746":4736,"4747":4736,"4748":4736,"4749":4736,"4750":4736,"4751":4736,"4753":4752,"4754":4752,"4755":4752,"4756":4752,"4757":4752,"4758":4752,"4759":4752,"4760":4752,"4761":4752,"4762":4752,"4763":4752,"4764":4752,"4765":4752,"4766":4752,"4767":4752,"4769":4768,"4770":4768,"4771":4768,"4772":4768,"4773":4768,"4774":4768,"4775":4768,"4776":4768,"4777":4768,"4778":4768,"4779":4768,"4780":4768,"4781":4768,"4782":4768,"4783":4768,"4785":4784,"4786":4784,"4787":4784,"4788":4784,"4789":4784,"4790":4784,"4791":4784,"4792":4784,"4793":4784,"4794":4784,"4795":4784,"4796":4784,"4797":4784,"4798":4784,"4799":4784,"4801":4800,"4802":4800,"4803":4800,"4804":4800,"4805":4800,"4806":4800,"4807":4800,"4808":4800,"4809":4800,"4810":4800,"4811":4800,"4812":4800,"4813":4800,"4814":4800,"4815":4800,"4817":4816,"4818":4816,"4819":4816,"4820":4816,"4821":4816,"4822":4816,"4823":4816,"4824":4816,"4825":4816,"4826":4816,"4827":4816,"4828":4816,"4829":4816,"4830":4816,"4831":4816,"4833":4832,"4834":4832,"4835":4832,"4836":4832,"4837":4832,"4838":4832,"4839":4832,"4840":4832,"4841":4832,"4842":4832,"4843":4832,"4844":4832,"4845":4832,"4846":4832,"4847":4832,"4849":4848,"4850":4848,"4851":4848,"4852":4848,"4853":4848,"4854":4848,"4855":4848,"4856":4848,"4857":4848,"4858":4848,"4859":4848,"4860":4848,"4861":4848,"4862":4848,"4863":4848,"4865":4864,"4866":4864,"4867":4864,"4868":4864,"4869":4864,"4870":4864,"4871":4864,"4872":4864,"4873":4864,"4874":4864,"4875":4864,"4876":4864,"4877":4864,"4878":4864,"4879":4864,"4881":4880,"4882":4880,"4883":4880,"4884":4880,"4885":4880,"4886":4880,"4887":4880,"4888":4880,"4889":4880,"4890":4880,"4891":4880,"4892":4880,"4893":4880,"4894":4880,"4895":4880,"4897":4896,"4898":4896,"4899":4896,"4900":4896,"4901":4896,"4902":4896,"4903":4896,"4904":4896,"4905":4896,"4906":4896,"4907":4896,"4908":4896,"4909":4896,"4910":4896,"4911":4896,"4913":4912,"4914":4912,"4915":4912,"4916":4912,"4917":4912,"4918":4912,"4919":4912,"4920":4912,"4921":4912,"4922":4912,"4923":4912,"4924":4912,"4925":4912,"4926":4912,"4927":4912,"4929":4928,"4930":4928,"4931":4928,"4932":4928,"4933":4928,"4934":4928,"4935":4928,"4936":4928,"4937":4928,"4938":4928,"4939":4928,"4940":4928,"4941":4928,"4942":4928,"4943":4928,"4945":4944,"4946":4944,"4947":4944,"4948":4944,"4949":4944,"4950":4944,"4951":4944,"4952":4944,"4953":4944,"4954":4944,"4955":4944,"4956":4944,"4957":4944,"4958":4944,"4959":4944,"4961":4960,"4962":4960,"4963":4960,"4964":4960,"4965":4960,"4966":4960,"4967":4960,"4968":4960,"4969":4960,"4970":4960,"4971":4960,"4972":4960,"4973":4960,"4974":4960,"4975":4960,"4977":4976,"4978":4976,"4979":4976,"4980":4976,"4981":4976,"4982":4976,"4983":4976,"4984":4976,"4985":4976,"4986":4976,"4987":4976,"4988":4976,"4989":4976,"4990":4976,"4991":4976,"4993":4992,"4994":4992,"4995":4992,"4996":4992,"4997":4992,"4998":4992,"4999":4992,"5000":4992,"5001":4992,"5002":4992,"5003":4992,"5004":4992,"5005":4992,"5006":4992,"5007":4992,"5009":5008,"5010":5008,"5011":5008,"5012":5008,"5013":5008,"5014":5008,"5015":5008,"5016":5008,"5017":5008,"5018":5008,"5019":5008,"5020":5008,"5021":5008,"5022":5008,"5023":5008,"5025":5024,"5026":5024,"5027":5024,"5028":5024,"5029":5024,"5030":5024,"5031":5024,"5032":5024,"5033":5024,"5034":5024,"5035":5024,"5036":5024,"5037":5024,"5038":5024,"5039":5024,"5041":5040,"5042":5040,"5043":5040,"5044":5040,"5045":5040,"5046":5040,"5047":5040,"5048":5040,"5049":5040,"5050":5040,"5051":5040,"5052":5040,"5053":5040,"5054":5040,"5055":5040,"5057":5056,"5058":5056,"5059":5056,"5060":5056,"5061":5056,"5062":5056,"5063":5056,"5064":5056,"5065":5056,"5066":5056,"5067":5056,"5068":5056,"5069":5056,"5070":5056,"5071":5056,"5073":5072,"5074":5072,"5075":5072,"5076":5072,"5077":5072,"5078":5072,"5079":5072,"5080":5072,"5081":5072,"5082":5072,"5083":5072,"5084":5072,"5085":5072,"5086":5072,"5087":5072,"5089":5088,"5090":5088,"5091":5088,"5092":5088,"5093":5088,"5094":5088,"5095":5088,"5096":5088,"5097":5088,"5098":5088,"5099":5088,"5100":5088,"5101":5088,"5102":5088,"5103":5088,"5105":5104,"5106":5104,"5107":5104,"5108":5104,"5109":5104,"5110":5104,"5111":5104,"5112":5104,"5113":5104,"5114":5104,"5115":5104,"5116":5104,"5117":5104,"5118":5104,"5119":5104,"5121":5120,"5122":5120,"5123":5120,"5124":5120,"5125":5120,"5126":5120,"5127":5120,"5128":5120,"5129":5120,"5130":5120,"5131":5120,"5132":5120,"5133":5120,"5134":5120,"5135":5120,"5137":5136,"5138":5136,"5139":5136,"5140":5136,"5141":5136,"5142":5136,"5143":5136,"5144":5136,"5145":5136,"5146":5136,"5147":5136,"5148":5136,"5149":5136,"5150":5136,"5151":5136,"5153":5152,"5154":5152,"5155":5152,"5156":5152,"5157":5152,"5158":5152,"5159":5152,"5160":5152,"5161":5152,"5162":5152,"5163":5152,"5164":5152,"5165":5152,"5166":5152,"5167":5152,"5169":5168,"5170":5168,"5171":5168,"5172":5168,"5173":5168,"5174":5168,"5175":5168,"5176":5168,"5177":5168,"5178":5168,"5179":5168,"5180":5168,"5181":5168,"5182":5168,"5183":5168,"5185":5184,"5186":5184,"5187":5184,"5188":5184,"5189":5184,"5190":5184,"5191":5184,"5192":5184,"5193":5184,"5194":5184,"5195":5184,"5196":5184,"5197":5184,"5198":5184,"5199":5184,"5201":5200,"5202":5200,"5203":5200,"5204":5200,"5205":5200,"5206":5200,"5207":5200,"5208":5200,"5209":5200,"5210":5200,"5211":5200,"5212":5200,"5213":5200,"5214":5200,"5215":5200,"5217":5216,"5218":5216,"5219":5216,"5220":5216,"5221":5216,"5222":5216,"5223":5216,"5224":5216,"5225":5216,"5226":5216,"5227":5216,"5228":5216,"5229":5216,"5230":5216,"5231":5216,"5233":5232,"5234":5232,"5235":5232,"5236":5232,"5237":5232,"5238":5232,"5239":5232,"5240":5232,"5241":5232,"5242":5232,"5243":5232,"5244":5232,"5245":5232,"5246":5232,"5247":5232,"5249":5248,"5250":5248,"5251":5248,"5252":5248,"5253":5248,"5254":5248,"5255":5248,"5256":5248,"5257":5248,"5258":5248,"5259":5248,"5260":5248,"5261":5248,"5262":5248,"5263":5248,"5265":5264,"5266":5264,"5267":5264,"5268":5264,"5269":5264,"5270":5264,"5271":5264,"5272":5264,"5273":5264,"5274":5264,"5275":5264,"5276":5264,"5277":5264,"5278":5264,"5279":5264,"5281":5280,"5282":5280,"5283":5280,"5284":5280,"5285":5280,"5286":5280,"5287":5280,"5288":5280,"5289":5280,"5290":5280,"5291":5280,"5292":5280,"5293":5280,"5294":5280,"5295":5280,"5297":5296,"5298":5296,"5299":5296,"5300":5296,"5301":5296,"5302":5296,"5303":5296,"5304":5296,"5305":5296,"5306":5296,"5307":5296,"5308":5296,"5309":5296,"5310":5296,"5311":5296,"5313":5312,"5314":5312,"5315":5312,"5316":5312,"5317":5312,"5318":5312,"5319":5312,"5320":5312,"5321":5312,"5322":5312,"5323":5312,"5324":5312,"5325":5312,"5326":5312,"5327":5312,"5329":5328,"5330":5328,"5331":5328,"5332":5328,"5333":5328,"5334":5328,"5335":5328,"5336":5328,"5337":5328,"5338":5328,"5339":5328,"5340":5328,"5341":5328,"5342":5328,"5343":5328,"5345":5344,"5346":5344,"5347":5344,"5348":5344,"5349":5344,"5350":5344,"5351":5344,"5352":5344,"5353":5344,"5354":5344,"5355":5344,"5356":5344,"5357":5344,"5358":5344,"5359":5344,"5361":5360,"5362":5360,"5363":5360,"5364":5360,"5365":5360,"5366":5360,"5367":5360,"5368":5360,"5369":5360,"5370":5360,"5371":5360,"5372":5360,"5373":5360,"5374":5360,"5375":5360,"5377":5376,"5378":5376,"5379":5376,"5380":5376,"5381":5376,"5382":5376,"5383":5376,"5384":5376,"5385":5376,"5386":5376,"5387":5376,"5388":5376,"5389":5376,"5390":5376,"5391":5376,"5393":5392,"5394":5392,"5395":5392,"5396":5392,"5397":5392,"5398":5392,"5399":5392,"5400":5392,"5401":5392,"5402":5392,"5403":5392,"5404":5392,"5405":5392,"5406":5392,"5407":5392,"5409":5408,"5410":5408,"5411":5408,"5412":5408,"5413":5408,"5414":5408,"5415":5408,"5416":5408,"5417":5408,"5418":5408,"5419":5408,"5420":5408,"5421":5408,"5422":5408,"5423":5408,"5425":5424,"5426":5424,"5427":5424,"5428":5424,"5429":5424,"5430":5424,"5431":5424,"5432":5424,"5433":5424,"5434":5424,"5435":5424,"5436":5424,"5437":5424,"5438":5424,"5439":5424,"5441":5440,"5442":5440,"5443":5440,"5444":5440,"5445":5440,"5446":5440,"5447":5440,"5448":5440,"5449":5440,"5450":5440,"5451":5440,"5452":5440,"5453":5440,"5454":5440,"5455":5440,"5457":5456,"5458":5456,"5459":5456,"5460":5456,"5461":5456,"5462":5456,"5463":5456,"5464":5456,"5465":5456,"5466":5456,"5467":5456,"5468":5456,"5469":5456,"5470":5456,"5471":5456,"5473":5472,"5474":5472,"5475":5472,"5476":5472,"5477":5472,"5478":5472,"5479":5472,"5480":5472,"5481":5472,"5482":5472,"5483":5472,"5484":5472,"5485":5472,"5486":5472,"5487":5472,"5489":5488,"5490":5488,"5491":5488,"5492":5488,"5493":5488,"5494":5488,"5495":5488,"5496":5488,"5497":5488,"5498":5488,"5499":5488,"5500":5488,"5501":5488,"5502":5488,"5503":5488,"5505":5504,"5506":5504,"5507":5504,"5508":5504,"5509":5504,"5510":5504,"5511":5504,"5512":5504,"5513":5504,"5514":5504,"5515":5504,"5516":5504,"5517":5504,"5518":5504,"5519":5504,"5521":5520,"5522":5520,"5523":5520,"5524":5520,"5525":5520,"5526":5520,"5527":5520,"5528":5520,"5529":5520,"5530":5520,"5531":5520,"5532":5520,"5533":5520,"5534":5520,"5535":5520,"5537":5536,"5538":5536,"5539":5536,"5540":5536,"5541":5536,"5542":5536,"5543":5536,"5544":5536,"5545":5536,"5546":5536,"5547":5536,"5548":5536,"5549":5536,"5550":5536,"5551":5536,"5553":5552,"5554":5552,"5555":5552,"5556":5552,"5557":5552,"5558":5552,"5559":5552,"5560":5552,"5561":5552,"5562":5552,"5563":5552,"5564":5552,"5565":5552,"5566":5552,"5567":5552,"5569":5568,"5570":5568,"5571":5568,"5572":5568,"5573":5568,"5574":5568,"5575":5568,"5576":5568,"5577":5568,"5578":5568,"5579":5568,"5580":5568,"5581":5568,"5582":5568,"5583":5568,"5585":5584,"5586":5584,"5587":5584,"5588":5584,"5589":5584,"5590":5584,"5591":5584,"5592":5584,"5593":5584,"5594":5584,"5595":5584,"5596":5584,"5597":5584,"5598":5584,"5599":5584,"5601":5600,"5602":5600,"5603":5600,"5604":5600,"5605":5600,"5606":5600,"5607":5600,"5608":5600,"5609":5600,"5610":5600,"5611":5600,"5612":5600,"5613":5600,"5614":5600,"5615":5600,"5617":5616,"5618":5616,"5619":5616,"5620":5616,"5621":5616,"5622":5616,"5623":5616,"5624":5616,"5625":5616,"5626":5616,"5627":5616,"5628":5616,"5629":5616,"5630":5616,"5631":5616,"5633":5632,"5634":5632,"5635":5632,"5636":5632,"5637":5632,"5638":5632,"5639":5632,"5640":5632,"5641":5632,"5642":5632,"5643":5632,"5644":5632,"5645":5632,"5646":5632,"5647":5632,"5649":5648,"5650":5648,"5651":5648,"5652":5648,"5653":5648,"5654":5648,"5655":5648,"5656":5648,"5657":5648,"5658":5648,"5659":5648,"5660":5648,"5661":5648,"5662":5648,"5663":5648,"5665":5664,"5666":5664,"5667":5664,"5668":5664,"5669":5664,"5670":5664,"5671":5664,"5672":5664,"5673":5664,"5674":5664,"5675":5664,"5676":5664,"5677":5664,"5678":5664,"5679":5664,"5681":5680,"5682":5680,"5683":5680,"5684":5680,"5685":5680,"5686":5680,"5687":5680,"5688":5680,"5689":5680,"5690":5680,"5691":5680,"5692":5680,"5693":5680,"5694":5680,"5695":5680,"5697":5696,"5698":5696,"5699":5696,"5700":5696,"5701":5696,"5702":5696,"5703":5696,"5704":5696,"5705":5696,"5706":5696,"5707":5696,"5708":5696,"5709":5696,"5710":5696,"5711":5696,"5713":5712,"5714":5712,"5715":5712,"5716":5712,"5717":5712,"5718":5712,"5719":5712,"5720":5712,"5721":5712,"5722":5712,"5723":5712,"5724":5712,"5725":5712,"5726":5712,"5727":5712,"5729":5728,"5730":5728,"5731":5728,"5732":5728,"5733":5728,"5734":5728,"5735":5728,"5736":5728,"5737":5728,"5738":5728,"5739":5728,"5740":5728,"5741":5728,"5742":5728,"5743":5728,"5745":5744,"5746":5744,"5747":5744,"5748":5744,"5749":5744,"5750":5744,"5751":5744,"5752":5744,"5753":5744,"5754":5744,"5755":5744,"5756":5744,"5757":5744,"5758":5744,"5759":5744,"5761":5760,"5762":5760,"5763":5760,"5764":5760,"5765":5760,"5766":5760,"5767":5760,"5768":5760,"5769":5760,"5770":5760,"5771":5760,"5772":5760,"5773":5760,"5774":5760,"5775":5760,"5777":5776,"5778":5776,"5779":5776,"5780":5776,"5781":5776,"5782":5776,"5783":5776,"5784":5776,"5785":5776,"5786":5776,"5787":5776,"5788":5776,"5789":5776,"5790":5776,"5791":5776,"5793":5792,"5794":5792,"5795":5792,"5796":5792,"5797":5792,"5798":5792,"5799":5792,"5800":5792,"5801":5792,"5802":5792,"5803":5792,"5804":5792,"5805":5792,"5806":5792,"5807":5792,"5809":5808,"5810":5808,"5811":5808,"5812":5808,"5813":5808,"5814":5808,"5815":5808,"5816":5808,"5817":5808,"5818":5808,"5819":5808,"5820":5808,"5821":5808,"5822":5808,"5823":5808,"5825":5824,"5826":5824,"5827":5824,"5828":5824,"5829":5824,"5830":5824,"5831":5824,"5832":5824,"5833":5824,"5834":5824,"5835":5824,"5836":5824,"5837":5824,"5838":5824,"5839":5824,"5841":5840,"5842":5840,"5843":5840,"5844":5840,"5845":5840,"5846":5840,"5847":5840,"5848":5840,"5849":5840,"5850":5840,"5851":5840,"5852":5840,"5853":5840,"5854":5840,"5855":5840,"5857":5856,"5858":5856,"5859":5856,"5860":5856,"5861":5856,"5862":5856,"5863":5856,"5864":5856,"5865":5856,"5866":5856,"5867":5856,"5868":5856,"5869":5856,"5870":5856,"5871":5856,"5873":5872,"5874":5872,"5875":5872,"5876":5872,"5877":5872,"5878":5872,"5879":5872,"5880":5872,"5881":5872,"5882":5872,"5883":5872,"5884":5872,"5885":5872,"5886":5872,"5887":5872,"5889":5888,"5890":5888,"5891":5888,"5892":5888,"5893":5888,"5894":5888,"5895":5888,"5896":5888,"5897":5888,"5898":5888,"5899":5888,"5900":5888,"5901":5888,"5902":5888,"5903":5888,"5905":5904,"5906":5904,"5907":5904,"5908":5904,"5909":5904,"5910":5904,"5911":5904,"5912":5904,"5913":5904,"5914":5904,"5915":5904,"5916":5904,"5917":5904,"5918":5904,"5919":5904,"5921":5920,"5922":5920,"5923":5920,"5924":5920,"5925":5920,"5926":5920,"5927":5920,"5928":5920,"5929":5920,"5930":5920,"5931":5920,"5932":5920,"5933":5920,"5934":5920,"5935":5920,"5937":5936,"5938":5936,"5939":5936,"5940":5936,"5941":5936,"5942":5936,"5943":5936,"5944":5936,"5945":5936,"5946":5936,"5947":5936,"5948":5936,"5949":5936,"5950":5936,"5951":5936,"5953":5952,"5954":5952,"5955":5952,"5956":5952,"5957":5952,"5958":5952,"5959":5952,"5960":5952,"5961":5952,"5962":5952,"5963":5952,"5964":5952,"5965":5952,"5966":5952,"5967":5952,"5969":5968,"5970":5968,"5971":5968,"5972":5968,"5973":5968,"5974":5968,"5975":5968,"5976":5968,"5977":5968,"5978":5968,"5979":5968,"5980":5968,"5981":5968,"5982":5968,"5983":5968,"5985":5984,"5986":5984,"5987":5984,"5988":5984,"5989":5984,"5990":5984,"5991":5984,"5992":5984,"5993":5984,"5994":5984,"5995":5984,"5996":5984,"5997":5984,"5998":5984,"5999":5984,"6001":6000,"6002":6000,"6003":6000,"6004":6000,"6005":6000,"6006":6000,"6007":6000,"6008":6000,"6009":6000,"6010":6000,"6011":6000,"6012":6000,"6013":6000,"6014":6000,"6015":6000,"6017":6016,"6018":6016,"6019":6016,"6020":6016,"6021":6016,"6022":6016,"6023":6016,"6024":6016,"6025":6016,"6026":6016,"6027":6016,"6028":6016,"6029":6016,"6030":6016,"6031":6016,"6033":6032,"6034":6032,"6035":6032,"6036":6032,"6037":6032,"6038":6032,"6039":6032,"6040":6032,"6041":6032,"6042":6032,"6043":6032,"6044":6032,"6045":6032,"6046":6032,"6047":6032,"6049":6048,"6050":6048,"6051":6048,"6052":6048,"6053":6048,"6054":6048,"6055":6048,"6056":6048,"6057":6048,"6058":6048,"6059":6048,"6060":6048,"6061":6048,"6062":6048,"6063":6048,"6065":6064,"6066":6064,"6067":6064,"6068":6064,"6069":6064,"6070":6064,"6071":6064,"6072":6064,"6073":6064,"6074":6064,"6075":6064,"6076":6064,"6077":6064,"6078":6064,"6079":6064,"6081":6080,"6082":6080,"6083":6080,"6084":6080,"6085":6080,"6086":6080,"6087":6080,"6088":6080,"6089":6080,"6090":6080,"6091":6080,"6092":6080,"6093":6080,"6094":6080,"6095":6080,"6097":6096,"6098":6096,"6099":6096,"6100":6096,"6101":6096,"6102":6096,"6103":6096,"6104":6096,"6105":6096,"6106":6096,"6107":6096,"6108":6096,"6109":6096,"6110":6096,"6111":6096,"6113":6112,"6114":6112,"6115":6112,"6116":6112,"6117":6112,"6118":6112,"6119":6112,"6120":6112,"6121":6112,"6122":6112,"6123":6112,"6124":6112,"6125":6112,"6126":6112,"6127":6112,"6129":6128,"6130":6128,"6131":6128,"6132":6128,"6133":6128,"6134":6128,"6135":6128,"6136":6128,"6137":6128,"6138":6128,"6139":6128,"6140":6128,"6141":6128,"6142":6128,"6143":6128,"6145":6144,"6146":6144,"6147":6144,"6148":6144,"6149":6144,"6150":6144,"6151":6144,"6152":6144,"6153":6144,"6154":6144,"6155":6144,"6156":6144,"6157":6144,"6158":6144,"6159":6144,"6181":6176,"6182":6176,"6183":6176,"6184":6176,"6185":6176,"6186":6176,"6187":6176,"6188":6176,"6189":6176,"6190":6176,"6191":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6305":6304,"6306":6304,"6307":6304,"6308":6304,"6309":6304,"6310":6304,"6311":6304,"6312":6304,"6313":6304,"6314":6304,"6315":6304,"6316":6304,"6317":6304,"6318":6304,"6319":6304,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6482":6480,"6483":6480,"6484":6480,"6485":6480,"6486":6480,"6487":6480,"6488":6480,"6489":6480,"6490":6480,"6491":6480,"6492":6480,"6493":6480,"6494":6480,"6495":6480,"6498":6496,"6499":6496,"6500":6496,"6501":6496,"6502":6496,"6503":6496,"6504":6496,"6505":6496,"6506":6496,"6507":6496,"6508":6496,"6509":6496,"6510":6496,"6511":6496,"6514":6512,"6515":6512,"6516":6512,"6517":6512,"6518":6512,"6519":6512,"6520":6512,"6521":6512,"6522":6512,"6523":6512,"6524":6512,"6525":6512,"6526":6512,"6527":6512,"6530":6528,"6531":6528,"6532":6528,"6533":6528,"6534":6528,"6535":6528,"6536":6528,"6537":6528,"6538":6528,"6539":6528,"6540":6528,"6541":6528,"6542":6528,"6543":6528,"6546":6544,"6547":6544,"6548":6544,"6549":6544,"6550":6544,"6551":6544,"6552":6544,"6553":6544,"6554":6544,"6555":6544,"6556":6544,"6557":6544,"6558":6544,"6559":6544,"6564":6562,"6565":6562,"6566":6562,"6567":6562,"6568":6562,"6569":6562,"6570":6562,"6571":6562,"6572":6562,"6573":6562,"6574":6562,"6575":6562,"6584":6580,"6585":6580,"6586":6580,"6587":6580,"6588":6580,"6589":6580,"6590":6580,"6591":6580,"6657":6656,"6658":6656,"6659":6656,"6660":6656,"6661":6656,"6662":6656,"6663":6656,"6664":6656,"6665":6656,"6666":6656,"6667":6656,"6668":6656,"6669":6656,"6670":6656,"6671":6656,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6705":6704,"6706":6704,"6707":6704,"6708":6704,"6709":6704,"6710":6704,"6711":6704,"6713":6704,"6714":6704,"6715":6704,"6716":6704,"6717":6704,"6718":6704,"6719":6704,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6792":6787,"6793":6787,"6794":6787,"6795":6787,"6796":6787,"6797":6787,"6798":6787,"6799":6787,"6808":6803,"6809":6803,"6810":6803,"6811":6803,"6812":6803,"6813":6803,"6814":6803,"6815":6803,"6824":6819,"6825":6819,"6826":6819,"6827":6819,"6828":6819,"6829":6819,"6830":6819,"6831":6819,"6840":6835,"6841":6835,"6842":6835,"6843":6835,"6844":6835,"6845":6835,"6846":6835,"6847":6835,"6856":6851,"6857":6851,"6858":6851,"6859":6851,"6860":6851,"6861":6851,"6862":6851,"6863":6851,"6872":6867,"6873":6867,"6874":6867,"6875":6867,"6876":6867,"6877":6867,"6878":6867,"6879":6867,"6888":6883,"6889":6883,"6890":6883,"6891":6883,"6892":6883,"6893":6883,"6894":6883,"6895":6883,"6904":6899,"6905":6899,"6906":6899,"6907":6899,"6908":6899,"6909":6899,"6910":6899,"6911":6899,"6920":6915,"6921":6915,"6922":6915,"6923":6915,"6924":6915,"6925":6915,"6926":6915,"6927":6915,"6936":6931,"6937":6931,"6938":6931,"6939":6931,"6940":6931,"6941":6931,"6942":6931,"6943":6931,"6952":6947,"6953":6947,"6954":6947,"6955":6947,"6956":6947,"6957":6947,"6958":6947,"6959":6947,"6968":6963,"6969":6963,"6970":6963,"6971":6963,"6972":6963,"6973":6963,"6974":6963,"6975":6963,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7000":6994,"7001":6994,"7002":6994,"7003":6994,"7004":6994,"7005":6994,"7006":6994,"7007":6994,"7009":7008,"7010":7008,"7011":7008,"7012":7008,"7013":7008,"7014":7008,"7015":7008,"7016":7008,"7017":7008,"7018":7008,"7019":7008,"7020":7008,"7021":7008,"7022":7008,"7023":7008,"7032":7027,"7033":7027,"7034":7027,"7035":7027,"7036":7027,"7037":7027,"7038":7027,"7039":7027,"7048":7043,"7049":7043,"7050":7043,"7051":7043,"7052":7043,"7053":7043,"7054":7043,"7055":7043,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7080":7074,"7081":7074,"7082":7074,"7083":7074,"7084":7074,"7085":7074,"7086":7074,"7087":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7112":7106,"7113":7106,"7114":7106,"7115":7106,"7116":7106,"7117":7106,"7118":7106,"7119":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7144":7138,"7145":7138,"7146":7138,"7147":7138,"7148":7138,"7149":7138,"7150":7138,"7151":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7176":7170,"7177":7170,"7178":7170,"7179":7170,"7180":7170,"7181":7170,"7182":7170,"7183":7170,"7188":7186,"7189":7186,"7190":7186,"7191":7186,"7192":7186,"7193":7186,"7194":7186,"7195":7186,"7196":7186,"7197":7186,"7198":7186,"7199":7186,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7224":7218,"7225":7218,"7226":7218,"7227":7218,"7228":7218,"7229":7218,"7230":7218,"7231":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7256":7250,"7257":7250,"7258":7250,"7259":7250,"7260":7250,"7261":7250,"7262":7250,"7263":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7272":7250,"7273":7250,"7274":7250,"7275":7250,"7276":7250,"7277":7250,"7278":7250,"7279":7250,"7297":7296,"7298":7296,"7299":7296,"7300":7296,"7301":7296,"7302":7296,"7303":7296,"7304":7296,"7305":7296,"7306":7296,"7307":7296,"7308":7296,"7309":7296,"7310":7296,"7311":7296,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7348":7346,"7349":7346,"7350":7346,"7351":7346,"7352":7346,"7353":7346,"7354":7346,"7355":7346,"7356":7346,"7357":7346,"7358":7346,"7359":7346,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7400":7392,"7401":7392,"7402":7392,"7403":7392,"7404":7392,"7405":7392,"7406":7392,"7407":7392,"7410":7408,"7411":7408,"7412":7408,"7413":7408,"7414":7408,"7415":7408,"7416":7408,"7417":7408,"7418":7408,"7419":7408,"7420":7408,"7421":7408,"7422":7408,"7423":7408,"7478":7472,"7479":7472,"7486":7472,"7487":7472,"7504":7218,"7505":7218,"7510":7218,"7511":7218,"7512":7218,"7513":7218,"7514":7218,"7515":7218,"7516":7218,"7517":7218,"7518":7218,"7519":7218}} \ No newline at end of file +{"knownStates":{"0":"Air","16":"Stone","17":"Granite","18":"Polished Granite","19":"Diorite","20":"Polished Diorite","21":"Andesite","22":"Polished Andesite","32":"Grass","48":"Dirt","49":"Dirt","64":"Cobblestone","80":"Oak Planks","81":"Spruce Planks","82":"Birch Planks","83":"Jungle Planks","84":"Acacia Planks","85":"Dark Oak Planks","96":"Oak Sapling","97":"Spruce Sapling","98":"Birch Sapling","99":"Jungle Sapling","100":"Acacia Sapling","101":"Dark Oak Sapling","104":"Oak Sapling","105":"Spruce Sapling","106":"Birch Sapling","107":"Jungle Sapling","108":"Acacia Sapling","109":"Dark Oak Sapling","112":"Bedrock","113":"Bedrock","128":"Water","129":"Water","130":"Water","131":"Water","132":"Water","133":"Water","134":"Water","135":"Water","136":"Water","137":"Water","138":"Water","139":"Water","140":"Water","141":"Water","142":"Water","143":"Water","144":"Water","145":"Water","146":"Water","147":"Water","148":"Water","149":"Water","150":"Water","151":"Water","152":"Water","153":"Water","154":"Water","155":"Water","156":"Water","157":"Water","158":"Water","159":"Water","160":"Lava","161":"Lava","162":"Lava","163":"Lava","164":"Lava","165":"Lava","166":"Lava","167":"Lava","168":"Lava","169":"Lava","170":"Lava","171":"Lava","172":"Lava","173":"Lava","174":"Lava","175":"Lava","176":"Lava","177":"Lava","178":"Lava","179":"Lava","180":"Lava","181":"Lava","182":"Lava","183":"Lava","184":"Lava","185":"Lava","186":"Lava","187":"Lava","188":"Lava","189":"Lava","190":"Lava","191":"Lava","192":"Sand","193":"Red Sand","208":"Gravel","224":"Gold Ore","240":"Iron Ore","256":"Coal Ore","272":"Oak Log","273":"Spruce Log","274":"Birch Log","275":"Jungle Log","276":"Oak Log","277":"Spruce Log","278":"Birch Log","279":"Jungle Log","280":"Oak Log","281":"Spruce Log","282":"Birch Log","283":"Jungle Log","288":"Oak Leaves","289":"Spruce Leaves","290":"Birch Leaves","291":"Jungle Leaves","292":"Oak Leaves","293":"Spruce Leaves","294":"Birch Leaves","295":"Jungle Leaves","296":"Oak Leaves","297":"Spruce Leaves","298":"Birch Leaves","299":"Jungle Leaves","300":"Oak Leaves","301":"Spruce Leaves","302":"Birch Leaves","303":"Jungle Leaves","304":"Sponge","305":"Sponge","320":"Glass","336":"Lapis Lazuli Ore","352":"Lapis Lazuli Block","384":"Sandstone","385":"Chiseled Sandstone","386":"Cut Sandstone","387":"Smooth Sandstone","400":"Note Block","416":"Bed Block","417":"Bed Block","418":"Bed Block","419":"Bed Block","420":"Bed Block","421":"Bed Block","422":"Bed Block","423":"Bed Block","424":"Bed Block","425":"Bed Block","426":"Bed Block","427":"Bed Block","428":"Bed Block","429":"Bed Block","430":"Bed Block","431":"Bed Block","432":"Powered Rail","433":"Powered Rail","434":"Powered Rail","435":"Powered Rail","436":"Powered Rail","437":"Powered Rail","440":"Powered Rail","441":"Powered Rail","442":"Powered Rail","443":"Powered Rail","444":"Powered Rail","445":"Powered Rail","448":"Detector Rail","449":"Detector Rail","450":"Detector Rail","451":"Detector Rail","452":"Detector Rail","453":"Detector Rail","456":"Detector Rail","457":"Detector Rail","458":"Detector Rail","459":"Detector Rail","460":"Detector Rail","461":"Detector Rail","480":"Cobweb","497":"Tall Grass","498":"Fern","512":"Dead Bush","560":"Wool","561":"Wool","562":"Wool","563":"Wool","564":"Wool","565":"Wool","566":"Wool","567":"Wool","568":"Wool","569":"Wool","570":"Wool","571":"Wool","572":"Wool","573":"Wool","574":"Wool","575":"Wool","576":"???","592":"Dandelion","608":"Poppy","609":"Blue Orchid","610":"Allium","611":"Azure Bluet","612":"Red Tulip","613":"Orange Tulip","614":"White Tulip","615":"Pink Tulip","616":"Oxeye Daisy","617":"Cornflower","618":"Lily of the Valley","624":"Brown Mushroom","640":"Red Mushroom","656":"Gold Block","672":"Iron Block","688":"Smooth Stone Slab","689":"Sandstone Slab","690":"Fake Wooden Slab","691":"Cobblestone Slab","692":"Brick Slab","693":"Stone Brick Slab","694":"Quartz Slab","695":"Nether Brick Slab","704":"Smooth Stone Slab","705":"Sandstone Slab","706":"Fake Wooden Slab","707":"Cobblestone Slab","708":"Brick Slab","709":"Stone Brick Slab","710":"Quartz Slab","711":"Nether Brick Slab","712":"Smooth Stone Slab","713":"Sandstone Slab","714":"Fake Wooden Slab","715":"Cobblestone Slab","716":"Brick Slab","717":"Stone Brick Slab","718":"Quartz Slab","719":"Nether Brick Slab","720":"Bricks","736":"TNT","737":"TNT","738":"TNT","739":"TNT","752":"Bookshelf","768":"Mossy Cobblestone","784":"Obsidian","801":"Torch","802":"Torch","803":"Torch","804":"Torch","805":"Torch","816":"Fire Block","817":"Fire Block","818":"Fire Block","819":"Fire Block","820":"Fire Block","821":"Fire Block","822":"Fire Block","823":"Fire Block","824":"Fire Block","825":"Fire Block","826":"Fire Block","827":"Fire Block","828":"Fire Block","829":"Fire Block","830":"Fire Block","831":"Fire Block","832":"Monster Spawner","848":"Oak Stairs","849":"Oak Stairs","850":"Oak Stairs","851":"Oak Stairs","852":"Oak Stairs","853":"Oak Stairs","854":"Oak Stairs","855":"Oak Stairs","866":"Chest","867":"Chest","868":"Chest","869":"Chest","880":"Redstone","881":"Redstone","882":"Redstone","883":"Redstone","884":"Redstone","885":"Redstone","886":"Redstone","887":"Redstone","888":"Redstone","889":"Redstone","890":"Redstone","891":"Redstone","892":"Redstone","893":"Redstone","894":"Redstone","895":"Redstone","896":"Diamond Ore","912":"Diamond Block","928":"Crafting Table","944":"Wheat Block","945":"Wheat Block","946":"Wheat Block","947":"Wheat Block","948":"Wheat Block","949":"Wheat Block","950":"Wheat Block","951":"Wheat Block","960":"Farmland","961":"Farmland","962":"Farmland","963":"Farmland","964":"Farmland","965":"Farmland","966":"Farmland","967":"Farmland","978":"Furnace","979":"Furnace","980":"Furnace","981":"Furnace","994":"Furnace","995":"Furnace","996":"Furnace","997":"Furnace","1008":"Oak Sign","1009":"Oak Sign","1010":"Oak Sign","1011":"Oak Sign","1012":"Oak Sign","1013":"Oak Sign","1014":"Oak Sign","1015":"Oak Sign","1016":"Oak Sign","1017":"Oak Sign","1018":"Oak Sign","1019":"Oak Sign","1020":"Oak Sign","1021":"Oak Sign","1022":"Oak Sign","1023":"Oak Sign","1024":"Oak Door","1025":"Oak Door","1026":"Oak Door","1027":"Oak Door","1028":"Oak Door","1029":"Oak Door","1030":"Oak Door","1031":"Oak Door","1032":"Oak Door","1033":"Oak Door","1034":"Oak Door","1035":"Oak Door","1042":"Ladder","1043":"Ladder","1044":"Ladder","1045":"Ladder","1056":"Rail","1057":"Rail","1058":"Rail","1059":"Rail","1060":"Rail","1061":"Rail","1062":"Rail","1063":"Rail","1064":"Rail","1065":"Rail","1072":"Cobblestone Stairs","1073":"Cobblestone Stairs","1074":"Cobblestone Stairs","1075":"Cobblestone Stairs","1076":"Cobblestone Stairs","1077":"Cobblestone Stairs","1078":"Cobblestone Stairs","1079":"Cobblestone Stairs","1090":"Oak Wall Sign","1091":"Oak Wall Sign","1092":"Oak Wall Sign","1093":"Oak Wall Sign","1104":"Lever","1105":"Lever","1106":"Lever","1107":"Lever","1108":"Lever","1109":"Lever","1110":"Lever","1111":"Lever","1112":"Lever","1113":"Lever","1114":"Lever","1115":"Lever","1116":"Lever","1117":"Lever","1118":"Lever","1119":"Lever","1120":"Stone Pressure Plate","1121":"Stone Pressure Plate","1136":"Iron Door","1137":"Iron Door","1138":"Iron Door","1139":"Iron Door","1140":"Iron Door","1141":"Iron Door","1142":"Iron Door","1143":"Iron Door","1144":"Iron Door","1145":"Iron Door","1146":"Iron Door","1147":"Iron Door","1152":"Oak Pressure Plate","1153":"Oak Pressure Plate","1168":"Redstone Ore","1184":"Redstone Ore","1201":"Redstone Torch","1202":"Redstone Torch","1203":"Redstone Torch","1204":"Redstone Torch","1205":"Redstone Torch","1217":"Redstone Torch","1218":"Redstone Torch","1219":"Redstone Torch","1220":"Redstone Torch","1221":"Redstone Torch","1232":"Stone Button","1233":"Stone Button","1234":"Stone Button","1235":"Stone Button","1236":"Stone Button","1237":"Stone Button","1240":"Stone Button","1241":"Stone Button","1242":"Stone Button","1243":"Stone Button","1244":"Stone Button","1245":"Stone Button","1248":"Snow Layer","1249":"Snow Layer","1250":"Snow Layer","1251":"Snow Layer","1252":"Snow Layer","1253":"Snow Layer","1254":"Snow Layer","1255":"Snow Layer","1264":"Ice","1280":"Snow Block","1296":"Cactus","1297":"Cactus","1298":"Cactus","1299":"Cactus","1300":"Cactus","1301":"Cactus","1302":"Cactus","1303":"Cactus","1304":"Cactus","1305":"Cactus","1306":"Cactus","1307":"Cactus","1308":"Cactus","1309":"Cactus","1310":"Cactus","1311":"Cactus","1312":"Clay Block","1328":"Sugarcane","1329":"Sugarcane","1330":"Sugarcane","1331":"Sugarcane","1332":"Sugarcane","1333":"Sugarcane","1334":"Sugarcane","1335":"Sugarcane","1336":"Sugarcane","1337":"Sugarcane","1338":"Sugarcane","1339":"Sugarcane","1340":"Sugarcane","1341":"Sugarcane","1342":"Sugarcane","1343":"Sugarcane","1344":"Jukebox","1360":"Oak Fence","1361":"Spruce Fence","1362":"Birch Fence","1363":"Jungle Fence","1364":"Acacia Fence","1365":"Dark Oak Fence","1376":"Pumpkin","1392":"Netherrack","1408":"Soul Sand","1424":"Glowstone","1441":"Nether Portal","1442":"Nether Portal","1456":"Jack o'Lantern","1457":"Jack o'Lantern","1458":"Jack o'Lantern","1459":"Jack o'Lantern","1472":"Cake","1473":"Cake","1474":"Cake","1475":"Cake","1476":"Cake","1477":"Cake","1478":"Cake","1488":"Redstone Repeater","1489":"Redstone Repeater","1490":"Redstone Repeater","1491":"Redstone Repeater","1492":"Redstone Repeater","1493":"Redstone Repeater","1494":"Redstone Repeater","1495":"Redstone Repeater","1496":"Redstone Repeater","1497":"Redstone Repeater","1498":"Redstone Repeater","1499":"Redstone Repeater","1500":"Redstone Repeater","1501":"Redstone Repeater","1502":"Redstone Repeater","1503":"Redstone Repeater","1504":"Redstone Repeater","1505":"Redstone Repeater","1506":"Redstone Repeater","1507":"Redstone Repeater","1508":"Redstone Repeater","1509":"Redstone Repeater","1510":"Redstone Repeater","1511":"Redstone Repeater","1512":"Redstone Repeater","1513":"Redstone Repeater","1514":"Redstone Repeater","1515":"Redstone Repeater","1516":"Redstone Repeater","1517":"Redstone Repeater","1518":"Redstone Repeater","1519":"Redstone Repeater","1520":"Invisible Bedrock","1536":"Oak Trapdoor","1537":"Oak Trapdoor","1538":"Oak Trapdoor","1539":"Oak Trapdoor","1540":"Oak Trapdoor","1541":"Oak Trapdoor","1542":"Oak Trapdoor","1543":"Oak Trapdoor","1544":"Oak Trapdoor","1545":"Oak Trapdoor","1546":"Oak Trapdoor","1547":"Oak Trapdoor","1548":"Oak Trapdoor","1549":"Oak Trapdoor","1550":"Oak Trapdoor","1551":"Oak Trapdoor","1552":"Infested Stone","1553":"Infested Cobblestone","1554":"Infested Stone Brick","1555":"Infested Mossy Stone Brick","1556":"Infested Cracked Stone Brick","1557":"Infested Chiseled Stone Brick","1568":"Stone Bricks","1569":"Mossy Stone Bricks","1570":"Cracked Stone Bricks","1571":"Chiseled Stone Bricks","1584":"Brown Mushroom Block","1585":"Brown Mushroom Block","1586":"Brown Mushroom Block","1587":"Brown Mushroom Block","1588":"Brown Mushroom Block","1589":"Brown Mushroom Block","1590":"Brown Mushroom Block","1591":"Brown Mushroom Block","1592":"Brown Mushroom Block","1593":"Brown Mushroom Block","1594":"Mushroom Stem","1598":"Brown Mushroom Block","1599":"All Sided Mushroom Stem","1600":"Red Mushroom Block","1601":"Red Mushroom Block","1602":"Red Mushroom Block","1603":"Red Mushroom Block","1604":"Red Mushroom Block","1605":"Red Mushroom Block","1606":"Red Mushroom Block","1607":"Red Mushroom Block","1608":"Red Mushroom Block","1609":"Red Mushroom Block","1614":"Red Mushroom Block","1616":"Iron Bars","1632":"Glass Pane","1648":"Melon Block","1664":"Pumpkin Stem","1665":"Pumpkin Stem","1666":"Pumpkin Stem","1667":"Pumpkin Stem","1668":"Pumpkin Stem","1669":"Pumpkin Stem","1670":"Pumpkin Stem","1671":"Pumpkin Stem","1680":"Melon Stem","1681":"Melon Stem","1682":"Melon Stem","1683":"Melon Stem","1684":"Melon Stem","1685":"Melon Stem","1686":"Melon Stem","1687":"Melon Stem","1696":"Vines","1697":"Vines","1698":"Vines","1699":"Vines","1700":"Vines","1701":"Vines","1702":"Vines","1703":"Vines","1704":"Vines","1705":"Vines","1706":"Vines","1707":"Vines","1708":"Vines","1709":"Vines","1710":"Vines","1711":"Vines","1712":"Oak Fence Gate","1713":"Oak Fence Gate","1714":"Oak Fence Gate","1715":"Oak Fence Gate","1716":"Oak Fence Gate","1717":"Oak Fence Gate","1718":"Oak Fence Gate","1719":"Oak Fence Gate","1720":"Oak Fence Gate","1721":"Oak Fence Gate","1722":"Oak Fence Gate","1723":"Oak Fence Gate","1724":"Oak Fence Gate","1725":"Oak Fence Gate","1726":"Oak Fence Gate","1727":"Oak Fence Gate","1728":"Brick Stairs","1729":"Brick Stairs","1730":"Brick Stairs","1731":"Brick Stairs","1732":"Brick Stairs","1733":"Brick Stairs","1734":"Brick Stairs","1735":"Brick Stairs","1744":"Stone Brick Stairs","1745":"Stone Brick Stairs","1746":"Stone Brick Stairs","1747":"Stone Brick Stairs","1748":"Stone Brick Stairs","1749":"Stone Brick Stairs","1750":"Stone Brick Stairs","1751":"Stone Brick Stairs","1760":"Mycelium","1776":"Lily Pad","1792":"Nether Bricks","1808":"Nether Brick Fence","1824":"Nether Brick Stairs","1825":"Nether Brick Stairs","1826":"Nether Brick Stairs","1827":"Nether Brick Stairs","1828":"Nether Brick Stairs","1829":"Nether Brick Stairs","1830":"Nether Brick Stairs","1831":"Nether Brick Stairs","1840":"Nether Wart","1841":"Nether Wart","1842":"Nether Wart","1843":"Nether Wart","1856":"Enchanting Table","1872":"Brewing Stand","1873":"Brewing Stand","1874":"Brewing Stand","1875":"Brewing Stand","1876":"Brewing Stand","1877":"Brewing Stand","1878":"Brewing Stand","1879":"Brewing Stand","1920":"End Portal Frame","1921":"End Portal Frame","1922":"End Portal Frame","1923":"End Portal Frame","1924":"End Portal Frame","1925":"End Portal Frame","1926":"End Portal Frame","1927":"End Portal Frame","1936":"End Stone","1952":"Dragon Egg","1968":"Redstone Lamp","1984":"Redstone Lamp","2016":"Activator Rail","2017":"Activator Rail","2018":"Activator Rail","2019":"Activator Rail","2020":"Activator Rail","2021":"Activator Rail","2024":"Activator Rail","2025":"Activator Rail","2026":"Activator Rail","2027":"Activator Rail","2028":"Activator Rail","2029":"Activator Rail","2032":"Cocoa Block","2033":"Cocoa Block","2034":"Cocoa Block","2035":"Cocoa Block","2036":"Cocoa Block","2037":"Cocoa Block","2038":"Cocoa Block","2039":"Cocoa Block","2040":"Cocoa Block","2041":"Cocoa Block","2042":"Cocoa Block","2043":"Cocoa Block","2048":"Sandstone Stairs","2049":"Sandstone Stairs","2050":"Sandstone Stairs","2051":"Sandstone Stairs","2052":"Sandstone Stairs","2053":"Sandstone Stairs","2054":"Sandstone Stairs","2055":"Sandstone Stairs","2064":"Emerald Ore","2082":"Ender Chest","2083":"Ender Chest","2084":"Ender Chest","2085":"Ender Chest","2096":"Tripwire Hook","2097":"Tripwire Hook","2098":"Tripwire Hook","2099":"Tripwire Hook","2100":"Tripwire Hook","2101":"Tripwire Hook","2102":"Tripwire Hook","2103":"Tripwire Hook","2104":"Tripwire Hook","2105":"Tripwire Hook","2106":"Tripwire Hook","2107":"Tripwire Hook","2108":"Tripwire Hook","2109":"Tripwire Hook","2110":"Tripwire Hook","2111":"Tripwire Hook","2112":"Tripwire","2113":"Tripwire","2114":"Tripwire","2115":"Tripwire","2116":"Tripwire","2117":"Tripwire","2118":"Tripwire","2119":"Tripwire","2120":"Tripwire","2121":"Tripwire","2122":"Tripwire","2123":"Tripwire","2124":"Tripwire","2125":"Tripwire","2126":"Tripwire","2127":"Tripwire","2128":"Emerald Block","2144":"Spruce Stairs","2145":"Spruce Stairs","2146":"Spruce Stairs","2147":"Spruce Stairs","2148":"Spruce Stairs","2149":"Spruce Stairs","2150":"Spruce Stairs","2151":"Spruce Stairs","2160":"Birch Stairs","2161":"Birch Stairs","2162":"Birch Stairs","2163":"Birch Stairs","2164":"Birch Stairs","2165":"Birch Stairs","2166":"Birch Stairs","2167":"Birch Stairs","2176":"Jungle Stairs","2177":"Jungle Stairs","2178":"Jungle Stairs","2179":"Jungle Stairs","2180":"Jungle Stairs","2181":"Jungle Stairs","2182":"Jungle Stairs","2183":"Jungle Stairs","2208":"Beacon","2224":"Cobblestone Wall","2225":"Mossy Cobblestone Wall","2226":"Granite Wall","2227":"Diorite Wall","2228":"Andesite Wall","2229":"Sandstone Wall","2230":"Brick Wall","2231":"Stone Brick Wall","2232":"Mossy Stone Brick Wall","2233":"Nether Brick Wall","2234":"End Stone Brick Wall","2235":"Prismarine Wall","2236":"Red Sandstone Wall","2237":"Red Nether Brick Wall","2240":"Flower Pot","2256":"Carrot Block","2257":"Carrot Block","2258":"Carrot Block","2259":"Carrot Block","2260":"Carrot Block","2261":"Carrot Block","2262":"Carrot Block","2263":"Carrot Block","2272":"Potato Block","2273":"Potato Block","2274":"Potato Block","2275":"Potato Block","2276":"Potato Block","2277":"Potato Block","2278":"Potato Block","2279":"Potato Block","2288":"Oak Button","2289":"Oak Button","2290":"Oak Button","2291":"Oak Button","2292":"Oak Button","2293":"Oak Button","2296":"Oak Button","2297":"Oak Button","2298":"Oak Button","2299":"Oak Button","2300":"Oak Button","2301":"Oak Button","2305":"Mob Head","2306":"Mob Head","2307":"Mob Head","2308":"Mob Head","2309":"Mob Head","2320":"Anvil","2321":"Anvil","2322":"Anvil","2323":"Anvil","2324":"Anvil","2325":"Anvil","2326":"Anvil","2327":"Anvil","2328":"Anvil","2329":"Anvil","2330":"Anvil","2331":"Anvil","2338":"Trapped Chest","2339":"Trapped Chest","2340":"Trapped Chest","2341":"Trapped Chest","2352":"Weighted Pressure Plate Light","2353":"Weighted Pressure Plate Light","2354":"Weighted Pressure Plate Light","2355":"Weighted Pressure Plate Light","2356":"Weighted Pressure Plate Light","2357":"Weighted Pressure Plate Light","2358":"Weighted Pressure Plate Light","2359":"Weighted Pressure Plate Light","2360":"Weighted Pressure Plate Light","2361":"Weighted Pressure Plate Light","2362":"Weighted Pressure Plate Light","2363":"Weighted Pressure Plate Light","2364":"Weighted Pressure Plate Light","2365":"Weighted Pressure Plate Light","2366":"Weighted Pressure Plate Light","2367":"Weighted Pressure Plate Light","2368":"Weighted Pressure Plate Heavy","2369":"Weighted Pressure Plate Heavy","2370":"Weighted Pressure Plate Heavy","2371":"Weighted Pressure Plate Heavy","2372":"Weighted Pressure Plate Heavy","2373":"Weighted Pressure Plate Heavy","2374":"Weighted Pressure Plate Heavy","2375":"Weighted Pressure Plate Heavy","2376":"Weighted Pressure Plate Heavy","2377":"Weighted Pressure Plate Heavy","2378":"Weighted Pressure Plate Heavy","2379":"Weighted Pressure Plate Heavy","2380":"Weighted Pressure Plate Heavy","2381":"Weighted Pressure Plate Heavy","2382":"Weighted Pressure Plate Heavy","2383":"Weighted Pressure Plate Heavy","2384":"Redstone Comparator","2385":"Redstone Comparator","2386":"Redstone Comparator","2387":"Redstone Comparator","2388":"Redstone Comparator","2389":"Redstone Comparator","2390":"Redstone Comparator","2391":"Redstone Comparator","2408":"Redstone Comparator","2409":"Redstone Comparator","2410":"Redstone Comparator","2411":"Redstone Comparator","2412":"Redstone Comparator","2413":"Redstone Comparator","2414":"Redstone Comparator","2415":"Redstone Comparator","2416":"Daylight Sensor","2417":"Daylight Sensor","2418":"Daylight Sensor","2419":"Daylight Sensor","2420":"Daylight Sensor","2421":"Daylight Sensor","2422":"Daylight Sensor","2423":"Daylight Sensor","2424":"Daylight Sensor","2425":"Daylight Sensor","2426":"Daylight Sensor","2427":"Daylight Sensor","2428":"Daylight Sensor","2429":"Daylight Sensor","2430":"Daylight Sensor","2431":"Daylight Sensor","2432":"Redstone Block","2448":"Nether Quartz Ore","2464":"Hopper","2466":"Hopper","2467":"Hopper","2468":"Hopper","2469":"Hopper","2472":"Hopper","2474":"Hopper","2475":"Hopper","2476":"Hopper","2477":"Hopper","2480":"Quartz Block","2481":"Chiseled Quartz Block","2482":"Quartz Pillar","2483":"Smooth Quartz Block","2485":"Chiseled Quartz Block","2486":"Quartz Pillar","2489":"Chiseled Quartz Block","2490":"Quartz Pillar","2496":"Quartz Stairs","2497":"Quartz Stairs","2498":"Quartz Stairs","2499":"Quartz Stairs","2500":"Quartz Stairs","2501":"Quartz Stairs","2502":"Quartz Stairs","2503":"Quartz Stairs","2512":"Oak Slab","2513":"Spruce Slab","2514":"Birch Slab","2515":"Jungle Slab","2516":"Acacia Slab","2517":"Dark Oak Slab","2528":"Oak Slab","2529":"Spruce Slab","2530":"Birch Slab","2531":"Jungle Slab","2532":"Acacia Slab","2533":"Dark Oak Slab","2536":"Oak Slab","2537":"Spruce Slab","2538":"Birch Slab","2539":"Jungle Slab","2540":"Acacia Slab","2541":"Dark Oak Slab","2544":"Stained Clay","2545":"Stained Clay","2546":"Stained Clay","2547":"Stained Clay","2548":"Stained Clay","2549":"Stained Clay","2550":"Stained Clay","2551":"Stained Clay","2552":"Stained Clay","2553":"Stained Clay","2554":"Stained Clay","2555":"Stained Clay","2556":"Stained Clay","2557":"Stained Clay","2558":"Stained Clay","2559":"Stained Clay","2560":"Stained Glass Pane","2561":"Stained Glass Pane","2562":"Stained Glass Pane","2563":"Stained Glass Pane","2564":"Stained Glass Pane","2565":"Stained Glass Pane","2566":"Stained Glass Pane","2567":"Stained Glass Pane","2568":"Stained Glass Pane","2569":"Stained Glass Pane","2570":"Stained Glass Pane","2571":"Stained Glass Pane","2572":"Stained Glass Pane","2573":"Stained Glass Pane","2574":"Stained Glass Pane","2575":"Stained Glass Pane","2576":"Acacia Leaves","2577":"Dark Oak Leaves","2580":"Acacia Leaves","2581":"Dark Oak Leaves","2584":"Acacia Leaves","2585":"Dark Oak Leaves","2588":"Acacia Leaves","2589":"Dark Oak Leaves","2592":"Acacia Log","2593":"Dark Oak Log","2596":"Acacia Log","2597":"Dark Oak Log","2600":"Acacia Log","2601":"Dark Oak Log","2608":"Acacia Stairs","2609":"Acacia Stairs","2610":"Acacia Stairs","2611":"Acacia Stairs","2612":"Acacia Stairs","2613":"Acacia Stairs","2614":"Acacia Stairs","2615":"Acacia Stairs","2624":"Dark Oak Stairs","2625":"Dark Oak Stairs","2626":"Dark Oak Stairs","2627":"Dark Oak Stairs","2628":"Dark Oak Stairs","2629":"Dark Oak Stairs","2630":"Dark Oak Stairs","2631":"Dark Oak Stairs","2640":"Slime Block","2672":"Iron Trapdoor","2673":"Iron Trapdoor","2674":"Iron Trapdoor","2675":"Iron Trapdoor","2676":"Iron Trapdoor","2677":"Iron Trapdoor","2678":"Iron Trapdoor","2679":"Iron Trapdoor","2680":"Iron Trapdoor","2681":"Iron Trapdoor","2682":"Iron Trapdoor","2683":"Iron Trapdoor","2684":"Iron Trapdoor","2685":"Iron Trapdoor","2686":"Iron Trapdoor","2687":"Iron Trapdoor","2688":"Prismarine","2689":"Dark Prismarine","2690":"Prismarine Bricks","2704":"Sea Lantern","2720":"Hay Bale","2724":"Hay Bale","2728":"Hay Bale","2736":"Carpet","2737":"Carpet","2738":"Carpet","2739":"Carpet","2740":"Carpet","2741":"Carpet","2742":"Carpet","2743":"Carpet","2744":"Carpet","2745":"Carpet","2746":"Carpet","2747":"Carpet","2748":"Carpet","2749":"Carpet","2750":"Carpet","2751":"Carpet","2752":"Hardened Clay","2768":"Coal Block","2784":"Packed Ice","2800":"Sunflower","2801":"Lilac","2802":"Double Tallgrass","2803":"Large Fern","2804":"Rose Bush","2805":"Peony","2808":"Sunflower","2809":"Lilac","2810":"Double Tallgrass","2811":"Large Fern","2812":"Rose Bush","2813":"Peony","2816":"Banner","2817":"Banner","2818":"Banner","2819":"Banner","2820":"Banner","2821":"Banner","2822":"Banner","2823":"Banner","2824":"Banner","2825":"Banner","2826":"Banner","2827":"Banner","2828":"Banner","2829":"Banner","2830":"Banner","2831":"Banner","2834":"Wall Banner","2835":"Wall Banner","2836":"Wall Banner","2837":"Wall Banner","2848":"Daylight Sensor","2849":"Daylight Sensor","2850":"Daylight Sensor","2851":"Daylight Sensor","2852":"Daylight Sensor","2853":"Daylight Sensor","2854":"Daylight Sensor","2855":"Daylight Sensor","2856":"Daylight Sensor","2857":"Daylight Sensor","2858":"Daylight Sensor","2859":"Daylight Sensor","2860":"Daylight Sensor","2861":"Daylight Sensor","2862":"Daylight Sensor","2863":"Daylight Sensor","2864":"Red Sandstone","2865":"Chiseled Red Sandstone","2866":"Cut Red Sandstone","2867":"Smooth Red Sandstone","2880":"Red Sandstone Stairs","2881":"Red Sandstone Stairs","2882":"Red Sandstone Stairs","2883":"Red Sandstone Stairs","2884":"Red Sandstone Stairs","2885":"Red Sandstone Stairs","2886":"Red Sandstone Stairs","2887":"Red Sandstone Stairs","2896":"Red Sandstone Slab","2897":"Purpur Slab","2898":"Prismarine Slab","2899":"Dark Prismarine Slab","2900":"Prismarine Bricks Slab","2901":"Mossy Cobblestone Slab","2902":"Smooth Sandstone Slab","2903":"Red Nether Brick Slab","2912":"Red Sandstone Slab","2913":"Purpur Slab","2914":"Prismarine Slab","2915":"Dark Prismarine Slab","2916":"Prismarine Bricks Slab","2917":"Mossy Cobblestone Slab","2918":"Smooth Sandstone Slab","2919":"Red Nether Brick Slab","2920":"Red Sandstone Slab","2921":"Purpur Slab","2922":"Prismarine Slab","2923":"Dark Prismarine Slab","2924":"Prismarine Bricks Slab","2925":"Mossy Cobblestone Slab","2926":"Smooth Sandstone Slab","2927":"Red Nether Brick Slab","2928":"Spruce Fence Gate","2929":"Spruce Fence Gate","2930":"Spruce Fence Gate","2931":"Spruce Fence Gate","2932":"Spruce Fence Gate","2933":"Spruce Fence Gate","2934":"Spruce Fence Gate","2935":"Spruce Fence Gate","2936":"Spruce Fence Gate","2937":"Spruce Fence Gate","2938":"Spruce Fence Gate","2939":"Spruce Fence Gate","2940":"Spruce Fence Gate","2941":"Spruce Fence Gate","2942":"Spruce Fence Gate","2943":"Spruce Fence Gate","2944":"Birch Fence Gate","2945":"Birch Fence Gate","2946":"Birch Fence Gate","2947":"Birch Fence Gate","2948":"Birch Fence Gate","2949":"Birch Fence Gate","2950":"Birch Fence Gate","2951":"Birch Fence Gate","2952":"Birch Fence Gate","2953":"Birch Fence Gate","2954":"Birch Fence Gate","2955":"Birch Fence Gate","2956":"Birch Fence Gate","2957":"Birch Fence Gate","2958":"Birch Fence Gate","2959":"Birch Fence Gate","2960":"Jungle Fence Gate","2961":"Jungle Fence Gate","2962":"Jungle Fence Gate","2963":"Jungle Fence Gate","2964":"Jungle Fence Gate","2965":"Jungle Fence Gate","2966":"Jungle Fence Gate","2967":"Jungle Fence Gate","2968":"Jungle Fence Gate","2969":"Jungle Fence Gate","2970":"Jungle Fence Gate","2971":"Jungle Fence Gate","2972":"Jungle Fence Gate","2973":"Jungle Fence Gate","2974":"Jungle Fence Gate","2975":"Jungle Fence Gate","2976":"Dark Oak Fence Gate","2977":"Dark Oak Fence Gate","2978":"Dark Oak Fence Gate","2979":"Dark Oak Fence Gate","2980":"Dark Oak Fence Gate","2981":"Dark Oak Fence Gate","2982":"Dark Oak Fence Gate","2983":"Dark Oak Fence Gate","2984":"Dark Oak Fence Gate","2985":"Dark Oak Fence Gate","2986":"Dark Oak Fence Gate","2987":"Dark Oak Fence Gate","2988":"Dark Oak Fence Gate","2989":"Dark Oak Fence Gate","2990":"Dark Oak Fence Gate","2991":"Dark Oak Fence Gate","2992":"Acacia Fence Gate","2993":"Acacia Fence Gate","2994":"Acacia Fence Gate","2995":"Acacia Fence Gate","2996":"Acacia Fence Gate","2997":"Acacia Fence Gate","2998":"Acacia Fence Gate","2999":"Acacia Fence Gate","3000":"Acacia Fence Gate","3001":"Acacia Fence Gate","3002":"Acacia Fence Gate","3003":"Acacia Fence Gate","3004":"Acacia Fence Gate","3005":"Acacia Fence Gate","3006":"Acacia Fence Gate","3007":"Acacia Fence Gate","3040":"Hardened Glass Pane","3056":"Stained Hardened Glass Pane","3057":"Stained Hardened Glass Pane","3058":"Stained Hardened Glass Pane","3059":"Stained Hardened Glass Pane","3060":"Stained Hardened Glass Pane","3061":"Stained Hardened Glass Pane","3062":"Stained Hardened Glass Pane","3063":"Stained Hardened Glass Pane","3064":"Stained Hardened Glass Pane","3065":"Stained Hardened Glass Pane","3066":"Stained Hardened Glass Pane","3067":"Stained Hardened Glass Pane","3068":"Stained Hardened Glass Pane","3069":"Stained Hardened Glass Pane","3070":"Stained Hardened Glass Pane","3071":"Stained Hardened Glass Pane","3072":"Heat Block","3088":"Spruce Door","3089":"Spruce Door","3090":"Spruce Door","3091":"Spruce Door","3092":"Spruce Door","3093":"Spruce Door","3094":"Spruce Door","3095":"Spruce Door","3096":"Spruce Door","3097":"Spruce Door","3098":"Spruce Door","3099":"Spruce Door","3104":"Birch Door","3105":"Birch Door","3106":"Birch Door","3107":"Birch Door","3108":"Birch Door","3109":"Birch Door","3110":"Birch Door","3111":"Birch Door","3112":"Birch Door","3113":"Birch Door","3114":"Birch Door","3115":"Birch Door","3120":"Jungle Door","3121":"Jungle Door","3122":"Jungle Door","3123":"Jungle Door","3124":"Jungle Door","3125":"Jungle Door","3126":"Jungle Door","3127":"Jungle Door","3128":"Jungle Door","3129":"Jungle Door","3130":"Jungle Door","3131":"Jungle Door","3136":"Acacia Door","3137":"Acacia Door","3138":"Acacia Door","3139":"Acacia Door","3140":"Acacia Door","3141":"Acacia Door","3142":"Acacia Door","3143":"Acacia Door","3144":"Acacia Door","3145":"Acacia Door","3146":"Acacia Door","3147":"Acacia Door","3152":"Dark Oak Door","3153":"Dark Oak Door","3154":"Dark Oak Door","3155":"Dark Oak Door","3156":"Dark Oak Door","3157":"Dark Oak Door","3158":"Dark Oak Door","3159":"Dark Oak Door","3160":"Dark Oak Door","3161":"Dark Oak Door","3162":"Dark Oak Door","3163":"Dark Oak Door","3168":"Grass Path","3184":"Item Frame","3185":"Item Frame","3186":"Item Frame","3187":"Item Frame","3188":"Item Frame","3189":"Item Frame","3190":"Item Frame","3191":"Item Frame","3216":"Purpur Block","3218":"Purpur Pillar","3222":"Purpur Pillar","3226":"Purpur Pillar","3233":"Red Torch","3234":"Red Torch","3235":"Red Torch","3236":"Red Torch","3237":"Red Torch","3241":"Green Torch","3242":"Green Torch","3243":"Green Torch","3244":"Green Torch","3245":"Green Torch","3248":"Purpur Stairs","3249":"Purpur Stairs","3250":"Purpur Stairs","3251":"Purpur Stairs","3252":"Purpur Stairs","3253":"Purpur Stairs","3254":"Purpur Stairs","3255":"Purpur Stairs","3265":"Blue Torch","3266":"Blue Torch","3267":"Blue Torch","3268":"Blue Torch","3269":"Blue Torch","3273":"Purple Torch","3274":"Purple Torch","3275":"Purple Torch","3276":"Purple Torch","3277":"Purple Torch","3280":"Shulker Box","3296":"End Stone Bricks","3312":"Frosted Ice","3313":"Frosted Ice","3314":"Frosted Ice","3315":"Frosted Ice","3328":"End Rod","3329":"End Rod","3330":"End Rod","3331":"End Rod","3332":"End Rod","3333":"End Rod","3408":"Magma Block","3424":"Nether Wart Block","3440":"Red Nether Bricks","3456":"Bone Block","3460":"Bone Block","3464":"Bone Block","3488":"Dyed Shulker Box","3489":"Dyed Shulker Box","3490":"Dyed Shulker Box","3491":"Dyed Shulker Box","3492":"Dyed Shulker Box","3493":"Dyed Shulker Box","3494":"Dyed Shulker Box","3495":"Dyed Shulker Box","3496":"Dyed Shulker Box","3497":"Dyed Shulker Box","3498":"Dyed Shulker Box","3499":"Dyed Shulker Box","3500":"Dyed Shulker Box","3501":"Dyed Shulker Box","3502":"Dyed Shulker Box","3503":"Dyed Shulker Box","3506":"Purple Glazed Terracotta","3507":"Purple Glazed Terracotta","3508":"Purple Glazed Terracotta","3509":"Purple Glazed Terracotta","3522":"White Glazed Terracotta","3523":"White Glazed Terracotta","3524":"White Glazed Terracotta","3525":"White Glazed Terracotta","3538":"Orange Glazed Terracotta","3539":"Orange Glazed Terracotta","3540":"Orange Glazed Terracotta","3541":"Orange Glazed Terracotta","3554":"Magenta Glazed Terracotta","3555":"Magenta Glazed Terracotta","3556":"Magenta Glazed Terracotta","3557":"Magenta Glazed Terracotta","3570":"Light Blue Glazed Terracotta","3571":"Light Blue Glazed Terracotta","3572":"Light Blue Glazed Terracotta","3573":"Light Blue Glazed Terracotta","3586":"Yellow Glazed Terracotta","3587":"Yellow Glazed Terracotta","3588":"Yellow Glazed Terracotta","3589":"Yellow Glazed Terracotta","3602":"Lime Glazed Terracotta","3603":"Lime Glazed Terracotta","3604":"Lime Glazed Terracotta","3605":"Lime Glazed Terracotta","3618":"Pink Glazed Terracotta","3619":"Pink Glazed Terracotta","3620":"Pink Glazed Terracotta","3621":"Pink Glazed Terracotta","3634":"Gray Glazed Terracotta","3635":"Gray Glazed Terracotta","3636":"Gray Glazed Terracotta","3637":"Gray Glazed Terracotta","3650":"Light Gray Glazed Terracotta","3651":"Light Gray Glazed Terracotta","3652":"Light Gray Glazed Terracotta","3653":"Light Gray Glazed Terracotta","3666":"Cyan Glazed Terracotta","3667":"Cyan Glazed Terracotta","3668":"Cyan Glazed Terracotta","3669":"Cyan Glazed Terracotta","3698":"Blue Glazed Terracotta","3699":"Blue Glazed Terracotta","3700":"Blue Glazed Terracotta","3701":"Blue Glazed Terracotta","3714":"Brown Glazed Terracotta","3715":"Brown Glazed Terracotta","3716":"Brown Glazed Terracotta","3717":"Brown Glazed Terracotta","3730":"Green Glazed Terracotta","3731":"Green Glazed Terracotta","3732":"Green Glazed Terracotta","3733":"Green Glazed Terracotta","3746":"Red Glazed Terracotta","3747":"Red Glazed Terracotta","3748":"Red Glazed Terracotta","3749":"Red Glazed Terracotta","3762":"Black Glazed Terracotta","3763":"Black Glazed Terracotta","3764":"Black Glazed Terracotta","3765":"Black Glazed Terracotta","3776":"Concrete","3777":"Concrete","3778":"Concrete","3779":"Concrete","3780":"Concrete","3781":"Concrete","3782":"Concrete","3783":"Concrete","3784":"Concrete","3785":"Concrete","3786":"Concrete","3787":"Concrete","3788":"Concrete","3789":"Concrete","3790":"Concrete","3791":"Concrete","3792":"Concrete Powder","3793":"Concrete Powder","3794":"Concrete Powder","3795":"Concrete Powder","3796":"Concrete Powder","3797":"Concrete Powder","3798":"Concrete Powder","3799":"Concrete Powder","3800":"Concrete Powder","3801":"Concrete Powder","3802":"Concrete Powder","3803":"Concrete Powder","3804":"Concrete Powder","3805":"Concrete Powder","3806":"Concrete Powder","3807":"Concrete Powder","3808":"Compound Creator","3809":"Compound Creator","3810":"Compound Creator","3811":"Compound Creator","3812":"Material Reducer","3813":"Material Reducer","3814":"Material Reducer","3815":"Material Reducer","3816":"Element Constructor","3817":"Element Constructor","3818":"Element Constructor","3819":"Element Constructor","3820":"Lab Table","3821":"Lab Table","3822":"Lab Table","3823":"Lab Table","3825":"Underwater Torch","3826":"Underwater Torch","3827":"Underwater Torch","3828":"Underwater Torch","3829":"Underwater Torch","3856":"Stained Glass","3857":"Stained Glass","3858":"Stained Glass","3859":"Stained Glass","3860":"Stained Glass","3861":"Stained Glass","3862":"Stained Glass","3863":"Stained Glass","3864":"Stained Glass","3865":"Stained Glass","3866":"Stained Glass","3867":"Stained Glass","3868":"Stained Glass","3869":"Stained Glass","3870":"Stained Glass","3871":"Stained Glass","3888":"Podzol","3904":"Beetroot Block","3905":"Beetroot Block","3906":"Beetroot Block","3907":"Beetroot Block","3908":"Beetroot Block","3909":"Beetroot Block","3910":"Beetroot Block","3911":"Beetroot Block","3920":"Stonecutter","3936":"Glowing Obsidian","3952":"Nether Reactor Core","3953":"Nether Reactor Core","3954":"Nether Reactor Core","3968":"update!","3984":"ate!upd","4048":"Hardened Glass","4064":"Stained Hardened Glass","4065":"Stained Hardened Glass","4066":"Stained Hardened Glass","4067":"Stained Hardened Glass","4068":"Stained Hardened Glass","4069":"Stained Hardened Glass","4070":"Stained Hardened Glass","4071":"Stained Hardened Glass","4072":"Stained Hardened Glass","4073":"Stained Hardened Glass","4074":"Stained Hardened Glass","4075":"Stained Hardened Glass","4076":"Stained Hardened Glass","4077":"Stained Hardened Glass","4078":"Stained Hardened Glass","4079":"Stained Hardened Glass","4080":"reserved6","4112":"Prismarine Stairs","4113":"Prismarine Stairs","4114":"Prismarine Stairs","4115":"Prismarine Stairs","4116":"Prismarine Stairs","4117":"Prismarine Stairs","4118":"Prismarine Stairs","4119":"Prismarine Stairs","4128":"Dark Prismarine Stairs","4129":"Dark Prismarine Stairs","4130":"Dark Prismarine Stairs","4131":"Dark Prismarine Stairs","4132":"Dark Prismarine Stairs","4133":"Dark Prismarine Stairs","4134":"Dark Prismarine Stairs","4135":"Dark Prismarine Stairs","4144":"Prismarine Bricks Stairs","4145":"Prismarine Bricks Stairs","4146":"Prismarine Bricks Stairs","4147":"Prismarine Bricks Stairs","4148":"Prismarine Bricks Stairs","4149":"Prismarine Bricks Stairs","4150":"Prismarine Bricks Stairs","4151":"Prismarine Bricks Stairs","4160":"Stripped Spruce Log","4161":"Stripped Spruce Log","4162":"Stripped Spruce Log","4176":"Stripped Birch Log","4177":"Stripped Birch Log","4178":"Stripped Birch Log","4192":"Stripped Jungle Log","4193":"Stripped Jungle Log","4194":"Stripped Jungle Log","4208":"Stripped Acacia Log","4209":"Stripped Acacia Log","4210":"Stripped Acacia Log","4224":"Stripped Dark Oak Log","4225":"Stripped Dark Oak Log","4226":"Stripped Dark Oak Log","4240":"Stripped Oak Log","4241":"Stripped Oak Log","4242":"Stripped Oak Log","4256":"Blue Ice","4272":"Hydrogen","4288":"Helium","4304":"Lithium","4320":"Beryllium","4336":"Boron","4352":"Carbon","4368":"Nitrogen","4384":"Oxygen","4400":"Fluorine","4416":"Neon","4432":"Sodium","4448":"Magnesium","4464":"Aluminum","4480":"Silicon","4496":"Phosphorus","4512":"Sulfur","4528":"Chlorine","4544":"Argon","4560":"Potassium","4576":"Calcium","4592":"Scandium","4608":"Titanium","4624":"Vanadium","4640":"Chromium","4656":"Manganese","4672":"Iron","4688":"Cobalt","4704":"Nickel","4720":"Copper","4736":"Zinc","4752":"Gallium","4768":"Germanium","4784":"Arsenic","4800":"Selenium","4816":"Bromine","4832":"Krypton","4848":"Rubidium","4864":"Strontium","4880":"Yttrium","4896":"Zirconium","4912":"Niobium","4928":"Molybdenum","4944":"Technetium","4960":"Ruthenium","4976":"Rhodium","4992":"Palladium","5008":"Silver","5024":"Cadmium","5040":"Indium","5056":"Tin","5072":"Antimony","5088":"Tellurium","5104":"Iodine","5120":"Xenon","5136":"Cesium","5152":"Barium","5168":"Lanthanum","5184":"Cerium","5200":"Praseodymium","5216":"Neodymium","5232":"Promethium","5248":"Samarium","5264":"Europium","5280":"Gadolinium","5296":"Terbium","5312":"Dysprosium","5328":"Holmium","5344":"Erbium","5360":"Thulium","5376":"Ytterbium","5392":"Lutetium","5408":"Hafnium","5424":"Tantalum","5440":"Tungsten","5456":"Rhenium","5472":"Osmium","5488":"Iridium","5504":"Platinum","5520":"Gold","5536":"Mercury","5552":"Thallium","5568":"Lead","5584":"Bismuth","5600":"Polonium","5616":"Astatine","5632":"Radon","5648":"Francium","5664":"Radium","5680":"Actinium","5696":"Thorium","5712":"Protactinium","5728":"Uranium","5744":"Neptunium","5760":"Plutonium","5776":"Americium","5792":"Curium","5808":"Berkelium","5824":"Californium","5840":"Einsteinium","5856":"Fermium","5872":"Mendelevium","5888":"Nobelium","5904":"Lawrencium","5920":"Rutherfordium","5936":"Dubnium","5952":"Seaborgium","5968":"Bohrium","5984":"Hassium","6000":"Meitnerium","6016":"Darmstadtium","6032":"Roentgenium","6048":"Copernicium","6064":"Nihonium","6080":"Flerovium","6096":"Moscovium","6112":"Livermorium","6128":"Tennessine","6144":"Oganesson","6176":"Coral","6177":"Coral","6178":"Coral","6179":"Coral","6180":"Coral","6192":"Coral Block","6193":"Coral Block","6194":"Coral Block","6195":"Coral Block","6196":"Coral Block","6200":"Coral Block","6201":"Coral Block","6202":"Coral Block","6203":"Coral Block","6204":"Coral Block","6208":"Coral Fan","6209":"Coral Fan","6210":"Coral Fan","6211":"Coral Fan","6212":"Coral Fan","6216":"Coral Fan","6217":"Coral Fan","6218":"Coral Fan","6219":"Coral Fan","6220":"Coral Fan","6224":"Coral Fan","6225":"Coral Fan","6226":"Coral Fan","6227":"Coral Fan","6228":"Coral Fan","6232":"Coral Fan","6233":"Coral Fan","6234":"Coral Fan","6235":"Coral Fan","6236":"Coral Fan","6240":"Wall Coral Fan","6241":"Wall Coral Fan","6242":"Wall Coral Fan","6243":"Wall Coral Fan","6244":"Wall Coral Fan","6245":"Wall Coral Fan","6246":"Wall Coral Fan","6247":"Wall Coral Fan","6248":"Wall Coral Fan","6249":"Wall Coral Fan","6250":"Wall Coral Fan","6251":"Wall Coral Fan","6252":"Wall Coral Fan","6253":"Wall Coral Fan","6254":"Wall Coral Fan","6255":"Wall Coral Fan","6256":"Wall Coral Fan","6257":"Wall Coral Fan","6258":"Wall Coral Fan","6259":"Wall Coral Fan","6260":"Wall Coral Fan","6261":"Wall Coral Fan","6262":"Wall Coral Fan","6263":"Wall Coral Fan","6264":"Wall Coral Fan","6265":"Wall Coral Fan","6266":"Wall Coral Fan","6267":"Wall Coral Fan","6268":"Wall Coral Fan","6269":"Wall Coral Fan","6270":"Wall Coral Fan","6271":"Wall Coral Fan","6272":"Wall Coral Fan","6274":"Wall Coral Fan","6276":"Wall Coral Fan","6278":"Wall Coral Fan","6280":"Wall Coral Fan","6282":"Wall Coral Fan","6284":"Wall Coral Fan","6286":"Wall Coral Fan","6304":"Dried Kelp Block","6320":"Acacia Button","6321":"Acacia Button","6322":"Acacia Button","6323":"Acacia Button","6324":"Acacia Button","6325":"Acacia Button","6328":"Acacia Button","6329":"Acacia Button","6330":"Acacia Button","6331":"Acacia Button","6332":"Acacia Button","6333":"Acacia Button","6336":"Birch Button","6337":"Birch Button","6338":"Birch Button","6339":"Birch Button","6340":"Birch Button","6341":"Birch Button","6344":"Birch Button","6345":"Birch Button","6346":"Birch Button","6347":"Birch Button","6348":"Birch Button","6349":"Birch Button","6352":"Dark Oak Button","6353":"Dark Oak Button","6354":"Dark Oak Button","6355":"Dark Oak Button","6356":"Dark Oak Button","6357":"Dark Oak Button","6360":"Dark Oak Button","6361":"Dark Oak Button","6362":"Dark Oak Button","6363":"Dark Oak Button","6364":"Dark Oak Button","6365":"Dark Oak Button","6368":"Jungle Button","6369":"Jungle Button","6370":"Jungle Button","6371":"Jungle Button","6372":"Jungle Button","6373":"Jungle Button","6376":"Jungle Button","6377":"Jungle Button","6378":"Jungle Button","6379":"Jungle Button","6380":"Jungle Button","6381":"Jungle Button","6384":"Spruce Button","6385":"Spruce Button","6386":"Spruce Button","6387":"Spruce Button","6388":"Spruce Button","6389":"Spruce Button","6392":"Spruce Button","6393":"Spruce Button","6394":"Spruce Button","6395":"Spruce Button","6396":"Spruce Button","6397":"Spruce Button","6400":"Acacia Trapdoor","6401":"Acacia Trapdoor","6402":"Acacia Trapdoor","6403":"Acacia Trapdoor","6404":"Acacia Trapdoor","6405":"Acacia Trapdoor","6406":"Acacia Trapdoor","6407":"Acacia Trapdoor","6408":"Acacia Trapdoor","6409":"Acacia Trapdoor","6410":"Acacia Trapdoor","6411":"Acacia Trapdoor","6412":"Acacia Trapdoor","6413":"Acacia Trapdoor","6414":"Acacia Trapdoor","6415":"Acacia Trapdoor","6416":"Birch Trapdoor","6417":"Birch Trapdoor","6418":"Birch Trapdoor","6419":"Birch Trapdoor","6420":"Birch Trapdoor","6421":"Birch Trapdoor","6422":"Birch Trapdoor","6423":"Birch Trapdoor","6424":"Birch Trapdoor","6425":"Birch Trapdoor","6426":"Birch Trapdoor","6427":"Birch Trapdoor","6428":"Birch Trapdoor","6429":"Birch Trapdoor","6430":"Birch Trapdoor","6431":"Birch Trapdoor","6432":"Dark Oak Trapdoor","6433":"Dark Oak Trapdoor","6434":"Dark Oak Trapdoor","6435":"Dark Oak Trapdoor","6436":"Dark Oak Trapdoor","6437":"Dark Oak Trapdoor","6438":"Dark Oak Trapdoor","6439":"Dark Oak Trapdoor","6440":"Dark Oak Trapdoor","6441":"Dark Oak Trapdoor","6442":"Dark Oak Trapdoor","6443":"Dark Oak Trapdoor","6444":"Dark Oak Trapdoor","6445":"Dark Oak Trapdoor","6446":"Dark Oak Trapdoor","6447":"Dark Oak Trapdoor","6448":"Jungle Trapdoor","6449":"Jungle Trapdoor","6450":"Jungle Trapdoor","6451":"Jungle Trapdoor","6452":"Jungle Trapdoor","6453":"Jungle Trapdoor","6454":"Jungle Trapdoor","6455":"Jungle Trapdoor","6456":"Jungle Trapdoor","6457":"Jungle Trapdoor","6458":"Jungle Trapdoor","6459":"Jungle Trapdoor","6460":"Jungle Trapdoor","6461":"Jungle Trapdoor","6462":"Jungle Trapdoor","6463":"Jungle Trapdoor","6464":"Spruce Trapdoor","6465":"Spruce Trapdoor","6466":"Spruce Trapdoor","6467":"Spruce Trapdoor","6468":"Spruce Trapdoor","6469":"Spruce Trapdoor","6470":"Spruce Trapdoor","6471":"Spruce Trapdoor","6472":"Spruce Trapdoor","6473":"Spruce Trapdoor","6474":"Spruce Trapdoor","6475":"Spruce Trapdoor","6476":"Spruce Trapdoor","6477":"Spruce Trapdoor","6478":"Spruce Trapdoor","6479":"Spruce Trapdoor","6480":"Acacia Pressure Plate","6481":"Acacia Pressure Plate","6496":"Birch Pressure Plate","6497":"Birch Pressure Plate","6512":"Dark Oak Pressure Plate","6513":"Dark Oak Pressure Plate","6528":"Jungle Pressure Plate","6529":"Jungle Pressure Plate","6544":"Spruce Pressure Plate","6545":"Spruce Pressure Plate","6560":"Carved Pumpkin","6561":"Carved Pumpkin","6562":"Carved Pumpkin","6563":"Carved Pumpkin","6576":"Sea Pickle","6577":"Sea Pickle","6578":"Sea Pickle","6579":"Sea Pickle","6580":"Sea Pickle","6581":"Sea Pickle","6582":"Sea Pickle","6583":"Sea Pickle","6656":"Barrier","6672":"End Stone Brick Slab","6673":"Smooth Red Sandstone Slab","6674":"Polished Andesite Slab","6675":"Andesite Slab","6676":"Diorite Slab","6677":"Polished Diorite Slab","6678":"Granite Slab","6679":"Polished Granite Slab","6680":"End Stone Brick Slab","6681":"Smooth Red Sandstone Slab","6682":"Polished Andesite Slab","6683":"Andesite Slab","6684":"Diorite Slab","6685":"Polished Diorite Slab","6686":"Granite Slab","6687":"Polished Granite Slab","6688":"Bamboo","6689":"Bamboo","6690":"Bamboo","6691":"Bamboo","6692":"Bamboo","6693":"Bamboo","6696":"Bamboo","6697":"Bamboo","6698":"Bamboo","6699":"Bamboo","6700":"Bamboo","6701":"Bamboo","6704":"Bamboo Sapling","6712":"Bamboo Sapling","6736":"Mossy Stone Brick Slab","6737":"Smooth Quartz Slab","6738":"Stone Slab","6739":"Cut Sandstone Slab","6740":"Cut Red Sandstone Slab","6744":"Mossy Stone Brick Slab","6745":"Smooth Quartz Slab","6746":"Stone Slab","6747":"Cut Sandstone Slab","6748":"Cut Red Sandstone Slab","6752":"End Stone Brick Slab","6753":"Smooth Red Sandstone Slab","6754":"Polished Andesite Slab","6755":"Andesite Slab","6756":"Diorite Slab","6757":"Polished Diorite Slab","6758":"Granite Slab","6759":"Polished Granite Slab","6768":"Mossy Stone Brick Slab","6769":"Smooth Quartz Slab","6770":"Stone Slab","6771":"Cut Sandstone Slab","6772":"Cut Red Sandstone Slab","6784":"Granite Stairs","6785":"Granite Stairs","6786":"Granite Stairs","6787":"Granite Stairs","6788":"Granite Stairs","6789":"Granite Stairs","6790":"Granite Stairs","6791":"Granite Stairs","6800":"Diorite Stairs","6801":"Diorite Stairs","6802":"Diorite Stairs","6803":"Diorite Stairs","6804":"Diorite Stairs","6805":"Diorite Stairs","6806":"Diorite Stairs","6807":"Diorite Stairs","6816":"Andesite Stairs","6817":"Andesite Stairs","6818":"Andesite Stairs","6819":"Andesite Stairs","6820":"Andesite Stairs","6821":"Andesite Stairs","6822":"Andesite Stairs","6823":"Andesite Stairs","6832":"Polished Granite Stairs","6833":"Polished Granite Stairs","6834":"Polished Granite Stairs","6835":"Polished Granite Stairs","6836":"Polished Granite Stairs","6837":"Polished Granite Stairs","6838":"Polished Granite Stairs","6839":"Polished Granite Stairs","6848":"Polished Diorite Stairs","6849":"Polished Diorite Stairs","6850":"Polished Diorite Stairs","6851":"Polished Diorite Stairs","6852":"Polished Diorite Stairs","6853":"Polished Diorite Stairs","6854":"Polished Diorite Stairs","6855":"Polished Diorite Stairs","6864":"Polished Andesite Stairs","6865":"Polished Andesite Stairs","6866":"Polished Andesite Stairs","6867":"Polished Andesite Stairs","6868":"Polished Andesite Stairs","6869":"Polished Andesite Stairs","6870":"Polished Andesite Stairs","6871":"Polished Andesite Stairs","6880":"Mossy Stone Brick Stairs","6881":"Mossy Stone Brick Stairs","6882":"Mossy Stone Brick Stairs","6883":"Mossy Stone Brick Stairs","6884":"Mossy Stone Brick Stairs","6885":"Mossy Stone Brick Stairs","6886":"Mossy Stone Brick Stairs","6887":"Mossy Stone Brick Stairs","6896":"Smooth Red Sandstone Stairs","6897":"Smooth Red Sandstone Stairs","6898":"Smooth Red Sandstone Stairs","6899":"Smooth Red Sandstone Stairs","6900":"Smooth Red Sandstone Stairs","6901":"Smooth Red Sandstone Stairs","6902":"Smooth Red Sandstone Stairs","6903":"Smooth Red Sandstone Stairs","6912":"Smooth Sandstone Stairs","6913":"Smooth Sandstone Stairs","6914":"Smooth Sandstone Stairs","6915":"Smooth Sandstone Stairs","6916":"Smooth Sandstone Stairs","6917":"Smooth Sandstone Stairs","6918":"Smooth Sandstone Stairs","6919":"Smooth Sandstone Stairs","6928":"End Stone Brick Stairs","6929":"End Stone Brick Stairs","6930":"End Stone Brick Stairs","6931":"End Stone Brick Stairs","6932":"End Stone Brick Stairs","6933":"End Stone Brick Stairs","6934":"End Stone Brick Stairs","6935":"End Stone Brick Stairs","6944":"Mossy Cobblestone Stairs","6945":"Mossy Cobblestone Stairs","6946":"Mossy Cobblestone Stairs","6947":"Mossy Cobblestone Stairs","6948":"Mossy Cobblestone Stairs","6949":"Mossy Cobblestone Stairs","6950":"Mossy Cobblestone Stairs","6951":"Mossy Cobblestone Stairs","6960":"Stone Stairs","6961":"Stone Stairs","6962":"Stone Stairs","6963":"Stone Stairs","6964":"Stone Stairs","6965":"Stone Stairs","6966":"Stone Stairs","6967":"Stone Stairs","6976":"Spruce Sign","6977":"Spruce Sign","6978":"Spruce Sign","6979":"Spruce Sign","6980":"Spruce Sign","6981":"Spruce Sign","6982":"Spruce Sign","6983":"Spruce Sign","6984":"Spruce Sign","6985":"Spruce Sign","6986":"Spruce Sign","6987":"Spruce Sign","6988":"Spruce Sign","6989":"Spruce Sign","6990":"Spruce Sign","6991":"Spruce Sign","6994":"Spruce Wall Sign","6995":"Spruce Wall Sign","6996":"Spruce Wall Sign","6997":"Spruce Wall Sign","7008":"Smooth Stone","7024":"Red Nether Brick Stairs","7025":"Red Nether Brick Stairs","7026":"Red Nether Brick Stairs","7027":"Red Nether Brick Stairs","7028":"Red Nether Brick Stairs","7029":"Red Nether Brick Stairs","7030":"Red Nether Brick Stairs","7031":"Red Nether Brick Stairs","7040":"Smooth Quartz Stairs","7041":"Smooth Quartz Stairs","7042":"Smooth Quartz Stairs","7043":"Smooth Quartz Stairs","7044":"Smooth Quartz Stairs","7045":"Smooth Quartz Stairs","7046":"Smooth Quartz Stairs","7047":"Smooth Quartz Stairs","7056":"Birch Sign","7057":"Birch Sign","7058":"Birch Sign","7059":"Birch Sign","7060":"Birch Sign","7061":"Birch Sign","7062":"Birch Sign","7063":"Birch Sign","7064":"Birch Sign","7065":"Birch Sign","7066":"Birch Sign","7067":"Birch Sign","7068":"Birch Sign","7069":"Birch Sign","7070":"Birch Sign","7071":"Birch Sign","7074":"Birch Wall Sign","7075":"Birch Wall Sign","7076":"Birch Wall Sign","7077":"Birch Wall Sign","7088":"Jungle Sign","7089":"Jungle Sign","7090":"Jungle Sign","7091":"Jungle Sign","7092":"Jungle Sign","7093":"Jungle Sign","7094":"Jungle Sign","7095":"Jungle Sign","7096":"Jungle Sign","7097":"Jungle Sign","7098":"Jungle Sign","7099":"Jungle Sign","7100":"Jungle Sign","7101":"Jungle Sign","7102":"Jungle Sign","7103":"Jungle Sign","7106":"Jungle Wall Sign","7107":"Jungle Wall Sign","7108":"Jungle Wall Sign","7109":"Jungle Wall Sign","7120":"Acacia Sign","7121":"Acacia Sign","7122":"Acacia Sign","7123":"Acacia Sign","7124":"Acacia Sign","7125":"Acacia Sign","7126":"Acacia Sign","7127":"Acacia Sign","7128":"Acacia Sign","7129":"Acacia Sign","7130":"Acacia Sign","7131":"Acacia Sign","7132":"Acacia Sign","7133":"Acacia Sign","7134":"Acacia Sign","7135":"Acacia Sign","7138":"Acacia Wall Sign","7139":"Acacia Wall Sign","7140":"Acacia Wall Sign","7141":"Acacia Wall Sign","7152":"Dark Oak Sign","7153":"Dark Oak Sign","7154":"Dark Oak Sign","7155":"Dark Oak Sign","7156":"Dark Oak Sign","7157":"Dark Oak Sign","7158":"Dark Oak Sign","7159":"Dark Oak Sign","7160":"Dark Oak Sign","7161":"Dark Oak Sign","7162":"Dark Oak Sign","7163":"Dark Oak Sign","7164":"Dark Oak Sign","7165":"Dark Oak Sign","7166":"Dark Oak Sign","7167":"Dark Oak Sign","7170":"Dark Oak Wall Sign","7171":"Dark Oak Wall Sign","7172":"Dark Oak Wall Sign","7173":"Dark Oak Wall Sign","7184":"Lectern","7185":"Lectern","7186":"Lectern","7187":"Lectern","7188":"Lectern","7189":"Lectern","7190":"Lectern","7191":"Lectern","7218":"Blast Furnace","7219":"Blast Furnace","7220":"Blast Furnace","7221":"Blast Furnace","7250":"Smoker","7251":"Smoker","7252":"Smoker","7253":"Smoker","7266":"Smoker","7267":"Smoker","7268":"Smoker","7269":"Smoker","7296":"Fletching Table","7328":"Barrel","7329":"Barrel","7330":"Barrel","7331":"Barrel","7332":"Barrel","7333":"Barrel","7336":"Barrel","7337":"Barrel","7338":"Barrel","7339":"Barrel","7340":"Barrel","7341":"Barrel","7344":"Loom","7345":"Loom","7346":"Loom","7347":"Loom","7376":"Bell","7377":"Bell","7378":"Bell","7379":"Bell","7380":"Bell","7381":"Bell","7382":"Bell","7383":"Bell","7384":"Bell","7385":"Bell","7386":"Bell","7387":"Bell","7388":"Bell","7389":"Bell","7390":"Bell","7391":"Bell","7392":"Sweet Berry Bush","7393":"Sweet Berry Bush","7394":"Sweet Berry Bush","7395":"Sweet Berry Bush","7408":"Lantern","7409":"Lantern","7472":"Oak Wood","7473":"Spruce Wood","7474":"Birch Wood","7475":"Jungle Wood","7476":"Acacia Wood","7477":"Dark Oak Wood","7480":"Stripped Oak Wood","7481":"Stripped Spruce Wood","7482":"Stripped Birch Wood","7483":"Stripped Jungle Wood","7484":"Stripped Acacia Wood","7485":"Stripped Dark Oak Wood","7506":"Blast Furnace","7507":"Blast Furnace","7508":"Blast Furnace","7509":"Blast Furnace"},"remaps":{"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"23":16,"24":16,"25":16,"26":16,"27":16,"28":16,"29":16,"30":16,"31":16,"33":32,"34":32,"35":32,"36":32,"37":32,"38":32,"39":32,"40":32,"41":32,"42":32,"43":32,"44":32,"45":32,"46":32,"47":32,"50":48,"51":48,"52":48,"53":48,"54":48,"55":48,"56":48,"57":48,"58":48,"59":48,"60":48,"61":48,"62":48,"63":48,"65":64,"66":64,"67":64,"68":64,"69":64,"70":64,"71":64,"72":64,"73":64,"74":64,"75":64,"76":64,"77":64,"78":64,"79":64,"86":80,"87":80,"88":80,"89":80,"90":80,"91":80,"92":80,"93":80,"94":80,"95":80,"102":96,"103":96,"110":96,"111":96,"114":112,"115":112,"116":112,"117":112,"118":112,"119":112,"120":112,"121":112,"122":112,"123":112,"124":112,"125":112,"126":112,"127":112,"194":192,"195":192,"196":192,"197":192,"198":192,"199":192,"200":192,"201":192,"202":192,"203":192,"204":192,"205":192,"206":192,"207":192,"209":208,"210":208,"211":208,"212":208,"213":208,"214":208,"215":208,"216":208,"217":208,"218":208,"219":208,"220":208,"221":208,"222":208,"223":208,"225":224,"226":224,"227":224,"228":224,"229":224,"230":224,"231":224,"232":224,"233":224,"234":224,"235":224,"236":224,"237":224,"238":224,"239":224,"241":240,"242":240,"243":240,"244":240,"245":240,"246":240,"247":240,"248":240,"249":240,"250":240,"251":240,"252":240,"253":240,"254":240,"255":240,"257":256,"258":256,"259":256,"260":256,"261":256,"262":256,"263":256,"264":256,"265":256,"266":256,"267":256,"268":256,"269":256,"270":256,"271":256,"284":7472,"285":7473,"286":7474,"287":7475,"306":304,"307":304,"308":304,"309":304,"310":304,"311":304,"312":304,"313":304,"314":304,"315":304,"316":304,"317":304,"318":304,"319":304,"321":320,"322":320,"323":320,"324":320,"325":320,"326":320,"327":320,"328":320,"329":320,"330":320,"331":320,"332":320,"333":320,"334":320,"335":320,"337":336,"338":336,"339":336,"340":336,"341":336,"342":336,"343":336,"344":336,"345":336,"346":336,"347":336,"348":336,"349":336,"350":336,"351":336,"353":352,"354":352,"355":352,"356":352,"357":352,"358":352,"359":352,"360":352,"361":352,"362":352,"363":352,"364":352,"365":352,"366":352,"367":352,"388":384,"389":384,"390":384,"391":384,"392":384,"393":384,"394":384,"395":384,"396":384,"397":384,"398":384,"399":384,"401":400,"402":400,"403":400,"404":400,"405":400,"406":400,"407":400,"408":400,"409":400,"410":400,"411":400,"412":400,"413":400,"414":400,"415":400,"438":432,"439":432,"446":432,"447":432,"454":448,"455":448,"462":448,"463":448,"481":480,"482":480,"483":480,"484":480,"485":480,"486":480,"487":480,"488":480,"489":480,"490":480,"491":480,"492":480,"493":480,"494":480,"495":480,"496":498,"499":498,"500":498,"501":498,"502":498,"503":498,"504":498,"505":498,"506":498,"507":498,"508":498,"509":498,"510":498,"511":498,"513":512,"514":512,"515":512,"516":512,"517":512,"518":512,"519":512,"520":512,"521":512,"522":512,"523":512,"524":512,"525":512,"526":512,"527":512,"577":576,"578":576,"579":576,"580":576,"581":576,"582":576,"583":576,"584":576,"585":576,"586":576,"587":576,"588":576,"589":576,"590":576,"591":576,"593":592,"594":592,"595":592,"596":592,"597":592,"598":592,"599":592,"600":592,"601":592,"602":592,"603":592,"604":592,"605":592,"606":592,"607":592,"619":608,"620":608,"621":608,"622":608,"623":608,"625":624,"626":624,"627":624,"628":624,"629":624,"630":624,"631":624,"632":624,"633":624,"634":624,"635":624,"636":624,"637":624,"638":624,"639":624,"641":640,"642":640,"643":640,"644":640,"645":640,"646":640,"647":640,"648":640,"649":640,"650":640,"651":640,"652":640,"653":640,"654":640,"655":640,"657":656,"658":656,"659":656,"660":656,"661":656,"662":656,"663":656,"664":656,"665":656,"666":656,"667":656,"668":656,"669":656,"670":656,"671":656,"673":672,"674":672,"675":672,"676":672,"677":672,"678":672,"679":672,"680":672,"681":672,"682":672,"683":672,"684":672,"685":672,"686":672,"687":672,"696":688,"697":689,"698":690,"699":691,"700":692,"701":693,"702":694,"703":695,"721":720,"722":720,"723":720,"724":720,"725":720,"726":720,"727":720,"728":720,"729":720,"730":720,"731":720,"732":720,"733":720,"734":720,"735":720,"740":736,"741":736,"742":736,"743":736,"744":736,"745":736,"746":736,"747":736,"748":736,"749":736,"750":736,"751":736,"753":752,"754":752,"755":752,"756":752,"757":752,"758":752,"759":752,"760":752,"761":752,"762":752,"763":752,"764":752,"765":752,"766":752,"767":752,"769":768,"770":768,"771":768,"772":768,"773":768,"774":768,"775":768,"776":768,"777":768,"778":768,"779":768,"780":768,"781":768,"782":768,"783":768,"785":784,"786":784,"787":784,"788":784,"789":784,"790":784,"791":784,"792":784,"793":784,"794":784,"795":784,"796":784,"797":784,"798":784,"799":784,"800":805,"806":805,"807":805,"808":805,"809":805,"810":805,"811":805,"812":805,"813":805,"814":805,"815":805,"833":832,"834":832,"835":832,"836":832,"837":832,"838":832,"839":832,"840":832,"841":832,"842":832,"843":832,"844":832,"845":832,"846":832,"847":832,"856":851,"857":851,"858":851,"859":851,"860":851,"861":851,"862":851,"863":851,"864":866,"865":866,"870":866,"871":866,"872":866,"873":866,"874":866,"875":866,"876":866,"877":866,"878":866,"879":866,"897":896,"898":896,"899":896,"900":896,"901":896,"902":896,"903":896,"904":896,"905":896,"906":896,"907":896,"908":896,"909":896,"910":896,"911":896,"913":912,"914":912,"915":912,"916":912,"917":912,"918":912,"919":912,"920":912,"921":912,"922":912,"923":912,"924":912,"925":912,"926":912,"927":912,"929":928,"930":928,"931":928,"932":928,"933":928,"934":928,"935":928,"936":928,"937":928,"938":928,"939":928,"940":928,"941":928,"942":928,"943":928,"952":944,"953":944,"954":944,"955":944,"956":944,"957":944,"958":944,"959":944,"968":960,"969":960,"970":960,"971":960,"972":960,"973":960,"974":960,"975":960,"976":978,"977":978,"982":978,"983":978,"984":978,"985":978,"986":978,"987":978,"988":978,"989":978,"990":978,"991":978,"992":978,"993":978,"998":978,"999":978,"1000":978,"1001":978,"1002":978,"1003":978,"1004":978,"1005":978,"1006":978,"1007":978,"1036":1027,"1037":1027,"1038":1027,"1039":1027,"1040":1042,"1041":1042,"1046":1042,"1047":1042,"1048":1042,"1049":1042,"1050":1042,"1051":1042,"1052":1042,"1053":1042,"1054":1042,"1055":1042,"1066":1056,"1067":1056,"1068":1056,"1069":1056,"1070":1056,"1071":1056,"1080":1075,"1081":1075,"1082":1075,"1083":1075,"1084":1075,"1085":1075,"1086":1075,"1087":1075,"1088":1090,"1089":1090,"1094":1090,"1095":1090,"1096":1090,"1097":1090,"1098":1090,"1099":1090,"1100":1090,"1101":1090,"1102":1090,"1103":1090,"1122":1120,"1123":1120,"1124":1120,"1125":1120,"1126":1120,"1127":1120,"1128":1120,"1129":1120,"1130":1120,"1131":1120,"1132":1120,"1133":1120,"1134":1120,"1135":1120,"1148":1139,"1149":1139,"1150":1139,"1151":1139,"1154":1152,"1155":1152,"1156":1152,"1157":1152,"1158":1152,"1159":1152,"1160":1152,"1161":1152,"1162":1152,"1163":1152,"1164":1152,"1165":1152,"1166":1152,"1167":1152,"1169":1168,"1170":1168,"1171":1168,"1172":1168,"1173":1168,"1174":1168,"1175":1168,"1176":1168,"1177":1168,"1178":1168,"1179":1168,"1180":1168,"1181":1168,"1182":1168,"1183":1168,"1185":1168,"1186":1168,"1187":1168,"1188":1168,"1189":1168,"1190":1168,"1191":1168,"1192":1168,"1193":1168,"1194":1168,"1195":1168,"1196":1168,"1197":1168,"1198":1168,"1199":1168,"1200":1221,"1206":1221,"1207":1221,"1208":1221,"1209":1221,"1210":1221,"1211":1221,"1212":1221,"1213":1221,"1214":1221,"1215":1221,"1216":1221,"1222":1221,"1223":1221,"1224":1221,"1225":1221,"1226":1221,"1227":1221,"1228":1221,"1229":1221,"1230":1221,"1231":1221,"1238":1232,"1239":1232,"1246":1232,"1247":1232,"1256":1248,"1257":1248,"1258":1248,"1259":1248,"1260":1248,"1261":1248,"1262":1248,"1263":1248,"1265":1264,"1266":1264,"1267":1264,"1268":1264,"1269":1264,"1270":1264,"1271":1264,"1272":1264,"1273":1264,"1274":1264,"1275":1264,"1276":1264,"1277":1264,"1278":1264,"1279":1264,"1281":1280,"1282":1280,"1283":1280,"1284":1280,"1285":1280,"1286":1280,"1287":1280,"1288":1280,"1289":1280,"1290":1280,"1291":1280,"1292":1280,"1293":1280,"1294":1280,"1295":1280,"1313":1312,"1314":1312,"1315":1312,"1316":1312,"1317":1312,"1318":1312,"1319":1312,"1320":1312,"1321":1312,"1322":1312,"1323":1312,"1324":1312,"1325":1312,"1326":1312,"1327":1312,"1345":1344,"1346":1344,"1347":1344,"1348":1344,"1349":1344,"1350":1344,"1351":1344,"1352":1344,"1353":1344,"1354":1344,"1355":1344,"1356":1344,"1357":1344,"1358":1344,"1359":1344,"1366":1360,"1367":1360,"1368":1360,"1369":1360,"1370":1360,"1371":1360,"1372":1360,"1373":1360,"1374":1360,"1375":1360,"1377":1376,"1378":1376,"1379":1376,"1380":1376,"1381":1376,"1382":1376,"1383":1376,"1384":1376,"1385":1376,"1386":1376,"1387":1376,"1388":1376,"1389":1376,"1390":1376,"1391":1376,"1393":1392,"1394":1392,"1395":1392,"1396":1392,"1397":1392,"1398":1392,"1399":1392,"1400":1392,"1401":1392,"1402":1392,"1403":1392,"1404":1392,"1405":1392,"1406":1392,"1407":1392,"1409":1408,"1410":1408,"1411":1408,"1412":1408,"1413":1408,"1414":1408,"1415":1408,"1416":1408,"1417":1408,"1418":1408,"1419":1408,"1420":1408,"1421":1408,"1422":1408,"1423":1408,"1425":1424,"1426":1424,"1427":1424,"1428":1424,"1429":1424,"1430":1424,"1431":1424,"1432":1424,"1433":1424,"1434":1424,"1435":1424,"1436":1424,"1437":1424,"1438":1424,"1439":1424,"1440":1441,"1443":1441,"1444":1441,"1445":1441,"1446":1441,"1447":1441,"1448":1441,"1449":1441,"1450":1441,"1451":1441,"1452":1441,"1453":1441,"1454":1441,"1455":1441,"1460":1458,"1461":1458,"1462":1458,"1463":1458,"1464":1458,"1465":1458,"1466":1458,"1467":1458,"1468":1458,"1469":1458,"1470":1458,"1471":1458,"1479":1472,"1480":1472,"1481":1472,"1482":1472,"1483":1472,"1484":1472,"1485":1472,"1486":1472,"1487":1472,"1521":1520,"1522":1520,"1523":1520,"1524":1520,"1525":1520,"1526":1520,"1527":1520,"1528":1520,"1529":1520,"1530":1520,"1531":1520,"1532":1520,"1533":1520,"1534":1520,"1535":1520,"1558":1552,"1559":1552,"1560":1552,"1561":1552,"1562":1552,"1563":1552,"1564":1552,"1565":1552,"1566":1552,"1567":1552,"1572":1568,"1573":1568,"1574":1568,"1575":1568,"1576":1568,"1577":1568,"1578":1568,"1579":1568,"1580":1568,"1581":1568,"1582":1568,"1583":1568,"1595":1598,"1596":1598,"1597":1598,"1610":1594,"1611":1614,"1612":1614,"1613":1614,"1615":1599,"1617":1616,"1618":1616,"1619":1616,"1620":1616,"1621":1616,"1622":1616,"1623":1616,"1624":1616,"1625":1616,"1626":1616,"1627":1616,"1628":1616,"1629":1616,"1630":1616,"1631":1616,"1633":1632,"1634":1632,"1635":1632,"1636":1632,"1637":1632,"1638":1632,"1639":1632,"1640":1632,"1641":1632,"1642":1632,"1643":1632,"1644":1632,"1645":1632,"1646":1632,"1647":1632,"1649":1648,"1650":1648,"1651":1648,"1652":1648,"1653":1648,"1654":1648,"1655":1648,"1656":1648,"1657":1648,"1658":1648,"1659":1648,"1660":1648,"1661":1648,"1662":1648,"1663":1648,"1672":1664,"1673":1664,"1674":1664,"1675":1664,"1676":1664,"1677":1664,"1678":1664,"1679":1664,"1688":1680,"1689":1680,"1690":1680,"1691":1680,"1692":1680,"1693":1680,"1694":1680,"1695":1680,"1736":1731,"1737":1731,"1738":1731,"1739":1731,"1740":1731,"1741":1731,"1742":1731,"1743":1731,"1752":1747,"1753":1747,"1754":1747,"1755":1747,"1756":1747,"1757":1747,"1758":1747,"1759":1747,"1761":1760,"1762":1760,"1763":1760,"1764":1760,"1765":1760,"1766":1760,"1767":1760,"1768":1760,"1769":1760,"1770":1760,"1771":1760,"1772":1760,"1773":1760,"1774":1760,"1775":1760,"1777":1776,"1778":1776,"1779":1776,"1780":1776,"1781":1776,"1782":1776,"1783":1776,"1784":1776,"1785":1776,"1786":1776,"1787":1776,"1788":1776,"1789":1776,"1790":1776,"1791":1776,"1793":1792,"1794":1792,"1795":1792,"1796":1792,"1797":1792,"1798":1792,"1799":1792,"1800":1792,"1801":1792,"1802":1792,"1803":1792,"1804":1792,"1805":1792,"1806":1792,"1807":1792,"1809":1808,"1810":1808,"1811":1808,"1812":1808,"1813":1808,"1814":1808,"1815":1808,"1816":1808,"1817":1808,"1818":1808,"1819":1808,"1820":1808,"1821":1808,"1822":1808,"1823":1808,"1832":1827,"1833":1827,"1834":1827,"1835":1827,"1836":1827,"1837":1827,"1838":1827,"1839":1827,"1844":1840,"1845":1840,"1846":1840,"1847":1840,"1848":1840,"1849":1840,"1850":1840,"1851":1840,"1852":1840,"1853":1840,"1854":1840,"1855":1840,"1857":1856,"1858":1856,"1859":1856,"1860":1856,"1861":1856,"1862":1856,"1863":1856,"1864":1856,"1865":1856,"1866":1856,"1867":1856,"1868":1856,"1869":1856,"1870":1856,"1871":1856,"1880":1872,"1881":1872,"1882":1872,"1883":1872,"1884":1872,"1885":1872,"1886":1872,"1887":1872,"1928":1922,"1929":1922,"1930":1922,"1931":1922,"1932":1922,"1933":1922,"1934":1922,"1935":1922,"1937":1936,"1938":1936,"1939":1936,"1940":1936,"1941":1936,"1942":1936,"1943":1936,"1944":1936,"1945":1936,"1946":1936,"1947":1936,"1948":1936,"1949":1936,"1950":1936,"1951":1936,"1953":1952,"1954":1952,"1955":1952,"1956":1952,"1957":1952,"1958":1952,"1959":1952,"1960":1952,"1961":1952,"1962":1952,"1963":1952,"1964":1952,"1965":1952,"1966":1952,"1967":1952,"1969":1968,"1970":1968,"1971":1968,"1972":1968,"1973":1968,"1974":1968,"1975":1968,"1976":1968,"1977":1968,"1978":1968,"1979":1968,"1980":1968,"1981":1968,"1982":1968,"1983":1968,"1985":1968,"1986":1968,"1987":1968,"1988":1968,"1989":1968,"1990":1968,"1991":1968,"1992":1968,"1993":1968,"1994":1968,"1995":1968,"1996":1968,"1997":1968,"1998":1968,"1999":1968,"2022":2016,"2023":2016,"2030":2016,"2031":2016,"2044":2032,"2045":2032,"2046":2032,"2047":2032,"2056":2051,"2057":2051,"2058":2051,"2059":2051,"2060":2051,"2061":2051,"2062":2051,"2063":2051,"2065":2064,"2066":2064,"2067":2064,"2068":2064,"2069":2064,"2070":2064,"2071":2064,"2072":2064,"2073":2064,"2074":2064,"2075":2064,"2076":2064,"2077":2064,"2078":2064,"2079":2064,"2080":2082,"2081":2082,"2086":2082,"2087":2082,"2088":2082,"2089":2082,"2090":2082,"2091":2082,"2092":2082,"2093":2082,"2094":2082,"2095":2082,"2129":2128,"2130":2128,"2131":2128,"2132":2128,"2133":2128,"2134":2128,"2135":2128,"2136":2128,"2137":2128,"2138":2128,"2139":2128,"2140":2128,"2141":2128,"2142":2128,"2143":2128,"2152":2147,"2153":2147,"2154":2147,"2155":2147,"2156":2147,"2157":2147,"2158":2147,"2159":2147,"2168":2163,"2169":2163,"2170":2163,"2171":2163,"2172":2163,"2173":2163,"2174":2163,"2175":2163,"2184":2179,"2185":2179,"2186":2179,"2187":2179,"2188":2179,"2189":2179,"2190":2179,"2191":2179,"2209":2208,"2210":2208,"2211":2208,"2212":2208,"2213":2208,"2214":2208,"2215":2208,"2216":2208,"2217":2208,"2218":2208,"2219":2208,"2220":2208,"2221":2208,"2222":2208,"2223":2208,"2238":2224,"2239":2224,"2241":2240,"2242":2240,"2243":2240,"2244":2240,"2245":2240,"2246":2240,"2247":2240,"2248":2240,"2249":2240,"2250":2240,"2251":2240,"2252":2240,"2253":2240,"2254":2240,"2255":2240,"2264":2256,"2265":2256,"2266":2256,"2267":2256,"2268":2256,"2269":2256,"2270":2256,"2271":2256,"2280":2272,"2281":2272,"2282":2272,"2283":2272,"2284":2272,"2285":2272,"2286":2272,"2287":2272,"2294":2288,"2295":2288,"2302":2288,"2303":2288,"2304":2306,"2310":2306,"2311":2306,"2312":2306,"2313":2306,"2314":2306,"2315":2306,"2316":2306,"2317":2306,"2318":2306,"2319":2306,"2332":2322,"2333":2322,"2334":2322,"2335":2322,"2336":2338,"2337":2338,"2342":2338,"2343":2338,"2344":2338,"2345":2338,"2346":2338,"2347":2338,"2348":2338,"2349":2338,"2350":2338,"2351":2338,"2392":2386,"2393":2386,"2394":2386,"2395":2386,"2396":2386,"2397":2386,"2398":2386,"2399":2386,"2400":2386,"2401":2386,"2402":2386,"2403":2386,"2404":2386,"2405":2386,"2406":2386,"2407":2386,"2433":2432,"2434":2432,"2435":2432,"2436":2432,"2437":2432,"2438":2432,"2439":2432,"2440":2432,"2441":2432,"2442":2432,"2443":2432,"2444":2432,"2445":2432,"2446":2432,"2447":2432,"2449":2448,"2450":2448,"2451":2448,"2452":2448,"2453":2448,"2454":2448,"2455":2448,"2456":2448,"2457":2448,"2458":2448,"2459":2448,"2460":2448,"2461":2448,"2462":2448,"2463":2448,"2465":2464,"2470":2464,"2471":2464,"2473":2464,"2478":2464,"2479":2464,"2484":2480,"2487":2480,"2488":2480,"2491":2480,"2492":2480,"2493":2481,"2494":2482,"2495":2480,"2504":2499,"2505":2499,"2506":2499,"2507":2499,"2508":2499,"2509":2499,"2510":2499,"2511":2499,"2520":2512,"2521":2513,"2522":2514,"2523":2515,"2524":2516,"2525":2517,"2578":288,"2579":288,"2582":288,"2583":288,"2586":288,"2587":288,"2590":288,"2591":288,"2604":7476,"2605":7477,"2616":2611,"2617":2611,"2618":2611,"2619":2611,"2620":2611,"2621":2611,"2622":2611,"2623":2611,"2632":2627,"2633":2627,"2634":2627,"2635":2627,"2636":2627,"2637":2627,"2638":2627,"2639":2627,"2641":2640,"2642":2640,"2643":2640,"2644":2640,"2645":2640,"2646":2640,"2647":2640,"2648":2640,"2649":2640,"2650":2640,"2651":2640,"2652":2640,"2653":2640,"2654":2640,"2655":2640,"2691":2688,"2692":2688,"2693":2688,"2694":2688,"2695":2688,"2696":2688,"2697":2688,"2698":2688,"2699":2688,"2700":2688,"2701":2688,"2702":2688,"2703":2688,"2705":2704,"2706":2704,"2707":2704,"2708":2704,"2709":2704,"2710":2704,"2711":2704,"2712":2704,"2713":2704,"2714":2704,"2715":2704,"2716":2704,"2717":2704,"2718":2704,"2719":2704,"2721":2720,"2722":2720,"2723":2720,"2725":2720,"2726":2720,"2727":2720,"2729":2720,"2730":2720,"2731":2720,"2732":2720,"2733":2720,"2734":2720,"2735":2720,"2753":2752,"2754":2752,"2755":2752,"2756":2752,"2757":2752,"2758":2752,"2759":2752,"2760":2752,"2761":2752,"2762":2752,"2763":2752,"2764":2752,"2765":2752,"2766":2752,"2767":2752,"2769":2768,"2770":2768,"2771":2768,"2772":2768,"2773":2768,"2774":2768,"2775":2768,"2776":2768,"2777":2768,"2778":2768,"2779":2768,"2780":2768,"2781":2768,"2782":2768,"2783":2768,"2785":2784,"2786":2784,"2787":2784,"2788":2784,"2789":2784,"2790":2784,"2791":2784,"2792":2784,"2793":2784,"2794":2784,"2795":2784,"2796":2784,"2797":2784,"2798":2784,"2799":2784,"2806":2800,"2807":2800,"2814":2800,"2815":2800,"2832":2834,"2833":2834,"2838":2834,"2839":2834,"2840":2834,"2841":2834,"2842":2834,"2843":2834,"2844":2834,"2845":2834,"2846":2834,"2847":2834,"2868":2864,"2869":2864,"2870":2864,"2871":2864,"2872":2864,"2873":2864,"2874":2864,"2875":2864,"2876":2864,"2877":2864,"2878":2864,"2879":2864,"2888":2883,"2889":2883,"2890":2883,"2891":2883,"2892":2883,"2893":2883,"2894":2883,"2895":2883,"2904":2896,"2905":2897,"2906":2898,"2907":2899,"2908":2900,"2909":2901,"2910":2902,"2911":2903,"3041":3040,"3042":3040,"3043":3040,"3044":3040,"3045":3040,"3046":3040,"3047":3040,"3048":3040,"3049":3040,"3050":3040,"3051":3040,"3052":3040,"3053":3040,"3054":3040,"3055":3040,"3073":3072,"3074":3072,"3075":3072,"3076":3072,"3077":3072,"3078":3072,"3079":3072,"3080":3072,"3081":3072,"3082":3072,"3083":3072,"3084":3072,"3085":3072,"3086":3072,"3087":3072,"3100":3091,"3101":3091,"3102":3091,"3103":3091,"3116":3107,"3117":3107,"3118":3107,"3119":3107,"3132":3123,"3133":3123,"3134":3123,"3135":3123,"3148":3139,"3149":3139,"3150":3139,"3151":3139,"3164":3155,"3165":3155,"3166":3155,"3167":3155,"3169":3168,"3170":3168,"3171":3168,"3172":3168,"3173":3168,"3174":3168,"3175":3168,"3176":3168,"3177":3168,"3178":3168,"3179":3168,"3180":3168,"3181":3168,"3182":3168,"3183":3168,"3192":3187,"3193":3187,"3194":3187,"3195":3187,"3196":3187,"3197":3187,"3198":3187,"3199":3187,"3217":3216,"3219":3216,"3220":3216,"3221":3216,"3223":3216,"3224":3216,"3225":3216,"3227":3216,"3228":3216,"3229":3216,"3230":3218,"3231":3216,"3232":3237,"3238":3237,"3239":3237,"3240":3245,"3246":3245,"3247":3245,"3256":3251,"3257":3251,"3258":3251,"3259":3251,"3260":3251,"3261":3251,"3262":3251,"3263":3251,"3264":3269,"3270":3269,"3271":3269,"3272":3277,"3278":3277,"3279":3277,"3281":3280,"3282":3280,"3283":3280,"3284":3280,"3285":3280,"3286":3280,"3287":3280,"3288":3280,"3289":3280,"3290":3280,"3291":3280,"3292":3280,"3293":3280,"3294":3280,"3295":3280,"3297":3296,"3298":3296,"3299":3296,"3300":3296,"3301":3296,"3302":3296,"3303":3296,"3304":3296,"3305":3296,"3306":3296,"3307":3296,"3308":3296,"3309":3296,"3310":3296,"3311":3296,"3316":3312,"3317":3312,"3318":3312,"3319":3312,"3320":3312,"3321":3312,"3322":3312,"3323":3312,"3324":3312,"3325":3312,"3326":3312,"3327":3312,"3334":3328,"3335":3328,"3336":3328,"3337":3328,"3338":3328,"3339":3328,"3340":3328,"3341":3328,"3342":3328,"3343":3328,"3409":3408,"3410":3408,"3411":3408,"3412":3408,"3413":3408,"3414":3408,"3415":3408,"3416":3408,"3417":3408,"3418":3408,"3419":3408,"3420":3408,"3421":3408,"3422":3408,"3423":3408,"3425":3424,"3426":3424,"3427":3424,"3428":3424,"3429":3424,"3430":3424,"3431":3424,"3432":3424,"3433":3424,"3434":3424,"3435":3424,"3436":3424,"3437":3424,"3438":3424,"3439":3424,"3441":3440,"3442":3440,"3443":3440,"3444":3440,"3445":3440,"3446":3440,"3447":3440,"3448":3440,"3449":3440,"3450":3440,"3451":3440,"3452":3440,"3453":3440,"3454":3440,"3455":3440,"3457":3456,"3458":3456,"3459":3456,"3461":3456,"3462":3456,"3463":3456,"3465":3456,"3466":3456,"3467":3456,"3468":3456,"3469":3456,"3470":3456,"3471":3456,"3504":3506,"3505":3506,"3510":3506,"3511":3506,"3512":3506,"3513":3506,"3514":3506,"3515":3506,"3516":3506,"3517":3506,"3518":3506,"3519":3506,"3520":3522,"3521":3522,"3526":3522,"3527":3522,"3528":3522,"3529":3522,"3530":3522,"3531":3522,"3532":3522,"3533":3522,"3534":3522,"3535":3522,"3536":3538,"3537":3538,"3542":3538,"3543":3538,"3544":3538,"3545":3538,"3546":3538,"3547":3538,"3548":3538,"3549":3538,"3550":3538,"3551":3538,"3552":3554,"3553":3554,"3558":3554,"3559":3554,"3560":3554,"3561":3554,"3562":3554,"3563":3554,"3564":3554,"3565":3554,"3566":3554,"3567":3554,"3568":3570,"3569":3570,"3574":3570,"3575":3570,"3576":3570,"3577":3570,"3578":3570,"3579":3570,"3580":3570,"3581":3570,"3582":3570,"3583":3570,"3584":3586,"3585":3586,"3590":3586,"3591":3586,"3592":3586,"3593":3586,"3594":3586,"3595":3586,"3596":3586,"3597":3586,"3598":3586,"3599":3586,"3600":3602,"3601":3602,"3606":3602,"3607":3602,"3608":3602,"3609":3602,"3610":3602,"3611":3602,"3612":3602,"3613":3602,"3614":3602,"3615":3602,"3616":3618,"3617":3618,"3622":3618,"3623":3618,"3624":3618,"3625":3618,"3626":3618,"3627":3618,"3628":3618,"3629":3618,"3630":3618,"3631":3618,"3632":3634,"3633":3634,"3638":3634,"3639":3634,"3640":3634,"3641":3634,"3642":3634,"3643":3634,"3644":3634,"3645":3634,"3646":3634,"3647":3634,"3648":3650,"3649":3650,"3654":3650,"3655":3650,"3656":3650,"3657":3650,"3658":3650,"3659":3650,"3660":3650,"3661":3650,"3662":3650,"3663":3650,"3664":3666,"3665":3666,"3670":3666,"3671":3666,"3672":3666,"3673":3666,"3674":3666,"3675":3666,"3676":3666,"3677":3666,"3678":3666,"3679":3666,"3696":3698,"3697":3698,"3702":3698,"3703":3698,"3704":3698,"3705":3698,"3706":3698,"3707":3698,"3708":3698,"3709":3698,"3710":3698,"3711":3698,"3712":3714,"3713":3714,"3718":3714,"3719":3714,"3720":3714,"3721":3714,"3722":3714,"3723":3714,"3724":3714,"3725":3714,"3726":3714,"3727":3714,"3728":3730,"3729":3730,"3734":3730,"3735":3730,"3736":3730,"3737":3730,"3738":3730,"3739":3730,"3740":3730,"3741":3730,"3742":3730,"3743":3730,"3744":3746,"3745":3746,"3750":3746,"3751":3746,"3752":3746,"3753":3746,"3754":3746,"3755":3746,"3756":3746,"3757":3746,"3758":3746,"3759":3746,"3760":3762,"3761":3762,"3766":3762,"3767":3762,"3768":3762,"3769":3762,"3770":3762,"3771":3762,"3772":3762,"3773":3762,"3774":3762,"3775":3762,"3824":3829,"3830":3829,"3831":3829,"3832":3829,"3833":3829,"3834":3829,"3835":3829,"3836":3829,"3837":3829,"3838":3829,"3839":3829,"3889":3888,"3890":3888,"3891":3888,"3892":3888,"3893":3888,"3894":3888,"3895":3888,"3896":3888,"3897":3888,"3898":3888,"3899":3888,"3900":3888,"3901":3888,"3902":3888,"3903":3888,"3912":3904,"3913":3904,"3914":3904,"3915":3904,"3916":3904,"3917":3904,"3918":3904,"3919":3904,"3921":3920,"3922":3920,"3923":3920,"3924":3920,"3925":3920,"3926":3920,"3927":3920,"3928":3920,"3929":3920,"3930":3920,"3931":3920,"3932":3920,"3933":3920,"3934":3920,"3935":3920,"3937":3936,"3938":3936,"3939":3936,"3940":3936,"3941":3936,"3942":3936,"3943":3936,"3944":3936,"3945":3936,"3946":3936,"3947":3936,"3948":3936,"3949":3936,"3950":3936,"3951":3936,"3955":3952,"3956":3952,"3957":3952,"3958":3952,"3959":3952,"3960":3952,"3961":3952,"3962":3952,"3963":3952,"3964":3952,"3965":3952,"3966":3952,"3967":3952,"3969":3968,"3970":3968,"3971":3968,"3972":3968,"3973":3968,"3974":3968,"3975":3968,"3976":3968,"3977":3968,"3978":3968,"3979":3968,"3980":3968,"3981":3968,"3982":3968,"3983":3968,"3985":3984,"3986":3984,"3987":3984,"3988":3984,"3989":3984,"3990":3984,"3991":3984,"3992":3984,"3993":3984,"3994":3984,"3995":3984,"3996":3984,"3997":3984,"3998":3984,"3999":3984,"4049":4048,"4050":4048,"4051":4048,"4052":4048,"4053":4048,"4054":4048,"4055":4048,"4056":4048,"4057":4048,"4058":4048,"4059":4048,"4060":4048,"4061":4048,"4062":4048,"4063":4048,"4081":4080,"4082":4080,"4083":4080,"4084":4080,"4085":4080,"4086":4080,"4087":4080,"4088":4080,"4089":4080,"4090":4080,"4091":4080,"4092":4080,"4093":4080,"4094":4080,"4095":4080,"4120":4115,"4121":4115,"4122":4115,"4123":4115,"4124":4115,"4125":4115,"4126":4115,"4127":4115,"4136":4131,"4137":4131,"4138":4131,"4139":4131,"4140":4131,"4141":4131,"4142":4131,"4143":4131,"4152":4147,"4153":4147,"4154":4147,"4155":4147,"4156":4147,"4157":4147,"4158":4147,"4159":4147,"4163":4160,"4164":4160,"4165":4160,"4166":4160,"4167":4160,"4168":4160,"4169":4160,"4170":4160,"4171":4160,"4172":4160,"4173":4160,"4174":4160,"4175":4160,"4179":4176,"4180":4176,"4181":4176,"4182":4176,"4183":4176,"4184":4176,"4185":4176,"4186":4176,"4187":4176,"4188":4176,"4189":4176,"4190":4176,"4191":4176,"4195":4192,"4196":4192,"4197":4192,"4198":4192,"4199":4192,"4200":4192,"4201":4192,"4202":4192,"4203":4192,"4204":4192,"4205":4192,"4206":4192,"4207":4192,"4211":4208,"4212":4208,"4213":4208,"4214":4208,"4215":4208,"4216":4208,"4217":4208,"4218":4208,"4219":4208,"4220":4208,"4221":4208,"4222":4208,"4223":4208,"4227":4224,"4228":4224,"4229":4224,"4230":4224,"4231":4224,"4232":4224,"4233":4224,"4234":4224,"4235":4224,"4236":4224,"4237":4224,"4238":4224,"4239":4224,"4243":4240,"4244":4240,"4245":4240,"4246":4240,"4247":4240,"4248":4240,"4249":4240,"4250":4240,"4251":4240,"4252":4240,"4253":4240,"4254":4240,"4255":4240,"4257":4256,"4258":4256,"4259":4256,"4260":4256,"4261":4256,"4262":4256,"4263":4256,"4264":4256,"4265":4256,"4266":4256,"4267":4256,"4268":4256,"4269":4256,"4270":4256,"4271":4256,"4273":4272,"4274":4272,"4275":4272,"4276":4272,"4277":4272,"4278":4272,"4279":4272,"4280":4272,"4281":4272,"4282":4272,"4283":4272,"4284":4272,"4285":4272,"4286":4272,"4287":4272,"4289":4288,"4290":4288,"4291":4288,"4292":4288,"4293":4288,"4294":4288,"4295":4288,"4296":4288,"4297":4288,"4298":4288,"4299":4288,"4300":4288,"4301":4288,"4302":4288,"4303":4288,"4305":4304,"4306":4304,"4307":4304,"4308":4304,"4309":4304,"4310":4304,"4311":4304,"4312":4304,"4313":4304,"4314":4304,"4315":4304,"4316":4304,"4317":4304,"4318":4304,"4319":4304,"4321":4320,"4322":4320,"4323":4320,"4324":4320,"4325":4320,"4326":4320,"4327":4320,"4328":4320,"4329":4320,"4330":4320,"4331":4320,"4332":4320,"4333":4320,"4334":4320,"4335":4320,"4337":4336,"4338":4336,"4339":4336,"4340":4336,"4341":4336,"4342":4336,"4343":4336,"4344":4336,"4345":4336,"4346":4336,"4347":4336,"4348":4336,"4349":4336,"4350":4336,"4351":4336,"4353":4352,"4354":4352,"4355":4352,"4356":4352,"4357":4352,"4358":4352,"4359":4352,"4360":4352,"4361":4352,"4362":4352,"4363":4352,"4364":4352,"4365":4352,"4366":4352,"4367":4352,"4369":4368,"4370":4368,"4371":4368,"4372":4368,"4373":4368,"4374":4368,"4375":4368,"4376":4368,"4377":4368,"4378":4368,"4379":4368,"4380":4368,"4381":4368,"4382":4368,"4383":4368,"4385":4384,"4386":4384,"4387":4384,"4388":4384,"4389":4384,"4390":4384,"4391":4384,"4392":4384,"4393":4384,"4394":4384,"4395":4384,"4396":4384,"4397":4384,"4398":4384,"4399":4384,"4401":4400,"4402":4400,"4403":4400,"4404":4400,"4405":4400,"4406":4400,"4407":4400,"4408":4400,"4409":4400,"4410":4400,"4411":4400,"4412":4400,"4413":4400,"4414":4400,"4415":4400,"4417":4416,"4418":4416,"4419":4416,"4420":4416,"4421":4416,"4422":4416,"4423":4416,"4424":4416,"4425":4416,"4426":4416,"4427":4416,"4428":4416,"4429":4416,"4430":4416,"4431":4416,"4433":4432,"4434":4432,"4435":4432,"4436":4432,"4437":4432,"4438":4432,"4439":4432,"4440":4432,"4441":4432,"4442":4432,"4443":4432,"4444":4432,"4445":4432,"4446":4432,"4447":4432,"4449":4448,"4450":4448,"4451":4448,"4452":4448,"4453":4448,"4454":4448,"4455":4448,"4456":4448,"4457":4448,"4458":4448,"4459":4448,"4460":4448,"4461":4448,"4462":4448,"4463":4448,"4465":4464,"4466":4464,"4467":4464,"4468":4464,"4469":4464,"4470":4464,"4471":4464,"4472":4464,"4473":4464,"4474":4464,"4475":4464,"4476":4464,"4477":4464,"4478":4464,"4479":4464,"4481":4480,"4482":4480,"4483":4480,"4484":4480,"4485":4480,"4486":4480,"4487":4480,"4488":4480,"4489":4480,"4490":4480,"4491":4480,"4492":4480,"4493":4480,"4494":4480,"4495":4480,"4497":4496,"4498":4496,"4499":4496,"4500":4496,"4501":4496,"4502":4496,"4503":4496,"4504":4496,"4505":4496,"4506":4496,"4507":4496,"4508":4496,"4509":4496,"4510":4496,"4511":4496,"4513":4512,"4514":4512,"4515":4512,"4516":4512,"4517":4512,"4518":4512,"4519":4512,"4520":4512,"4521":4512,"4522":4512,"4523":4512,"4524":4512,"4525":4512,"4526":4512,"4527":4512,"4529":4528,"4530":4528,"4531":4528,"4532":4528,"4533":4528,"4534":4528,"4535":4528,"4536":4528,"4537":4528,"4538":4528,"4539":4528,"4540":4528,"4541":4528,"4542":4528,"4543":4528,"4545":4544,"4546":4544,"4547":4544,"4548":4544,"4549":4544,"4550":4544,"4551":4544,"4552":4544,"4553":4544,"4554":4544,"4555":4544,"4556":4544,"4557":4544,"4558":4544,"4559":4544,"4561":4560,"4562":4560,"4563":4560,"4564":4560,"4565":4560,"4566":4560,"4567":4560,"4568":4560,"4569":4560,"4570":4560,"4571":4560,"4572":4560,"4573":4560,"4574":4560,"4575":4560,"4577":4576,"4578":4576,"4579":4576,"4580":4576,"4581":4576,"4582":4576,"4583":4576,"4584":4576,"4585":4576,"4586":4576,"4587":4576,"4588":4576,"4589":4576,"4590":4576,"4591":4576,"4593":4592,"4594":4592,"4595":4592,"4596":4592,"4597":4592,"4598":4592,"4599":4592,"4600":4592,"4601":4592,"4602":4592,"4603":4592,"4604":4592,"4605":4592,"4606":4592,"4607":4592,"4609":4608,"4610":4608,"4611":4608,"4612":4608,"4613":4608,"4614":4608,"4615":4608,"4616":4608,"4617":4608,"4618":4608,"4619":4608,"4620":4608,"4621":4608,"4622":4608,"4623":4608,"4625":4624,"4626":4624,"4627":4624,"4628":4624,"4629":4624,"4630":4624,"4631":4624,"4632":4624,"4633":4624,"4634":4624,"4635":4624,"4636":4624,"4637":4624,"4638":4624,"4639":4624,"4641":4640,"4642":4640,"4643":4640,"4644":4640,"4645":4640,"4646":4640,"4647":4640,"4648":4640,"4649":4640,"4650":4640,"4651":4640,"4652":4640,"4653":4640,"4654":4640,"4655":4640,"4657":4656,"4658":4656,"4659":4656,"4660":4656,"4661":4656,"4662":4656,"4663":4656,"4664":4656,"4665":4656,"4666":4656,"4667":4656,"4668":4656,"4669":4656,"4670":4656,"4671":4656,"4673":4672,"4674":4672,"4675":4672,"4676":4672,"4677":4672,"4678":4672,"4679":4672,"4680":4672,"4681":4672,"4682":4672,"4683":4672,"4684":4672,"4685":4672,"4686":4672,"4687":4672,"4689":4688,"4690":4688,"4691":4688,"4692":4688,"4693":4688,"4694":4688,"4695":4688,"4696":4688,"4697":4688,"4698":4688,"4699":4688,"4700":4688,"4701":4688,"4702":4688,"4703":4688,"4705":4704,"4706":4704,"4707":4704,"4708":4704,"4709":4704,"4710":4704,"4711":4704,"4712":4704,"4713":4704,"4714":4704,"4715":4704,"4716":4704,"4717":4704,"4718":4704,"4719":4704,"4721":4720,"4722":4720,"4723":4720,"4724":4720,"4725":4720,"4726":4720,"4727":4720,"4728":4720,"4729":4720,"4730":4720,"4731":4720,"4732":4720,"4733":4720,"4734":4720,"4735":4720,"4737":4736,"4738":4736,"4739":4736,"4740":4736,"4741":4736,"4742":4736,"4743":4736,"4744":4736,"4745":4736,"4746":4736,"4747":4736,"4748":4736,"4749":4736,"4750":4736,"4751":4736,"4753":4752,"4754":4752,"4755":4752,"4756":4752,"4757":4752,"4758":4752,"4759":4752,"4760":4752,"4761":4752,"4762":4752,"4763":4752,"4764":4752,"4765":4752,"4766":4752,"4767":4752,"4769":4768,"4770":4768,"4771":4768,"4772":4768,"4773":4768,"4774":4768,"4775":4768,"4776":4768,"4777":4768,"4778":4768,"4779":4768,"4780":4768,"4781":4768,"4782":4768,"4783":4768,"4785":4784,"4786":4784,"4787":4784,"4788":4784,"4789":4784,"4790":4784,"4791":4784,"4792":4784,"4793":4784,"4794":4784,"4795":4784,"4796":4784,"4797":4784,"4798":4784,"4799":4784,"4801":4800,"4802":4800,"4803":4800,"4804":4800,"4805":4800,"4806":4800,"4807":4800,"4808":4800,"4809":4800,"4810":4800,"4811":4800,"4812":4800,"4813":4800,"4814":4800,"4815":4800,"4817":4816,"4818":4816,"4819":4816,"4820":4816,"4821":4816,"4822":4816,"4823":4816,"4824":4816,"4825":4816,"4826":4816,"4827":4816,"4828":4816,"4829":4816,"4830":4816,"4831":4816,"4833":4832,"4834":4832,"4835":4832,"4836":4832,"4837":4832,"4838":4832,"4839":4832,"4840":4832,"4841":4832,"4842":4832,"4843":4832,"4844":4832,"4845":4832,"4846":4832,"4847":4832,"4849":4848,"4850":4848,"4851":4848,"4852":4848,"4853":4848,"4854":4848,"4855":4848,"4856":4848,"4857":4848,"4858":4848,"4859":4848,"4860":4848,"4861":4848,"4862":4848,"4863":4848,"4865":4864,"4866":4864,"4867":4864,"4868":4864,"4869":4864,"4870":4864,"4871":4864,"4872":4864,"4873":4864,"4874":4864,"4875":4864,"4876":4864,"4877":4864,"4878":4864,"4879":4864,"4881":4880,"4882":4880,"4883":4880,"4884":4880,"4885":4880,"4886":4880,"4887":4880,"4888":4880,"4889":4880,"4890":4880,"4891":4880,"4892":4880,"4893":4880,"4894":4880,"4895":4880,"4897":4896,"4898":4896,"4899":4896,"4900":4896,"4901":4896,"4902":4896,"4903":4896,"4904":4896,"4905":4896,"4906":4896,"4907":4896,"4908":4896,"4909":4896,"4910":4896,"4911":4896,"4913":4912,"4914":4912,"4915":4912,"4916":4912,"4917":4912,"4918":4912,"4919":4912,"4920":4912,"4921":4912,"4922":4912,"4923":4912,"4924":4912,"4925":4912,"4926":4912,"4927":4912,"4929":4928,"4930":4928,"4931":4928,"4932":4928,"4933":4928,"4934":4928,"4935":4928,"4936":4928,"4937":4928,"4938":4928,"4939":4928,"4940":4928,"4941":4928,"4942":4928,"4943":4928,"4945":4944,"4946":4944,"4947":4944,"4948":4944,"4949":4944,"4950":4944,"4951":4944,"4952":4944,"4953":4944,"4954":4944,"4955":4944,"4956":4944,"4957":4944,"4958":4944,"4959":4944,"4961":4960,"4962":4960,"4963":4960,"4964":4960,"4965":4960,"4966":4960,"4967":4960,"4968":4960,"4969":4960,"4970":4960,"4971":4960,"4972":4960,"4973":4960,"4974":4960,"4975":4960,"4977":4976,"4978":4976,"4979":4976,"4980":4976,"4981":4976,"4982":4976,"4983":4976,"4984":4976,"4985":4976,"4986":4976,"4987":4976,"4988":4976,"4989":4976,"4990":4976,"4991":4976,"4993":4992,"4994":4992,"4995":4992,"4996":4992,"4997":4992,"4998":4992,"4999":4992,"5000":4992,"5001":4992,"5002":4992,"5003":4992,"5004":4992,"5005":4992,"5006":4992,"5007":4992,"5009":5008,"5010":5008,"5011":5008,"5012":5008,"5013":5008,"5014":5008,"5015":5008,"5016":5008,"5017":5008,"5018":5008,"5019":5008,"5020":5008,"5021":5008,"5022":5008,"5023":5008,"5025":5024,"5026":5024,"5027":5024,"5028":5024,"5029":5024,"5030":5024,"5031":5024,"5032":5024,"5033":5024,"5034":5024,"5035":5024,"5036":5024,"5037":5024,"5038":5024,"5039":5024,"5041":5040,"5042":5040,"5043":5040,"5044":5040,"5045":5040,"5046":5040,"5047":5040,"5048":5040,"5049":5040,"5050":5040,"5051":5040,"5052":5040,"5053":5040,"5054":5040,"5055":5040,"5057":5056,"5058":5056,"5059":5056,"5060":5056,"5061":5056,"5062":5056,"5063":5056,"5064":5056,"5065":5056,"5066":5056,"5067":5056,"5068":5056,"5069":5056,"5070":5056,"5071":5056,"5073":5072,"5074":5072,"5075":5072,"5076":5072,"5077":5072,"5078":5072,"5079":5072,"5080":5072,"5081":5072,"5082":5072,"5083":5072,"5084":5072,"5085":5072,"5086":5072,"5087":5072,"5089":5088,"5090":5088,"5091":5088,"5092":5088,"5093":5088,"5094":5088,"5095":5088,"5096":5088,"5097":5088,"5098":5088,"5099":5088,"5100":5088,"5101":5088,"5102":5088,"5103":5088,"5105":5104,"5106":5104,"5107":5104,"5108":5104,"5109":5104,"5110":5104,"5111":5104,"5112":5104,"5113":5104,"5114":5104,"5115":5104,"5116":5104,"5117":5104,"5118":5104,"5119":5104,"5121":5120,"5122":5120,"5123":5120,"5124":5120,"5125":5120,"5126":5120,"5127":5120,"5128":5120,"5129":5120,"5130":5120,"5131":5120,"5132":5120,"5133":5120,"5134":5120,"5135":5120,"5137":5136,"5138":5136,"5139":5136,"5140":5136,"5141":5136,"5142":5136,"5143":5136,"5144":5136,"5145":5136,"5146":5136,"5147":5136,"5148":5136,"5149":5136,"5150":5136,"5151":5136,"5153":5152,"5154":5152,"5155":5152,"5156":5152,"5157":5152,"5158":5152,"5159":5152,"5160":5152,"5161":5152,"5162":5152,"5163":5152,"5164":5152,"5165":5152,"5166":5152,"5167":5152,"5169":5168,"5170":5168,"5171":5168,"5172":5168,"5173":5168,"5174":5168,"5175":5168,"5176":5168,"5177":5168,"5178":5168,"5179":5168,"5180":5168,"5181":5168,"5182":5168,"5183":5168,"5185":5184,"5186":5184,"5187":5184,"5188":5184,"5189":5184,"5190":5184,"5191":5184,"5192":5184,"5193":5184,"5194":5184,"5195":5184,"5196":5184,"5197":5184,"5198":5184,"5199":5184,"5201":5200,"5202":5200,"5203":5200,"5204":5200,"5205":5200,"5206":5200,"5207":5200,"5208":5200,"5209":5200,"5210":5200,"5211":5200,"5212":5200,"5213":5200,"5214":5200,"5215":5200,"5217":5216,"5218":5216,"5219":5216,"5220":5216,"5221":5216,"5222":5216,"5223":5216,"5224":5216,"5225":5216,"5226":5216,"5227":5216,"5228":5216,"5229":5216,"5230":5216,"5231":5216,"5233":5232,"5234":5232,"5235":5232,"5236":5232,"5237":5232,"5238":5232,"5239":5232,"5240":5232,"5241":5232,"5242":5232,"5243":5232,"5244":5232,"5245":5232,"5246":5232,"5247":5232,"5249":5248,"5250":5248,"5251":5248,"5252":5248,"5253":5248,"5254":5248,"5255":5248,"5256":5248,"5257":5248,"5258":5248,"5259":5248,"5260":5248,"5261":5248,"5262":5248,"5263":5248,"5265":5264,"5266":5264,"5267":5264,"5268":5264,"5269":5264,"5270":5264,"5271":5264,"5272":5264,"5273":5264,"5274":5264,"5275":5264,"5276":5264,"5277":5264,"5278":5264,"5279":5264,"5281":5280,"5282":5280,"5283":5280,"5284":5280,"5285":5280,"5286":5280,"5287":5280,"5288":5280,"5289":5280,"5290":5280,"5291":5280,"5292":5280,"5293":5280,"5294":5280,"5295":5280,"5297":5296,"5298":5296,"5299":5296,"5300":5296,"5301":5296,"5302":5296,"5303":5296,"5304":5296,"5305":5296,"5306":5296,"5307":5296,"5308":5296,"5309":5296,"5310":5296,"5311":5296,"5313":5312,"5314":5312,"5315":5312,"5316":5312,"5317":5312,"5318":5312,"5319":5312,"5320":5312,"5321":5312,"5322":5312,"5323":5312,"5324":5312,"5325":5312,"5326":5312,"5327":5312,"5329":5328,"5330":5328,"5331":5328,"5332":5328,"5333":5328,"5334":5328,"5335":5328,"5336":5328,"5337":5328,"5338":5328,"5339":5328,"5340":5328,"5341":5328,"5342":5328,"5343":5328,"5345":5344,"5346":5344,"5347":5344,"5348":5344,"5349":5344,"5350":5344,"5351":5344,"5352":5344,"5353":5344,"5354":5344,"5355":5344,"5356":5344,"5357":5344,"5358":5344,"5359":5344,"5361":5360,"5362":5360,"5363":5360,"5364":5360,"5365":5360,"5366":5360,"5367":5360,"5368":5360,"5369":5360,"5370":5360,"5371":5360,"5372":5360,"5373":5360,"5374":5360,"5375":5360,"5377":5376,"5378":5376,"5379":5376,"5380":5376,"5381":5376,"5382":5376,"5383":5376,"5384":5376,"5385":5376,"5386":5376,"5387":5376,"5388":5376,"5389":5376,"5390":5376,"5391":5376,"5393":5392,"5394":5392,"5395":5392,"5396":5392,"5397":5392,"5398":5392,"5399":5392,"5400":5392,"5401":5392,"5402":5392,"5403":5392,"5404":5392,"5405":5392,"5406":5392,"5407":5392,"5409":5408,"5410":5408,"5411":5408,"5412":5408,"5413":5408,"5414":5408,"5415":5408,"5416":5408,"5417":5408,"5418":5408,"5419":5408,"5420":5408,"5421":5408,"5422":5408,"5423":5408,"5425":5424,"5426":5424,"5427":5424,"5428":5424,"5429":5424,"5430":5424,"5431":5424,"5432":5424,"5433":5424,"5434":5424,"5435":5424,"5436":5424,"5437":5424,"5438":5424,"5439":5424,"5441":5440,"5442":5440,"5443":5440,"5444":5440,"5445":5440,"5446":5440,"5447":5440,"5448":5440,"5449":5440,"5450":5440,"5451":5440,"5452":5440,"5453":5440,"5454":5440,"5455":5440,"5457":5456,"5458":5456,"5459":5456,"5460":5456,"5461":5456,"5462":5456,"5463":5456,"5464":5456,"5465":5456,"5466":5456,"5467":5456,"5468":5456,"5469":5456,"5470":5456,"5471":5456,"5473":5472,"5474":5472,"5475":5472,"5476":5472,"5477":5472,"5478":5472,"5479":5472,"5480":5472,"5481":5472,"5482":5472,"5483":5472,"5484":5472,"5485":5472,"5486":5472,"5487":5472,"5489":5488,"5490":5488,"5491":5488,"5492":5488,"5493":5488,"5494":5488,"5495":5488,"5496":5488,"5497":5488,"5498":5488,"5499":5488,"5500":5488,"5501":5488,"5502":5488,"5503":5488,"5505":5504,"5506":5504,"5507":5504,"5508":5504,"5509":5504,"5510":5504,"5511":5504,"5512":5504,"5513":5504,"5514":5504,"5515":5504,"5516":5504,"5517":5504,"5518":5504,"5519":5504,"5521":5520,"5522":5520,"5523":5520,"5524":5520,"5525":5520,"5526":5520,"5527":5520,"5528":5520,"5529":5520,"5530":5520,"5531":5520,"5532":5520,"5533":5520,"5534":5520,"5535":5520,"5537":5536,"5538":5536,"5539":5536,"5540":5536,"5541":5536,"5542":5536,"5543":5536,"5544":5536,"5545":5536,"5546":5536,"5547":5536,"5548":5536,"5549":5536,"5550":5536,"5551":5536,"5553":5552,"5554":5552,"5555":5552,"5556":5552,"5557":5552,"5558":5552,"5559":5552,"5560":5552,"5561":5552,"5562":5552,"5563":5552,"5564":5552,"5565":5552,"5566":5552,"5567":5552,"5569":5568,"5570":5568,"5571":5568,"5572":5568,"5573":5568,"5574":5568,"5575":5568,"5576":5568,"5577":5568,"5578":5568,"5579":5568,"5580":5568,"5581":5568,"5582":5568,"5583":5568,"5585":5584,"5586":5584,"5587":5584,"5588":5584,"5589":5584,"5590":5584,"5591":5584,"5592":5584,"5593":5584,"5594":5584,"5595":5584,"5596":5584,"5597":5584,"5598":5584,"5599":5584,"5601":5600,"5602":5600,"5603":5600,"5604":5600,"5605":5600,"5606":5600,"5607":5600,"5608":5600,"5609":5600,"5610":5600,"5611":5600,"5612":5600,"5613":5600,"5614":5600,"5615":5600,"5617":5616,"5618":5616,"5619":5616,"5620":5616,"5621":5616,"5622":5616,"5623":5616,"5624":5616,"5625":5616,"5626":5616,"5627":5616,"5628":5616,"5629":5616,"5630":5616,"5631":5616,"5633":5632,"5634":5632,"5635":5632,"5636":5632,"5637":5632,"5638":5632,"5639":5632,"5640":5632,"5641":5632,"5642":5632,"5643":5632,"5644":5632,"5645":5632,"5646":5632,"5647":5632,"5649":5648,"5650":5648,"5651":5648,"5652":5648,"5653":5648,"5654":5648,"5655":5648,"5656":5648,"5657":5648,"5658":5648,"5659":5648,"5660":5648,"5661":5648,"5662":5648,"5663":5648,"5665":5664,"5666":5664,"5667":5664,"5668":5664,"5669":5664,"5670":5664,"5671":5664,"5672":5664,"5673":5664,"5674":5664,"5675":5664,"5676":5664,"5677":5664,"5678":5664,"5679":5664,"5681":5680,"5682":5680,"5683":5680,"5684":5680,"5685":5680,"5686":5680,"5687":5680,"5688":5680,"5689":5680,"5690":5680,"5691":5680,"5692":5680,"5693":5680,"5694":5680,"5695":5680,"5697":5696,"5698":5696,"5699":5696,"5700":5696,"5701":5696,"5702":5696,"5703":5696,"5704":5696,"5705":5696,"5706":5696,"5707":5696,"5708":5696,"5709":5696,"5710":5696,"5711":5696,"5713":5712,"5714":5712,"5715":5712,"5716":5712,"5717":5712,"5718":5712,"5719":5712,"5720":5712,"5721":5712,"5722":5712,"5723":5712,"5724":5712,"5725":5712,"5726":5712,"5727":5712,"5729":5728,"5730":5728,"5731":5728,"5732":5728,"5733":5728,"5734":5728,"5735":5728,"5736":5728,"5737":5728,"5738":5728,"5739":5728,"5740":5728,"5741":5728,"5742":5728,"5743":5728,"5745":5744,"5746":5744,"5747":5744,"5748":5744,"5749":5744,"5750":5744,"5751":5744,"5752":5744,"5753":5744,"5754":5744,"5755":5744,"5756":5744,"5757":5744,"5758":5744,"5759":5744,"5761":5760,"5762":5760,"5763":5760,"5764":5760,"5765":5760,"5766":5760,"5767":5760,"5768":5760,"5769":5760,"5770":5760,"5771":5760,"5772":5760,"5773":5760,"5774":5760,"5775":5760,"5777":5776,"5778":5776,"5779":5776,"5780":5776,"5781":5776,"5782":5776,"5783":5776,"5784":5776,"5785":5776,"5786":5776,"5787":5776,"5788":5776,"5789":5776,"5790":5776,"5791":5776,"5793":5792,"5794":5792,"5795":5792,"5796":5792,"5797":5792,"5798":5792,"5799":5792,"5800":5792,"5801":5792,"5802":5792,"5803":5792,"5804":5792,"5805":5792,"5806":5792,"5807":5792,"5809":5808,"5810":5808,"5811":5808,"5812":5808,"5813":5808,"5814":5808,"5815":5808,"5816":5808,"5817":5808,"5818":5808,"5819":5808,"5820":5808,"5821":5808,"5822":5808,"5823":5808,"5825":5824,"5826":5824,"5827":5824,"5828":5824,"5829":5824,"5830":5824,"5831":5824,"5832":5824,"5833":5824,"5834":5824,"5835":5824,"5836":5824,"5837":5824,"5838":5824,"5839":5824,"5841":5840,"5842":5840,"5843":5840,"5844":5840,"5845":5840,"5846":5840,"5847":5840,"5848":5840,"5849":5840,"5850":5840,"5851":5840,"5852":5840,"5853":5840,"5854":5840,"5855":5840,"5857":5856,"5858":5856,"5859":5856,"5860":5856,"5861":5856,"5862":5856,"5863":5856,"5864":5856,"5865":5856,"5866":5856,"5867":5856,"5868":5856,"5869":5856,"5870":5856,"5871":5856,"5873":5872,"5874":5872,"5875":5872,"5876":5872,"5877":5872,"5878":5872,"5879":5872,"5880":5872,"5881":5872,"5882":5872,"5883":5872,"5884":5872,"5885":5872,"5886":5872,"5887":5872,"5889":5888,"5890":5888,"5891":5888,"5892":5888,"5893":5888,"5894":5888,"5895":5888,"5896":5888,"5897":5888,"5898":5888,"5899":5888,"5900":5888,"5901":5888,"5902":5888,"5903":5888,"5905":5904,"5906":5904,"5907":5904,"5908":5904,"5909":5904,"5910":5904,"5911":5904,"5912":5904,"5913":5904,"5914":5904,"5915":5904,"5916":5904,"5917":5904,"5918":5904,"5919":5904,"5921":5920,"5922":5920,"5923":5920,"5924":5920,"5925":5920,"5926":5920,"5927":5920,"5928":5920,"5929":5920,"5930":5920,"5931":5920,"5932":5920,"5933":5920,"5934":5920,"5935":5920,"5937":5936,"5938":5936,"5939":5936,"5940":5936,"5941":5936,"5942":5936,"5943":5936,"5944":5936,"5945":5936,"5946":5936,"5947":5936,"5948":5936,"5949":5936,"5950":5936,"5951":5936,"5953":5952,"5954":5952,"5955":5952,"5956":5952,"5957":5952,"5958":5952,"5959":5952,"5960":5952,"5961":5952,"5962":5952,"5963":5952,"5964":5952,"5965":5952,"5966":5952,"5967":5952,"5969":5968,"5970":5968,"5971":5968,"5972":5968,"5973":5968,"5974":5968,"5975":5968,"5976":5968,"5977":5968,"5978":5968,"5979":5968,"5980":5968,"5981":5968,"5982":5968,"5983":5968,"5985":5984,"5986":5984,"5987":5984,"5988":5984,"5989":5984,"5990":5984,"5991":5984,"5992":5984,"5993":5984,"5994":5984,"5995":5984,"5996":5984,"5997":5984,"5998":5984,"5999":5984,"6001":6000,"6002":6000,"6003":6000,"6004":6000,"6005":6000,"6006":6000,"6007":6000,"6008":6000,"6009":6000,"6010":6000,"6011":6000,"6012":6000,"6013":6000,"6014":6000,"6015":6000,"6017":6016,"6018":6016,"6019":6016,"6020":6016,"6021":6016,"6022":6016,"6023":6016,"6024":6016,"6025":6016,"6026":6016,"6027":6016,"6028":6016,"6029":6016,"6030":6016,"6031":6016,"6033":6032,"6034":6032,"6035":6032,"6036":6032,"6037":6032,"6038":6032,"6039":6032,"6040":6032,"6041":6032,"6042":6032,"6043":6032,"6044":6032,"6045":6032,"6046":6032,"6047":6032,"6049":6048,"6050":6048,"6051":6048,"6052":6048,"6053":6048,"6054":6048,"6055":6048,"6056":6048,"6057":6048,"6058":6048,"6059":6048,"6060":6048,"6061":6048,"6062":6048,"6063":6048,"6065":6064,"6066":6064,"6067":6064,"6068":6064,"6069":6064,"6070":6064,"6071":6064,"6072":6064,"6073":6064,"6074":6064,"6075":6064,"6076":6064,"6077":6064,"6078":6064,"6079":6064,"6081":6080,"6082":6080,"6083":6080,"6084":6080,"6085":6080,"6086":6080,"6087":6080,"6088":6080,"6089":6080,"6090":6080,"6091":6080,"6092":6080,"6093":6080,"6094":6080,"6095":6080,"6097":6096,"6098":6096,"6099":6096,"6100":6096,"6101":6096,"6102":6096,"6103":6096,"6104":6096,"6105":6096,"6106":6096,"6107":6096,"6108":6096,"6109":6096,"6110":6096,"6111":6096,"6113":6112,"6114":6112,"6115":6112,"6116":6112,"6117":6112,"6118":6112,"6119":6112,"6120":6112,"6121":6112,"6122":6112,"6123":6112,"6124":6112,"6125":6112,"6126":6112,"6127":6112,"6129":6128,"6130":6128,"6131":6128,"6132":6128,"6133":6128,"6134":6128,"6135":6128,"6136":6128,"6137":6128,"6138":6128,"6139":6128,"6140":6128,"6141":6128,"6142":6128,"6143":6128,"6145":6144,"6146":6144,"6147":6144,"6148":6144,"6149":6144,"6150":6144,"6151":6144,"6152":6144,"6153":6144,"6154":6144,"6155":6144,"6156":6144,"6157":6144,"6158":6144,"6159":6144,"6181":6176,"6182":6176,"6183":6176,"6184":6176,"6185":6176,"6186":6176,"6187":6176,"6188":6176,"6189":6176,"6190":6176,"6191":6176,"6197":6192,"6198":6192,"6199":6192,"6205":6192,"6206":6192,"6207":6192,"6213":6208,"6214":6208,"6215":6208,"6221":6208,"6222":6208,"6223":6208,"6229":6208,"6230":6208,"6231":6208,"6237":6208,"6238":6208,"6239":6208,"6273":6248,"6275":6248,"6277":6248,"6279":6248,"6281":6248,"6283":6248,"6285":6248,"6287":6248,"6305":6304,"6306":6304,"6307":6304,"6308":6304,"6309":6304,"6310":6304,"6311":6304,"6312":6304,"6313":6304,"6314":6304,"6315":6304,"6316":6304,"6317":6304,"6318":6304,"6319":6304,"6326":6320,"6327":6320,"6334":6320,"6335":6320,"6342":6336,"6343":6336,"6350":6336,"6351":6336,"6358":6352,"6359":6352,"6366":6352,"6367":6352,"6374":6368,"6375":6368,"6382":6368,"6383":6368,"6390":6384,"6391":6384,"6398":6384,"6399":6384,"6482":6480,"6483":6480,"6484":6480,"6485":6480,"6486":6480,"6487":6480,"6488":6480,"6489":6480,"6490":6480,"6491":6480,"6492":6480,"6493":6480,"6494":6480,"6495":6480,"6498":6496,"6499":6496,"6500":6496,"6501":6496,"6502":6496,"6503":6496,"6504":6496,"6505":6496,"6506":6496,"6507":6496,"6508":6496,"6509":6496,"6510":6496,"6511":6496,"6514":6512,"6515":6512,"6516":6512,"6517":6512,"6518":6512,"6519":6512,"6520":6512,"6521":6512,"6522":6512,"6523":6512,"6524":6512,"6525":6512,"6526":6512,"6527":6512,"6530":6528,"6531":6528,"6532":6528,"6533":6528,"6534":6528,"6535":6528,"6536":6528,"6537":6528,"6538":6528,"6539":6528,"6540":6528,"6541":6528,"6542":6528,"6543":6528,"6546":6544,"6547":6544,"6548":6544,"6549":6544,"6550":6544,"6551":6544,"6552":6544,"6553":6544,"6554":6544,"6555":6544,"6556":6544,"6557":6544,"6558":6544,"6559":6544,"6564":6562,"6565":6562,"6566":6562,"6567":6562,"6568":6562,"6569":6562,"6570":6562,"6571":6562,"6572":6562,"6573":6562,"6574":6562,"6575":6562,"6584":6580,"6585":6580,"6586":6580,"6587":6580,"6588":6580,"6589":6580,"6590":6580,"6591":6580,"6657":6656,"6658":6656,"6659":6656,"6660":6656,"6661":6656,"6662":6656,"6663":6656,"6664":6656,"6665":6656,"6666":6656,"6667":6656,"6668":6656,"6669":6656,"6670":6656,"6671":6656,"6694":6688,"6695":6688,"6702":6688,"6703":6688,"6705":6704,"6706":6704,"6707":6704,"6708":6704,"6709":6704,"6710":6704,"6711":6704,"6713":6704,"6714":6704,"6715":6704,"6716":6704,"6717":6704,"6718":6704,"6719":6704,"6760":6752,"6761":6753,"6762":6754,"6763":6755,"6764":6756,"6765":6757,"6766":6758,"6767":6759,"6776":6768,"6777":6769,"6778":6770,"6779":6771,"6780":6772,"6792":6787,"6793":6787,"6794":6787,"6795":6787,"6796":6787,"6797":6787,"6798":6787,"6799":6787,"6808":6803,"6809":6803,"6810":6803,"6811":6803,"6812":6803,"6813":6803,"6814":6803,"6815":6803,"6824":6819,"6825":6819,"6826":6819,"6827":6819,"6828":6819,"6829":6819,"6830":6819,"6831":6819,"6840":6835,"6841":6835,"6842":6835,"6843":6835,"6844":6835,"6845":6835,"6846":6835,"6847":6835,"6856":6851,"6857":6851,"6858":6851,"6859":6851,"6860":6851,"6861":6851,"6862":6851,"6863":6851,"6872":6867,"6873":6867,"6874":6867,"6875":6867,"6876":6867,"6877":6867,"6878":6867,"6879":6867,"6888":6883,"6889":6883,"6890":6883,"6891":6883,"6892":6883,"6893":6883,"6894":6883,"6895":6883,"6904":6899,"6905":6899,"6906":6899,"6907":6899,"6908":6899,"6909":6899,"6910":6899,"6911":6899,"6920":6915,"6921":6915,"6922":6915,"6923":6915,"6924":6915,"6925":6915,"6926":6915,"6927":6915,"6936":6931,"6937":6931,"6938":6931,"6939":6931,"6940":6931,"6941":6931,"6942":6931,"6943":6931,"6952":6947,"6953":6947,"6954":6947,"6955":6947,"6956":6947,"6957":6947,"6958":6947,"6959":6947,"6968":6963,"6969":6963,"6970":6963,"6971":6963,"6972":6963,"6973":6963,"6974":6963,"6975":6963,"6992":6994,"6993":6994,"6998":6994,"6999":6994,"7000":6994,"7001":6994,"7002":6994,"7003":6994,"7004":6994,"7005":6994,"7006":6994,"7007":6994,"7009":7008,"7010":7008,"7011":7008,"7012":7008,"7013":7008,"7014":7008,"7015":7008,"7016":7008,"7017":7008,"7018":7008,"7019":7008,"7020":7008,"7021":7008,"7022":7008,"7023":7008,"7032":7027,"7033":7027,"7034":7027,"7035":7027,"7036":7027,"7037":7027,"7038":7027,"7039":7027,"7048":7043,"7049":7043,"7050":7043,"7051":7043,"7052":7043,"7053":7043,"7054":7043,"7055":7043,"7072":7074,"7073":7074,"7078":7074,"7079":7074,"7080":7074,"7081":7074,"7082":7074,"7083":7074,"7084":7074,"7085":7074,"7086":7074,"7087":7074,"7104":7106,"7105":7106,"7110":7106,"7111":7106,"7112":7106,"7113":7106,"7114":7106,"7115":7106,"7116":7106,"7117":7106,"7118":7106,"7119":7106,"7136":7138,"7137":7138,"7142":7138,"7143":7138,"7144":7138,"7145":7138,"7146":7138,"7147":7138,"7148":7138,"7149":7138,"7150":7138,"7151":7138,"7168":7170,"7169":7170,"7174":7170,"7175":7170,"7176":7170,"7177":7170,"7178":7170,"7179":7170,"7180":7170,"7181":7170,"7182":7170,"7183":7170,"7192":7186,"7193":7186,"7194":7186,"7195":7186,"7196":7186,"7197":7186,"7198":7186,"7199":7186,"7216":7218,"7217":7218,"7222":7218,"7223":7218,"7224":7218,"7225":7218,"7226":7218,"7227":7218,"7228":7218,"7229":7218,"7230":7218,"7231":7218,"7248":7250,"7249":7250,"7254":7250,"7255":7250,"7256":7250,"7257":7250,"7258":7250,"7259":7250,"7260":7250,"7261":7250,"7262":7250,"7263":7250,"7264":7250,"7265":7250,"7270":7250,"7271":7250,"7272":7250,"7273":7250,"7274":7250,"7275":7250,"7276":7250,"7277":7250,"7278":7250,"7279":7250,"7297":7296,"7298":7296,"7299":7296,"7300":7296,"7301":7296,"7302":7296,"7303":7296,"7304":7296,"7305":7296,"7306":7296,"7307":7296,"7308":7296,"7309":7296,"7310":7296,"7311":7296,"7334":7328,"7335":7328,"7342":7328,"7343":7328,"7348":7346,"7349":7346,"7350":7346,"7351":7346,"7352":7346,"7353":7346,"7354":7346,"7355":7346,"7356":7346,"7357":7346,"7358":7346,"7359":7346,"7396":7392,"7397":7392,"7398":7392,"7399":7392,"7400":7392,"7401":7392,"7402":7392,"7403":7392,"7404":7392,"7405":7392,"7406":7392,"7407":7392,"7410":7408,"7411":7408,"7412":7408,"7413":7408,"7414":7408,"7415":7408,"7416":7408,"7417":7408,"7418":7408,"7419":7408,"7420":7408,"7421":7408,"7422":7408,"7423":7408,"7478":7472,"7479":7472,"7486":7472,"7487":7472,"7504":7218,"7505":7218,"7510":7218,"7511":7218,"7512":7218,"7513":7218,"7514":7218,"7515":7218,"7516":7218,"7517":7218,"7518":7218,"7519":7218}} \ No newline at end of file From d9deb571eda71f29e34ee47411097ff1b8a1bee2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 15 Jan 2022 22:26:56 +0000 Subject: [PATCH 631/710] Added LecternPlaceBookSound --- src/block/Lectern.php | 2 ++ src/world/sound/LecternPlaceBookSound.php | 35 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/world/sound/LecternPlaceBookSound.php diff --git a/src/block/Lectern.php b/src/block/Lectern.php index 11e9f2653..095824a16 100644 --- a/src/block/Lectern.php +++ b/src/block/Lectern.php @@ -33,6 +33,7 @@ use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; +use pocketmine\world\sound\LecternPlaceBookSound; class Lectern extends Transparent{ use FacesOppositePlacingPlayerTrait; @@ -122,6 +123,7 @@ class Lectern extends Transparent{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($this->book === null && $item instanceof WritableBookBase){ $this->position->getWorld()->setBlock($this->position, $this->setBook($item)); + $this->position->getWorld()->addSound($this->position, new LecternPlaceBookSound()); $item->pop(); } return true; diff --git a/src/world/sound/LecternPlaceBookSound.php b/src/world/sound/LecternPlaceBookSound.php new file mode 100644 index 000000000..f7cf5df7e --- /dev/null +++ b/src/world/sound/LecternPlaceBookSound.php @@ -0,0 +1,35 @@ + Date: Sat, 15 Jan 2022 22:27:06 +0000 Subject: [PATCH 632/710] fixed CS --- src/block/Lectern.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/block/Lectern.php b/src/block/Lectern.php index 095824a16..d56b73c63 100644 --- a/src/block/Lectern.php +++ b/src/block/Lectern.php @@ -34,6 +34,7 @@ use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\world\sound\LecternPlaceBookSound; +use function count; class Lectern extends Transparent{ use FacesOppositePlacingPlayerTrait; From 33421258b604bd8f9ec6b55168ccfc3329de8ffc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 16 Jan 2022 15:40:18 +0000 Subject: [PATCH 633/710] Silence MovePlayerPacket debug spam --- src/network/mcpe/handler/InGamePacketHandler.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index bed549378..de74046ee 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -73,6 +73,7 @@ use pocketmine\network\mcpe\protocol\MapInfoRequestPacket; use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket; use pocketmine\network\mcpe\protocol\MobEquipmentPacket; use pocketmine\network\mcpe\protocol\ModalFormResponsePacket; +use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket; use pocketmine\network\mcpe\protocol\PlayerActionPacket; use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket; @@ -174,6 +175,12 @@ class InGamePacketHandler extends PacketHandler{ return null; } + public function handleMovePlayer(MovePlayerPacket $packet) : bool{ + //The client sends this every time it lands on the ground, even when using PlayerAuthInputPacket. + //Silence the debug spam that this causes. + return true; + } + public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{ $rawPos = $packet->getPosition(); foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->getYaw(), $packet->getHeadYaw(), $packet->getPitch()] as $float){ From 853ecd2408821ba441fc05b6a59bea5fe1652383 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 16 Jan 2022 16:16:42 +0000 Subject: [PATCH 634/710] InGamePacketHandler: fix function ordering --- src/network/mcpe/handler/InGamePacketHandler.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index de74046ee..cd91f4f7f 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -166,6 +166,12 @@ class InGamePacketHandler extends PacketHandler{ return false; } + public function handleMovePlayer(MovePlayerPacket $packet) : bool{ + //The client sends this every time it lands on the ground, even when using PlayerAuthInputPacket. + //Silence the debug spam that this causes. + return true; + } + private function resolveOnOffInputFlags(PlayerAuthInputPacket $packet, int $startFlag, int $stopFlag) : ?bool{ $enabled = $packet->hasFlag($startFlag); if($enabled !== $packet->hasFlag($stopFlag)){ @@ -175,12 +181,6 @@ class InGamePacketHandler extends PacketHandler{ return null; } - public function handleMovePlayer(MovePlayerPacket $packet) : bool{ - //The client sends this every time it lands on the ground, even when using PlayerAuthInputPacket. - //Silence the debug spam that this causes. - return true; - } - public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{ $rawPos = $packet->getPosition(); foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->getYaw(), $packet->getHeadYaw(), $packet->getPitch()] as $float){ From 9f4fcfafdb11141a8bd063c716df120e33ac8ee0 Mon Sep 17 00:00:00 2001 From: Leo Lee Date: Mon, 17 Jan 2022 04:57:16 +0800 Subject: [PATCH 635/710] Fixed some incorrect block breaking times (#4723) --- src/block/BlockFactory.php | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index fd98293c5..1d651c96f 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -115,7 +115,14 @@ class BlockFactory{ $this->registerAllMeta(new ActivatorRail(new BID(Ids::ACTIVATOR_RAIL, 0), "Activator Rail", $railBreakInfo)); $this->registerAllMeta(new Air(new BID(Ids::AIR, 0), "Air", BlockBreakInfo::indestructible(-1.0))); $this->registerAllMeta(new Anvil(new BID(Ids::ANVIL, 0), "Anvil", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0))); - $this->registerAllMeta(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new BlockBreakInfo(2.0 /* 1.0 in PC */, BlockToolType::AXE))); + $this->registerAllMeta(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new class(2.0 /* 1.0 in PC */, BlockToolType::AXE) extends BlockBreakInfo{ + public function getBreakTime(Item $item) : float{ + if($item->getBlockToolType() === BlockToolType::SWORD){ + return 0.0; + } + return parent::getBreakTime($item); + } + })); $this->registerAllMeta(new BambooSapling(new BID(Ids::BAMBOO_SAPLING, 0), "Bamboo Sapling", BlockBreakInfo::instant())); $bannerBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE); @@ -270,7 +277,7 @@ class BlockFactory{ $this->registerAllMeta(new NetherPortal(new BID(Ids::PORTAL, 0), "Nether Portal", BlockBreakInfo::indestructible(0.0))); $this->registerAllMeta(new NetherQuartzOre(new BID(Ids::NETHER_QUARTZ_ORE, 0), "Nether Quartz Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); $this->registerAllMeta(new NetherReactor(new BID(Ids::NETHERREACTOR, 0), "Nether Reactor Core", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); - $this->registerAllMeta(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BlockBreakInfo(1.0))); + $this->registerAllMeta(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BlockBreakInfo(1.0, BlockToolType::HOE))); $this->registerAllMeta(new NetherWartPlant(new BID(Ids::NETHER_WART_PLANT, 0, ItemIds::NETHER_WART), "Nether Wart", BlockBreakInfo::instant())); $this->registerAllMeta(new Netherrack(new BID(Ids::NETHERRACK, 0), "Netherrack", new BlockBreakInfo(0.4, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); $this->registerAllMeta(new Note(new BID(Ids::NOTEBLOCK, 0, null, TileNote::class), "Note Block", new BlockBreakInfo(0.8, BlockToolType::AXE))); @@ -365,7 +372,7 @@ class BlockFactory{ $crackedStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CRACKED), "Cracked Stone Bricks", $stoneBreakInfo), $chiseledStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CHISELED), "Chiseled Stone Bricks", $stoneBreakInfo) ); - $infestedStoneBreakInfo = new BlockBreakInfo(0.75); + $infestedStoneBreakInfo = new BlockBreakInfo(0.75, BlockToolType::PICKAXE); $this->registerAllMeta( new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE), "Infested Stone", $infestedStoneBreakInfo, $stone), new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK), "Infested Stone Brick", $infestedStoneBreakInfo, $stoneBrick), @@ -441,7 +448,7 @@ class BlockFactory{ $this->registerAllMeta(new UnderwaterTorch(new BID(Ids::UNDERWATER_TORCH, 0), "Underwater Torch", BlockBreakInfo::instant())); $this->registerAllMeta(new Vine(new BID(Ids::VINE, 0), "Vines", new BlockBreakInfo(0.2, BlockToolType::AXE))); $this->registerAllMeta(new Water(new BIDFlattened(Ids::FLOWING_WATER, [Ids::STILL_WATER], 0), "Water", BlockBreakInfo::indestructible(500.0))); - $this->registerAllMeta(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", new BlockBreakInfo(0.6))); + $this->registerAllMeta(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", BlockBreakInfo::instant())); $weightedPressurePlateBreakInfo = new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()); $this->registerAllMeta(new WeightedPressurePlateHeavy(new BID(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Heavy", $weightedPressurePlateBreakInfo)); @@ -449,7 +456,14 @@ class BlockFactory{ $this->registerAllMeta(new Wheat(new BID(Ids::WHEAT_BLOCK, 0), "Wheat Block", BlockBreakInfo::instant())); $planksBreakInfo = new BlockBreakInfo(2.0, BlockToolType::AXE, 0, 15.0); - $leavesBreakInfo = new BlockBreakInfo(0.2, BlockToolType::SHEARS); + $leavesBreakInfo = new class(0.2, BlockToolType::HOE) extends BlockBreakInfo{ + public function getBreakTime(Item $item) : float{ + if($item->getBlockToolType() === BlockToolType::SHEARS){ + return 0.0; + } + return parent::getBreakTime($item); + } + }; $signBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE); $logBreakInfo = new BlockBreakInfo(2.0, BlockToolType::AXE); $woodenDoorBreakInfo = new BlockBreakInfo(3.0, BlockToolType::AXE, 0, 15.0); From b9b76eaed24c39d83952995fa583ee76229a8034 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 16 Jan 2022 22:11:50 +0000 Subject: [PATCH 636/710] Server: add notice about obsoletion --- src/pocketmine/Server.php | 5 +++++ src/pocketmine/lang/locale | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index f097ad243..48e598a8a 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1490,6 +1490,11 @@ class Server{ $this->getName(), (\pocketmine\IS_DEVELOPMENT_BUILD ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET ])); + + $this->logger->notice($this->getLanguage()->translateString("pocketmine.server.obsolete.warning1", ["3.x", "4.0"])); + $this->logger->notice($this->getLanguage()->translateString("pocketmine.server.obsolete.warning2", ["3.x", "2022-03-01"])); + $this->logger->notice($this->getLanguage()->translateString("pocketmine.server.obsolete.warning3", ["https://github.com/pmmp/PocketMine-MP/issues/4701"])); + $this->logger->info($this->getLanguage()->translateString("pocketmine.server.license", [$this->getName()])); Timings::init(); diff --git a/src/pocketmine/lang/locale b/src/pocketmine/lang/locale index c85a7b79f..ab3ac724e 160000 --- a/src/pocketmine/lang/locale +++ b/src/pocketmine/lang/locale @@ -1 +1 @@ -Subproject commit c85a7b79f35a3e4d55b85656dfd90be2864ebc8a +Subproject commit ab3ac724e8852dca5dbb1fabdee3bd5634ef8b32 From bac6a2a1ebf79192ae69102451163f110dda910d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 16 Jan 2022 22:12:51 +0000 Subject: [PATCH 637/710] cs: enable fully_qualified_strict_types rule --- .php-cs-fixer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 6fb364510..3ae16af6a 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -37,6 +37,7 @@ return (new PhpCsFixer\Config) ], 'declare_strict_types' => true, 'elseif' => true, + 'fully_qualified_strict_types' => true, 'global_namespace_import' => [ 'import_constants' => true, 'import_functions' => true, From 388622d55dde5ad6c6e052df5484834c7225e17a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jan 2022 20:46:38 +0000 Subject: [PATCH 638/710] Bump pocketmine/locale-data from 2.3.0 to 2.3.33 (#4735) Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.3.0 to 2.3.33. - [Release notes](https://github.com/pmmp/Language/releases) - [Commits](https://github.com/pmmp/Language/compare/2.3.0...2.3.33) --- updated-dependencies: - dependency-name: pocketmine/locale-data dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 392eff4ed..771a72cf9 100644 --- a/composer.lock +++ b/composer.lock @@ -535,16 +535,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.3.0", + "version": "2.3.33", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "a16e5899709387ff03db8bba7f903a15c7c0a9af" + "reference": "44998ca9c055f872a33e59cd4d2736d081ba84b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/a16e5899709387ff03db8bba7f903a15c7c0a9af", - "reference": "a16e5899709387ff03db8bba7f903a15c7c0a9af", + "url": "https://api.github.com/repos/pmmp/Language/zipball/44998ca9c055f872a33e59cd4d2736d081ba84b5", + "reference": "44998ca9c055f872a33e59cd4d2736d081ba84b5", "shasum": "" }, "type": "library", @@ -552,9 +552,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.3.0" + "source": "https://github.com/pmmp/Language/tree/2.3.33" }, - "time": "2022-01-04T00:42:11+00:00" + "time": "2022-01-16T22:08:04+00:00" }, { "name": "pocketmine/log", From 8da27ea0aa7c44438065b29ad85b08bdf68b4ade Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 18 Jan 2022 00:15:44 +0000 Subject: [PATCH 639/710] UnsafeForeachArrayOfStringRule: fixed outdated function name --- tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php b/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php index 952723278..9e6c799f1 100644 --- a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php +++ b/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php @@ -81,7 +81,7 @@ final class UnsafeForeachArrayOfStringRule implements Rule{ RuleErrorBuilder::message(sprintf( "Unsafe foreach on array with key type %s (they might be casted to int).", $iterableType->getIterableKeyType()->describe(VerbosityLevel::value()) - ))->tip("Use Utils::foreachWithStringKeys() for a safe Generator-based iterator.")->build() + ))->tip("Use Utils::stringifyKeys() for a safe Generator-based iterator.")->build() ]; } return []; From f1723acfd31913314855aeb67f01271af80d7f28 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 18 Jan 2022 00:23:29 +0000 Subject: [PATCH 640/710] UnsafeForeachArrayOfStringRule: use statically analysable function reference this will ensure that it get automatically updated during refactors. --- tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php b/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php index 9e6c799f1..269dcc48b 100644 --- a/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php +++ b/tests/phpstan/rules/UnsafeForeachArrayOfStringRule.php @@ -34,6 +34,7 @@ use PHPStan\Type\StringType; use PHPStan\Type\Type; use PHPStan\Type\TypeTraverser; use PHPStan\Type\VerbosityLevel; +use pocketmine\utils\Utils; use function sprintf; /** @@ -77,11 +78,12 @@ final class UnsafeForeachArrayOfStringRule implements Rule{ return $type; }); if($hasCastableKeyTypes && !$expectsIntKeyTypes){ + $func = \Closure::fromCallable([Utils::class, 'stringifyKeys']); return [ RuleErrorBuilder::message(sprintf( "Unsafe foreach on array with key type %s (they might be casted to int).", $iterableType->getIterableKeyType()->describe(VerbosityLevel::value()) - ))->tip("Use Utils::stringifyKeys() for a safe Generator-based iterator.")->build() + ))->tip(sprintf("Use %s() for a safe Generator-based iterator.", Utils::getNiceClosureName($func)))->build() ]; } return []; From 858024afb77b25bebb3b8823493b42275a9f3f10 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 18 Jan 2022 00:24:12 +0000 Subject: [PATCH 641/710] Remove useless docs noticed by php-cs-fixer 3.5 --- src/event/block/BlockBreakEvent.php | 2 -- src/inventory/Inventory.php | 4 ---- src/world/World.php | 2 -- 3 files changed, 8 deletions(-) diff --git a/src/event/block/BlockBreakEvent.php b/src/event/block/BlockBreakEvent.php index 2540ecec4..e11a71ebc 100644 --- a/src/event/block/BlockBreakEvent.php +++ b/src/event/block/BlockBreakEvent.php @@ -103,8 +103,6 @@ class BlockBreakEvent extends BlockEvent implements Cancellable{ /** * Variadic hack for easy array member type enforcement. - * - * @param Item ...$drops */ public function setDropsVariadic(Item ...$drops) : void{ $this->blockDrops = $drops; diff --git a/src/inventory/Inventory.php b/src/inventory/Inventory.php index b1fad3904..8eef250b1 100644 --- a/src/inventory/Inventory.php +++ b/src/inventory/Inventory.php @@ -52,8 +52,6 @@ interface Inventory{ * * Returns the Items that did not fit. * - * @param Item ...$slots - * * @return Item[] */ public function addItem(Item ...$slots) : array; @@ -72,8 +70,6 @@ interface Inventory{ * Removes the given Item from the inventory. * It will return the Items that couldn't be removed. * - * @param Item ...$slots - * * @return Item[] */ public function removeItem(Item ...$slots) : array; diff --git a/src/world/World.php b/src/world/World.php index be5e7c426..817b45730 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -755,8 +755,6 @@ class World implements ChunkManager{ /** * @internal - * - * @param Player ...$targets If empty, will send to all players in the world. */ public function sendTime(Player ...$targets) : void{ if(count($targets) === 0){ From 8cdfef78610c74ae076492b9a6b391521925fcfd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 19 Jan 2022 21:49:05 +0000 Subject: [PATCH 642/710] Added missing sound for creating grass path and farmland closes #2776 --- src/block/Dirt.php | 6 +++- src/block/Grass.php | 9 +++-- src/world/sound/ItemUseOnBlockSound.php | 48 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 src/world/sound/ItemUseOnBlockSound.php diff --git a/src/block/Dirt.php b/src/block/Dirt.php index 29df9f545..9264c0808 100644 --- a/src/block/Dirt.php +++ b/src/block/Dirt.php @@ -28,6 +28,7 @@ use pocketmine\item\Item; use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; +use pocketmine\world\sound\ItemUseOnBlockSound; class Dirt extends Opaque{ @@ -60,7 +61,10 @@ class Dirt extends Opaque{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($face === Facing::UP and $item instanceof Hoe){ $item->applyDamage(1); - $this->position->getWorld()->setBlock($this->position, $this->coarse ? VanillaBlocks::DIRT() : VanillaBlocks::FARMLAND()); + + $newBlock = $this->coarse ? VanillaBlocks::DIRT() : VanillaBlocks::FARMLAND(); + $this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock)); + $this->position->getWorld()->setBlock($this->position, $newBlock); return true; } diff --git a/src/block/Grass.php b/src/block/Grass.php index e6a128850..08565455f 100644 --- a/src/block/Grass.php +++ b/src/block/Grass.php @@ -33,6 +33,7 @@ use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\utils\Random; use pocketmine\world\generator\object\TallGrass as TallGrassObject; +use pocketmine\world\sound\ItemUseOnBlockSound; use function mt_rand; class Grass extends Opaque{ @@ -97,12 +98,16 @@ class Grass extends Opaque{ return true; }elseif($item instanceof Hoe){ $item->applyDamage(1); - $this->position->getWorld()->setBlock($this->position, VanillaBlocks::FARMLAND()); + $newBlock = VanillaBlocks::FARMLAND(); + $this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock)); + $this->position->getWorld()->setBlock($this->position, $newBlock); return true; }elseif($item instanceof Shovel and $this->getSide(Facing::UP)->getId() === BlockLegacyIds::AIR){ $item->applyDamage(1); - $this->position->getWorld()->setBlock($this->position, VanillaBlocks::GRASS_PATH()); + $newBlock = VanillaBlocks::GRASS_PATH(); + $this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock)); + $this->position->getWorld()->setBlock($this->position, $newBlock); return true; } diff --git a/src/world/sound/ItemUseOnBlockSound.php b/src/world/sound/ItemUseOnBlockSound.php new file mode 100644 index 000000000..cdebc2c64 --- /dev/null +++ b/src/world/sound/ItemUseOnBlockSound.php @@ -0,0 +1,48 @@ +block; } + + public function encode(Vector3 $pos) : array{ + return [LevelSoundEventPacket::nonActorSound( + LevelSoundEvent::ITEM_USE_ON, + $pos, + false, + RuntimeBlockMapping::getInstance()->toRuntimeId($this->block->getFullId()) + )]; + } +} From 088745cf3b9d2c98b1ca8000016e9102739e9ef4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 19 Jan 2022 22:08:06 +0000 Subject: [PATCH 643/710] Implemented ChestPairEvent closes #2829 --- src/block/Chest.php | 21 +++++++++------ src/event/block/ChestPairEvent.php | 42 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 src/event/block/ChestPairEvent.php diff --git a/src/block/Chest.php b/src/block/Chest.php index c89b3dde7..92cc44f9b 100644 --- a/src/block/Chest.php +++ b/src/block/Chest.php @@ -26,6 +26,7 @@ namespace pocketmine\block; use pocketmine\block\tile\Chest as TileChest; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait; +use pocketmine\event\block\ChestPairEvent; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -47,17 +48,21 @@ class Chest extends Transparent{ public function onPostPlace() : void{ $tile = $this->position->getWorld()->getTile($this->position); if($tile instanceof TileChest){ - foreach([ - Facing::rotateY($this->facing, true), - Facing::rotateY($this->facing, false) - ] as $side){ + foreach([false, true] as $clockwise){ + $side = Facing::rotateY($this->facing, $clockwise); $c = $this->getSide($side); if($c instanceof Chest and $c->isSameType($this) and $c->facing === $this->facing){ - $pair = $this->position->getWorld()->getTile($c->position); + $world = $this->position->getWorld(); + $pair = $world->getTile($c->position); if($pair instanceof TileChest and !$pair->isPaired()){ - $pair->pairWith($tile); - $tile->pairWith($pair); - break; + [$left, $right] = $clockwise ? [$c, $this] : [$this, $c]; + $ev = new ChestPairEvent($left, $right); + $ev->call(); + if(!$ev->isCancelled() && $world->getBlock($this->position)->isSameType($this) && $world->getBlock($c->position)->isSameType($c)){ + $pair->pairWith($tile); + $tile->pairWith($pair); + break; + } } } } diff --git a/src/event/block/ChestPairEvent.php b/src/event/block/ChestPairEvent.php new file mode 100644 index 000000000..5343edf6f --- /dev/null +++ b/src/event/block/ChestPairEvent.php @@ -0,0 +1,42 @@ +left; } + + public function getRight() : Chest{ return $this->right; } +} From a67aef04778b1ed74d008e2029f25c575d6e1521 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:10:37 +0000 Subject: [PATCH 644/710] PlayerInteractEvent: updated documentation --- src/event/player/PlayerInteractEvent.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/event/player/PlayerInteractEvent.php b/src/event/player/PlayerInteractEvent.php index f67b72d9c..b76a8226c 100644 --- a/src/event/player/PlayerInteractEvent.php +++ b/src/event/player/PlayerInteractEvent.php @@ -31,7 +31,8 @@ use pocketmine\math\Vector3; use pocketmine\player\Player; /** - * Called when a player interacts or touches a block (including air?) + * Called when a player interacts or touches a block. + * This is called for both left click (start break) and right click (use). */ class PlayerInteractEvent extends PlayerEvent implements Cancellable{ use CancellableTrait; From 061d851fbd12a51befe15ca38d8da77828d1efab Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:27:21 +0000 Subject: [PATCH 645/710] World: do not update entities which have been flagged for despawn fixes #4718 --- src/world/World.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/World.php b/src/world/World.php index 817b45730..8fff731dd 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -854,7 +854,7 @@ class World implements ChunkManager{ //Update entities that need update Timings::$tickEntity->startTiming(); foreach($this->updateEntities as $id => $entity){ - if($entity->isClosed() or !$entity->onUpdate($currentTick)){ + if($entity->isClosed() or $entity->isFlaggedForDespawn() or !$entity->onUpdate($currentTick)){ unset($this->updateEntities[$id]); } if($entity->isFlaggedForDespawn()){ From b60dd1e9b4edc8eba5bedb0ad07e1436093e9453 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:43:58 +0000 Subject: [PATCH 646/710] Ban 'and' and 'or' operators via PHPStan --- phpstan.neon.dist | 2 + .../rules/DisallowLogicalAndOperatorRule.php | 44 +++++++++++++++++++ .../rules/DisallowLogicalOrOperatorRule.php | 44 +++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 tests/phpstan/rules/DisallowLogicalAndOperatorRule.php create mode 100644 tests/phpstan/rules/DisallowLogicalOrOperatorRule.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 9ebc98502..0cc08a99d 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -12,6 +12,8 @@ includes: rules: - pocketmine\phpstan\rules\DisallowEnumComparisonRule + - pocketmine\phpstan\rules\DisallowLogicalAndOperatorRule + - pocketmine\phpstan\rules\DisallowLogicalOrOperatorRule - pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule # - pocketmine\phpstan\rules\ThreadedSupportedTypesRule diff --git a/tests/phpstan/rules/DisallowLogicalAndOperatorRule.php b/tests/phpstan/rules/DisallowLogicalAndOperatorRule.php new file mode 100644 index 000000000..49e6bbcc4 --- /dev/null +++ b/tests/phpstan/rules/DisallowLogicalAndOperatorRule.php @@ -0,0 +1,44 @@ + + */ +final class DisallowLogicalAndOperatorRule implements Rule{ + + public function getNodeType() : string{ + return LogicalAnd::class; + } + + public function processNode(Node $node, Scope $scope) : array{ + return [RuleErrorBuilder::message('Use of the "and" operator is discouraged. Use && instead.')->build()]; + } +} diff --git a/tests/phpstan/rules/DisallowLogicalOrOperatorRule.php b/tests/phpstan/rules/DisallowLogicalOrOperatorRule.php new file mode 100644 index 000000000..7aa43c706 --- /dev/null +++ b/tests/phpstan/rules/DisallowLogicalOrOperatorRule.php @@ -0,0 +1,44 @@ + + */ +final class DisallowLogicalOrOperatorRule implements Rule{ + + public function getNodeType() : string{ + return LogicalOr::class; + } + + public function processNode(Node $node, Scope $scope) : array{ + return [RuleErrorBuilder::message('Use of the "or" operator is discouraged. Use || instead.')->build()]; + } +} From 9c328690f8fc6ab5a84cad5f41e8d70e3a679b20 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:46:41 +0000 Subject: [PATCH 647/710] Baseline for new rules (for now) --- phpstan.neon.dist | 1 + tests/phpstan/configs/and-or-logical.neon | 1522 +++++++++++++++++++++ 2 files changed, 1523 insertions(+) create mode 100644 tests/phpstan/configs/and-or-logical.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 0cc08a99d..28e70f224 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,6 @@ includes: - tests/phpstan/configs/actual-problems.neon + - tests/phpstan/configs/and-or-logical.neon - tests/phpstan/configs/gc-hacks.neon - tests/phpstan/configs/impossible-generics.neon - tests/phpstan/configs/php-bugs.neon diff --git a/tests/phpstan/configs/and-or-logical.neon b/tests/phpstan/configs/and-or-logical.neon new file mode 100644 index 000000000..14b6e1c25 --- /dev/null +++ b/tests/phpstan/configs/and-or-logical.neon @@ -0,0 +1,1522 @@ +parameters: + ignoreErrors: + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../build/generate-registry-annotations.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 6 + path: ../../../src/MemoryManager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/MemoryManager.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/PocketMine.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 10 + path: ../../../src/Server.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 5 + path: ../../../src/Server.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Anvil.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Bamboo.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/block/BaseBanner.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/BaseRail.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/BaseRail.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 6 + path: ../../../src/block/Bed.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 4 + path: ../../../src/block/Block.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Block.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/BlockBreakInfo.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/BlockBreakInfo.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/block/BlockFactory.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/BlockFactory.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/BrewingStand.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Cactus.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/Cactus.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 4 + path: ../../../src/block/Chest.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Chest.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/CocoaBlock.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/Crops.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Dirt.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/block/Door.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Door.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 4 + path: ../../../src/block/DoublePlant.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/DoublePlant.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/DoubleTallGrass.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/DragonEgg.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/EndRod.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/EnderChest.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Fence.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 4 + path: ../../../src/block/Fence.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/FenceGate.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/FenceGate.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 6 + path: ../../../src/block/Fire.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/Fire.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Flower.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/FlowerPot.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 6 + path: ../../../src/block/FlowerPot.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/block/FrostedIce.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/FrostedIce.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/Furnace.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/Grass.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/block/Grass.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Gravel.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Ice.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/Ice.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/ItemFrame.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/block/ItemFrame.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Ladder.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Lantern.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/Lantern.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 4 + path: ../../../src/block/Leaves.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Leaves.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 9 + path: ../../../src/block/Liquid.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 6 + path: ../../../src/block/Liquid.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Magma.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/NetherPortal.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/NetherWartPlant.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/Note.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Pumpkin.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/RedstoneComparator.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Sand.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Sapling.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Sapling.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/SeaPickle.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/SeaPickle.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/ShulkerBox.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Skull.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 9 + path: ../../../src/block/Slab.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 5 + path: ../../../src/block/Slab.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/SnowLayer.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/block/SnowLayer.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/block/Stair.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/block/Stair.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Stem.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/Stem.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Sugarcane.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/block/Sugarcane.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/SweetBerryBush.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/TNT.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/TNT.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/TallGrass.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/block/Thin.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 5 + path: ../../../src/block/Torch.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/block/Torch.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Trapdoor.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/Trapdoor.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/Vine.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/Vine.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 8 + path: ../../../src/block/Wall.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/block/Wall.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/inventory/BarrelInventory.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/inventory/ChestInventory.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/inventory/DoubleChestInventory.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/inventory/EnderChestInventory.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/block/inventory/ShulkerBoxInventory.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/tile/Barrel.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/tile/BrewingStand.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 7 + path: ../../../src/block/tile/Chest.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/block/tile/Chest.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/tile/FlowerPot.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/tile/FlowerPot.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 10 + path: ../../../src/block/tile/Furnace.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/block/tile/Furnace.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/tile/Hopper.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/tile/ItemFrame.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/tile/Note.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/tile/Note.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/tile/ShulkerBox.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/block/tile/Skull.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/utils/BlockDataSerializer.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/utils/MinimumCostFlowCalculator.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/block/utils/SignText.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/command/Command.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/command/Command.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 6 + path: ../../../src/command/FormattedCommandAlias.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/command/PluginCommand.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/command/SimpleCommandMap.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/command/SimpleCommandMap.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/command/defaults/ClearCommand.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/command/defaults/EffectCommand.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/command/defaults/ListCommand.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/command/defaults/ParticleCommand.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/command/defaults/TimingsCommand.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/command/defaults/TimingsCommand.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/console/ConsoleCommandSender.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/crafting/CraftingGrid.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/crafting/ShapedRecipe.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 5 + path: ../../../src/crafting/ShapedRecipe.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/crafting/ShapelessRecipe.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/crash/CrashDump.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/data/bedrock/LegacyToStringBidirectionalIdMap.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/entity/Attribute.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 4 + path: ../../../src/entity/Attribute.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/entity/AttributeMap.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 29 + path: ../../../src/entity/Entity.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 19 + path: ../../../src/entity/Entity.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/entity/EntityDataHelper.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/entity/EntityDataHelper.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/entity/ExperienceManager.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 6 + path: ../../../src/entity/Human.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 4 + path: ../../../src/entity/HungerManager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/entity/HungerManager.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 9 + path: ../../../src/entity/Living.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 6 + path: ../../../src/entity/Living.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/entity/Location.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/entity/Skin.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/entity/Squid.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/entity/Villager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/entity/effect/EffectInstance.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/entity/effect/EffectManager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/entity/effect/EffectManager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/entity/effect/PoisonEffect.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 5 + path: ../../../src/entity/object/ExperienceOrb.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/entity/object/ExperienceOrb.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/entity/object/FallingBlock.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/entity/object/FallingBlock.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 7 + path: ../../../src/entity/object/ItemEntity.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/entity/object/ItemEntity.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/entity/object/Painting.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/entity/object/Painting.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/entity/object/PrimedTNT.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/entity/projectile/Arrow.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/entity/projectile/Arrow.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 7 + path: ../../../src/entity/projectile/Projectile.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/entity/projectile/SplashPotion.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/event/HandlerList.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/event/HandlerList.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/event/HandlerListManager.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/event/RegisteredListener.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 4 + path: ../../../src/inventory/BaseInventory.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/inventory/BaseInventory.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/inventory/PlayerInventory.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/inventory/transaction/CraftingTransaction.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/item/Armor.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/item/Bow.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/item/Bow.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/item/Bucket.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/item/ChorusFruit.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/item/ChorusFruit.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/item/Durable.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 7 + path: ../../../src/item/Item.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 6 + path: ../../../src/item/Item.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/item/ItemFactory.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/item/ItemFactory.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/item/ItemIdentifier.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/item/WrittenBook.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/item/enchantment/ProtectionEnchantment.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 5 + path: ../../../src/lang/Language.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 7 + path: ../../../src/lang/Language.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/network/Network.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/network/mcpe/InventoryManager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/network/mcpe/InventoryManager.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 6 + path: ../../../src/network/mcpe/NetworkSession.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 5 + path: ../../../src/network/mcpe/NetworkSession.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/network/mcpe/auth/ProcessLoginTask.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/network/mcpe/cache/ChunkCache.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/network/mcpe/compression/ZlibCompressor.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/network/mcpe/convert/ItemTranslator.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/network/mcpe/convert/TypeConverter.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 8 + path: ../../../src/network/mcpe/handler/InGamePacketHandler.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 4 + path: ../../../src/network/mcpe/handler/InGamePacketHandler.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/network/mcpe/handler/LoginPacketHandler.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/network/mcpe/handler/ResourcePacksPacketHandler.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/network/mcpe/raklib/RakLibInterface.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/network/mcpe/raklib/RakLibServer.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/network/query/QueryHandler.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/network/query/QueryInfo.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/permission/BanEntry.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/permission/PermissibleInternal.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/player/OfflinePlayer.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 51 + path: ../../../src/player/Player.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 15 + path: ../../../src/player/Player.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/player/SurvivalBlockBreakHandler.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/plugin/ApiVersion.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/plugin/PharPluginLoader.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/plugin/PluginBase.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/plugin/PluginBase.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/plugin/PluginDescription.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/plugin/PluginLoadabilityChecker.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/plugin/PluginLoadabilityChecker.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 4 + path: ../../../src/plugin/PluginManager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/plugin/PluginManager.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/plugin/ScriptPluginLoader.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/resourcepacks/ZippedResourcePack.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/resourcepacks/ZippedResourcePack.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/scheduler/AsyncPool.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/scheduler/AsyncPool.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/scheduler/AsyncTask.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/scheduler/AsyncTask.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/scheduler/Task.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/scheduler/TaskScheduler.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/thread/ThreadManager.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/updater/UpdateCheckTask.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/updater/UpdateChecker.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/utils/Config.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/utils/Config.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/utils/Filesystem.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/utils/Git.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/utils/Git.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 5 + path: ../../../src/utils/Internet.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/utils/MainLogger.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/utils/MainLogger.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/utils/Process.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/utils/Terminal.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/utils/Terminal.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 9 + path: ../../../src/utils/Timezone.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/utils/Utils.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 5 + path: ../../../src/utils/Utils.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/utils/VersionString.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 2 + path: ../../../src/wizard/SetupWizard.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 5 + path: ../../../src/world/Explosion.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/world/Position.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 5 + path: ../../../src/world/SimpleChunkManager.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 30 + path: ../../../src/world/World.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 17 + path: ../../../src/world/World.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 5 + path: ../../../src/world/WorldManager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/world/WorldManager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 4 + path: ../../../src/world/format/BiomeArray.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/world/format/Chunk.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/world/format/Chunk.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/world/format/HeightArray.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/world/format/io/WorldProviderManager.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 5 + path: ../../../src/world/format/io/leveldb/LevelDB.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/world/format/io/leveldb/LevelDB.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/world/format/io/region/RegionGarbageMap.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/world/format/io/region/RegionLoader.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 5 + path: ../../../src/world/format/io/region/RegionLoader.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/world/format/io/region/RegionLocationTableEntry.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/world/format/io/region/RegionLocationTableEntry.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/world/format/io/region/RegionWorldProvider.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/world/generator/Flat.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/world/generator/GeneratorManager.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/world/generator/hell/Nether.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 3 + path: ../../../src/world/generator/noise/Noise.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/world/generator/normal/Normal.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/world/generator/object/Ore.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/world/generator/object/SpruceTree.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/world/generator/object/TallGrass.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../../../src/world/generator/object/Tree.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 4 + path: ../../../src/world/generator/object/Tree.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/world/generator/populator/GroundCover.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 5 + path: ../../../src/world/generator/populator/TallGrass.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/world/generator/populator/TallGrass.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../src/world/generator/populator/Tree.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/world/generator/populator/Tree.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../src/world/light/LightUpdate.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/world/particle/DragonEggTeleportParticle.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../src/world/sound/NoteSound.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 4 + path: ../../../src/world/utils/SubChunkExplorer.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../tools/compact-regions.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../tools/compact-regions.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../../tools/convert-world.php + + - + message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" + count: 1 + path: ../../../tools/convert-world.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 3 + path: ../../../tools/ping-server.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../phpunit/item/ItemTest.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../phpunit/scheduler/AsyncPoolTest.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 1 + path: ../../plugins/TesterPlugin/src/Test.php + + - + message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" + count: 2 + path: ../rules/DisallowEnumComparisonRule.php + From 4d55935bd8a2f8a2ab1c00db0a988b112c02f635 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:48:06 +0000 Subject: [PATCH 648/710] Replace disallowed operators in tools/ --- tools/compact-regions.php | 4 ++-- tools/convert-world.php | 2 +- tools/ping-server.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/compact-regions.php b/tools/compact-regions.php index 62f1d35f4..f1091f101 100644 --- a/tools/compact-regions.php +++ b/tools/compact-regions.php @@ -62,12 +62,12 @@ function find_regions_recursive(string $dir, array &$files) : void{ return; } foreach($dirFiles as $file){ - if($file === "." or $file === ".."){ + if($file === "." || $file === ".."){ continue; } $fullPath = $dir . "/" . $file; if( - in_array(pathinfo($fullPath, PATHINFO_EXTENSION), SUPPORTED_EXTENSIONS, true) and + in_array(pathinfo($fullPath, PATHINFO_EXTENSION), SUPPORTED_EXTENSIONS, true) && is_file($fullPath) ){ $files[$fullPath] = filesize($fullPath); diff --git a/tools/convert-world.php b/tools/convert-world.php index 7d83d5fd8..bbe2ee9a7 100644 --- a/tools/convert-world.php +++ b/tools/convert-world.php @@ -59,7 +59,7 @@ if($inputPath === false){ exit(1); } $backupPath = realpath($args["backup"]); -if($backupPath === false || (!@mkdir($backupPath, 0777, true) and !is_dir($backupPath)) or !is_writable($backupPath)){ +if($backupPath === false || (!@mkdir($backupPath, 0777, true) && !is_dir($backupPath)) || !is_writable($backupPath)){ fwrite(STDERR, "Backup file path " . $args["backup"] . " is not writable (permission error or doesn't exist), aborting" . PHP_EOL); exit(1); } diff --git a/tools/ping-server.php b/tools/ping-server.php index ad2bd59ef..ae6f896c2 100644 --- a/tools/ping-server.php +++ b/tools/ping-server.php @@ -88,7 +88,7 @@ function ping_server(\Socket $socket, string $serverIp, int $serverPort, int $ti \GlobalLogger::get()->error("Error reading from socket: " . socket_strerror(socket_last_error($socket))); return false; } - if($recvAddr === $serverIp and $recvPort === $serverPort and $recvBuffer !== "" and ord($recvBuffer[0]) === MessageIdentifiers::ID_UNCONNECTED_PONG){ + if($recvAddr === $serverIp && $recvPort === $serverPort && $recvBuffer !== "" && ord($recvBuffer[0]) === MessageIdentifiers::ID_UNCONNECTED_PONG){ $pong = new UnconnectedPong(); $pong->decode(new PacketSerializer($recvBuffer)); \GlobalLogger::get()->info("--- Response received ---"); From 6846f1e78a70393d5f2d2e9f3db5c4b574ddf50d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:48:36 +0000 Subject: [PATCH 649/710] Replace disallowed operators in tests/ --- tests/phpstan/rules/DisallowEnumComparisonRule.php | 4 ++-- tests/phpunit/item/ItemTest.php | 2 +- tests/phpunit/scheduler/AsyncPoolTest.php | 2 +- tests/plugins/TesterPlugin/src/Test.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/phpstan/rules/DisallowEnumComparisonRule.php b/tests/phpstan/rules/DisallowEnumComparisonRule.php index 726c4cfbf..ec5ad3528 100644 --- a/tests/phpstan/rules/DisallowEnumComparisonRule.php +++ b/tests/phpstan/rules/DisallowEnumComparisonRule.php @@ -47,7 +47,7 @@ class DisallowEnumComparisonRule implements Rule{ } public function processNode(Node $node, Scope $scope) : array{ - if(!($node instanceof Identical) and !($node instanceof NotIdentical)){ + if(!($node instanceof Identical) && !($node instanceof NotIdentical)){ return []; } @@ -81,7 +81,7 @@ class DisallowEnumComparisonRule implements Rule{ continue; } $class = $containedType->getClassReflection(); - if($class !== null and $class->hasTraitUse(EnumTrait::class)){ + if($class !== null && $class->hasTraitUse(EnumTrait::class)){ return true; } } diff --git a/tests/phpunit/item/ItemTest.php b/tests/phpunit/item/ItemTest.php index 95aafd8a7..db29f14dc 100644 --- a/tests/phpunit/item/ItemTest.php +++ b/tests/phpunit/item/ItemTest.php @@ -99,7 +99,7 @@ class ItemTest extends TestCase{ } foreach($this->item->getEnchantments() as $enchantment){ foreach($enchantments as $k => $applied){ - if($enchantment->getType() === $applied->getType() and $enchantment->getLevel() === $applied->getLevel()){ + if($enchantment->getType() === $applied->getType() && $enchantment->getLevel() === $applied->getLevel()){ unset($enchantments[$k]); continue 2; } diff --git a/tests/phpunit/scheduler/AsyncPoolTest.php b/tests/phpunit/scheduler/AsyncPoolTest.php index e2aedfb93..878e99048 100644 --- a/tests/phpunit/scheduler/AsyncPoolTest.php +++ b/tests/phpunit/scheduler/AsyncPoolTest.php @@ -54,7 +54,7 @@ class AsyncPoolTest extends TestCase{ public function testTaskLeak() : void{ $start = microtime(true); $this->pool->submitTask(new LeakTestAsyncTask()); - while(!LeakTestAsyncTask::$destroyed and microtime(true) < $start + 30){ + while(!LeakTestAsyncTask::$destroyed && microtime(true) < $start + 30){ usleep(50 * 1000); $this->pool->collectTasks(); } diff --git a/tests/plugins/TesterPlugin/src/Test.php b/tests/plugins/TesterPlugin/src/Test.php index 7af551840..ce08c4a8d 100644 --- a/tests/plugins/TesterPlugin/src/Test.php +++ b/tests/plugins/TesterPlugin/src/Test.php @@ -72,7 +72,7 @@ abstract class Test{ } public function isTimedOut() : bool{ - return !$this->isFinished() and time() - $this->timeout > $this->startTime; + return !$this->isFinished() && time() - $this->timeout > $this->startTime; } protected function setTimeout(int $timeout) : void{ From 22bc3bc3f9b5055860b3808b74c7adbde277b886 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:49:04 +0000 Subject: [PATCH 650/710] Replace disallowed operators in src/console/ --- src/console/ConsoleCommandSender.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/console/ConsoleCommandSender.php b/src/console/ConsoleCommandSender.php index 45ae2f5ab..3879ab016 100644 --- a/src/console/ConsoleCommandSender.php +++ b/src/console/ConsoleCommandSender.php @@ -78,7 +78,7 @@ class ConsoleCommandSender implements CommandSender{ } public function setScreenLineHeight(?int $height) : void{ - if($height !== null and $height < 1){ + if($height !== null && $height < 1){ throw new \InvalidArgumentException("Line height must be at least 1"); } $this->lineHeight = $height; From 2f32bd877af48f24e07dfa6b27cd1e1c07c6f536 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:49:58 +0000 Subject: [PATCH 651/710] Replace disallowed operators in src/command/ --- src/command/Command.php | 6 +++--- src/command/FormattedCommandAlias.php | 12 ++++++------ src/command/PluginCommand.php | 2 +- src/command/SimpleCommandMap.php | 4 ++-- src/command/defaults/ClearCommand.php | 2 +- src/command/defaults/EffectCommand.php | 2 +- src/command/defaults/ListCommand.php | 2 +- src/command/defaults/ParticleCommand.php | 4 ++-- src/command/defaults/TimingsCommand.php | 4 ++-- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/command/Command.php b/src/command/Command.php index ea324a933..6b1d6ab33 100644 --- a/src/command/Command.php +++ b/src/command/Command.php @@ -127,7 +127,7 @@ abstract class Command{ public function testPermissionSilent(CommandSender $target, ?string $permission = null) : bool{ $permission ??= $this->permission; - if($permission === null or $permission === ""){ + if($permission === null || $permission === ""){ return true; } @@ -182,7 +182,7 @@ abstract class Command{ } private function allowChangesFrom(CommandMap $commandMap) : bool{ - return $this->commandMap === null or $this->commandMap === $commandMap; + return $this->commandMap === null || $this->commandMap === $commandMap; } public function isRegistered() : bool{ @@ -235,7 +235,7 @@ abstract class Command{ $result = KnownTranslationFactory::chat_type_admin($source->getName(), $message); $colored = $result->prefix(TextFormat::GRAY . TextFormat::ITALIC); - if($sendToSource and !($source instanceof ConsoleCommandSender)){ + if($sendToSource && !($source instanceof ConsoleCommandSender)){ $source->sendMessage($message); } diff --git a/src/command/FormattedCommandAlias.php b/src/command/FormattedCommandAlias.php index f6e11f5e5..968c10012 100644 --- a/src/command/FormattedCommandAlias.php +++ b/src/command/FormattedCommandAlias.php @@ -71,7 +71,7 @@ class FormattedCommandAlias extends Command{ $index = strpos($formatString, '$'); while($index !== false){ $start = $index; - if($index > 0 and $formatString[$start - 1] === "\\"){ + if($index > 0 && $formatString[$start - 1] === "\\"){ $formatString = substr($formatString, 0, $start - 1) . substr($formatString, $start); $index = strpos($formatString, '$', $index); continue; @@ -88,7 +88,7 @@ class FormattedCommandAlias extends Command{ $argStart = $index; - while($index < strlen($formatString) and self::inRange(ord($formatString[$index]) - 48, 0, 9)){ + while($index < strlen($formatString) && self::inRange(ord($formatString[$index]) - 48, 0, 9)){ ++$index; } @@ -106,19 +106,19 @@ class FormattedCommandAlias extends Command{ $rest = false; - if($index < strlen($formatString) and $formatString[$index] === "-"){ + if($index < strlen($formatString) && $formatString[$index] === "-"){ $rest = true; ++$index; } $end = $index; - if($required and $position >= count($args)){ + if($required && $position >= count($args)){ throw new \InvalidArgumentException("Missing required argument " . ($position + 1)); } $replacement = ""; - if($rest and $position < count($args)){ + if($rest && $position < count($args)){ for($i = $position, $c = count($args); $i < $c; ++$i){ if($i !== $position){ $replacement .= " "; @@ -141,6 +141,6 @@ class FormattedCommandAlias extends Command{ } private static function inRange(int $i, int $j, int $k) : bool{ - return $i >= $j and $i <= $k; + return $i >= $j && $i <= $k; } } diff --git a/src/command/PluginCommand.php b/src/command/PluginCommand.php index 2453f4025..634978006 100644 --- a/src/command/PluginCommand.php +++ b/src/command/PluginCommand.php @@ -53,7 +53,7 @@ final class PluginCommand extends Command implements PluginOwned{ $success = $this->executor->onCommand($sender, $this, $commandLabel, $args); - if(!$success and $this->usageMessage !== ""){ + if(!$success && $this->usageMessage !== ""){ throw new InvalidCommandSyntaxException(); } diff --git a/src/command/SimpleCommandMap.php b/src/command/SimpleCommandMap.php index 2d18972c5..116f59c23 100644 --- a/src/command/SimpleCommandMap.php +++ b/src/command/SimpleCommandMap.php @@ -183,11 +183,11 @@ class SimpleCommandMap implements CommandMap{ private function registerAlias(Command $command, bool $isAlias, string $fallbackPrefix, string $label) : bool{ $this->knownCommands[$fallbackPrefix . ":" . $label] = $command; - if(($command instanceof VanillaCommand or $isAlias) and isset($this->knownCommands[$label])){ + if(($command instanceof VanillaCommand || $isAlias) && isset($this->knownCommands[$label])){ return false; } - if(isset($this->knownCommands[$label]) and $this->knownCommands[$label]->getLabel() === $label){ + if(isset($this->knownCommands[$label]) && $this->knownCommands[$label]->getLabel() === $label){ return false; } diff --git a/src/command/defaults/ClearCommand.php b/src/command/defaults/ClearCommand.php index 472321135..237f3d108 100644 --- a/src/command/defaults/ClearCommand.php +++ b/src/command/defaults/ClearCommand.php @@ -105,7 +105,7 @@ class ClearCommand extends VanillaCommand{ ]; // Checking player's inventory for all the items matching the criteria - if($targetItem !== null and $maxCount === 0){ + if($targetItem !== null && $maxCount === 0){ $count = $this->countItems($inventories, $targetItem); if($count > 0){ $sender->sendMessage(KnownTranslationFactory::commands_clear_testing($target->getName(), (string) $count)); diff --git a/src/command/defaults/EffectCommand.php b/src/command/defaults/EffectCommand.php index 7b2541ea7..fe2db7d2d 100644 --- a/src/command/defaults/EffectCommand.php +++ b/src/command/defaults/EffectCommand.php @@ -96,7 +96,7 @@ class EffectCommand extends VanillaCommand{ $visible = true; if(count($args) >= 5){ $v = strtolower($args[4]); - if($v === "on" or $v === "true" or $v === "t" or $v === "1"){ + if($v === "on" || $v === "true" || $v === "t" || $v === "1"){ $visible = false; } } diff --git a/src/command/defaults/ListCommand.php b/src/command/defaults/ListCommand.php index a19130e3f..c451877ae 100644 --- a/src/command/defaults/ListCommand.php +++ b/src/command/defaults/ListCommand.php @@ -52,7 +52,7 @@ class ListCommand extends VanillaCommand{ $playerNames = array_map(function(Player $player) : string{ return $player->getName(); }, array_filter($sender->getServer()->getOnlinePlayers(), function(Player $player) use ($sender) : bool{ - return !($sender instanceof Player) or $sender->canSee($player); + return !($sender instanceof Player) || $sender->canSee($player); })); sort($playerNames, SORT_STRING); diff --git a/src/command/defaults/ParticleCommand.php b/src/command/defaults/ParticleCommand.php index ee7af129a..072ca9dc8 100644 --- a/src/command/defaults/ParticleCommand.php +++ b/src/command/defaults/ParticleCommand.php @@ -181,12 +181,12 @@ class ParticleCommand extends VanillaCommand{ case "slime": return new ItemBreakParticle(VanillaItems::SLIMEBALL()); case "itembreak": - if($data !== null and $data !== 0){ + if($data !== null && $data !== 0){ return new ItemBreakParticle(ItemFactory::getInstance()->get($data)); } break; case "terrain": - if($data !== null and $data !== 0){ + if($data !== null && $data !== 0){ return new TerrainParticle(BlockFactory::getInstance()->get($data, 0)); } break; diff --git a/src/command/defaults/TimingsCommand.php b/src/command/defaults/TimingsCommand.php index c894bb94f..13c95b5bd 100644 --- a/src/command/defaults/TimingsCommand.php +++ b/src/command/defaults/TimingsCommand.php @@ -103,7 +103,7 @@ class TimingsCommand extends VanillaCommand{ if($mode === "reset"){ TimingsHandler::reload(); Command::broadcastCommandMessage($sender, KnownTranslationFactory::pocketmine_command_timings_reset()); - }elseif($mode === "merged" or $mode === "report" or $paste){ + }elseif($mode === "merged" || $mode === "report" || $paste){ $timings = ""; if($paste){ $fileTimings = Utils::assumeNotFalse(fopen("php://temp", "r+b"), "Opening php://temp should never fail"); @@ -154,7 +154,7 @@ class TimingsCommand extends VanillaCommand{ )], function(array $results) use ($sender, $host) : void{ /** @phpstan-var array $results */ - if($sender instanceof Player and !$sender->isOnline()){ // TODO replace with a more generic API method for checking availability of CommandSender + if($sender instanceof Player && !$sender->isOnline()){ // TODO replace with a more generic API method for checking availability of CommandSender return; } $result = $results[0]; From 79d1feff9cca52704ce7b630c3c9eb4d03906a88 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:57:09 +0000 Subject: [PATCH 652/710] Replace disallowed operators in src/block/ --- src/block/Bamboo.php | 2 +- src/block/BaseBanner.php | 4 ++-- src/block/BaseRail.php | 6 ++--- src/block/Bed.php | 10 ++++---- src/block/Block.php | 10 ++++---- src/block/BlockBreakInfo.php | 4 ++-- src/block/BlockFactory.php | 8 +++---- src/block/BrewingStand.php | 2 +- src/block/Cactus.php | 4 ++-- src/block/Chest.php | 8 +++---- src/block/CocoaBlock.php | 2 +- src/block/Crops.php | 4 ++-- src/block/Dirt.php | 2 +- src/block/Door.php | 8 +++---- src/block/DoublePlant.php | 8 +++---- src/block/DoubleTallGrass.php | 2 +- src/block/EndRod.php | 4 ++-- src/block/EnderChest.php | 2 +- src/block/Fence.php | 6 ++--- src/block/FenceGate.php | 4 ++-- src/block/Fire.php | 12 +++++----- src/block/Flower.php | 2 +- src/block/FlowerPot.php | 14 +++++------ src/block/FrostedIce.php | 6 ++--- src/block/Furnace.php | 4 ++-- src/block/Grass.php | 10 ++++---- src/block/Ice.php | 2 +- src/block/ItemFrame.php | 6 ++--- src/block/Ladder.php | 2 +- src/block/Lantern.php | 4 ++-- src/block/Leaves.php | 10 ++++---- src/block/Liquid.php | 24 +++++++++---------- src/block/Magma.php | 2 +- src/block/NetherPortal.php | 2 +- src/block/NetherWartPlant.php | 2 +- src/block/Note.php | 2 +- src/block/Pumpkin.php | 2 +- src/block/RedstoneComparator.php | 2 +- src/block/Sapling.php | 4 ++-- src/block/SeaPickle.php | 4 ++-- src/block/ShulkerBox.php | 2 +- src/block/Skull.php | 2 +- src/block/Slab.php | 12 +++++----- src/block/SnowLayer.php | 2 +- src/block/Stair.php | 10 ++++---- src/block/Stem.php | 2 +- src/block/Sugarcane.php | 4 ++-- src/block/SweetBerryBush.php | 2 +- src/block/TNT.php | 4 ++-- src/block/TallGrass.php | 2 +- src/block/Thin.php | 6 ++--- src/block/Torch.php | 6 ++--- src/block/Trapdoor.php | 2 +- src/block/Vine.php | 4 ++-- src/block/Wall.php | 8 +++---- .../inventory/AnimatedBlockInventoryTrait.php | 4 ++-- src/block/tile/Chest.php | 16 ++++++------- src/block/tile/ContainerTrait.php | 2 +- src/block/tile/FlowerPot.php | 4 ++-- src/block/tile/Furnace.php | 12 +++++----- src/block/tile/ItemFrame.php | 2 +- src/block/tile/Note.php | 4 ++-- src/block/tile/Skull.php | 2 +- src/block/utils/BlockDataSerializer.php | 2 +- src/block/utils/FallableTrait.php | 2 +- src/block/utils/MinimumCostFlowCalculator.php | 2 +- src/block/utils/SignText.php | 2 +- 67 files changed, 169 insertions(+), 169 deletions(-) diff --git a/src/block/Bamboo.php b/src/block/Bamboo.php index 08817d12d..7fdf226a0 100644 --- a/src/block/Bamboo.php +++ b/src/block/Bamboo.php @@ -160,7 +160,7 @@ class Bamboo extends Transparent{ public function onNearbyBlockChange() : void{ $below = $this->position->getWorld()->getBlock($this->position->down()); - if(!$this->canBeSupportedBy($below) and !$below->isSameType($this)){ + if(!$this->canBeSupportedBy($below) && !$below->isSameType($this)){ $this->position->getWorld()->useBreakOn($this->position); } } diff --git a/src/block/BaseBanner.php b/src/block/BaseBanner.php index 0f7d55ae5..64e767897 100644 --- a/src/block/BaseBanner.php +++ b/src/block/BaseBanner.php @@ -130,7 +130,7 @@ abstract class BaseBanner extends Transparent{ public function getDropsForCompatibleTool(Item $item) : array{ $drop = $this->asItem(); - if($drop instanceof ItemBanner and count($this->patterns) > 0){ + if($drop instanceof ItemBanner && count($this->patterns) > 0){ $drop->setPatterns($this->patterns); } @@ -139,7 +139,7 @@ abstract class BaseBanner extends Transparent{ public function getPickedItem(bool $addUserData = false) : Item{ $result = $this->asItem(); - if($addUserData and $result instanceof ItemBanner and count($this->patterns) > 0){ + if($addUserData && $result instanceof ItemBanner && count($this->patterns) > 0){ $result->setPatterns($this->patterns); } return $result; diff --git a/src/block/BaseRail.php b/src/block/BaseRail.php index bf117cd7c..0344cdba8 100644 --- a/src/block/BaseRail.php +++ b/src/block/BaseRail.php @@ -101,7 +101,7 @@ abstract class BaseRail extends Flowable{ } if( - $other instanceof BaseRail and + $other instanceof BaseRail && in_array($otherConnection, $other->getCurrentShapeConnections(), true) ){ $connections[] = $connection; @@ -179,7 +179,7 @@ abstract class BaseRail extends Flowable{ $otherSide |= RailConnectionInfo::FLAG_ASCEND; } - if(!($other instanceof BaseRail) or count($otherConnections = $other->getConnectedDirections()) >= 2){ + if(!($other instanceof BaseRail) || count($otherConnections = $other->getConnectedDirections()) >= 2){ //we can only connect to a rail that has less than 2 connections continue; } @@ -224,7 +224,7 @@ abstract class BaseRail extends Flowable{ $this->position->getWorld()->useBreakOn($this->position); }else{ foreach($this->getCurrentShapeConnections() as $connection){ - if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 and $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->isTransparent()){ + if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->isTransparent()){ $this->position->getWorld()->useBreakOn($this->position); break; } diff --git a/src/block/Bed.php b/src/block/Bed.php index 731cf664e..fd566bca3 100644 --- a/src/block/Bed.php +++ b/src/block/Bed.php @@ -120,7 +120,7 @@ class Bed extends Transparent{ public function getOtherHalf() : ?Bed{ $other = $this->getSide($this->getOtherHalfSide()); - if($other instanceof Bed and $other->head !== $this->head and $other->facing === $this->facing){ + if($other instanceof Bed && $other->head !== $this->head && $other->facing === $this->facing){ return $other; } @@ -135,14 +135,14 @@ class Bed extends Transparent{ $player->sendMessage(TextFormat::GRAY . "This bed is incomplete"); return true; - }elseif($playerPos->distanceSquared($this->position) > 4 and $playerPos->distanceSquared($other->position) > 4){ + }elseif($playerPos->distanceSquared($this->position) > 4 && $playerPos->distanceSquared($other->position) > 4){ $player->sendMessage(KnownTranslationFactory::tile_bed_tooFar()->prefix(TextFormat::GRAY)); return true; } $time = $this->position->getWorld()->getTimeOfDay(); - $isNight = ($time >= World::TIME_NIGHT and $time < World::TIME_SUNRISE); + $isNight = ($time >= World::TIME_NIGHT && $time < World::TIME_SUNRISE); if(!$isNight){ $player->sendMessage(KnownTranslationFactory::tile_bed_noSleep()->prefix(TextFormat::GRAY)); @@ -166,7 +166,7 @@ class Bed extends Transparent{ } public function onNearbyBlockChange() : void{ - if(($other = $this->getOtherHalf()) !== null and $other->occupied !== $this->occupied){ + if(($other = $this->getOtherHalf()) !== null && $other->occupied !== $this->occupied){ $this->occupied = $other->occupied; $this->position->getWorld()->setBlock($this->position, $this); } @@ -186,7 +186,7 @@ class Bed extends Transparent{ $this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH; $next = $this->getSide($this->getOtherHalfSide()); - if($next->canBeReplaced() and !$next->getSide(Facing::DOWN)->isTransparent()){ + if($next->canBeReplaced() && !$next->getSide(Facing::DOWN)->isTransparent()){ $nextState = clone $this; $nextState->head = true; $tx->addBlock($blockReplace->position, $this)->addBlock($next->position, $nextState); diff --git a/src/block/Block.php b/src/block/Block.php index d49206f6c..ef2ba2b81 100644 --- a/src/block/Block.php +++ b/src/block/Block.php @@ -148,14 +148,14 @@ class Block{ $tileType = $this->idInfo->getTileClass(); $oldTile = $this->position->getWorld()->getTile($this->position); if($oldTile !== null){ - if($tileType === null or !($oldTile instanceof $tileType)){ + if($tileType === null || !($oldTile instanceof $tileType)){ $oldTile->close(); $oldTile = null; }elseif($oldTile instanceof Spawnable){ $oldTile->setDirty(); //destroy old network cache } } - if($oldTile === null and $tileType !== null){ + if($oldTile === null && $tileType !== null){ /** * @var Tile $tile * @see Tile::__construct() @@ -361,7 +361,7 @@ class Block{ */ public function getDrops(Item $item) : array{ if($this->breakInfo->isToolCompatible($item)){ - if($this->isAffectedBySilkTouch() and $item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){ + if($this->isAffectedBySilkTouch() && $item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){ return $this->getSilkTouchDrops($item); } @@ -402,7 +402,7 @@ class Block{ * Returns how much XP will be dropped by breaking this block with the given item. */ public function getXpDropForTool(Item $item) : int{ - if($item->hasEnchantment(VanillaEnchantments::SILK_TOUCH()) or !$this->breakInfo->isToolCompatible($item)){ + if($item->hasEnchantment(VanillaEnchantments::SILK_TOUCH()) || !$this->breakInfo->isToolCompatible($item)){ return 0; } @@ -613,7 +613,7 @@ class Block{ public function isFullCube() : bool{ $bb = $this->getCollisionBoxes(); - return count($bb) === 1 and $bb[0]->getAverageEdgeLength() >= 1 and $bb[0]->isCube(); + return count($bb) === 1 && $bb[0]->getAverageEdgeLength() >= 1 && $bb[0]->isCube(); } public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{ diff --git a/src/block/BlockBreakInfo.php b/src/block/BlockBreakInfo.php index 0290b02ab..184195aee 100644 --- a/src/block/BlockBreakInfo.php +++ b/src/block/BlockBreakInfo.php @@ -119,8 +119,8 @@ class BlockBreakInfo{ return false; } - return $this->toolType === BlockToolType::NONE or $this->toolHarvestLevel === 0 or ( - ($this->toolType & $tool->getBlockToolType()) !== 0 and $tool->getBlockToolHarvestLevel() >= $this->toolHarvestLevel); + return $this->toolType === BlockToolType::NONE || $this->toolHarvestLevel === 0 || ( + ($this->toolType & $tool->getBlockToolType()) !== 0 && $tool->getBlockToolHarvestLevel() >= $this->toolHarvestLevel); } /** diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index 5a6f2ce50..914e1edca 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -974,7 +974,7 @@ class BlockFactory{ } foreach($block->getIdInfo()->getAllBlockIds() as $id){ - if(!$override and $this->isRegistered($id, $variant)){ + if(!$override && $this->isRegistered($id, $variant)){ throw new \InvalidArgumentException("Block registration $id:$variant conflicts with an existing block"); } @@ -983,7 +983,7 @@ class BlockFactory{ continue; } - if(!$override and $this->isRegistered($id, $m)){ + if(!$override && $this->isRegistered($id, $m)){ throw new \InvalidArgumentException("Block registration " . get_class($block) . " has states which conflict with other blocks"); } @@ -1036,7 +1036,7 @@ class BlockFactory{ * Deserializes a block from the provided legacy ID and legacy meta. */ public function get(int $id, int $meta) : Block{ - if($meta < 0 or $meta >= (1 << Block::INTERNAL_METADATA_BITS)){ + if($meta < 0 || $meta >= (1 << Block::INTERNAL_METADATA_BITS)){ throw new \InvalidArgumentException("Block meta value $meta is out of bounds"); } @@ -1062,7 +1062,7 @@ class BlockFactory{ */ public function isRegistered(int $id, int $meta = 0) : bool{ $b = $this->fullList[($id << Block::INTERNAL_METADATA_BITS) | $meta]; - return $b !== null and !($b instanceof UnknownBlock); + return $b !== null && !($b instanceof UnknownBlock); } /** diff --git a/src/block/BrewingStand.php b/src/block/BrewingStand.php index 87f8d3c1f..e0366b7d3 100644 --- a/src/block/BrewingStand.php +++ b/src/block/BrewingStand.php @@ -116,7 +116,7 @@ class BrewingStand extends Transparent{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($player instanceof Player){ $stand = $this->position->getWorld()->getTile($this->position); - if($stand instanceof TileBrewingStand and $stand->canOpenWith($item->getCustomName())){ + if($stand instanceof TileBrewingStand && $stand->canOpenWith($item->getCustomName())){ $player->setCurrentWindow($stand->getInventory()); } } diff --git a/src/block/Cactus.php b/src/block/Cactus.php index 56ee7017f..2802c4966 100644 --- a/src/block/Cactus.php +++ b/src/block/Cactus.php @@ -82,7 +82,7 @@ class Cactus extends Transparent{ public function onNearbyBlockChange() : void{ $down = $this->getSide(Facing::DOWN); - if($down->getId() !== BlockLegacyIds::SAND and !$down->isSameType($this)){ + if($down->getId() !== BlockLegacyIds::SAND && !$down->isSameType($this)){ $this->position->getWorld()->useBreakOn($this->position); }else{ foreach(Facing::HORIZONTAL as $side){ @@ -129,7 +129,7 @@ class Cactus extends Transparent{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $down = $this->getSide(Facing::DOWN); - if($down->getId() === BlockLegacyIds::SAND or $down->isSameType($this)){ + if($down->getId() === BlockLegacyIds::SAND || $down->isSameType($this)){ foreach(Facing::HORIZONTAL as $side){ if($this->getSide($side)->isSolid()){ return false; diff --git a/src/block/Chest.php b/src/block/Chest.php index 92cc44f9b..c270246e5 100644 --- a/src/block/Chest.php +++ b/src/block/Chest.php @@ -51,10 +51,10 @@ class Chest extends Transparent{ foreach([false, true] as $clockwise){ $side = Facing::rotateY($this->facing, $clockwise); $c = $this->getSide($side); - if($c instanceof Chest and $c->isSameType($this) and $c->facing === $this->facing){ + if($c instanceof Chest && $c->isSameType($this) && $c->facing === $this->facing){ $world = $this->position->getWorld(); $pair = $world->getTile($c->position); - if($pair instanceof TileChest and !$pair->isPaired()){ + if($pair instanceof TileChest && !$pair->isPaired()){ [$left, $right] = $clockwise ? [$c, $this] : [$this, $c]; $ev = new ChestPairEvent($left, $right); $ev->call(); @@ -75,8 +75,8 @@ class Chest extends Transparent{ $chest = $this->position->getWorld()->getTile($this->position); if($chest instanceof TileChest){ if( - !$this->getSide(Facing::UP)->isTransparent() or - (($pair = $chest->getPair()) !== null and !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) or + !$this->getSide(Facing::UP)->isTransparent() || + (($pair = $chest->getPair()) !== null && !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) || !$chest->canOpenWith($item->getCustomName()) ){ return true; diff --git a/src/block/CocoaBlock.php b/src/block/CocoaBlock.php index efcc4590f..ef19356e8 100644 --- a/src/block/CocoaBlock.php +++ b/src/block/CocoaBlock.php @@ -86,7 +86,7 @@ class CocoaBlock extends Transparent{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(Facing::axis($face) !== Axis::Y and $this->canAttachTo($blockClicked)){ + if(Facing::axis($face) !== Axis::Y && $this->canAttachTo($blockClicked)){ $this->facing = $face; return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } diff --git a/src/block/Crops.php b/src/block/Crops.php index c7f201b41..054fed254 100644 --- a/src/block/Crops.php +++ b/src/block/Crops.php @@ -69,7 +69,7 @@ abstract class Crops extends Flowable{ } public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($this->age < 7 and $item instanceof Fertilizer){ + if($this->age < 7 && $item instanceof Fertilizer){ $block = clone $this; $block->age += mt_rand(2, 5); if($block->age > 7){ @@ -100,7 +100,7 @@ abstract class Crops extends Flowable{ } public function onRandomTick() : void{ - if($this->age < 7 and mt_rand(0, 2) === 1){ + if($this->age < 7 && mt_rand(0, 2) === 1){ $block = clone $this; ++$block->age; $ev = new BlockGrowEvent($this, $block); diff --git a/src/block/Dirt.php b/src/block/Dirt.php index 9264c0808..390098216 100644 --- a/src/block/Dirt.php +++ b/src/block/Dirt.php @@ -59,7 +59,7 @@ class Dirt extends Opaque{ } public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($face === Facing::UP and $item instanceof Hoe){ + if($face === Facing::UP && $item instanceof Hoe){ $item->applyDamage(1); $newBlock = $this->coarse ? VanillaBlocks::DIRT() : VanillaBlocks::FARMLAND(); diff --git a/src/block/Door.php b/src/block/Door.php index 74a9f1b78..a52e51d9d 100644 --- a/src/block/Door.php +++ b/src/block/Door.php @@ -72,7 +72,7 @@ class Door extends Transparent{ //copy door properties from other half $other = $this->getSide($this->top ? Facing::DOWN : Facing::UP); - if($other instanceof Door and $other->isSameType($this)){ + if($other instanceof Door && $other->isSameType($this)){ if($this->top){ $this->facing = $other->facing; $this->open = $other->open; @@ -129,7 +129,7 @@ class Door extends Transparent{ if($face === Facing::UP){ $blockUp = $this->getSide(Facing::UP); $blockDown = $this->getSide(Facing::DOWN); - if(!$blockUp->canBeReplaced() or $blockDown->isTransparent()){ + if(!$blockUp->canBeReplaced() || $blockDown->isTransparent()){ return false; } @@ -140,7 +140,7 @@ class Door extends Transparent{ $next = $this->getSide(Facing::rotateY($this->facing, false)); $next2 = $this->getSide(Facing::rotateY($this->facing, true)); - if($next->isSameType($this) or (!$next2->isTransparent() and $next->isTransparent())){ //Door hinge + if($next->isSameType($this) || (!$next2->isTransparent() && $next->isTransparent())){ //Door hinge $this->hingeRight = true; } @@ -158,7 +158,7 @@ class Door extends Transparent{ $this->open = !$this->open; $other = $this->getSide($this->top ? Facing::DOWN : Facing::UP); - if($other instanceof Door and $other->isSameType($this)){ + if($other instanceof Door && $other->isSameType($this)){ $other->open = $this->open; $this->position->getWorld()->setBlock($other->position, $other); } diff --git a/src/block/DoublePlant.php b/src/block/DoublePlant.php index 00d361832..155a8e59d 100644 --- a/src/block/DoublePlant.php +++ b/src/block/DoublePlant.php @@ -55,7 +55,7 @@ class DoublePlant extends Flowable{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $id = $blockReplace->getSide(Facing::DOWN)->getId(); - if(($id === BlockLegacyIds::GRASS or $id === BlockLegacyIds::DIRT) and $blockReplace->getSide(Facing::UP)->canBeReplaced()){ + if(($id === BlockLegacyIds::GRASS || $id === BlockLegacyIds::DIRT) && $blockReplace->getSide(Facing::UP)->canBeReplaced()){ $top = clone $this; $top->top = true; $tx->addBlock($blockReplace->position, $this)->addBlock($blockReplace->position->getSide(Facing::UP), $top); @@ -72,14 +72,14 @@ class DoublePlant extends Flowable{ $other = $this->getSide($this->top ? Facing::DOWN : Facing::UP); return ( - $other instanceof DoublePlant and - $other->isSameType($this) and + $other instanceof DoublePlant && + $other->isSameType($this) && $other->top !== $this->top ); } public function onNearbyBlockChange() : void{ - if(!$this->isValidHalfPlant() or (!$this->top and $this->getSide(Facing::DOWN)->isTransparent())){ + if(!$this->isValidHalfPlant() || (!$this->top && $this->getSide(Facing::DOWN)->isTransparent())){ $this->position->getWorld()->useBreakOn($this->position); } } diff --git a/src/block/DoubleTallGrass.php b/src/block/DoubleTallGrass.php index 6fee40e32..f3d98b265 100644 --- a/src/block/DoubleTallGrass.php +++ b/src/block/DoubleTallGrass.php @@ -34,7 +34,7 @@ class DoubleTallGrass extends DoublePlant{ } public function getDropsForIncompatibleTool(Item $item) : array{ - if($this->top and mt_rand(0, 7) === 0){ + if($this->top && mt_rand(0, 7) === 0){ return [VanillaItems::WHEAT_SEEDS()]; } return []; diff --git a/src/block/EndRod.php b/src/block/EndRod.php index 39c28a097..18fd438b5 100644 --- a/src/block/EndRod.php +++ b/src/block/EndRod.php @@ -46,7 +46,7 @@ class EndRod extends Flowable{ } public function readStateFromData(int $id, int $stateMeta) : void{ - if($stateMeta !== 0 and $stateMeta !== 1){ + if($stateMeta !== 0 && $stateMeta !== 1){ $stateMeta ^= 1; } @@ -59,7 +59,7 @@ class EndRod extends Flowable{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $this->facing = $face; - if($blockClicked instanceof EndRod and $blockClicked->facing === $this->facing){ + if($blockClicked instanceof EndRod && $blockClicked->facing === $this->facing){ $this->facing = Facing::opposite($face); } diff --git a/src/block/EnderChest.php b/src/block/EnderChest.php index e37632008..54dba5277 100644 --- a/src/block/EnderChest.php +++ b/src/block/EnderChest.php @@ -52,7 +52,7 @@ class EnderChest extends Transparent{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($player instanceof Player){ $enderChest = $this->position->getWorld()->getTile($this->position); - if($enderChest instanceof TileEnderChest and $this->getSide(Facing::UP)->isTransparent()){ + if($enderChest instanceof TileEnderChest && $this->getSide(Facing::UP)->isTransparent()){ $enderChest->setViewerCount($enderChest->getViewerCount() + 1); $player->setCurrentWindow(new EnderChestInventory($this->position, $player->getEnderInventory())); } diff --git a/src/block/Fence.php b/src/block/Fence.php index 0ee3cdaf1..cbcdd62e9 100644 --- a/src/block/Fence.php +++ b/src/block/Fence.php @@ -41,7 +41,7 @@ class Fence extends Transparent{ foreach(Facing::HORIZONTAL as $facing){ $block = $this->getSide($facing); - if($block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent())){ + if($block instanceof static || $block instanceof FenceGate || ($block->isSolid() && !$block->isTransparent())){ $this->connections[$facing] = true; }else{ unset($this->connections[$facing]); @@ -61,7 +61,7 @@ class Fence extends Transparent{ $connectWest = isset($this->connections[Facing::WEST]); $connectEast = isset($this->connections[Facing::EAST]); - if($connectWest or $connectEast){ + if($connectWest || $connectEast){ //X axis (west/east) $bbs[] = AxisAlignedBB::one() ->squash(Axis::Z, $inset) @@ -73,7 +73,7 @@ class Fence extends Transparent{ $connectNorth = isset($this->connections[Facing::NORTH]); $connectSouth = isset($this->connections[Facing::SOUTH]); - if($connectNorth or $connectSouth){ + if($connectNorth || $connectSouth){ //Z axis (north/south) $bbs[] = AxisAlignedBB::one() ->squash(Axis::X, $inset) diff --git a/src/block/FenceGate.php b/src/block/FenceGate.php index 32d79eba3..4255ee5ef 100644 --- a/src/block/FenceGate.php +++ b/src/block/FenceGate.php @@ -80,7 +80,7 @@ class FenceGate extends Transparent{ private function checkInWall() : bool{ return ( - $this->getSide(Facing::rotateY($this->facing, false)) instanceof Wall or + $this->getSide(Facing::rotateY($this->facing, false)) instanceof Wall || $this->getSide(Facing::rotateY($this->facing, true)) instanceof Wall ); } @@ -105,7 +105,7 @@ class FenceGate extends Transparent{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $this->open = !$this->open; - if($this->open and $player !== null){ + if($this->open && $player !== null){ $playerFacing = $player->getHorizontalFacing(); if($playerFacing === Facing::opposite($this->facing)){ $this->facing = $playerFacing; diff --git a/src/block/Fire.php b/src/block/Fire.php index adf6209a3..1b73882b0 100644 --- a/src/block/Fire.php +++ b/src/block/Fire.php @@ -99,7 +99,7 @@ class Fire extends Flowable{ } public function onNearbyBlockChange() : void{ - if(!$this->getSide(Facing::DOWN)->isSolid() and !$this->hasAdjacentFlammableBlocks()){ + if(!$this->getSide(Facing::DOWN)->isSolid() && !$this->hasAdjacentFlammableBlocks()){ $this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR()); }else{ $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(30, 40)); @@ -114,7 +114,7 @@ class Fire extends Flowable{ $down = $this->getSide(Facing::DOWN); $result = null; - if($this->age < 15 and mt_rand(0, 2) === 0){ + if($this->age < 15 && mt_rand(0, 2) === 0){ $this->age++; $result = $this; } @@ -123,13 +123,13 @@ class Fire extends Flowable{ if(!$down->burnsForever()){ //TODO: check rain if($this->age === 15){ - if(!$down->isFlammable() and mt_rand(0, 3) === 3){ //1/4 chance to extinguish + if(!$down->isFlammable() && mt_rand(0, 3) === 3){ //1/4 chance to extinguish $canSpread = false; $result = VanillaBlocks::AIR(); } }elseif(!$this->hasAdjacentFlammableBlocks()){ $canSpread = false; - if(!$down->isSolid() or $this->age > 3){ + if(!$down->isSolid() || $this->age > 3){ $result = VanillaBlocks::AIR(); } } @@ -209,7 +209,7 @@ class Fire extends Flowable{ for($z = -1; $z <= 1; ++$z){ $targetZ = $z + (int) $this->position->z; for($x = -1; $x <= 1; ++$x){ - if($x === 0 and $y === 0 and $z === 0){ + if($x === 0 && $y === 0 && $z === 0){ continue; } $targetX = $x + (int) $this->position->x; @@ -241,7 +241,7 @@ class Fire extends Flowable{ $maxChance = intdiv($encouragement + 40 + $difficultyChanceIncrease, $ageDivisor); //TODO: max chance is lowered by half in humid biomes - if($maxChance > 0 and mt_rand(0, $randomBound - 1) <= $maxChance){ + if($maxChance > 0 && mt_rand(0, $randomBound - 1) <= $maxChance){ $new = clone $this; $new->age = min(15, $this->age + (mt_rand(0, 4) >> 2)); $this->spreadBlock($block, $new); diff --git a/src/block/Flower.php b/src/block/Flower.php index a7e10dfab..ff2d0344b 100644 --- a/src/block/Flower.php +++ b/src/block/Flower.php @@ -33,7 +33,7 @@ class Flower extends Flowable{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $down = $this->getSide(Facing::DOWN); - if($down->getId() === BlockLegacyIds::GRASS or $down->getId() === BlockLegacyIds::DIRT or $down->getId() === BlockLegacyIds::FARMLAND){ + if($down->getId() === BlockLegacyIds::GRASS || $down->getId() === BlockLegacyIds::DIRT || $down->getId() === BlockLegacyIds::FARMLAND){ return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } diff --git a/src/block/FlowerPot.php b/src/block/FlowerPot.php index 79e8e80b1..6dc21eb44 100644 --- a/src/block/FlowerPot.php +++ b/src/block/FlowerPot.php @@ -69,7 +69,7 @@ class FlowerPot extends Flowable{ /** @return $this */ public function setPlant(?Block $plant) : self{ - if($plant === null or $plant instanceof Air){ + if($plant === null || $plant instanceof Air){ $this->plant = null; }else{ $this->plant = clone $plant; @@ -83,12 +83,12 @@ class FlowerPot extends Flowable{ } return - $block instanceof Cactus or - $block instanceof DeadBush or - $block instanceof Flower or - $block instanceof RedMushroom or - $block instanceof Sapling or - ($block instanceof TallGrass and $block->getIdInfo()->getVariant() === BlockLegacyMetadata::TALLGRASS_FERN); //TODO: clean up + $block instanceof Cactus || + $block instanceof DeadBush || + $block instanceof Flower || + $block instanceof RedMushroom || + $block instanceof Sapling || + ($block instanceof TallGrass && $block->getIdInfo()->getVariant() === BlockLegacyMetadata::TALLGRASS_FERN); //TODO: clean up //TODO: bamboo } diff --git a/src/block/FrostedIce.php b/src/block/FrostedIce.php index 3f7c0ef10..217263e92 100644 --- a/src/block/FrostedIce.php +++ b/src/block/FrostedIce.php @@ -63,7 +63,7 @@ class FrostedIce extends Ice{ } public function onRandomTick() : void{ - if((!$this->checkAdjacentBlocks(4) or mt_rand(0, 2) === 0) and + if((!$this->checkAdjacentBlocks(4) || mt_rand(0, 2) === 0) && $this->position->getWorld()->getHighestAdjacentFullLightAt($this->position->x, $this->position->y, $this->position->z) >= 12 - $this->age){ if($this->tryMelt()){ foreach($this->getAllSides() as $block){ @@ -85,11 +85,11 @@ class FrostedIce extends Ice{ $found = 0; for($x = -1; $x <= 1; ++$x){ for($z = -1; $z <= 1; ++$z){ - if($x === 0 and $z === 0){ + if($x === 0 && $z === 0){ continue; } if( - $this->position->getWorld()->getBlockAt($this->position->x + $x, $this->position->y, $this->position->z + $z) instanceof FrostedIce and + $this->position->getWorld()->getBlockAt($this->position->x + $x, $this->position->y, $this->position->z + $z) instanceof FrostedIce && ++$found >= $requirement ){ return true; diff --git a/src/block/Furnace.php b/src/block/Furnace.php index c49ffa35b..d4b74ea7c 100644 --- a/src/block/Furnace.php +++ b/src/block/Furnace.php @@ -73,7 +73,7 @@ class Furnace extends Opaque{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($player instanceof Player){ $furnace = $this->position->getWorld()->getTile($this->position); - if($furnace instanceof TileFurnace and $furnace->canOpenWith($item->getCustomName())){ + if($furnace instanceof TileFurnace && $furnace->canOpenWith($item->getCustomName())){ $player->setCurrentWindow($furnace->getInventory()); } } @@ -83,7 +83,7 @@ class Furnace extends Opaque{ public function onScheduledUpdate() : void{ $furnace = $this->position->getWorld()->getTile($this->position); - if($furnace instanceof TileFurnace and $furnace->onUpdate()){ + if($furnace instanceof TileFurnace && $furnace->onUpdate()){ $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); //TODO: check this } } diff --git a/src/block/Grass.php b/src/block/Grass.php index 08565455f..82d42c55f 100644 --- a/src/block/Grass.php +++ b/src/block/Grass.php @@ -54,7 +54,7 @@ class Grass extends Opaque{ public function onRandomTick() : void{ $lightAbove = $this->position->getWorld()->getFullLightAt($this->position->x, $this->position->y + 1, $this->position->z); - if($lightAbove < 4 and $this->position->getWorld()->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z)->getLightFilter() >= 2){ + if($lightAbove < 4 && $this->position->getWorld()->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z)->getLightFilter() >= 2){ //grass dies $ev = new BlockSpreadEvent($this, $this, VanillaBlocks::DIRT()); $ev->call(); @@ -70,9 +70,9 @@ class Grass extends Opaque{ $b = $this->position->getWorld()->getBlockAt($x, $y, $z); if( - !($b instanceof Dirt) or - $b->isCoarse() or - $this->position->getWorld()->getFullLightAt($x, $y + 1, $z) < 4 or + !($b instanceof Dirt) || + $b->isCoarse() || + $this->position->getWorld()->getFullLightAt($x, $y + 1, $z) < 4 || $this->position->getWorld()->getBlockAt($x, $y + 1, $z)->getLightFilter() >= 2 ){ continue; @@ -103,7 +103,7 @@ class Grass extends Opaque{ $this->position->getWorld()->setBlock($this->position, $newBlock); return true; - }elseif($item instanceof Shovel and $this->getSide(Facing::UP)->getId() === BlockLegacyIds::AIR){ + }elseif($item instanceof Shovel && $this->getSide(Facing::UP)->getId() === BlockLegacyIds::AIR){ $item->applyDamage(1); $newBlock = VanillaBlocks::GRASS_PATH(); $this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock)); diff --git a/src/block/Ice.php b/src/block/Ice.php index f41426ead..eb7d6a1df 100644 --- a/src/block/Ice.php +++ b/src/block/Ice.php @@ -39,7 +39,7 @@ class Ice extends Transparent{ } public function onBreak(Item $item, ?Player $player = null) : bool{ - if(($player === null or $player->isSurvival()) and !$item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){ + if(($player === null || $player->isSurvival()) && !$item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){ $this->position->getWorld()->setBlock($this->position, VanillaBlocks::WATER()); return true; } diff --git a/src/block/ItemFrame.php b/src/block/ItemFrame.php index aff9f6566..270938d75 100644 --- a/src/block/ItemFrame.php +++ b/src/block/ItemFrame.php @@ -86,7 +86,7 @@ class ItemFrame extends Flowable{ /** @return $this */ public function setFramedItem(?Item $item) : self{ - if($item === null or $item->isNull()){ + if($item === null || $item->isNull()){ $this->framedItem = null; $this->itemRotation = 0; }else{ @@ -161,7 +161,7 @@ class ItemFrame extends Flowable{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($face === Facing::DOWN or $face === Facing::UP or !$blockClicked->isSolid()){ + if($face === Facing::DOWN || $face === Facing::UP || !$blockClicked->isSolid()){ return false; } @@ -172,7 +172,7 @@ class ItemFrame extends Flowable{ public function getDropsForCompatibleTool(Item $item) : array{ $drops = parent::getDropsForCompatibleTool($item); - if($this->framedItem !== null and lcg_value() <= $this->itemDropChance){ + if($this->framedItem !== null && lcg_value() <= $this->itemDropChance){ $drops[] = clone $this->framedItem; } diff --git a/src/block/Ladder.php b/src/block/Ladder.php index f76a28b6f..bd4de7e0f 100644 --- a/src/block/Ladder.php +++ b/src/block/Ladder.php @@ -65,7 +65,7 @@ class Ladder extends Transparent{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$blockClicked->isTransparent() and Facing::axis($face) !== Axis::Y){ + if(!$blockClicked->isTransparent() && Facing::axis($face) !== Axis::Y){ $this->facing = $face; return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } diff --git a/src/block/Lantern.php b/src/block/Lantern.php index 4bd2f5918..516374a4d 100644 --- a/src/block/Lantern.php +++ b/src/block/Lantern.php @@ -77,11 +77,11 @@ class Lantern extends Transparent{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->up())) and !$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->down()))){ + if(!$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->up())) && !$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->down()))){ return false; } - $this->hanging = ($face === Facing::DOWN or !$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->down()))); + $this->hanging = ($face === Facing::DOWN || !$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->down()))); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } diff --git a/src/block/Leaves.php b/src/block/Leaves.php index 03c99936e..7ca55c6dc 100644 --- a/src/block/Leaves.php +++ b/src/block/Leaves.php @@ -96,7 +96,7 @@ class Leaves extends Transparent{ return true; } - if($block->getId() === $this->getId() and $distance <= 4){ + if($block->getId() === $this->getId() && $distance <= 4){ foreach(Facing::ALL as $side){ if($this->findLog($pos->getSide($side), $visited, $distance + 1)){ return true; @@ -108,7 +108,7 @@ class Leaves extends Transparent{ } public function onNearbyBlockChange() : void{ - if(!$this->noDecay and !$this->checkDecay){ + if(!$this->noDecay && !$this->checkDecay){ $this->checkDecay = true; $this->position->getWorld()->setBlock($this->position, $this, false); } @@ -119,10 +119,10 @@ class Leaves extends Transparent{ } public function onRandomTick() : void{ - if(!$this->noDecay and $this->checkDecay){ + if(!$this->noDecay && $this->checkDecay){ $ev = new LeavesDecayEvent($this); $ev->call(); - if($ev->isCancelled() or $this->findLog($this->position)){ + if($ev->isCancelled() || $this->findLog($this->position)){ $this->checkDecay = false; $this->position->getWorld()->setBlock($this->position, $this, false); }else{ @@ -145,7 +145,7 @@ class Leaves extends Transparent{ if(mt_rand(1, 20) === 1){ //Saplings $drops[] = ItemFactory::getInstance()->get(ItemIds::SAPLING, $this->treeType->getMagicNumber()); } - if(($this->treeType->equals(TreeType::OAK()) or $this->treeType->equals(TreeType::DARK_OAK())) and mt_rand(1, 200) === 1){ //Apples + if(($this->treeType->equals(TreeType::OAK()) || $this->treeType->equals(TreeType::DARK_OAK())) && mt_rand(1, 200) === 1){ //Apples $drops[] = VanillaItems::APPLE(); } diff --git a/src/block/Liquid.php b/src/block/Liquid.php index 6e3c8df35..46e9c487d 100644 --- a/src/block/Liquid.php +++ b/src/block/Liquid.php @@ -131,7 +131,7 @@ abstract class Liquid extends Transparent{ abstract public function getBucketEmptySound() : Sound; public function isSource() : bool{ - return !$this->falling and $this->decay === 0; + return !$this->falling && $this->decay === 0; } /** @@ -154,7 +154,7 @@ abstract class Liquid extends Transparent{ } protected function getEffectiveFlowDecay(Block $block) : int{ - if(!($block instanceof Liquid) or !$block->isSameType($this)){ + if(!($block instanceof Liquid) || !$block->isSameType($this)){ return -1; } @@ -279,7 +279,7 @@ abstract class Liquid extends Transparent{ $newDecay = $smallestFlowDecay + $multiplier; $falling = false; - if($newDecay >= 8 or $smallestFlowDecay < 0){ + if($newDecay >= 8 || $smallestFlowDecay < 0){ $newDecay = -1; } @@ -290,14 +290,14 @@ abstract class Liquid extends Transparent{ $minAdjacentSources = $this->getMinAdjacentSourcesToFormSource(); if($minAdjacentSources !== null && $this->adjacentSources >= $minAdjacentSources){ $bottomBlock = $world->getBlockAt($this->position->x, $this->position->y - 1, $this->position->z); - if($bottomBlock->isSolid() or ($bottomBlock instanceof Liquid and $bottomBlock->isSameType($this) and $bottomBlock->isSource())){ + if($bottomBlock->isSolid() || ($bottomBlock instanceof Liquid && $bottomBlock->isSameType($this) && $bottomBlock->isSource())){ $newDecay = 0; $falling = false; } } - if($falling !== $this->falling or (!$falling and $newDecay !== $this->decay)){ - if(!$falling and $newDecay < 0){ + if($falling !== $this->falling || (!$falling && $newDecay !== $this->decay)){ + if(!$falling && $newDecay < 0){ $world->setBlock($this->position, VanillaBlocks::AIR()); return; } @@ -312,7 +312,7 @@ abstract class Liquid extends Transparent{ $this->flowIntoBlock($bottomBlock, 0, true); - if($this->isSource() or !$bottomBlock->canBeFlowedInto()){ + if($this->isSource() || !$bottomBlock->canBeFlowedInto()){ if($this->falling){ $adjacentDecay = 1; //falling liquid behaves like source block }else{ @@ -331,7 +331,7 @@ abstract class Liquid extends Transparent{ } protected function flowIntoBlock(Block $block, int $newFlowDecay, bool $falling) : void{ - if($this->canFlowInto($block) and !($block instanceof Liquid)){ + if($this->canFlowInto($block) && !($block instanceof Liquid)){ $new = clone $this; $new->falling = $falling; $new->decay = $falling ? 0 : $newFlowDecay; @@ -350,7 +350,7 @@ abstract class Liquid extends Transparent{ /** @phpstan-impure */ private function getSmallestFlowDecay(Block $block, int $decay) : int{ - if(!($block instanceof Liquid) or !$block->isSameType($this)){ + if(!($block instanceof Liquid) || !$block->isSameType($this)){ return $decay; } @@ -381,8 +381,8 @@ abstract class Liquid extends Transparent{ protected function canFlowInto(Block $block) : bool{ return - $this->position->getWorld()->isInWorld($block->position->x, $block->position->y, $block->position->z) and - $block->canBeFlowedInto() and - !($block instanceof Liquid and $block->isSource()); //TODO: I think this should only be liquids of the same type + $this->position->getWorld()->isInWorld($block->position->x, $block->position->y, $block->position->z) && + $block->canBeFlowedInto() && + !($block instanceof Liquid && $block->isSource()); //TODO: I think this should only be liquids of the same type } } diff --git a/src/block/Magma.php b/src/block/Magma.php index e698a6431..fbff583aa 100644 --- a/src/block/Magma.php +++ b/src/block/Magma.php @@ -39,7 +39,7 @@ class Magma extends Opaque{ } public function onEntityInside(Entity $entity) : bool{ - if($entity instanceof Living and !$entity->isSneaking()){ + if($entity instanceof Living && !$entity->isSneaking()){ $ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1); $entity->attack($ev); } diff --git a/src/block/NetherPortal.php b/src/block/NetherPortal.php index b8c73d0a7..5ba1f0d41 100644 --- a/src/block/NetherPortal.php +++ b/src/block/NetherPortal.php @@ -53,7 +53,7 @@ class NetherPortal extends Transparent{ * @return $this */ public function setAxis(int $axis) : self{ - if($axis !== Axis::X and $axis !== Axis::Z){ + if($axis !== Axis::X && $axis !== Axis::Z){ throw new \InvalidArgumentException("Invalid axis"); } $this->axis = $axis; diff --git a/src/block/NetherWartPlant.php b/src/block/NetherWartPlant.php index 5809c8a4e..c6b441915 100644 --- a/src/block/NetherWartPlant.php +++ b/src/block/NetherWartPlant.php @@ -79,7 +79,7 @@ class NetherWartPlant extends Flowable{ } public function onRandomTick() : void{ - if($this->age < 3 and mt_rand(0, 10) === 0){ //Still growing + if($this->age < 3 && mt_rand(0, 10) === 0){ //Still growing $block = clone $this; $block->age++; $ev = new BlockGrowEvent($this, $block); diff --git a/src/block/Note.php b/src/block/Note.php index d8ff22402..1dc24733a 100644 --- a/src/block/Note.php +++ b/src/block/Note.php @@ -59,7 +59,7 @@ class Note extends Opaque{ /** @return $this */ public function setPitch(int $pitch) : self{ - if($pitch < self::MIN_PITCH or $pitch > self::MAX_PITCH){ + if($pitch < self::MIN_PITCH || $pitch > self::MAX_PITCH){ throw new \InvalidArgumentException("Pitch must be in range " . self::MIN_PITCH . " - " . self::MAX_PITCH); } $this->pitch = $pitch; diff --git a/src/block/Pumpkin.php b/src/block/Pumpkin.php index 57d305806..835c68f31 100644 --- a/src/block/Pumpkin.php +++ b/src/block/Pumpkin.php @@ -34,7 +34,7 @@ use function in_array; class Pumpkin extends Opaque{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($item instanceof Shears and in_array($face, Facing::HORIZONTAL, true)){ + if($item instanceof Shears && in_array($face, Facing::HORIZONTAL, true)){ $item->applyDamage(1); $this->position->getWorld()->setBlock($this->position, VanillaBlocks::CARVED_PUMPKIN()->setFacing($face)); $this->position->getWorld()->dropItem($this->position->add(0.5, 0.5, 0.5), VanillaItems::PUMPKIN_SEEDS()->setCount(1)); diff --git a/src/block/RedstoneComparator.php b/src/block/RedstoneComparator.php index 764676953..95471bd98 100644 --- a/src/block/RedstoneComparator.php +++ b/src/block/RedstoneComparator.php @@ -57,7 +57,7 @@ class RedstoneComparator extends Flowable{ public function readStateFromData(int $id, int $stateMeta) : void{ $this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03); $this->isSubtractMode = ($stateMeta & BlockLegacyMetadata::REDSTONE_COMPARATOR_FLAG_SUBTRACT) !== 0; - $this->powered = ($id === $this->idInfoFlattened->getSecondId() or ($stateMeta & BlockLegacyMetadata::REDSTONE_COMPARATOR_FLAG_POWERED) !== 0); + $this->powered = ($id === $this->idInfoFlattened->getSecondId() || ($stateMeta & BlockLegacyMetadata::REDSTONE_COMPARATOR_FLAG_POWERED) !== 0); } public function writeStateToMeta() : int{ diff --git a/src/block/Sapling.php b/src/block/Sapling.php index 85e092451..9709032c5 100644 --- a/src/block/Sapling.php +++ b/src/block/Sapling.php @@ -68,7 +68,7 @@ class Sapling extends Flowable{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $down = $this->getSide(Facing::DOWN); - if($down->getId() === BlockLegacyIds::GRASS or $down->getId() === BlockLegacyIds::DIRT or $down->getId() === BlockLegacyIds::FARMLAND){ + if($down->getId() === BlockLegacyIds::GRASS || $down->getId() === BlockLegacyIds::DIRT || $down->getId() === BlockLegacyIds::FARMLAND){ return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } @@ -96,7 +96,7 @@ class Sapling extends Flowable{ } public function onRandomTick() : void{ - if($this->position->getWorld()->getFullLightAt($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ()) >= 8 and mt_rand(1, 7) === 1){ + if($this->position->getWorld()->getFullLightAt($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ()) >= 8 && mt_rand(1, 7) === 1){ if($this->ready){ $this->grow(null); }else{ diff --git a/src/block/SeaPickle.php b/src/block/SeaPickle.php index 9110dc22c..fb931f004 100644 --- a/src/block/SeaPickle.php +++ b/src/block/SeaPickle.php @@ -83,12 +83,12 @@ class SeaPickle extends Transparent{ public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{ //TODO: proper placement logic (needs a supporting face below) - return ($blockReplace instanceof SeaPickle and $blockReplace->count < 4) or parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock); + return ($blockReplace instanceof SeaPickle && $blockReplace->count < 4) || parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock); } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $this->underwater = false; //TODO: implement this once we have new water logic in place - if($blockReplace instanceof SeaPickle and $blockReplace->count < 4){ + if($blockReplace instanceof SeaPickle && $blockReplace->count < 4){ $this->count = $blockReplace->count + 1; } diff --git a/src/block/ShulkerBox.php b/src/block/ShulkerBox.php index a81e5009d..18cd38ff8 100644 --- a/src/block/ShulkerBox.php +++ b/src/block/ShulkerBox.php @@ -91,7 +91,7 @@ class ShulkerBox extends Opaque{ $shulker = $this->position->getWorld()->getTile($this->position); if($shulker instanceof TileShulkerBox){ if( - $this->getSide($this->facing)->getId() !== BlockLegacyIds::AIR or + $this->getSide($this->facing)->getId() !== BlockLegacyIds::AIR || !$shulker->canOpenWith($item->getCustomName()) ){ return true; diff --git a/src/block/Skull.php b/src/block/Skull.php index 47476abce..b403924cf 100644 --- a/src/block/Skull.php +++ b/src/block/Skull.php @@ -140,7 +140,7 @@ class Skull extends Flowable{ } $this->facing = $face; - if($player !== null and $face === Facing::UP){ + if($player !== null && $face === Facing::UP){ $this->rotation = ((int) floor(($player->getLocation()->getYaw() * 16 / 360) + 0.5)) & 0xf; } return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); diff --git a/src/block/Slab.php b/src/block/Slab.php index 610c6ee8c..1bddeba94 100644 --- a/src/block/Slab.php +++ b/src/block/Slab.php @@ -90,11 +90,11 @@ class Slab extends Transparent{ return true; } - if($blockReplace instanceof Slab and !$blockReplace->slabType->equals(SlabType::DOUBLE()) and $blockReplace->isSameType($this)){ + if($blockReplace instanceof Slab && !$blockReplace->slabType->equals(SlabType::DOUBLE()) && $blockReplace->isSameType($this)){ if($blockReplace->slabType->equals(SlabType::TOP())){ //Trying to combine with top slab - return $clickVector->y <= 0.5 or (!$isClickedBlock and $face === Facing::UP); + return $clickVector->y <= 0.5 || (!$isClickedBlock && $face === Facing::UP); }else{ - return $clickVector->y >= 0.5 or (!$isClickedBlock and $face === Facing::DOWN); + return $clickVector->y >= 0.5 || (!$isClickedBlock && $face === Facing::DOWN); } } @@ -102,9 +102,9 @@ class Slab extends Transparent{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($blockReplace instanceof Slab and !$blockReplace->slabType->equals(SlabType::DOUBLE()) and $blockReplace->isSameType($this) and ( - ($blockReplace->slabType->equals(SlabType::TOP()) and ($clickVector->y <= 0.5 or $face === Facing::UP)) or - ($blockReplace->slabType->equals(SlabType::BOTTOM()) and ($clickVector->y >= 0.5 or $face === Facing::DOWN)) + if($blockReplace instanceof Slab && !$blockReplace->slabType->equals(SlabType::DOUBLE()) && $blockReplace->isSameType($this) && ( + ($blockReplace->slabType->equals(SlabType::TOP()) && ($clickVector->y <= 0.5 || $face === Facing::UP)) || + ($blockReplace->slabType->equals(SlabType::BOTTOM()) && ($clickVector->y >= 0.5 || $face === Facing::DOWN)) )){ //Clicked in empty half of existing slab $this->slabType = SlabType::DOUBLE(); diff --git a/src/block/SnowLayer.php b/src/block/SnowLayer.php index 4bea77df5..015733a76 100644 --- a/src/block/SnowLayer.php +++ b/src/block/SnowLayer.php @@ -78,7 +78,7 @@ class SnowLayer extends Flowable implements Fallable{ } private function canBeSupportedBy(Block $b) : bool{ - return $b->isSolid() or ($b instanceof SnowLayer and $b->isSameType($this) and $b->layers === 8); + return $b->isSolid() || ($b instanceof SnowLayer && $b->isSameType($this) && $b->layers === 8); } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ diff --git a/src/block/Stair.php b/src/block/Stair.php index b4dd2c65a..39bf4ab3a 100644 --- a/src/block/Stair.php +++ b/src/block/Stair.php @@ -96,9 +96,9 @@ class Stair extends Transparent{ ->trim(Facing::opposite($topStepFace), 0.5) ->trim(Facing::opposite($this->facing), 0.5); - if($this->shape->equals(StairShape::OUTER_LEFT()) or $this->shape->equals(StairShape::OUTER_RIGHT())){ + if($this->shape->equals(StairShape::OUTER_LEFT()) || $this->shape->equals(StairShape::OUTER_RIGHT())){ $topStep->trim(Facing::rotateY($this->facing, $this->shape->equals(StairShape::OUTER_LEFT())), 0.5); - }elseif($this->shape->equals(StairShape::INNER_LEFT()) or $this->shape->equals(StairShape::INNER_RIGHT())){ + }elseif($this->shape->equals(StairShape::INNER_LEFT()) || $this->shape->equals(StairShape::INNER_RIGHT())){ //add an extra cube $bbs[] = AxisAlignedBB::one() ->trim(Facing::opposite($topStepFace), 0.5) @@ -114,8 +114,8 @@ class Stair extends Transparent{ private function getPossibleCornerFacing(bool $oppositeFacing) : ?int{ $side = $this->getSide($oppositeFacing ? Facing::opposite($this->facing) : $this->facing); return ( - $side instanceof Stair and - $side->upsideDown === $this->upsideDown and + $side instanceof Stair && + $side->upsideDown === $this->upsideDown && Facing::axis($side->facing) !== Facing::axis($this->facing) //perpendicular ) ? $side->facing : null; } @@ -124,7 +124,7 @@ class Stair extends Transparent{ if($player !== null){ $this->facing = $player->getHorizontalFacing(); } - $this->upsideDown = (($clickVector->y > 0.5 and $face !== Facing::UP) or $face === Facing::DOWN); + $this->upsideDown = (($clickVector->y > 0.5 && $face !== Facing::UP) || $face === Facing::DOWN); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } diff --git a/src/block/Stem.php b/src/block/Stem.php index 5904736f7..e223b18be 100644 --- a/src/block/Stem.php +++ b/src/block/Stem.php @@ -53,7 +53,7 @@ abstract class Stem extends Crops{ $side = $this->getSide(Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)]); $d = $side->getSide(Facing::DOWN); - if($side->getId() === BlockLegacyIds::AIR and ($d->getId() === BlockLegacyIds::FARMLAND or $d->getId() === BlockLegacyIds::GRASS or $d->getId() === BlockLegacyIds::DIRT)){ + if($side->getId() === BlockLegacyIds::AIR && ($d->getId() === BlockLegacyIds::FARMLAND || $d->getId() === BlockLegacyIds::GRASS || $d->getId() === BlockLegacyIds::DIRT)){ $ev = new BlockGrowEvent($side, $grow); $ev->call(); if(!$ev->isCancelled()){ diff --git a/src/block/Sugarcane.php b/src/block/Sugarcane.php index 90eef3d4b..d2c13308a 100644 --- a/src/block/Sugarcane.php +++ b/src/block/Sugarcane.php @@ -97,7 +97,7 @@ class Sugarcane extends Flowable{ public function onNearbyBlockChange() : void{ $down = $this->getSide(Facing::DOWN); - if($down->isTransparent() and !$down->isSameType($this)){ + if($down->isTransparent() && !$down->isSameType($this)){ $this->position->getWorld()->useBreakOn($this->position); } } @@ -121,7 +121,7 @@ class Sugarcane extends Flowable{ $down = $this->getSide(Facing::DOWN); if($down->isSameType($this)){ return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); - }elseif($down->getId() === BlockLegacyIds::GRASS or $down->getId() === BlockLegacyIds::DIRT or $down->getId() === BlockLegacyIds::SAND or $down->getId() === BlockLegacyIds::PODZOL){ + }elseif($down->getId() === BlockLegacyIds::GRASS || $down->getId() === BlockLegacyIds::DIRT || $down->getId() === BlockLegacyIds::SAND || $down->getId() === BlockLegacyIds::PODZOL){ foreach(Facing::HORIZONTAL as $side){ if($down->getSide($side) instanceof Water){ return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); diff --git a/src/block/SweetBerryBush.php b/src/block/SweetBerryBush.php index 4412d0cff..4983bfea4 100644 --- a/src/block/SweetBerryBush.php +++ b/src/block/SweetBerryBush.php @@ -135,7 +135,7 @@ class SweetBerryBush extends Flowable{ } public function onRandomTick() : void{ - if($this->age < self::STAGE_MATURE and mt_rand(0, 2) === 1){ + if($this->age < self::STAGE_MATURE && mt_rand(0, 2) === 1){ $block = clone $this; ++$block->age; $ev = new BlockGrowEvent($this, $block); diff --git a/src/block/TNT.php b/src/block/TNT.php index 27383e996..5af0b5267 100644 --- a/src/block/TNT.php +++ b/src/block/TNT.php @@ -86,7 +86,7 @@ class TNT extends Opaque{ } public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($item instanceof FlintSteel or $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){ + if($item instanceof FlintSteel || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){ if($item instanceof Durable){ $item->applyDamage(1); } @@ -102,7 +102,7 @@ class TNT extends Opaque{ } public function onEntityInside(Entity $entity) : bool{ - if($entity instanceof Arrow and $entity->isOnFire()){ + if($entity instanceof Arrow && $entity->isOnFire()){ $this->ignite(); return false; } diff --git a/src/block/TallGrass.php b/src/block/TallGrass.php index 7f5daf731..b77a828fe 100644 --- a/src/block/TallGrass.php +++ b/src/block/TallGrass.php @@ -39,7 +39,7 @@ class TallGrass extends Flowable{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $down = $this->getSide(Facing::DOWN)->getId(); - if($down === BlockLegacyIds::GRASS or $down === BlockLegacyIds::DIRT){ + if($down === BlockLegacyIds::GRASS || $down === BlockLegacyIds::DIRT){ return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } diff --git a/src/block/Thin.php b/src/block/Thin.php index 3f3dc86e7..567e4e86c 100644 --- a/src/block/Thin.php +++ b/src/block/Thin.php @@ -37,7 +37,7 @@ class Thin extends Transparent{ foreach(Facing::HORIZONTAL as $facing){ $side = $this->getSide($facing); - if($side instanceof Thin or $side->isFullCube()){ + if($side instanceof Thin || $side->isFullCube()){ $this->connections[$facing] = true; }else{ unset($this->connections[$facing]); @@ -51,7 +51,7 @@ class Thin extends Transparent{ /** @var AxisAlignedBB[] $bbs */ $bbs = []; - if(isset($this->connections[Facing::WEST]) or isset($this->connections[Facing::EAST])){ + if(isset($this->connections[Facing::WEST]) || isset($this->connections[Facing::EAST])){ $bb = AxisAlignedBB::one()->squash(Axis::Z, $inset); if(!isset($this->connections[Facing::WEST])){ @@ -62,7 +62,7 @@ class Thin extends Transparent{ $bbs[] = $bb; } - if(isset($this->connections[Facing::NORTH]) or isset($this->connections[Facing::SOUTH])){ + if(isset($this->connections[Facing::NORTH]) || isset($this->connections[Facing::SOUTH])){ $bb = AxisAlignedBB::one()->squash(Axis::X, $inset); if(!isset($this->connections[Facing::NORTH])){ diff --git a/src/block/Torch.php b/src/block/Torch.php index 292bfbb18..cb5bf8fb8 100644 --- a/src/block/Torch.php +++ b/src/block/Torch.php @@ -66,16 +66,16 @@ class Torch extends Flowable{ $below = $this->getSide(Facing::DOWN); $face = Facing::opposite($this->facing); - if($this->getSide($face)->isTransparent() and !($face === Facing::DOWN and ($below->getId() === BlockLegacyIds::FENCE or $below->getId() === BlockLegacyIds::COBBLESTONE_WALL))){ + if($this->getSide($face)->isTransparent() && !($face === Facing::DOWN && ($below->getId() === BlockLegacyIds::FENCE || $below->getId() === BlockLegacyIds::COBBLESTONE_WALL))){ $this->position->getWorld()->useBreakOn($this->position); } } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($blockClicked->canBeReplaced() and !$blockClicked->getSide(Facing::DOWN)->isTransparent()){ + if($blockClicked->canBeReplaced() && !$blockClicked->getSide(Facing::DOWN)->isTransparent()){ $this->facing = Facing::UP; return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); - }elseif($face !== Facing::DOWN and (!$blockClicked->isTransparent() or ($face === Facing::UP and ($blockClicked->getId() === BlockLegacyIds::FENCE or $blockClicked->getId() === BlockLegacyIds::COBBLESTONE_WALL)))){ + }elseif($face !== Facing::DOWN && (!$blockClicked->isTransparent() || ($face === Facing::UP && ($blockClicked->getId() === BlockLegacyIds::FENCE || $blockClicked->getId() === BlockLegacyIds::COBBLESTONE_WALL)))){ $this->facing = $face; return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); }else{ diff --git a/src/block/Trapdoor.php b/src/block/Trapdoor.php index 6f9d7b34c..08cb4b200 100644 --- a/src/block/Trapdoor.php +++ b/src/block/Trapdoor.php @@ -82,7 +82,7 @@ class Trapdoor extends Transparent{ if($player !== null){ $this->facing = Facing::opposite($player->getHorizontalFacing()); } - if(($clickVector->y > 0.5 and $face !== Facing::UP) or $face === Facing::DOWN){ + if(($clickVector->y > 0.5 && $face !== Facing::UP) || $face === Facing::DOWN){ $this->top = true; } diff --git a/src/block/Vine.php b/src/block/Vine.php index b9331bc40..16f684846 100644 --- a/src/block/Vine.php +++ b/src/block/Vine.php @@ -116,7 +116,7 @@ class Vine extends Flowable{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$blockClicked->isSolid() or Facing::axis($face) === Axis::Y){ + if(!$blockClicked->isSolid() || Facing::axis($face) === Axis::Y){ return false; } @@ -134,7 +134,7 @@ class Vine extends Flowable{ $supportedFaces = $up instanceof Vine ? array_intersect_key($this->faces, $up->faces) : []; foreach($this->faces as $face){ - if(!isset($supportedFaces[$face]) and !$this->getSide($face)->isSolid()){ + if(!isset($supportedFaces[$face]) && !$this->getSide($face)->isSolid()){ unset($this->faces[$face]); $changed = true; } diff --git a/src/block/Wall.php b/src/block/Wall.php index 5a1323d14..6c827d190 100644 --- a/src/block/Wall.php +++ b/src/block/Wall.php @@ -37,7 +37,7 @@ class Wall extends Transparent{ foreach(Facing::HORIZONTAL as $facing){ $block = $this->getSide($facing); - if($block instanceof static or $block instanceof FenceGate or ($block->isSolid() and !$block->isTransparent())){ + if($block instanceof static || $block instanceof FenceGate || ($block->isSolid() && !$block->isTransparent())){ $this->connections[$facing] = $facing; }else{ unset($this->connections[$facing]); @@ -57,10 +57,10 @@ class Wall extends Transparent{ $inset = 0.25; if( - !$this->up and //if there is a block on top, it stays as a post + !$this->up && //if there is a block on top, it stays as a post ( - ($north and $south and !$west and !$east) or - (!$north and !$south and $west and $east) + ($north && $south && !$west && !$east) || + (!$north && !$south && $west && $east) ) ){ //If connected to two sides on the same axis but not any others, AND there is not a block on top, there is no post and the wall is thinner diff --git a/src/block/inventory/AnimatedBlockInventoryTrait.php b/src/block/inventory/AnimatedBlockInventoryTrait.php index e0bb9fee0..c80fced3a 100644 --- a/src/block/inventory/AnimatedBlockInventoryTrait.php +++ b/src/block/inventory/AnimatedBlockInventoryTrait.php @@ -47,7 +47,7 @@ trait AnimatedBlockInventoryTrait{ public function onOpen(Player $who) : void{ parent::onOpen($who); - if($this->getHolder()->isValid() and $this->getViewerCount() === 1){ + if($this->getHolder()->isValid() && $this->getViewerCount() === 1){ //TODO: this crap really shouldn't be managed by the inventory $this->animateBlock(true); $this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound()); @@ -57,7 +57,7 @@ trait AnimatedBlockInventoryTrait{ abstract protected function animateBlock(bool $isOpen) : void; public function onClose(Player $who) : void{ - if($this->getHolder()->isValid() and $this->getViewerCount() === 1){ + if($this->getHolder()->isValid() && $this->getViewerCount() === 1){ //TODO: this crap really shouldn't be managed by the inventory $this->animateBlock(false); $this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound()); diff --git a/src/block/tile/Chest.php b/src/block/tile/Chest.php index 67534f123..614d7f0cd 100644 --- a/src/block/tile/Chest.php +++ b/src/block/tile/Chest.php @@ -60,12 +60,12 @@ class Chest extends Spawnable implements Container, Nameable{ } public function readSaveData(CompoundTag $nbt) : void{ - if(($pairXTag = $nbt->getTag(self::TAG_PAIRX)) instanceof IntTag and ($pairZTag = $nbt->getTag(self::TAG_PAIRZ)) instanceof IntTag){ + if(($pairXTag = $nbt->getTag(self::TAG_PAIRX)) instanceof IntTag && ($pairZTag = $nbt->getTag(self::TAG_PAIRZ)) instanceof IntTag){ $pairX = $pairXTag->getValue(); $pairZ = $pairZTag->getValue(); if( - ($this->position->x === $pairX and abs($this->position->z - $pairZ) === 1) or - ($this->position->z === $pairZ and abs($this->position->x - $pairX) === 1) + ($this->position->x === $pairX && abs($this->position->z - $pairZ) === 1) || + ($this->position->z === $pairZ && abs($this->position->x - $pairX) === 1) ){ $this->pairX = $pairX; $this->pairZ = $pairZ; @@ -100,7 +100,7 @@ class Chest extends Spawnable implements Container, Nameable{ $this->inventory->removeAllViewers(); if($this->doubleInventory !== null){ - if($this->isPaired() and $this->position->getWorld()->isChunkLoaded($this->pairX >> Chunk::COORD_BIT_SIZE, $this->pairZ >> Chunk::COORD_BIT_SIZE)){ + if($this->isPaired() && $this->position->getWorld()->isChunkLoaded($this->pairX >> Chunk::COORD_BIT_SIZE, $this->pairZ >> Chunk::COORD_BIT_SIZE)){ $this->doubleInventory->removeAllViewers(); if(($pair = $this->getPair()) !== null){ $pair->doubleInventory = null; @@ -122,7 +122,7 @@ class Chest extends Spawnable implements Container, Nameable{ * @return ChestInventory|DoubleChestInventory */ public function getInventory(){ - if($this->isPaired() and $this->doubleInventory === null){ + if($this->isPaired() && $this->doubleInventory === null){ $this->checkPairing(); } return $this->doubleInventory instanceof DoubleChestInventory ? $this->doubleInventory : $this->inventory; @@ -136,7 +136,7 @@ class Chest extends Spawnable implements Container, Nameable{ } protected function checkPairing() : void{ - if($this->isPaired() and !$this->position->getWorld()->isInLoadedTerrain(new Vector3($this->pairX, $this->position->y, $this->pairZ))){ + if($this->isPaired() && !$this->position->getWorld()->isInLoadedTerrain(new Vector3($this->pairX, $this->position->y, $this->pairZ))){ //paired to a tile in an unloaded chunk $this->doubleInventory = null; @@ -167,7 +167,7 @@ class Chest extends Spawnable implements Container, Nameable{ } public function isPaired() : bool{ - return $this->pairX !== null and $this->pairZ !== null; + return $this->pairX !== null && $this->pairZ !== null; } public function getPair() : ?Chest{ @@ -182,7 +182,7 @@ class Chest extends Spawnable implements Container, Nameable{ } public function pairWith(Chest $tile) : bool{ - if($this->isPaired() or $tile->isPaired()){ + if($this->isPaired() || $tile->isPaired()){ return false; } diff --git a/src/block/tile/ContainerTrait.php b/src/block/tile/ContainerTrait.php index f3dc42390..2abe134f2 100644 --- a/src/block/tile/ContainerTrait.php +++ b/src/block/tile/ContainerTrait.php @@ -81,7 +81,7 @@ trait ContainerTrait{ * @see Container::canOpenWith() */ public function canOpenWith(string $key) : bool{ - return $this->lock === null or $this->lock === $key; + return $this->lock === null || $this->lock === $key; } /** diff --git a/src/block/tile/FlowerPot.php b/src/block/tile/FlowerPot.php index f44e73e37..221453ae6 100644 --- a/src/block/tile/FlowerPot.php +++ b/src/block/tile/FlowerPot.php @@ -42,7 +42,7 @@ class FlowerPot extends Spawnable{ private $plant = null; public function readSaveData(CompoundTag $nbt) : void{ - if(($itemIdTag = $nbt->getTag(self::TAG_ITEM)) instanceof ShortTag and ($itemMetaTag = $nbt->getTag(self::TAG_ITEM_DATA)) instanceof IntTag){ + if(($itemIdTag = $nbt->getTag(self::TAG_ITEM)) instanceof ShortTag && ($itemMetaTag = $nbt->getTag(self::TAG_ITEM_DATA)) instanceof IntTag){ try{ $this->setPlant(BlockFactory::getInstance()->get($itemIdTag->getValue(), $itemMetaTag->getValue())); }catch(\InvalidArgumentException $e){ @@ -65,7 +65,7 @@ class FlowerPot extends Spawnable{ } public function setPlant(?Block $plant) : void{ - if($plant === null or $plant instanceof Air){ + if($plant === null || $plant instanceof Air){ $this->plant = null; }else{ $this->plant = clone $plant; diff --git a/src/block/tile/Furnace.php b/src/block/tile/Furnace.php index b527317d6..21b05f504 100644 --- a/src/block/tile/Furnace.php +++ b/src/block/tile/Furnace.php @@ -132,14 +132,14 @@ abstract class Furnace extends Spawnable implements Container, Nameable{ $this->maxFuelTime = $this->remainingFuelTime = $ev->getBurnTime(); $this->onStartSmelting(); - if($this->remainingFuelTime > 0 and $ev->isBurning()){ + if($this->remainingFuelTime > 0 && $ev->isBurning()){ $this->inventory->setFuel($fuel->getFuelResidue()); } } protected function onStartSmelting() : void{ $block = $this->getBlock(); - if($block instanceof BlockFurnace and !$block->isLit()){ + if($block instanceof BlockFurnace && !$block->isLit()){ $block->setLit(true); $this->position->getWorld()->setBlock($block->getPosition(), $block); } @@ -147,7 +147,7 @@ abstract class Furnace extends Spawnable implements Container, Nameable{ protected function onStopSmelting() : void{ $block = $this->getBlock(); - if($block instanceof BlockFurnace and $block->isLit()){ + if($block instanceof BlockFurnace && $block->isLit()){ $block->setLit(false); $this->position->getWorld()->setBlock($block->getPosition(), $block); } @@ -175,16 +175,16 @@ abstract class Furnace extends Spawnable implements Container, Nameable{ $furnaceType = $this->getFurnaceType(); $smelt = $this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($furnaceType)->match($raw); - $canSmelt = ($smelt instanceof FurnaceRecipe and $raw->getCount() > 0 and (($smelt->getResult()->equals($product) and $product->getCount() < $product->getMaxStackSize()) or $product->isNull())); + $canSmelt = ($smelt instanceof FurnaceRecipe && $raw->getCount() > 0 && (($smelt->getResult()->equals($product) && $product->getCount() < $product->getMaxStackSize()) || $product->isNull())); - if($this->remainingFuelTime <= 0 and $canSmelt and $fuel->getFuelTime() > 0 and $fuel->getCount() > 0){ + if($this->remainingFuelTime <= 0 && $canSmelt && $fuel->getFuelTime() > 0 && $fuel->getCount() > 0){ $this->checkFuel($fuel); } if($this->remainingFuelTime > 0){ --$this->remainingFuelTime; - if($smelt instanceof FurnaceRecipe and $canSmelt){ + if($smelt instanceof FurnaceRecipe && $canSmelt){ ++$this->cookTime; if($this->cookTime >= $furnaceType->getCookDurationTicks()){ diff --git a/src/block/tile/ItemFrame.php b/src/block/tile/ItemFrame.php index eb8ff3d32..f4f679e7e 100644 --- a/src/block/tile/ItemFrame.php +++ b/src/block/tile/ItemFrame.php @@ -73,7 +73,7 @@ class ItemFrame extends Spawnable{ } public function setItem(?Item $item) : void{ - if($item !== null and !$item->isNull()){ + if($item !== null && !$item->isNull()){ $this->item = clone $item; }else{ $this->item = VanillaItems::AIR(); diff --git a/src/block/tile/Note.php b/src/block/tile/Note.php index 5157f7436..30c252593 100644 --- a/src/block/tile/Note.php +++ b/src/block/tile/Note.php @@ -34,7 +34,7 @@ class Note extends Tile{ private $pitch = 0; public function readSaveData(CompoundTag $nbt) : void{ - if(($pitch = $nbt->getByte("note", $this->pitch)) > BlockNote::MIN_PITCH and $pitch <= BlockNote::MAX_PITCH){ + if(($pitch = $nbt->getByte("note", $this->pitch)) > BlockNote::MIN_PITCH && $pitch <= BlockNote::MAX_PITCH){ $this->pitch = $pitch; } } @@ -48,7 +48,7 @@ class Note extends Tile{ } public function setPitch(int $pitch) : void{ - if($pitch < BlockNote::MIN_PITCH or $pitch > BlockNote::MAX_PITCH){ + if($pitch < BlockNote::MIN_PITCH || $pitch > BlockNote::MAX_PITCH){ throw new \InvalidArgumentException("Pitch must be in range " . BlockNote::MIN_PITCH . " - " . BlockNote::MAX_PITCH); } $this->pitch = $pitch; diff --git a/src/block/tile/Skull.php b/src/block/tile/Skull.php index 4db9ebd93..8ff40898d 100644 --- a/src/block/tile/Skull.php +++ b/src/block/tile/Skull.php @@ -59,7 +59,7 @@ class Skull extends Spawnable{ } } $rotation = $nbt->getByte(self::TAG_ROT, 0); - if($rotation >= 0 and $rotation <= 15){ + if($rotation >= 0 && $rotation <= 15){ $this->skullRotation = $rotation; } } diff --git a/src/block/utils/BlockDataSerializer.php b/src/block/utils/BlockDataSerializer.php index 0c0c8005b..4bf5e9b75 100644 --- a/src/block/utils/BlockDataSerializer.php +++ b/src/block/utils/BlockDataSerializer.php @@ -150,7 +150,7 @@ final class BlockDataSerializer{ } public static function readBoundedInt(string $name, int $v, int $min, int $max) : int{ - if($v < $min or $v > $max){ + if($v < $min || $v > $max){ throw new InvalidBlockStateException("$name should be in range $min - $max, got $v"); } return $v; diff --git a/src/block/utils/FallableTrait.php b/src/block/utils/FallableTrait.php index 33f71a890..6afcc52bf 100644 --- a/src/block/utils/FallableTrait.php +++ b/src/block/utils/FallableTrait.php @@ -50,7 +50,7 @@ trait FallableTrait{ public function onNearbyBlockChange() : void{ $pos = $this->getPosition(); $down = $pos->getWorld()->getBlock($pos->getSide(Facing::DOWN)); - if($down->getId() === BlockLegacyIds::AIR or $down instanceof Liquid or $down instanceof Fire){ + if($down->getId() === BlockLegacyIds::AIR || $down instanceof Liquid || $down instanceof Fire){ $pos->getWorld()->setBlock($pos, VanillaBlocks::AIR()); $block = $this; diff --git a/src/block/utils/MinimumCostFlowCalculator.php b/src/block/utils/MinimumCostFlowCalculator.php index 95e845791..e299caaa3 100644 --- a/src/block/utils/MinimumCostFlowCalculator.php +++ b/src/block/utils/MinimumCostFlowCalculator.php @@ -55,7 +55,7 @@ final class MinimumCostFlowCalculator{ $cost = 1000; foreach(Facing::HORIZONTAL as $j){ - if($j === $originOpposite or $j === $lastOpposite){ + if($j === $originOpposite || $j === $lastOpposite){ continue; } diff --git a/src/block/utils/SignText.php b/src/block/utils/SignText.php index 753e25bb3..4c7eeeb02 100644 --- a/src/block/utils/SignText.php +++ b/src/block/utils/SignText.php @@ -89,7 +89,7 @@ class SignText{ if(!is_int($index)){ throw new \InvalidArgumentException("Index must be an integer"); } - if($index < 0 or $index >= self::LINE_COUNT){ + if($index < 0 || $index >= self::LINE_COUNT){ throw new \InvalidArgumentException("Line index is out of bounds"); } } From 8db137882cdcc0b817b1a013ae6c51014db29aa1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 16:58:38 +0000 Subject: [PATCH 653/710] Scrub baseline --- tests/phpstan/configs/and-or-logical.neon | 670 ---------------------- 1 file changed, 670 deletions(-) diff --git a/tests/phpstan/configs/and-or-logical.neon b/tests/phpstan/configs/and-or-logical.neon index 14b6e1c25..59144f71a 100644 --- a/tests/phpstan/configs/and-or-logical.neon +++ b/tests/phpstan/configs/and-or-logical.neon @@ -30,631 +30,6 @@ parameters: count: 5 path: ../../../src/Server.php - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Anvil.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Bamboo.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/block/BaseBanner.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/BaseRail.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/BaseRail.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 6 - path: ../../../src/block/Bed.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 4 - path: ../../../src/block/Block.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Block.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/BlockBreakInfo.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/BlockBreakInfo.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/block/BlockFactory.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/BlockFactory.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/BrewingStand.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Cactus.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/Cactus.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 4 - path: ../../../src/block/Chest.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Chest.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/CocoaBlock.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/Crops.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Dirt.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/block/Door.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Door.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 4 - path: ../../../src/block/DoublePlant.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/DoublePlant.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/DoubleTallGrass.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/DragonEgg.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/EndRod.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/EnderChest.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Fence.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 4 - path: ../../../src/block/Fence.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/FenceGate.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/FenceGate.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 6 - path: ../../../src/block/Fire.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/Fire.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Flower.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/FlowerPot.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 6 - path: ../../../src/block/FlowerPot.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/block/FrostedIce.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/FrostedIce.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/Furnace.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/Grass.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/block/Grass.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Gravel.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Ice.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/Ice.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/ItemFrame.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/block/ItemFrame.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Ladder.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Lantern.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/Lantern.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 4 - path: ../../../src/block/Leaves.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Leaves.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 9 - path: ../../../src/block/Liquid.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 6 - path: ../../../src/block/Liquid.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Magma.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/NetherPortal.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/NetherWartPlant.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/Note.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Pumpkin.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/RedstoneComparator.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Sand.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Sapling.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Sapling.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/SeaPickle.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/SeaPickle.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/ShulkerBox.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Skull.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 9 - path: ../../../src/block/Slab.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 5 - path: ../../../src/block/Slab.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/SnowLayer.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/block/SnowLayer.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/block/Stair.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/block/Stair.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Stem.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/Stem.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Sugarcane.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/block/Sugarcane.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/SweetBerryBush.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/TNT.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/TNT.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/TallGrass.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/block/Thin.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 5 - path: ../../../src/block/Torch.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/block/Torch.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Trapdoor.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/Trapdoor.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/Vine.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/Vine.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 8 - path: ../../../src/block/Wall.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/block/Wall.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/inventory/BarrelInventory.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/inventory/ChestInventory.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/inventory/DoubleChestInventory.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/inventory/EnderChestInventory.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/block/inventory/ShulkerBoxInventory.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/tile/Barrel.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/tile/BrewingStand.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 7 - path: ../../../src/block/tile/Chest.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/block/tile/Chest.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/tile/FlowerPot.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/tile/FlowerPot.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 10 - path: ../../../src/block/tile/Furnace.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/block/tile/Furnace.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/tile/Hopper.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/tile/ItemFrame.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/tile/Note.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/tile/Note.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/tile/ShulkerBox.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/block/tile/Skull.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/utils/BlockDataSerializer.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/utils/MinimumCostFlowCalculator.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/block/utils/SignText.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/command/Command.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/command/Command.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 6 - path: ../../../src/command/FormattedCommandAlias.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/command/PluginCommand.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/command/SimpleCommandMap.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/command/SimpleCommandMap.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/command/defaults/ClearCommand.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/command/defaults/EffectCommand.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/command/defaults/ListCommand.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/command/defaults/ParticleCommand.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/command/defaults/TimingsCommand.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/command/defaults/TimingsCommand.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/console/ConsoleCommandSender.php - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" count: 1 @@ -1475,48 +850,3 @@ parameters: count: 4 path: ../../../src/world/utils/SubChunkExplorer.php - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../tools/compact-regions.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../tools/compact-regions.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../tools/convert-world.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../tools/convert-world.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../tools/ping-server.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../phpunit/item/ItemTest.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../phpunit/scheduler/AsyncPoolTest.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../plugins/TesterPlugin/src/Test.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../rules/DisallowEnumComparisonRule.php - From c47dfa1fb807240f8399c05bf7ceeb7b0f9c7cf0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:00:54 +0000 Subject: [PATCH 654/710] Replace disallowed operators in build/ --- build/generate-registry-annotations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/generate-registry-annotations.php b/build/generate-registry-annotations.php index a5959eaf5..ebc39631b 100644 --- a/build/generate-registry-annotations.php +++ b/build/generate-registry-annotations.php @@ -58,7 +58,7 @@ function generateMethodAnnotations(string $namespaceName, array $members) : stri $memberLines = []; foreach($members as $name => $member){ $reflect = new \ReflectionClass($member); - while($reflect !== false and $reflect->isAnonymous()){ + while($reflect !== false && $reflect->isAnonymous()){ $reflect = $reflect->getParentClass(); } if($reflect === false){ From 282b430b1fc2a6ff7187679202632fbcaaa12f1e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:02:26 +0000 Subject: [PATCH 655/710] Replace disallowed operators in src/utils/ --- src/utils/Config.php | 4 ++-- src/utils/Filesystem.php | 2 +- src/utils/Git.php | 4 ++-- src/utils/Internet.php | 10 +++++----- src/utils/MainLogger.php | 4 ++-- src/utils/Process.php | 6 +++--- src/utils/Terminal.php | 6 +++--- src/utils/Timezone.php | 16 ++++++++-------- src/utils/Utils.php | 14 +++++++------- src/utils/VersionString.php | 2 +- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/utils/Config.php b/src/utils/Config.php index 78bd4c955..f15bfe1e5 100644 --- a/src/utils/Config.php +++ b/src/utils/Config.php @@ -393,7 +393,7 @@ class Config{ while(count($vars) > 0){ $baseKey = array_shift($vars); - if(is_array($base) and isset($base[$baseKey])){ + if(is_array($base) && isset($base[$baseKey])){ $base = $base[$baseKey]; }else{ return $default; @@ -505,7 +505,7 @@ class Config{ $changed = 0; foreach(Utils::stringifyKeys($default) as $k => $v){ if(is_array($v)){ - if(!isset($data[$k]) or !is_array($data[$k])){ + if(!isset($data[$k]) || !is_array($data[$k])){ $data[$k] = []; } $changed += $this->fillDefaults($v, $data[$k]); diff --git a/src/utils/Filesystem.php b/src/utils/Filesystem.php index 9545bad1a..56d45790e 100644 --- a/src/utils/Filesystem.php +++ b/src/utils/Filesystem.php @@ -81,7 +81,7 @@ final class Filesystem{ if(is_dir($dir)){ $objects = Utils::assumeNotFalse(scandir($dir, SCANDIR_SORT_NONE), "scandir() shouldn't return false when is_dir() returns true"); foreach($objects as $object){ - if($object !== "." and $object !== ".."){ + if($object !== "." && $object !== ".."){ $fullObject = Path::join($dir, $object); if(is_dir($fullObject)){ self::recursiveUnlink($fullObject); diff --git a/src/utils/Git.php b/src/utils/Git.php index dd83eb033..65142330b 100644 --- a/src/utils/Git.php +++ b/src/utils/Git.php @@ -39,8 +39,8 @@ final class Git{ * @param bool $dirty reference parameter, set to whether the repo has local changes */ public static function getRepositoryState(string $dir, bool &$dirty) : ?string{ - if(Process::execute("git -C \"$dir\" rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){ - if(Process::execute("git -C \"$dir\" diff --quiet") === 1 or Process::execute("git -C \"$dir\" diff --cached --quiet") === 1){ //Locally-modified + if(Process::execute("git -C \"$dir\" rev-parse HEAD", $out) === 0 && $out !== false && strlen($out = trim($out)) === 40){ + if(Process::execute("git -C \"$dir\" diff --quiet") === 1 || Process::execute("git -C \"$dir\" diff --cached --quiet") === 1){ //Locally-modified $dirty = true; } return $out; diff --git a/src/utils/Internet.php b/src/utils/Internet.php index 329457b26..ff0c3ca21 100644 --- a/src/utils/Internet.php +++ b/src/utils/Internet.php @@ -80,7 +80,7 @@ class Internet{ public static function getIP(bool $force = false){ if(!self::$online){ return false; - }elseif(self::$ip !== false and !$force){ + }elseif(self::$ip !== false && !$force){ return self::$ip; } @@ -90,22 +90,22 @@ class Internet{ } $ip = self::getURL("http://checkip.dyndns.org/"); - if($ip !== null and preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', trim(strip_tags($ip->getBody())), $matches) > 0){ + if($ip !== null && preg_match('#Current IP Address\: ([0-9a-fA-F\:\.]*)#', trim(strip_tags($ip->getBody())), $matches) > 0){ return self::$ip = $matches[1]; } $ip = self::getURL("http://www.checkip.org/"); - if($ip !== null and preg_match('#">([0-9a-fA-F\:\.]*)
#', $ip->getBody(), $matches) > 0){ + if($ip !== null && preg_match('#">([0-9a-fA-F\:\.]*)
#', $ip->getBody(), $matches) > 0){ return self::$ip = $matches[1]; } $ip = self::getURL("http://checkmyip.org/"); - if($ip !== null and preg_match('#Your IP address is ([0-9a-fA-F\:\.]*)#', $ip->getBody(), $matches) > 0){ + if($ip !== null && preg_match('#Your IP address is ([0-9a-fA-F\:\.]*)#', $ip->getBody(), $matches) > 0){ return self::$ip = $matches[1]; } $ip = self::getURL("http://ifconfig.me/ip"); - if($ip !== null and ($addr = trim($ip->getBody())) != ""){ + if($ip !== null && ($addr = trim($ip->getBody())) != ""){ return self::$ip = $addr; } diff --git a/src/utils/MainLogger.php b/src/utils/MainLogger.php index c7290f0d2..415f59b2c 100644 --- a/src/utils/MainLogger.php +++ b/src/utils/MainLogger.php @@ -115,7 +115,7 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ } public function debug($message, bool $force = false){ - if(!$this->logDebug and !$force){ + if(!$this->logDebug && !$force){ return; } $this->send($message, \LogLevel::DEBUG, "DEBUG", TextFormat::GRAY); @@ -193,7 +193,7 @@ class MainLogger extends \AttachableThreadedLogger implements \BufferedLogger{ $thread = \Thread::getCurrentThread(); if($thread === null){ $threadName = $this->mainThreadName . " thread"; - }elseif($thread instanceof Thread or $thread instanceof Worker){ + }elseif($thread instanceof Thread || $thread instanceof Worker){ $threadName = $thread->getThreadName() . " thread"; }else{ $threadName = (new \ReflectionClass($thread))->getShortName() . " thread"; diff --git a/src/utils/Process.php b/src/utils/Process.php index 8e93f9b1c..503bba7c5 100644 --- a/src/utils/Process.php +++ b/src/utils/Process.php @@ -56,7 +56,7 @@ final class Process{ $reserved = memory_get_usage(); $VmSize = null; $VmRSS = null; - if(Utils::getOS() === Utils::OS_LINUX or Utils::getOS() === Utils::OS_ANDROID){ + if(Utils::getOS() === Utils::OS_LINUX || Utils::getOS() === Utils::OS_ANDROID){ $status = @file_get_contents("/proc/self/status"); if($status === false) throw new AssumptionFailedError("/proc/self/status should always be accessible"); @@ -94,7 +94,7 @@ final class Process{ $stack = 0; $heap = 0; - if(Utils::getOS() === Utils::OS_LINUX or Utils::getOS() === Utils::OS_ANDROID){ + if(Utils::getOS() === Utils::OS_LINUX || Utils::getOS() === Utils::OS_ANDROID){ $mappings = @file("/proc/self/maps"); if($mappings === false) throw new AssumptionFailedError("/proc/self/maps should always be accessible"); foreach($mappings as $line){ @@ -112,7 +112,7 @@ final class Process{ } public static function getThreadCount() : int{ - if(Utils::getOS() === Utils::OS_LINUX or Utils::getOS() === Utils::OS_ANDROID){ + if(Utils::getOS() === Utils::OS_LINUX || Utils::getOS() === Utils::OS_ANDROID){ $status = @file_get_contents("/proc/self/status"); if($status === false) throw new AssumptionFailedError("/proc/self/status should always be accessible"); if(preg_match("/Threads:[ \t]+([0-9]+)/", $status, $matches) > 0){ diff --git a/src/utils/Terminal.php b/src/utils/Terminal.php index 46aeaccae..955abc660 100644 --- a/src/utils/Terminal.php +++ b/src/utils/Terminal.php @@ -74,10 +74,10 @@ abstract class Terminal{ $stdout = fopen("php://stdout", "w"); if($stdout === false) throw new AssumptionFailedError("Opening php://stdout should never fail"); $result = ( - stream_isatty($stdout) and //STDOUT isn't being piped + stream_isatty($stdout) && //STDOUT isn't being piped ( - getenv('TERM') !== false or //Console says it supports colours - (function_exists('sapi_windows_vt100_support') and sapi_windows_vt100_support($stdout)) //we're on windows and have vt100 support + getenv('TERM') !== false || //Console says it supports colours + (function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support($stdout)) //we're on windows and have vt100 support ) ); fclose($stdout); diff --git a/src/utils/Timezone.php b/src/utils/Timezone.php index 79884751a..95358e704 100644 --- a/src/utils/Timezone.php +++ b/src/utils/Timezone.php @@ -77,7 +77,7 @@ abstract class Timezone{ } } - if(($timezone = self::detectSystemTimezone()) !== false and date_default_timezone_set($timezone)){ + if(($timezone = self::detectSystemTimezone()) !== false && date_default_timezone_set($timezone)){ //Success! Timezone has already been set and validated in the if statement. //This here is just for redundancy just in case some program wants to read timezone data from the ini. ini_set("date.timezone", $timezone); @@ -85,11 +85,11 @@ abstract class Timezone{ } if(($response = Internet::getURL("http://ip-api.com/json")) !== null //If system timezone detection fails or timezone is an invalid value. - and is_array($ip_geolocation_data = json_decode($response->getBody(), true)) - and isset($ip_geolocation_data['status']) - and $ip_geolocation_data['status'] !== 'fail' - and is_string($ip_geolocation_data['timezone']) - and date_default_timezone_set($ip_geolocation_data['timezone']) + && is_array($ip_geolocation_data = json_decode($response->getBody(), true)) + && isset($ip_geolocation_data['status']) + && $ip_geolocation_data['status'] !== 'fail' + && is_string($ip_geolocation_data['timezone']) + && date_default_timezone_set($ip_geolocation_data['timezone']) ){ //Again, for redundancy. ini_set("date.timezone", $ip_geolocation_data['timezone']); @@ -150,7 +150,7 @@ abstract class Timezone{ // RHEL / CentOS $data = @parse_ini_file('/etc/sysconfig/clock'); - if($data !== false and isset($data['ZONE']) and is_string($data['ZONE'])){ + if($data !== false && isset($data['ZONE']) && is_string($data['ZONE'])){ return trim($data['ZONE']); } @@ -165,7 +165,7 @@ abstract class Timezone{ return self::parseOffset($offset); case Utils::OS_MACOS: $filename = @readlink('/etc/localtime'); - if($filename !== false and strpos($filename, '/usr/share/zoneinfo/') === 0){ + if($filename !== false && strpos($filename, '/usr/share/zoneinfo/') === 0){ $timezone = substr($filename, 20); return trim($timezone); } diff --git a/src/utils/Utils.php b/src/utils/Utils.php index d3f4ae1a4..0b772ae64 100644 --- a/src/utils/Utils.php +++ b/src/utils/Utils.php @@ -189,7 +189,7 @@ final class Utils{ * @param string $extra optional, additional data to identify the machine */ public static function getMachineUniqueId(string $extra = "") : UuidInterface{ - if(self::$serverUniqueId !== null and $extra === ""){ + if(self::$serverUniqueId !== null && $extra === ""){ return self::$serverUniqueId; } @@ -265,7 +265,7 @@ final class Utils{ * Other => other */ public static function getOS(bool $recalculate = false) : string{ - if(self::$os === null or $recalculate){ + if(self::$os === null || $recalculate){ $uname = php_uname("s"); if(stripos($uname, "Darwin") !== false){ if(strpos(php_uname("m"), "iP") === 0){ @@ -273,7 +273,7 @@ final class Utils{ }else{ self::$os = self::OS_MACOS; } - }elseif(stripos($uname, "Win") !== false or $uname === "Msys"){ + }elseif(stripos($uname, "Win") !== false || $uname === "Msys"){ self::$os = self::OS_WINDOWS; }elseif(stripos($uname, "Linux") !== false){ if(@file_exists("/system/build.prop")){ @@ -281,7 +281,7 @@ final class Utils{ }else{ self::$os = self::OS_LINUX; } - }elseif(stripos($uname, "BSD") !== false or $uname === "DragonFly"){ + }elseif(stripos($uname, "BSD") !== false || $uname === "DragonFly"){ self::$os = self::OS_BSD; }else{ self::$os = self::OS_UNKNOWN; @@ -294,7 +294,7 @@ final class Utils{ public static function getCoreCount(bool $recalculate = false) : int{ static $processors = 0; - if($processors > 0 and !$recalculate){ + if($processors > 0 && !$recalculate){ return $processors; }else{ $processors = 0; @@ -443,7 +443,7 @@ final class Utils{ $messages = []; for($i = 0; isset($trace[$i]); ++$i){ $params = ""; - if(isset($trace[$i]["args"]) or isset($trace[$i]["params"])){ + if(isset($trace[$i]["args"]) || isset($trace[$i]["params"])){ if(isset($trace[$i]["args"])){ $args = $trace[$i]["args"]; }else{ @@ -466,7 +466,7 @@ final class Utils{ return gettype($value) . " " . Utils::printable((string) $value); }, $args)); } - $messages[] = "#$i " . (isset($trace[$i]["file"]) ? Filesystem::cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" or $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")"; + $messages[] = "#$i " . (isset($trace[$i]["file"]) ? Filesystem::cleanPath($trace[$i]["file"]) : "") . "(" . (isset($trace[$i]["line"]) ? $trace[$i]["line"] : "") . "): " . (isset($trace[$i]["class"]) ? $trace[$i]["class"] . (($trace[$i]["type"] === "dynamic" || $trace[$i]["type"] === "->") ? "->" : "::") : "") . $trace[$i]["function"] . "(" . Utils::printable($params) . ")"; } return $messages; } diff --git a/src/utils/VersionString.php b/src/utils/VersionString.php index 095be3c2c..0b2aed47a 100644 --- a/src/utils/VersionString.php +++ b/src/utils/VersionString.php @@ -79,7 +79,7 @@ class VersionString{ $retval = $this->baseVersion; if($this->development){ $retval .= "+dev"; - if($build and $this->build > 0){ + if($build && $this->build > 0){ $retval .= "." . $this->build; } } From aae5962f6a3deea7218dcac57fdf4d5e77728533 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:05:23 +0000 Subject: [PATCH 656/710] Replace disallowed operators in src/world/ --- src/world/Explosion.php | 2 +- src/world/Position.php | 6 +- src/world/SimpleChunkManager.php | 6 +- src/world/World.php | 70 +++++++++---------- src/world/WorldManager.php | 14 ++-- src/world/format/BiomeArray.php | 4 +- src/world/format/Chunk.php | 4 +- src/world/format/HeightArray.php | 2 +- src/world/format/io/WorldProviderManager.php | 2 +- src/world/format/io/leveldb/LevelDB.php | 12 ++-- .../format/io/region/RegionGarbageMap.php | 2 +- src/world/format/io/region/RegionLoader.php | 10 +-- .../io/region/RegionLocationTableEntry.php | 8 +-- .../format/io/region/RegionWorldProvider.php | 4 +- src/world/generator/Flat.php | 2 +- src/world/generator/GeneratorManager.php | 2 +- src/world/generator/hell/Nether.php | 2 +- src/world/generator/noise/Noise.php | 4 +- src/world/generator/normal/Normal.php | 2 +- src/world/generator/object/Ore.php | 4 +- src/world/generator/object/SpruceTree.php | 2 +- src/world/generator/object/TallGrass.php | 2 +- src/world/generator/object/Tree.php | 6 +- src/world/generator/populator/GroundCover.php | 6 +- src/world/generator/populator/TallGrass.php | 6 +- src/world/generator/populator/Tree.php | 4 +- src/world/light/LightUpdate.php | 6 +- .../particle/DragonEggTeleportParticle.php | 2 +- src/world/sound/NoteSound.php | 2 +- src/world/utils/SubChunkExplorer.php | 6 +- 30 files changed, 102 insertions(+), 102 deletions(-) diff --git a/src/world/Explosion.php b/src/world/Explosion.php index b02964dd6..f67d9034f 100644 --- a/src/world/Explosion.php +++ b/src/world/Explosion.php @@ -102,7 +102,7 @@ class Explosion{ for($i = 0; $i < $this->rays; ++$i){ for($j = 0; $j < $this->rays; ++$j){ for($k = 0; $k < $this->rays; ++$k){ - if($i === 0 or $i === $mRays or $j === 0 or $j === $mRays or $k === 0 or $k === $mRays){ + if($i === 0 || $i === $mRays || $j === 0 || $j === $mRays || $k === 0 || $k === $mRays){ //this could be written as new Vector3(...)->normalize()->multiply(stepLen), but we're avoiding Vector3 for performance here [$shiftX, $shiftY, $shiftZ] = [$i / $mRays * 2 - 1, $j / $mRays * 2 - 1, $k / $mRays * 2 - 1]; $len = sqrt($shiftX ** 2 + $shiftY ** 2 + $shiftZ ** 2); diff --git a/src/world/Position.php b/src/world/Position.php index f3fe84caa..5339adbec 100644 --- a/src/world/Position.php +++ b/src/world/Position.php @@ -39,7 +39,7 @@ class Position extends Vector3{ */ public function __construct($x, $y, $z, ?World $world){ parent::__construct($x, $y, $z); - if($world !== null and !$world->isLoaded()){ + if($world !== null && !$world->isLoaded()){ throw new \InvalidArgumentException("Specified world has been unloaded and cannot be used"); } @@ -77,7 +77,7 @@ class Position extends Vector3{ * Checks if this object has a valid reference to a loaded world */ public function isValid() : bool{ - if($this->world !== null and !$this->world->isLoaded()){ + if($this->world !== null && !$this->world->isLoaded()){ $this->world = null; return false; @@ -103,7 +103,7 @@ class Position extends Vector3{ public function equals(Vector3 $v) : bool{ if($v instanceof Position){ - return parent::equals($v) and $v->world === $this->world; + return parent::equals($v) && $v->world === $this->world; } return parent::equals($v); } diff --git a/src/world/SimpleChunkManager.php b/src/world/SimpleChunkManager.php index 105412bb5..1b2605f33 100644 --- a/src/world/SimpleChunkManager.php +++ b/src/world/SimpleChunkManager.php @@ -81,9 +81,9 @@ class SimpleChunkManager implements ChunkManager{ public function isInWorld(int $x, int $y, int $z) : bool{ return ( - $x <= Limits::INT32_MAX and $x >= Limits::INT32_MIN and - $y < $this->maxY and $y >= $this->minY and - $z <= Limits::INT32_MAX and $z >= Limits::INT32_MIN + $x <= Limits::INT32_MAX && $x >= Limits::INT32_MIN && + $y < $this->maxY && $y >= $this->minY && + $z <= Limits::INT32_MAX && $z >= Limits::INT32_MIN ); } } diff --git a/src/world/World.php b/src/world/World.php index 8806ffef8..65ded6fa4 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -839,7 +839,7 @@ class World implements ChunkManager{ $this->timings->scheduledBlockUpdates->startTiming(); //Delayed updates - while($this->scheduledBlockUpdateQueue->count() > 0 and $this->scheduledBlockUpdateQueue->current()["priority"] <= $currentTick){ + while($this->scheduledBlockUpdateQueue->count() > 0 && $this->scheduledBlockUpdateQueue->current()["priority"] <= $currentTick){ /** @var Vector3 $vec */ $vec = $this->scheduledBlockUpdateQueue->extract()["data"]; unset($this->scheduledBlockUpdateQueueIndex[World::blockHash($vec->x, $vec->y, $vec->z)]); @@ -878,7 +878,7 @@ class World implements ChunkManager{ //Update entities that need update Timings::$tickEntity->startTiming(); foreach($this->updateEntities as $id => $entity){ - if($entity->isClosed() or $entity->isFlaggedForDespawn() or !$entity->onUpdate($currentTick)){ + if($entity->isClosed() || $entity->isFlaggedForDespawn() || !$entity->onUpdate($currentTick)){ unset($this->updateEntities[$id]); } if($entity->isFlaggedForDespawn()){ @@ -918,7 +918,7 @@ class World implements ChunkManager{ } - if($this->sleepTicks > 0 and --$this->sleepTicks <= 0){ + if($this->sleepTicks > 0 && --$this->sleepTicks <= 0){ $this->checkSleep(); } @@ -949,7 +949,7 @@ class World implements ChunkManager{ if($resetTime){ $time = $this->getTimeOfDay(); - if($time >= World::TIME_NIGHT and $time < World::TIME_SUNRISE){ + if($time >= World::TIME_NIGHT && $time < World::TIME_SUNRISE){ $this->setTime($this->getTime() + World::TIME_FULL - $time); foreach($this->getPlayers() as $p){ @@ -1028,7 +1028,7 @@ class World implements ChunkManager{ } private function tickChunks() : void{ - if($this->chunksPerTick <= 0 or count($this->tickingLoaders) === 0){ + if($this->chunksPerTick <= 0 || count($this->tickingLoaders) === 0){ return; } @@ -1049,7 +1049,7 @@ class World implements ChunkManager{ $dx = mt_rand(-$randRange, $randRange); $dz = mt_rand(-$randRange, $randRange); $hash = World::chunkHash($dx + $chunkX, $dz + $chunkZ); - if(!isset($chunkTickList[$hash]) and isset($this->chunks[$hash]) and $this->isChunkTickable($dx + $chunkX, $dz + $chunkZ)){ + if(!isset($chunkTickList[$hash]) && isset($this->chunks[$hash]) && $this->isChunkTickable($dx + $chunkX, $dz + $chunkZ)){ $chunkTickList[$hash] = true; } } @@ -1164,7 +1164,7 @@ class World implements ChunkManager{ public function save(bool $force = false) : bool{ - if(!$this->getAutoSave() and !$force){ + if(!$this->getAutoSave() && !$force){ return false; } @@ -1200,8 +1200,8 @@ class World implements ChunkManager{ */ public function scheduleDelayedBlockUpdate(Vector3 $pos, int $delay) : void{ if( - !$this->isInWorld($pos->x, $pos->y, $pos->z) or - (isset($this->scheduledBlockUpdateQueueIndex[$index = World::blockHash($pos->x, $pos->y, $pos->z)]) and $this->scheduledBlockUpdateQueueIndex[$index] <= $delay) + !$this->isInWorld($pos->x, $pos->y, $pos->z) || + (isset($this->scheduledBlockUpdateQueueIndex[$index = World::blockHash($pos->x, $pos->y, $pos->z)]) && $this->scheduledBlockUpdateQueueIndex[$index] <= $delay) ){ return; } @@ -1520,9 +1520,9 @@ class World implements ChunkManager{ public function isInWorld(int $x, int $y, int $z) : bool{ return ( - $x <= Limits::INT32_MAX and $x >= Limits::INT32_MIN and - $y < $this->maxY and $y >= $this->minY and - $z <= Limits::INT32_MAX and $z >= Limits::INT32_MIN + $x <= Limits::INT32_MAX && $x >= Limits::INT32_MIN && + $y < $this->maxY && $y >= $this->minY && + $z <= Limits::INT32_MAX && $z >= Limits::INT32_MIN ); } @@ -1556,7 +1556,7 @@ class World implements ChunkManager{ if($this->isInWorld($x, $y, $z)){ $relativeBlockHash = World::chunkBlockHash($x, $y, $z); - if($cached and isset($this->blockCache[$chunkHash][$relativeBlockHash])){ + if($cached && isset($this->blockCache[$chunkHash][$relativeBlockHash])){ return $this->blockCache[$chunkHash][$relativeBlockHash]; } @@ -1586,7 +1586,7 @@ class World implements ChunkManager{ $dynamicStateRead = false; } - if($addToCache and $relativeBlockHash !== null){ + if($addToCache && $relativeBlockHash !== null){ $this->blockCache[$chunkHash][$relativeBlockHash] = $block; } @@ -1713,23 +1713,23 @@ class World implements ChunkManager{ } $drops = []; - if($player === null or $player->hasFiniteResources()){ + if($player === null || $player->hasFiniteResources()){ $drops = array_merge(...array_map(fn(Block $block) => $block->getDrops($item), $affectedBlocks)); } $xpDrop = 0; - if($player !== null and $player->hasFiniteResources()){ + if($player !== null && $player->hasFiniteResources()){ $xpDrop = array_sum(array_map(fn(Block $block) => $block->getXpDropForTool($item), $affectedBlocks)); } if($player !== null){ $ev = new BlockBreakEvent($player, $target, $item, $player->isCreative(), $drops, $xpDrop); - if($target instanceof Air or ($player->isSurvival() and !$target->getBreakInfo()->isBreakable()) or $player->isSpectator()){ + if($target instanceof Air || ($player->isSurvival() && !$target->getBreakInfo()->isBreakable()) || $player->isSpectator()){ $ev->cancel(); } - if($player->isAdventure(true) and !$ev->isCancelled()){ + if($player->isAdventure(true) && !$ev->isCancelled()){ $canBreak = false; $itemParser = LegacyStringToItemParser::getInstance(); foreach($item->getCanDestroy() as $v){ @@ -1828,7 +1828,7 @@ class World implements ChunkManager{ $ev->call(); if(!$ev->isCancelled()){ - if((!$player->isSneaking() or $item->isNull()) and $blockClicked->onInteract($item, $face, $clickVector, $player)){ + if((!$player->isSneaking() || $item->isNull()) && $blockClicked->onInteract($item, $face, $clickVector, $player)){ return true; } @@ -1843,7 +1843,7 @@ class World implements ChunkManager{ return true; } - if($item->isNull() or !$item->canBePlaced()){ + if($item->isNull() || !$item->canBePlaced()){ return false; } $hand = $item->getBlock($face); @@ -1876,7 +1876,7 @@ class World implements ChunkManager{ $ev->cancel(); } - if($player->isAdventure(true) and !$ev->isCancelled()){ + if($player->isAdventure(true) && !$ev->isCancelled()){ $canPlace = false; $itemParser = LegacyStringToItemParser::getInstance(); foreach($item->getCanPlaceOn() as $v){ @@ -1941,9 +1941,9 @@ class World implements ChunkManager{ public function getCollidingEntities(AxisAlignedBB $bb, ?Entity $entity = null) : array{ $nearby = []; - if($entity === null or $entity->canCollide){ + if($entity === null || $entity->canCollide){ foreach($this->getNearbyEntities($bb, $entity) as $ent){ - if($ent->canBeCollidedWith() and ($entity === null or $entity->canCollideWith($ent))){ + if($ent->canBeCollidedWith() && ($entity === null || $entity->canCollideWith($ent))){ $nearby[] = $ent; } } @@ -1971,7 +1971,7 @@ class World implements ChunkManager{ continue; } foreach($this->getChunkEntities($x, $z) as $ent){ - if($ent !== $entity and $ent->boundingBox->intersectsWith($bb)){ + if($ent !== $entity && $ent->boundingBox->intersectsWith($bb)){ $nearby[] = $ent; } } @@ -2014,7 +2014,7 @@ class World implements ChunkManager{ continue; } foreach($this->getChunkEntities($x, $z) as $entity){ - if(!($entity instanceof $entityType) or $entity->isFlaggedForDespawn() or (!$includeDead and !$entity->isAlive())){ + if(!($entity instanceof $entityType) || $entity->isFlaggedForDespawn() || (!$includeDead && !$entity->isAlive())){ continue; } $distSq = $entity->getPosition()->distanceSquared($pos); @@ -2173,7 +2173,7 @@ class World implements ChunkManager{ public function setChunk(int $chunkX, int $chunkZ, Chunk $chunk) : void{ $chunkHash = World::chunkHash($chunkX, $chunkZ); $oldChunk = $this->loadChunk($chunkX, $chunkZ); - if($oldChunk !== null and $oldChunk !== $chunk){ + if($oldChunk !== null && $oldChunk !== $chunk){ $deletedTiles = 0; $transferredTiles = 0; foreach($oldChunk->getTiles() as $oldTile){ @@ -2439,7 +2439,7 @@ class World implements ChunkManager{ } public function isChunkInUse(int $x, int $z) : bool{ - return isset($this->chunkLoaders[$index = World::chunkHash($x, $z)]) and count($this->chunkLoaders[$index]) > 0; + return isset($this->chunkLoaders[$index = World::chunkHash($x, $z)]) && count($this->chunkLoaders[$index]) > 0; } /** @@ -2582,7 +2582,7 @@ class World implements ChunkManager{ } public function unloadChunkRequest(int $x, int $z, bool $safe = true) : bool{ - if(($safe and $this->isChunkInUse($x, $z)) or $this->isSpawnChunk($x, $z)){ + if(($safe && $this->isChunkInUse($x, $z)) || $this->isSpawnChunk($x, $z)){ return false; } @@ -2596,7 +2596,7 @@ class World implements ChunkManager{ } public function unloadChunk(int $x, int $z, bool $safe = true, bool $trySave = true) : bool{ - if($safe and $this->isChunkInUse($x, $z)){ + if($safe && $this->isChunkInUse($x, $z)){ return false; } @@ -2619,7 +2619,7 @@ class World implements ChunkManager{ return false; } - if($trySave and $this->getAutoSave()){ + if($trySave && $this->getAutoSave()){ $this->timings->syncChunkSave->startTiming(); try{ $this->provider->saveChunk($x, $z, new ChunkData( @@ -2668,14 +2668,14 @@ class World implements ChunkManager{ $spawnX = $spawn->x >> Chunk::COORD_BIT_SIZE; $spawnZ = $spawn->z >> Chunk::COORD_BIT_SIZE; - return abs($X - $spawnX) <= 1 and abs($Z - $spawnZ) <= 1; + return abs($X - $spawnX) <= 1 && abs($Z - $spawnZ) <= 1; } /** * @throws WorldException if the terrain is not generated */ public function getSafeSpawn(?Vector3 $spawn = null) : Position{ - if(!($spawn instanceof Vector3) or $spawn->y < 1){ + if(!($spawn instanceof Vector3) || $spawn->y < 1){ $spawn = $this->getSpawnLocation(); } @@ -2700,7 +2700,7 @@ class World implements ChunkManager{ } } - for(; $y >= $this->minY and $y < $max; ++$y){ + for(; $y >= $this->minY && $y < $max; ++$y){ if(!$this->getBlockAt($x, $y + 1, $z)->isFullCube()){ if(!$this->getBlockAt($x, $y, $z)->isFullCube()){ return new Position($spawn->x, $y === (int) $spawn->y ? $spawn->y : $y, $spawn->z, $this); @@ -2786,7 +2786,7 @@ class World implements ChunkManager{ } public function setDifficulty(int $difficulty) : void{ - if($difficulty < 0 or $difficulty > 3){ + if($difficulty < 0 || $difficulty > 3){ throw new \InvalidArgumentException("Invalid difficulty level $difficulty"); } $this->provider->getWorldData()->setDifficulty($difficulty); @@ -3013,7 +3013,7 @@ class World implements ChunkManager{ $this->setChunk($x + $relativeX, $z + $relativeZ, $adjacentChunk); } - if(($oldChunk === null or !$oldChunk->isPopulated()) and $chunk->isPopulated()){ + if(($oldChunk === null || !$oldChunk->isPopulated()) && $chunk->isPopulated()){ (new ChunkPopulateEvent($this, $x, $z, $chunk))->call(); foreach($this->getChunkListeners($x, $z) as $listener){ diff --git a/src/world/WorldManager.php b/src/world/WorldManager.php index aa906e4ab..65fe54726 100644 --- a/src/world/WorldManager.php +++ b/src/world/WorldManager.php @@ -104,7 +104,7 @@ class WorldManager{ * it only affects the server on runtime */ public function setDefaultWorld(?World $world) : void{ - if($world === null or ($this->isWorldLoaded($world->getFolderName()) and $world !== $this->defaultWorld)){ + if($world === null || ($this->isWorldLoaded($world->getFolderName()) && $world !== $this->defaultWorld)){ $this->defaultWorld = $world; } } @@ -134,7 +134,7 @@ class WorldManager{ * @throws \InvalidArgumentException */ public function unloadWorld(World $world, bool $forceUnload = false) : bool{ - if($world === $this->getDefaultWorld() and !$forceUnload){ + if($world === $this->getDefaultWorld() && !$forceUnload){ throw new \InvalidArgumentException("The default world cannot be unloaded while running, please switch worlds."); } if($world->isDoingTick()){ @@ -142,13 +142,13 @@ class WorldManager{ } $ev = new WorldUnloadEvent($world); - if($world === $this->defaultWorld and !$forceUnload){ + if($world === $this->defaultWorld && !$forceUnload){ $ev->cancel(); } $ev->call(); - if(!$forceUnload and $ev->isCancelled()){ + if(!$forceUnload && $ev->isCancelled()){ return false; } @@ -159,7 +159,7 @@ class WorldManager{ $safeSpawn = null; } foreach($world->getPlayers() as $player){ - if($world === $this->defaultWorld or $safeSpawn === null){ + if($world === $this->defaultWorld || $safeSpawn === null){ $player->disconnect("Forced default world unload"); }else{ $player->teleport($safeSpawn); @@ -271,7 +271,7 @@ class WorldManager{ * @throws \InvalidArgumentException */ public function generateWorld(string $name, WorldCreationOptions $options, bool $backgroundGeneration = true) : bool{ - if(trim($name) === "" or $this->isWorldGenerated($name)){ + if(trim($name) === "" || $this->isWorldGenerated($name)){ return false; } @@ -365,7 +365,7 @@ class WorldManager{ } } - if($this->autoSave and ++$this->autoSaveTicker >= $this->autoSaveTicks){ + if($this->autoSave && ++$this->autoSaveTicker >= $this->autoSaveTicks){ $this->autoSaveTicker = 0; $this->server->getLogger()->debug("[Auto Save] Saving worlds..."); $start = microtime(true); diff --git a/src/world/format/BiomeArray.php b/src/world/format/BiomeArray.php index 30a5d2cb0..ed45e88fc 100644 --- a/src/world/format/BiomeArray.php +++ b/src/world/format/BiomeArray.php @@ -48,7 +48,7 @@ final class BiomeArray{ } private static function idx(int $x, int $z) : int{ - if($x < 0 or $x >= 16 or $z < 0 or $z >= 16){ + if($x < 0 || $x >= 16 || $z < 0 || $z >= 16){ throw new \InvalidArgumentException("x and z must be in the range 0-15"); } return ($z << 4) | $x; @@ -59,7 +59,7 @@ final class BiomeArray{ } public function set(int $x, int $z, int $biomeId) : void{ - if($biomeId < 0 or $biomeId >= 256){ + if($biomeId < 0 || $biomeId >= 256){ throw new \InvalidArgumentException("Biome ID must be in the range 0-255"); } $this->payload[self::idx($x, $z)] = chr($biomeId); diff --git a/src/world/format/Chunk.php b/src/world/format/Chunk.php index 8bb5eed9f..6a8dad59c 100644 --- a/src/world/format/Chunk.php +++ b/src/world/format/Chunk.php @@ -197,7 +197,7 @@ class Chunk{ } $pos = $tile->getPosition(); - if(isset($this->tiles[$index = Chunk::blockHash($pos->x, $pos->y, $pos->z)]) and $this->tiles[$index] !== $tile){ + if(isset($this->tiles[$index = Chunk::blockHash($pos->x, $pos->y, $pos->z)]) && $this->tiles[$index] !== $tile){ throw new \InvalidArgumentException("Another tile is already at this location"); } $this->tiles[$index] = $tile; @@ -292,7 +292,7 @@ class Chunk{ * Sets a subchunk in the chunk index */ public function setSubChunk(int $y, ?SubChunk $subChunk) : void{ - if($y < self::MIN_SUBCHUNK_INDEX or $y > self::MAX_SUBCHUNK_INDEX){ + if($y < self::MIN_SUBCHUNK_INDEX || $y > self::MAX_SUBCHUNK_INDEX){ throw new \InvalidArgumentException("Invalid subchunk Y coordinate $y"); } diff --git a/src/world/format/HeightArray.php b/src/world/format/HeightArray.php index 54c8e19f3..88df7299b 100644 --- a/src/world/format/HeightArray.php +++ b/src/world/format/HeightArray.php @@ -50,7 +50,7 @@ final class HeightArray{ } private static function idx(int $x, int $z) : int{ - if($x < 0 or $x >= 16 or $z < 0 or $z >= 16){ + if($x < 0 || $x >= 16 || $z < 0 || $z >= 16){ throw new \InvalidArgumentException("x and z must be in the range 0-15"); } return ($z << 4) | $x; diff --git a/src/world/format/io/WorldProviderManager.php b/src/world/format/io/WorldProviderManager.php index 64dad0816..db67c6221 100644 --- a/src/world/format/io/WorldProviderManager.php +++ b/src/world/format/io/WorldProviderManager.php @@ -63,7 +63,7 @@ final class WorldProviderManager{ public function addProvider(WorldProviderManagerEntry $providerEntry, string $name, bool $overwrite = false) : void{ $name = strtolower($name); - if(!$overwrite and isset($this->providers[$name])){ + if(!$overwrite && isset($this->providers[$name])){ throw new \InvalidArgumentException("Alias \"$name\" is already assigned"); } diff --git a/src/world/format/io/leveldb/LevelDB.php b/src/world/format/io/leveldb/LevelDB.php index acd8ffed4..91d367fb0 100644 --- a/src/world/format/io/leveldb/LevelDB.php +++ b/src/world/format/io/leveldb/LevelDB.php @@ -144,7 +144,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ } public static function isValid(string $path) : bool{ - return file_exists(Path::join($path, "level.dat")) and is_dir(Path::join($path, "db")); + return file_exists(Path::join($path, "level.dat")) && is_dir(Path::join($path, "db")); } public static function generate(string $path, string $name, WorldCreationOptions $options) : void{ @@ -207,7 +207,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ * @return PalettedBlockArray[] */ protected function deserializeLegacyExtraData(string $index, int $chunkVersion) : array{ - if(($extraRawData = $this->db->get($index . self::TAG_BLOCK_EXTRA_DATA)) === false or $extraRawData === ""){ + if(($extraRawData = $this->db->get($index . self::TAG_BLOCK_EXTRA_DATA)) === false || $extraRawData === ""){ return []; } @@ -391,7 +391,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ /** @var CompoundTag[] $entities */ $entities = []; - if(($entityData = $this->db->get($index . self::TAG_ENTITY)) !== false and $entityData !== ""){ + if(($entityData = $this->db->get($index . self::TAG_ENTITY)) !== false && $entityData !== ""){ try{ $entities = array_map(fn(TreeRoot $root) => $root->mustGetCompoundTag(), $nbt->readMultiple($entityData)); }catch(NbtDataException $e){ @@ -401,7 +401,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ /** @var CompoundTag[] $tiles */ $tiles = []; - if(($tileData = $this->db->get($index . self::TAG_BLOCK_ENTITY)) !== false and $tileData !== ""){ + if(($tileData = $this->db->get($index . self::TAG_BLOCK_ENTITY)) !== false && $tileData !== ""){ try{ $tiles = array_map(fn(TreeRoot $root) => $root->mustGetCompoundTag(), $nbt->readMultiple($tileData)); }catch(NbtDataException $e){ @@ -527,7 +527,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ public function getAllChunks(bool $skipCorrupted = false, ?\Logger $logger = null) : \Generator{ foreach($this->db->getIterator() as $key => $_){ - if(strlen($key) === 9 and substr($key, -1) === self::TAG_VERSION){ + if(strlen($key) === 9 && substr($key, -1) === self::TAG_VERSION){ $chunkX = Binary::readLInt(substr($key, 0, 4)); $chunkZ = Binary::readLInt(substr($key, 4, 4)); try{ @@ -549,7 +549,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{ public function calculateChunkCount() : int{ $count = 0; foreach($this->db->getIterator() as $key => $_){ - if(strlen($key) === 9 and substr($key, -1) === self::TAG_VERSION){ + if(strlen($key) === 9 && substr($key, -1) === self::TAG_VERSION){ $count++; } } diff --git a/src/world/format/io/region/RegionGarbageMap.php b/src/world/format/io/region/RegionGarbageMap.php index a3dd8e542..9b0373449 100644 --- a/src/world/format/io/region/RegionGarbageMap.php +++ b/src/world/format/io/region/RegionGarbageMap.php @@ -95,7 +95,7 @@ final class RegionGarbageMap{ /** @var int|null $prevIndex */ $prevIndex = null; foreach($this->entries as $k => $entry){ - if($prevIndex !== null and $this->entries[$prevIndex]->getLastSector() + 1 === $entry->getFirstSector()){ + if($prevIndex !== null && $this->entries[$prevIndex]->getLastSector() + 1 === $entry->getFirstSector()){ //this SHOULD overwrite the previous index and not appear at the end $this->entries[$prevIndex] = new RegionLocationTableEntry( $this->entries[$prevIndex]->getFirstSector(), diff --git a/src/world/format/io/region/RegionLoader.php b/src/world/format/io/region/RegionLoader.php index dd50f6c38..449052454 100644 --- a/src/world/format/io/region/RegionLoader.php +++ b/src/world/format/io/region/RegionLoader.php @@ -169,7 +169,7 @@ class RegionLoader{ } $compression = $stream->getByte(); - if($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP){ + if($compression !== self::COMPRESSION_ZLIB && $compression !== self::COMPRESSION_GZIP){ throw new CorruptedChunkException("Invalid compression type (got $compression, expected " . self::COMPRESSION_ZLIB . " or " . self::COMPRESSION_GZIP . ")"); } @@ -192,7 +192,7 @@ class RegionLoader{ $endGarbage = $this->garbageTable->end(); $nextSector = $this->nextSector; - for(; $endGarbage !== null and $endGarbage->getLastSector() + 1 === $nextSector; $endGarbage = $this->garbageTable->end()){ + for(; $endGarbage !== null && $endGarbage->getLastSector() + 1 === $nextSector; $endGarbage = $this->garbageTable->end()){ $nextSector = $endGarbage->getFirstSector(); $this->garbageTable->remove($endGarbage); } @@ -267,7 +267,7 @@ class RegionLoader{ * @throws \InvalidArgumentException */ protected static function getChunkOffset(int $x, int $z) : int{ - if($x < 0 or $x > 31 or $z < 0 or $z > 31){ + if($x < 0 || $x > 31 || $z < 0 || $z > 31){ throw new \InvalidArgumentException("Invalid chunk position in region, expected x/z in range 0-31, got x=$x, z=$z"); } return $x | ($z << 5); @@ -298,7 +298,7 @@ class RegionLoader{ fseek($this->filePointer, 0); $headerRaw = fread($this->filePointer, self::REGION_HEADER_LENGTH); - if($headerRaw === false or strlen($headerRaw) !== self::REGION_HEADER_LENGTH){ + if($headerRaw === false || strlen($headerRaw) !== self::REGION_HEADER_LENGTH){ throw new CorruptedRegionException("Corrupted region header (unexpected end of file)"); } @@ -311,7 +311,7 @@ class RegionLoader{ $sectorCount = $index & 0xff; $timestamp = $data[$i + 1025]; - if($offset === 0 or $sectorCount === 0){ + if($offset === 0 || $sectorCount === 0){ $this->locationTable[$i] = null; }elseif($offset >= self::FIRST_SECTOR){ $this->bumpNextFreeSector($this->locationTable[$i] = new RegionLocationTableEntry($offset, $sectorCount, $timestamp)); diff --git a/src/world/format/io/region/RegionLocationTableEntry.php b/src/world/format/io/region/RegionLocationTableEntry.php index 8a7fdfaeb..c3c68be87 100644 --- a/src/world/format/io/region/RegionLocationTableEntry.php +++ b/src/world/format/io/region/RegionLocationTableEntry.php @@ -38,7 +38,7 @@ class RegionLocationTableEntry{ * @throws \InvalidArgumentException */ public function __construct(int $firstSector, int $sectorCount, int $timestamp){ - if($firstSector < 0 or $firstSector >= 2 ** 24){ + if($firstSector < 0 || $firstSector >= 2 ** 24){ throw new \InvalidArgumentException("Start sector must be positive, got $firstSector"); } $this->firstSector = $firstSector; @@ -79,10 +79,10 @@ class RegionLocationTableEntry{ $entry2Last = $entry2->getLastSector(); return ( - ($entry2->firstSector >= $entry1->firstSector and $entry2->firstSector <= $entry1Last) or - ($entry2Last >= $entry1->firstSector and $entry2Last <= $entry1Last) + ($entry2->firstSector >= $entry1->firstSector && $entry2->firstSector <= $entry1Last) || + ($entry2Last >= $entry1->firstSector && $entry2Last <= $entry1Last) ); }; - return $overlapCheck($this, $other) or $overlapCheck($other, $this); + return $overlapCheck($this, $other) || $overlapCheck($other, $this); } } diff --git a/src/world/format/io/region/RegionWorldProvider.php b/src/world/format/io/region/RegionWorldProvider.php index 1fe62912c..25fcf65b3 100644 --- a/src/world/format/io/region/RegionWorldProvider.php +++ b/src/world/format/io/region/RegionWorldProvider.php @@ -59,7 +59,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{ abstract protected static function getPcWorldFormatVersion() : int; public static function isValid(string $path) : bool{ - if(file_exists(Path::join($path, "level.dat")) and is_dir($regionPath = Path::join($path, "region"))){ + if(file_exists(Path::join($path, "level.dat")) && is_dir($regionPath = Path::join($path, "region"))){ foreach(scandir($regionPath, SCANDIR_SORT_NONE) as $file){ $extPos = strrpos($file, "."); if($extPos !== false && substr($file, $extPos + 1) === static::getRegionFileExtension()){ @@ -191,7 +191,7 @@ abstract class RegionWorldProvider extends BaseWorldProvider{ public function loadChunk(int $chunkX, int $chunkZ) : ?ChunkData{ $regionX = $regionZ = null; self::getRegionIndex($chunkX, $chunkZ, $regionX, $regionZ); - assert(is_int($regionX) and is_int($regionZ)); + assert(is_int($regionX) && is_int($regionZ)); if(!file_exists($this->pathToRegion($regionX, $regionZ))){ return null; diff --git a/src/world/generator/Flat.php b/src/world/generator/Flat.php index 26a658b6d..06dadc517 100644 --- a/src/world/generator/Flat.php +++ b/src/world/generator/Flat.php @@ -75,7 +75,7 @@ class Flat extends Generator{ $count = count($structure); for($sy = 0; $sy < $count; $sy += SubChunk::EDGE_LENGTH){ $subchunk = $this->chunk->getSubChunk($sy >> SubChunk::COORD_BIT_SIZE); - for($y = 0; $y < SubChunk::EDGE_LENGTH and isset($structure[$y | $sy]); ++$y){ + for($y = 0; $y < SubChunk::EDGE_LENGTH && isset($structure[$y | $sy]); ++$y){ $id = $structure[$y | $sy]; for($Z = 0; $Z < SubChunk::EDGE_LENGTH; ++$Z){ diff --git a/src/world/generator/GeneratorManager.php b/src/world/generator/GeneratorManager.php index f90c6ae4a..76bda57b6 100644 --- a/src/world/generator/GeneratorManager.php +++ b/src/world/generator/GeneratorManager.php @@ -73,7 +73,7 @@ final class GeneratorManager{ Utils::testValidInstance($class, Generator::class); $name = strtolower($name); - if(!$overwrite and isset($this->list[$name])){ + if(!$overwrite && isset($this->list[$name])){ throw new \InvalidArgumentException("Alias \"$name\" is already assigned"); } diff --git a/src/world/generator/hell/Nether.php b/src/world/generator/hell/Nether.php index 8657e2580..5440c6d04 100644 --- a/src/world/generator/hell/Nether.php +++ b/src/world/generator/hell/Nether.php @@ -86,7 +86,7 @@ class Nether extends Generator{ $chunk->setBiomeId($x, $z, BiomeIds::HELL); for($y = 0; $y < 128; ++$y){ - if($y === 0 or $y === 127){ + if($y === 0 || $y === 127){ $chunk->setFullBlock($x, $y, $z, $bedrock); continue; } diff --git a/src/world/generator/noise/Noise.php b/src/world/generator/noise/Noise.php index fde81d10b..1d0b7b3b1 100644 --- a/src/world/generator/noise/Noise.php +++ b/src/world/generator/noise/Noise.php @@ -256,7 +256,7 @@ abstract class Noise{ } for($zz = 0; $zz < $zSize; ++$zz){ - if($xx % $samplingRate !== 0 or $zz % $samplingRate !== 0){ + if($xx % $samplingRate !== 0 || $zz % $samplingRate !== 0){ $nx = (int) ($xx / $samplingRate) * $samplingRate; $nz = (int) ($zz / $samplingRate) * $samplingRate; $noiseArray[$xx][$zz] = Noise::bilinearLerp( @@ -320,7 +320,7 @@ abstract class Noise{ $dz2 = ($zz - $nz) / ($nnz - $nz); for($yy = 0; $yy < $ySize; ++$yy){ - if($xx % $xSamplingRate !== 0 or $zz % $zSamplingRate !== 0 or $yy % $ySamplingRate !== 0){ + if($xx % $xSamplingRate !== 0 || $zz % $zSamplingRate !== 0 || $yy % $ySamplingRate !== 0){ $ny = (int) ($yy / $ySamplingRate) * $ySamplingRate; $nny = $ny + $ySamplingRate; diff --git a/src/world/generator/normal/Normal.php b/src/world/generator/normal/Normal.php index f8a006663..a1aebfc1b 100644 --- a/src/world/generator/normal/Normal.php +++ b/src/world/generator/normal/Normal.php @@ -173,7 +173,7 @@ class Normal extends Generator{ $weight = $this->gaussian->kernel[$sx + $this->gaussian->smoothSize][$sz + $this->gaussian->smoothSize]; - if($sx === 0 and $sz === 0){ + if($sx === 0 && $sz === 0){ $adjacent = $biome; }else{ $index = World::chunkHash($absoluteX + $sx, $absoluteZ + $sz); diff --git a/src/world/generator/object/Ore.php b/src/world/generator/object/Ore.php index aad9cc034..5a3066030 100644 --- a/src/world/generator/object/Ore.php +++ b/src/world/generator/object/Ore.php @@ -80,12 +80,12 @@ class Ore{ $sizeY = ($yy + 0.5 - $seedY) / $size; $sizeY *= $sizeY; - if($yy > 0 and ($sizeX + $sizeY) < 1){ + if($yy > 0 && ($sizeX + $sizeY) < 1){ for($zz = $startZ; $zz <= $endZ; ++$zz){ $sizeZ = ($zz + 0.5 - $seedZ) / $size; $sizeZ *= $sizeZ; - if(($sizeX + $sizeY + $sizeZ) < 1 and $world->getBlockAt($xx, $yy, $zz)->isSameType($this->type->replaces)){ + if(($sizeX + $sizeY + $sizeZ) < 1 && $world->getBlockAt($xx, $yy, $zz)->isSameType($this->type->replaces)){ $world->setBlockAt($xx, $yy, $zz, $this->type->material); } } diff --git a/src/world/generator/object/SpruceTree.php b/src/world/generator/object/SpruceTree.php index 3439b03d4..acac1210a 100644 --- a/src/world/generator/object/SpruceTree.php +++ b/src/world/generator/object/SpruceTree.php @@ -58,7 +58,7 @@ class SpruceTree extends Tree{ $xOff = abs($xx - $x); for($zz = $z - $radius; $zz <= $z + $radius; ++$zz){ $zOff = abs($zz - $z); - if($xOff === $radius and $zOff === $radius and $radius > 0){ + if($xOff === $radius && $zOff === $radius && $radius > 0){ continue; } diff --git a/src/world/generator/object/TallGrass.php b/src/world/generator/object/TallGrass.php index 80e75e5a1..8fe70e0c8 100644 --- a/src/world/generator/object/TallGrass.php +++ b/src/world/generator/object/TallGrass.php @@ -47,7 +47,7 @@ class TallGrass{ for($c = 0; $c < $count; ++$c){ $x = $random->nextRange($pos->x - $radius, $pos->x + $radius); $z = $random->nextRange($pos->z - $radius, $pos->z + $radius); - if($world->getBlockAt($x, $pos->y + 1, $z)->getId() === BlockLegacyIds::AIR and $world->getBlockAt($x, $pos->y, $z)->getId() === BlockLegacyIds::GRASS){ + if($world->getBlockAt($x, $pos->y + 1, $z)->getId() === BlockLegacyIds::AIR && $world->getBlockAt($x, $pos->y, $z)->getId() === BlockLegacyIds::GRASS){ $world->setBlockAt($x, $pos->y + 1, $z, $arr[$random->nextRange(0, $arrC)]); } } diff --git a/src/world/generator/object/Tree.php b/src/world/generator/object/Tree.php index 90eef6c3a..9b032ad95 100644 --- a/src/world/generator/object/Tree.php +++ b/src/world/generator/object/Tree.php @@ -51,7 +51,7 @@ abstract class Tree{ public function canPlaceObject(ChunkManager $world, int $x, int $y, int $z, Random $random) : bool{ $radiusToCheck = 0; for($yy = 0; $yy < $this->treeHeight + 3; ++$yy){ - if($yy === 1 or $yy === $this->treeHeight){ + if($yy === 1 || $yy === $this->treeHeight){ ++$radiusToCheck; } for($xx = -$radiusToCheck; $xx < ($radiusToCheck + 1); ++$xx){ @@ -105,7 +105,7 @@ abstract class Tree{ $xOff = abs($xx - $x); for($zz = $z - $mid; $zz <= $z + $mid; ++$zz){ $zOff = abs($zz - $z); - if($xOff === $mid and $zOff === $mid and ($yOff === 0 or $random->nextBoundedInt(2) === 0)){ + if($xOff === $mid && $zOff === $mid && ($yOff === 0 || $random->nextBoundedInt(2) === 0)){ continue; } if(!$transaction->fetchBlockAt($xx, $yy, $zz)->isSolid()){ @@ -117,6 +117,6 @@ abstract class Tree{ } protected function canOverride(Block $block) : bool{ - return $block->canBeReplaced() or $block instanceof Sapling or $block instanceof Leaves; + return $block->canBeReplaced() || $block instanceof Sapling || $block instanceof Leaves; } } diff --git a/src/world/generator/populator/GroundCover.php b/src/world/generator/populator/GroundCover.php index da5a336a3..7a72e021c 100644 --- a/src/world/generator/populator/GroundCover.php +++ b/src/world/generator/populator/GroundCover.php @@ -57,13 +57,13 @@ class GroundCover implements Populator{ } $startY = min(127, $startY + $diffY); $endY = $startY - count($cover); - for($y = $startY; $y > $endY and $y >= 0; --$y){ + for($y = $startY; $y > $endY && $y >= 0; --$y){ $b = $cover[$startY - $y]; $id = $factory->fromFullBlock($chunk->getFullBlock($x, $y, $z)); - if($id->getId() === BlockLegacyIds::AIR and $b->isSolid()){ + if($id->getId() === BlockLegacyIds::AIR && $b->isSolid()){ break; } - if($b->canBeFlowedInto() and $id instanceof Liquid){ + if($b->canBeFlowedInto() && $id instanceof Liquid){ continue; } diff --git a/src/world/generator/populator/TallGrass.php b/src/world/generator/populator/TallGrass.php index 6783e6537..10e3d53c5 100644 --- a/src/world/generator/populator/TallGrass.php +++ b/src/world/generator/populator/TallGrass.php @@ -52,7 +52,7 @@ class TallGrass implements Populator{ $z = $random->nextRange($chunkZ * Chunk::EDGE_LENGTH, $chunkZ * Chunk::EDGE_LENGTH + (Chunk::EDGE_LENGTH - 1)); $y = $this->getHighestWorkableBlock($world, $x, $z); - if($y !== -1 and $this->canTallGrassStay($world, $x, $y, $z)){ + if($y !== -1 && $this->canTallGrassStay($world, $x, $y, $z)){ $world->setBlockAt($x, $y, $z, $block); } } @@ -60,13 +60,13 @@ class TallGrass implements Populator{ private function canTallGrassStay(ChunkManager $world, int $x, int $y, int $z) : bool{ $b = $world->getBlockAt($x, $y, $z)->getId(); - return ($b === BlockLegacyIds::AIR or $b === BlockLegacyIds::SNOW_LAYER) and $world->getBlockAt($x, $y - 1, $z)->getId() === BlockLegacyIds::GRASS; + return ($b === BlockLegacyIds::AIR || $b === BlockLegacyIds::SNOW_LAYER) && $world->getBlockAt($x, $y - 1, $z)->getId() === BlockLegacyIds::GRASS; } private function getHighestWorkableBlock(ChunkManager $world, int $x, int $z) : int{ for($y = 127; $y >= 0; --$y){ $b = $world->getBlockAt($x, $y, $z)->getId(); - if($b !== BlockLegacyIds::AIR and $b !== BlockLegacyIds::LEAVES and $b !== BlockLegacyIds::LEAVES2 and $b !== BlockLegacyIds::SNOW_LAYER){ + if($b !== BlockLegacyIds::AIR && $b !== BlockLegacyIds::LEAVES && $b !== BlockLegacyIds::LEAVES2 && $b !== BlockLegacyIds::SNOW_LAYER){ return $y + 1; } } diff --git a/src/world/generator/populator/Tree.php b/src/world/generator/populator/Tree.php index 45eb64835..ba4e7d0ae 100644 --- a/src/world/generator/populator/Tree.php +++ b/src/world/generator/populator/Tree.php @@ -72,9 +72,9 @@ class Tree implements Populator{ private function getHighestWorkableBlock(ChunkManager $world, int $x, int $z) : int{ for($y = 127; $y >= 0; --$y){ $b = $world->getBlockAt($x, $y, $z)->getId(); - if($b === BlockLegacyIds::DIRT or $b === BlockLegacyIds::GRASS){ + if($b === BlockLegacyIds::DIRT || $b === BlockLegacyIds::GRASS){ return $y + 1; - }elseif($b !== BlockLegacyIds::AIR and $b !== BlockLegacyIds::SNOW_LAYER){ + }elseif($b !== BlockLegacyIds::AIR && $b !== BlockLegacyIds::SNOW_LAYER){ return -1; } } diff --git a/src/world/light/LightUpdate.php b/src/world/light/LightUpdate.php index a8b196a52..45fa19df3 100644 --- a/src/world/light/LightUpdate.php +++ b/src/world/light/LightUpdate.php @@ -134,7 +134,7 @@ abstract class LightUpdate{ if($this->subChunkExplorer->moveTo($cx, $cy, $cz) !== SubChunkExplorerStatus::INVALID){ $this->computeRemoveLight($cx, $cy, $cz, $oldAdjacentLight, $context); - }elseif($this->getEffectiveLight($cx, $cy, $cz) > 0 and !isset($context->spreadVisited[$index = World::blockHash($cx, $cy, $cz)])){ + }elseif($this->getEffectiveLight($cx, $cy, $cz) > 0 && !isset($context->spreadVisited[$index = World::blockHash($cx, $cy, $cz)])){ $context->spreadVisited[$index] = true; $context->spreadQueue->enqueue([$cx, $cy, $cz]); } @@ -173,7 +173,7 @@ abstract class LightUpdate{ $lz = $z & SubChunk::COORD_MASK; $current = $lightArray->get($lx, $ly, $lz); - if($current !== 0 and $current < $oldAdjacentLevel){ + if($current !== 0 && $current < $oldAdjacentLevel){ $lightArray->set($lx, $ly, $lz, 0); if(!isset($context->removalVisited[$index = World::blockHash($x, $y, $z)])){ @@ -201,7 +201,7 @@ abstract class LightUpdate{ if($current < $potentialLight){ $lightArray->set($lx, $ly, $lz, $potentialLight); - if(!isset($context->spreadVisited[$index = World::blockHash($x, $y, $z)]) and $potentialLight > 1){ + if(!isset($context->spreadVisited[$index = World::blockHash($x, $y, $z)]) && $potentialLight > 1){ $context->spreadVisited[$index] = true; $context->spreadQueue->enqueue([$x, $y, $z]); } diff --git a/src/world/particle/DragonEggTeleportParticle.php b/src/world/particle/DragonEggTeleportParticle.php index a2f2ae3ac..924fba112 100644 --- a/src/world/particle/DragonEggTeleportParticle.php +++ b/src/world/particle/DragonEggTeleportParticle.php @@ -44,7 +44,7 @@ class DragonEggTeleportParticle implements Particle{ } private static function boundOrThrow(int $v) : int{ - if($v < -255 or $v > 255){ + if($v < -255 || $v > 255){ throw new \InvalidArgumentException("Value must be between -255 and 255"); } return $v; diff --git a/src/world/sound/NoteSound.php b/src/world/sound/NoteSound.php index 00101b8d7..c8822a1a9 100644 --- a/src/world/sound/NoteSound.php +++ b/src/world/sound/NoteSound.php @@ -35,7 +35,7 @@ class NoteSound implements Sound{ private $note; public function __construct(NoteInstrument $instrument, int $note){ - if($note < 0 or $note > 255){ + if($note < 0 || $note > 255){ throw new \InvalidArgumentException("Note $note is outside accepted range"); } $this->instrument = $instrument; diff --git a/src/world/utils/SubChunkExplorer.php b/src/world/utils/SubChunkExplorer.php index 69bdb44e1..1a52dd9cb 100644 --- a/src/world/utils/SubChunkExplorer.php +++ b/src/world/utils/SubChunkExplorer.php @@ -53,7 +53,7 @@ class SubChunkExplorer{ public function moveTo(int $x, int $y, int $z) : int{ $newChunkX = $x >> SubChunk::COORD_BIT_SIZE; $newChunkZ = $z >> SubChunk::COORD_BIT_SIZE; - if($this->currentChunk === null or $this->currentX !== $newChunkX or $this->currentZ !== $newChunkZ){ + if($this->currentChunk === null || $this->currentX !== $newChunkX || $this->currentZ !== $newChunkZ){ $this->currentX = $newChunkX; $this->currentZ = $newChunkZ; $this->currentSubChunk = null; @@ -65,10 +65,10 @@ class SubChunkExplorer{ } $newChunkY = $y >> SubChunk::COORD_BIT_SIZE; - if($this->currentSubChunk === null or $this->currentY !== $newChunkY){ + if($this->currentSubChunk === null || $this->currentY !== $newChunkY){ $this->currentY = $newChunkY; - if($this->currentY < Chunk::MIN_SUBCHUNK_INDEX or $this->currentY > Chunk::MAX_SUBCHUNK_INDEX){ + if($this->currentY < Chunk::MIN_SUBCHUNK_INDEX || $this->currentY > Chunk::MAX_SUBCHUNK_INDEX){ $this->currentSubChunk = null; return SubChunkExplorerStatus::INVALID; } From 2bcb629d7838d23f4b95ba63d2447c6ee1180ef7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:08:44 +0000 Subject: [PATCH 657/710] Scrub baseline --- tests/phpstan/configs/and-or-logical.neon | 275 ---------------------- 1 file changed, 275 deletions(-) diff --git a/tests/phpstan/configs/and-or-logical.neon b/tests/phpstan/configs/and-or-logical.neon index 59144f71a..3c3e513bf 100644 --- a/tests/phpstan/configs/and-or-logical.neon +++ b/tests/phpstan/configs/and-or-logical.neon @@ -1,10 +1,5 @@ parameters: ignoreErrors: - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../build/generate-registry-annotations.php - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" count: 6 @@ -575,278 +570,8 @@ parameters: count: 2 path: ../../../src/updater/UpdateChecker.php - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/utils/Config.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/utils/Config.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/utils/Filesystem.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/utils/Git.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/utils/Git.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 5 - path: ../../../src/utils/Internet.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/utils/MainLogger.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/utils/MainLogger.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/utils/Process.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/utils/Terminal.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/utils/Terminal.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 9 - path: ../../../src/utils/Timezone.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/utils/Utils.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 5 - path: ../../../src/utils/Utils.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/utils/VersionString.php - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" count: 2 path: ../../../src/wizard/SetupWizard.php - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 5 - path: ../../../src/world/Explosion.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/world/Position.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 5 - path: ../../../src/world/SimpleChunkManager.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 30 - path: ../../../src/world/World.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 17 - path: ../../../src/world/World.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 5 - path: ../../../src/world/WorldManager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/world/WorldManager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 4 - path: ../../../src/world/format/BiomeArray.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/world/format/Chunk.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/world/format/Chunk.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/world/format/HeightArray.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/world/format/io/WorldProviderManager.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 5 - path: ../../../src/world/format/io/leveldb/LevelDB.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/world/format/io/leveldb/LevelDB.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/world/format/io/region/RegionGarbageMap.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/world/format/io/region/RegionLoader.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 5 - path: ../../../src/world/format/io/region/RegionLoader.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/world/format/io/region/RegionLocationTableEntry.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/world/format/io/region/RegionLocationTableEntry.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/world/format/io/region/RegionWorldProvider.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/world/generator/Flat.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/world/generator/GeneratorManager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/world/generator/hell/Nether.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/world/generator/noise/Noise.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/world/generator/normal/Normal.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/world/generator/object/Ore.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/world/generator/object/SpruceTree.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/world/generator/object/TallGrass.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/world/generator/object/Tree.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 4 - path: ../../../src/world/generator/object/Tree.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/world/generator/populator/GroundCover.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 5 - path: ../../../src/world/generator/populator/TallGrass.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/world/generator/populator/TallGrass.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/world/generator/populator/Tree.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/world/generator/populator/Tree.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/world/light/LightUpdate.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/world/particle/DragonEggTeleportParticle.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/world/sound/NoteSound.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 4 - path: ../../../src/world/utils/SubChunkExplorer.php - From be1996752aeefa24a23092a7507864b49fc1261a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:11:32 +0000 Subject: [PATCH 658/710] Replace disallowed operators in src/network/ --- src/network/Network.php | 2 +- src/network/mcpe/InventoryManager.php | 4 ++-- src/network/mcpe/NetworkSession.php | 16 +++++++------- src/network/mcpe/auth/ProcessLoginTask.php | 4 ++-- src/network/mcpe/cache/ChunkCache.php | 2 +- .../mcpe/compression/ZlibCompressor.php | 2 +- src/network/mcpe/convert/ItemTranslator.php | 2 +- src/network/mcpe/convert/TypeConverter.php | 4 ++-- .../mcpe/handler/InGamePacketHandler.php | 22 +++++++++---------- .../mcpe/handler/LoginPacketHandler.php | 2 +- .../handler/ResourcePacksPacketHandler.php | 2 +- src/network/mcpe/raklib/RakLibInterface.php | 2 +- src/network/mcpe/raklib/RakLibServer.php | 2 +- src/network/query/QueryHandler.php | 2 +- src/network/query/QueryInfo.php | 2 +- 15 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/network/Network.php b/src/network/Network.php index fc65e3aca..2502809b1 100644 --- a/src/network/Network.php +++ b/src/network/Network.php @@ -191,7 +191,7 @@ class Network{ } public function processRawPacket(AdvancedNetworkInterface $interface, string $address, int $port, string $packet) : void{ - if(isset($this->bannedIps[$address]) and time() < $this->bannedIps[$address]){ + if(isset($this->bannedIps[$address]) && time() < $this->bannedIps[$address]){ $this->logger->debug("Dropped raw packet from banned address $address $port"); return; } diff --git a/src/network/mcpe/InventoryManager.php b/src/network/mcpe/InventoryManager.php index 2c3fff30c..e7e53b4d3 100644 --- a/src/network/mcpe/InventoryManager.php +++ b/src/network/mcpe/InventoryManager.php @@ -138,7 +138,7 @@ class InventoryManager{ public function onTransactionStart(InventoryTransaction $tx) : void{ foreach($tx->getActions() as $action){ - if($action instanceof SlotChangeAction and ($windowId = $this->getWindowId($action->getInventory())) !== null){ + if($action instanceof SlotChangeAction && ($windowId = $this->getWindowId($action->getInventory())) !== null){ //in some cases the inventory might not have a window ID, but still be referenced by a transaction (e.g. crafting grid changes), so we can't unconditionally record the change here or we might leak things $this->initiatedSlotChanges[$windowId][$action->getSlot()] = $action->getTargetItem(); } @@ -236,7 +236,7 @@ class InventoryManager{ if($windowId !== null){ $currentItem = $inventory->getItem($slot); $clientSideItem = $this->initiatedSlotChanges[$windowId][$slot] ?? null; - if($clientSideItem === null or !$clientSideItem->equalsExact($currentItem)){ + if($clientSideItem === null || !$clientSideItem->equalsExact($currentItem)){ $itemStackWrapper = ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($currentItem)); if($windowId === ContainerIds::OFFHAND){ //TODO: HACK! diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index 66b77fbb3..3c97db45e 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -392,7 +392,7 @@ class NetworkSession{ $ev = new DataPacketReceiveEvent($this, $packet); $ev->call(); - if(!$ev->isCancelled() and ($this->handler === null or !$packet->handle($this->handler))){ + if(!$ev->isCancelled() && ($this->handler === null || !$packet->handle($this->handler))){ $this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer())); } }finally{ @@ -402,7 +402,7 @@ class NetworkSession{ public function sendDataPacket(ClientboundPacket $packet, bool $immediate = false) : bool{ //Basic safety restriction. TODO: improve this - if(!$this->loggedIn and !$packet->canBeSentBeforeLogin()){ + if(!$this->loggedIn && !$packet->canBeSentBeforeLogin()){ throw new \InvalidArgumentException("Attempted to send " . get_class($packet) . " to " . $this->getDisplayName() . " too early"); } @@ -473,7 +473,7 @@ class NetworkSession{ }else{ $this->compressedQueue->enqueue($payload); $payload->onResolve(function(CompressBatchPromise $payload) : void{ - if($this->connected and $this->compressedQueue->bottom() === $payload){ + if($this->connected && $this->compressedQueue->bottom() === $payload){ $this->compressedQueue->dequeue(); //result unused $this->sendEncoded($payload->getResult()); @@ -507,7 +507,7 @@ class NetworkSession{ * @phpstan-param \Closure() : void $func */ private function tryDisconnect(\Closure $func, string $reason) : void{ - if($this->connected and !$this->disconnectGuard){ + if($this->connected && !$this->disconnectGuard){ $this->disconnectGuard = true; $func(); $this->disconnectGuard = false; @@ -586,7 +586,7 @@ class NetworkSession{ return; } if($error === null){ - if($authenticated and !($this->info instanceof XboxLivePlayerInfo)){ + if($authenticated && !($this->info instanceof XboxLivePlayerInfo)){ $error = "Expected XUID but none found"; }elseif($clientPubKey === null){ $error = "Missing client public key"; //failsafe @@ -633,7 +633,7 @@ class NetworkSession{ continue; } $info = $existingSession->getPlayerInfo(); - if($info !== null and ($info->getUsername() === $this->info->getUsername() or $info->getUuid()->equals($this->info->getUuid()))){ + if($info !== null && ($info->getUsername() === $this->info->getUsername() || $info->getUuid()->equals($this->info->getUuid()))){ if($kickForXUIDMismatch($info instanceof XboxLivePlayerInfo ? $info->getXuid() : "")){ return; } @@ -840,7 +840,7 @@ class NetworkSession{ public function syncAvailableCommands() : void{ $commandData = []; foreach($this->server->getCommandMap()->getCommands() as $name => $command){ - if(isset($commandData[$command->getName()]) or $command->getName() === "help" or !$command->testPermissionSilent($this->player)){ + if(isset($commandData[$command->getName()]) || $command->getName() === "help" || !$command->testPermissionSilent($this->player)){ continue; } @@ -920,7 +920,7 @@ class NetworkSession{ return; } $currentWorld = $this->player->getLocation()->getWorld(); - if($world !== $currentWorld or ($status = $this->player->getUsedChunkStatus($chunkX, $chunkZ)) === null){ + if($world !== $currentWorld || ($status = $this->player->getUsedChunkStatus($chunkX, $chunkZ)) === null){ $this->logger->debug("Tried to send no-longer-active chunk $chunkX $chunkZ in world " . $world->getFolderName()); return; } diff --git a/src/network/mcpe/auth/ProcessLoginTask.php b/src/network/mcpe/auth/ProcessLoginTask.php index 15cafe952..940dd8bad 100644 --- a/src/network/mcpe/auth/ProcessLoginTask.php +++ b/src/network/mcpe/auth/ProcessLoginTask.php @@ -174,11 +174,11 @@ class ProcessLoginTask extends AsyncTask{ } $time = time(); - if(isset($claims->nbf) and $claims->nbf > $time + self::CLOCK_DRIFT_MAX){ + if(isset($claims->nbf) && $claims->nbf > $time + self::CLOCK_DRIFT_MAX){ throw new VerifyLoginException(KnownTranslationKeys::POCKETMINE_DISCONNECT_INVALIDSESSION_TOOEARLY); } - if(isset($claims->exp) and $claims->exp < $time - self::CLOCK_DRIFT_MAX){ + if(isset($claims->exp) && $claims->exp < $time - self::CLOCK_DRIFT_MAX){ throw new VerifyLoginException(KnownTranslationKeys::POCKETMINE_DISCONNECT_INVALIDSESSION_TOOLATE); } diff --git a/src/network/mcpe/cache/ChunkCache.php b/src/network/mcpe/cache/ChunkCache.php index 1eb02a118..f8107e356 100644 --- a/src/network/mcpe/cache/ChunkCache.php +++ b/src/network/mcpe/cache/ChunkCache.php @@ -160,7 +160,7 @@ class ChunkCache implements ChunkListener{ private function restartPendingRequest(int $chunkX, int $chunkZ) : void{ $chunkHash = World::chunkHash($chunkX, $chunkZ); $existing = $this->caches[$chunkHash] ?? null; - if($existing === null or $existing->hasResult()){ + if($existing === null || $existing->hasResult()){ throw new \InvalidArgumentException("Restart can only be applied to unresolved promises"); } $existing->cancel(); diff --git a/src/network/mcpe/compression/ZlibCompressor.php b/src/network/mcpe/compression/ZlibCompressor.php index 284a8dcb7..a489aa153 100644 --- a/src/network/mcpe/compression/ZlibCompressor.php +++ b/src/network/mcpe/compression/ZlibCompressor.php @@ -60,7 +60,7 @@ final class ZlibCompressor implements Compressor{ } public function willCompress(string $data) : bool{ - return $this->threshold > -1 and strlen($data) >= $this->threshold; + return $this->threshold > -1 && strlen($data) >= $this->threshold; } /** diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index 87e1a6ae6..d00a6f90c 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -69,7 +69,7 @@ final class ItemTranslator{ private static function make() : self{ $data = Utils::assumeNotFalse(file_get_contents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'r16_to_current_item_map.json')), "Missing required resource file"); $json = json_decode($data, true); - if(!is_array($json) or !isset($json["simple"], $json["complex"]) || !is_array($json["simple"]) || !is_array($json["complex"])){ + if(!is_array($json) || !isset($json["simple"], $json["complex"]) || !is_array($json["simple"]) || !is_array($json["complex"])){ throw new AssumptionFailedError("Invalid item table format"); } diff --git a/src/network/mcpe/convert/TypeConverter.php b/src/network/mcpe/convert/TypeConverter.php index efa4e79c0..d03918efd 100644 --- a/src/network/mcpe/convert/TypeConverter.php +++ b/src/network/mcpe/convert/TypeConverter.php @@ -156,7 +156,7 @@ class TypeConverter{ }else{ [$id, $meta] = $idMeta; - if($itemStack instanceof Durable and $itemStack->getDamage() > 0){ + if($itemStack instanceof Durable && $itemStack->getDamage() > 0){ if($nbt !== null){ if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){ $nbt->removeTag(self::DAMAGE_TAG); @@ -266,7 +266,7 @@ class TypeConverter{ switch($action->sourceType){ case NetworkInventoryAction::SOURCE_CONTAINER: $window = null; - if($action->windowId === ContainerIds::UI and $action->inventorySlot > 0){ + if($action->windowId === ContainerIds::UI && $action->inventorySlot > 0){ if($action->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT){ return null; //useless noise } diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index cd91f4f7f..baa0d22d7 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -201,7 +201,7 @@ class InGamePacketHandler extends PacketHandler{ $curPos = $this->player->getLocation(); $newPos = $rawPos->round(4)->subtract(0, 1.62, 0); - if($this->forceMoveSync and $newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks + if($this->forceMoveSync && $newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks $this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos); //Still getting movements from before teleport, ignore them return false; @@ -316,11 +316,11 @@ class InGamePacketHandler extends PacketHandler{ foreach($data->getActions() as $networkInventoryAction){ if( ( - $networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_TODO and ( - $networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT or + $networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_TODO && ( + $networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT || $networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_USE_INGREDIENT ) - ) or ( + ) || ( $this->craftingTransaction !== null && !$networkInventoryAction->oldItem->getItemStack()->equals($networkInventoryAction->newItem->getItemStack()) && $networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER && @@ -415,10 +415,10 @@ class InGamePacketHandler extends PacketHandler{ case UseItemTransactionData::ACTION_CLICK_BLOCK: //TODO: start hack for client spam bug $clickPos = $data->getClickPosition(); - $spamBug = ($this->lastRightClickData !== null and - microtime(true) - $this->lastRightClickTime < 0.1 and //100ms - $this->lastRightClickData->getPlayerPosition()->distanceSquared($data->getPlayerPosition()) < 0.00001 and - $this->lastRightClickData->getBlockPosition()->equals($data->getBlockPosition()) and + $spamBug = ($this->lastRightClickData !== null && + microtime(true) - $this->lastRightClickTime < 0.1 && //100ms + $this->lastRightClickData->getPlayerPosition()->distanceSquared($data->getPlayerPosition()) < 0.00001 && + $this->lastRightClickData->getBlockPosition()->equals($data->getBlockPosition()) && $this->lastRightClickData->getClickPosition()->distanceSquared($clickPos) < 0.00001 //signature spam bug has 0 distance, but allow some error ); //get rid of continued spam if the player clicks and holds right-click @@ -731,7 +731,7 @@ class InGamePacketHandler extends PacketHandler{ public function handleItemFrameDropItem(ItemFrameDropItemPacket $packet) : bool{ $blockPosition = $packet->blockPosition; $block = $this->player->getWorld()->getBlockAt($blockPosition->getX(), $blockPosition->getY(), $blockPosition->getZ()); - if($block instanceof ItemFrame and $block->getFramedItem() !== null){ + if($block instanceof ItemFrame && $block->getFramedItem() !== null){ return $this->player->attackBlock(new Vector3($blockPosition->getX(), $blockPosition->getY(), $blockPosition->getZ()), $block->getFacing()); } return false; @@ -822,7 +822,7 @@ class InGamePacketHandler extends PacketHandler{ $modifiedPages[] = $packet->pageNumber; break; case BookEditPacket::TYPE_SWAP_PAGES: - if(!$newBook->pageExists($packet->pageNumber) or !$newBook->pageExists($packet->secondaryPageNumber)){ + if(!$newBook->pageExists($packet->pageNumber) || !$newBook->pageExists($packet->secondaryPageNumber)){ //the client will create pages on its own without telling us until it tries to switch them $newBook->addPage(max($packet->pageNumber, $packet->secondaryPageNumber)); } @@ -897,7 +897,7 @@ class InGamePacketHandler extends PacketHandler{ $newParts = []; $inQuotes = false; for($i = 0, $len = strlen($raw); $i <= $len; ++$i){ - if($i === $len or ($raw[$i] === "," and !$inQuotes)){ + if($i === $len || ($raw[$i] === "," && !$inQuotes)){ $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 = '""'; diff --git a/src/network/mcpe/handler/LoginPacketHandler.php b/src/network/mcpe/handler/LoginPacketHandler.php index 3ff77e2c4..f2ff2e0df 100644 --- a/src/network/mcpe/handler/LoginPacketHandler.php +++ b/src/network/mcpe/handler/LoginPacketHandler.php @@ -145,7 +145,7 @@ class LoginPacketHandler extends PacketHandler{ if(!$this->server->isWhitelisted($playerInfo->getUsername())){ $ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_SERVER_WHITELISTED, "Server is whitelisted"); } - if($this->server->getNameBans()->isBanned($playerInfo->getUsername()) or $this->server->getIPBans()->isBanned($this->session->getIp())){ + if($this->server->getNameBans()->isBanned($playerInfo->getUsername()) || $this->server->getIPBans()->isBanned($this->session->getIp())){ $ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_BANNED, "You are banned"); } diff --git a/src/network/mcpe/handler/ResourcePacksPacketHandler.php b/src/network/mcpe/handler/ResourcePacksPacketHandler.php index f82ed1232..356a95a76 100644 --- a/src/network/mcpe/handler/ResourcePacksPacketHandler.php +++ b/src/network/mcpe/handler/ResourcePacksPacketHandler.php @@ -163,7 +163,7 @@ class ResourcePacksPacketHandler extends PacketHandler{ } $offset = $packet->chunkIndex * self::PACK_CHUNK_SIZE; - if($offset < 0 or $offset >= $pack->getPackSize()){ + if($offset < 0 || $offset >= $pack->getPackSize()){ $this->disconnectWithError("Invalid out-of-bounds request for chunk $packet->chunkIndex of $packet->packId: offset $offset, file size " . $pack->getPackSize()); return false; } diff --git a/src/network/mcpe/raklib/RakLibInterface.php b/src/network/mcpe/raklib/RakLibInterface.php index 15a8177fb..5d34ad352 100644 --- a/src/network/mcpe/raklib/RakLibInterface.php +++ b/src/network/mcpe/raklib/RakLibInterface.php @@ -180,7 +180,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{ public function onPacketReceive(int $sessionId, string $packet) : void{ if(isset($this->sessions[$sessionId])){ - if($packet === "" or $packet[0] !== self::MCPE_RAKNET_PACKET_ID){ + if($packet === "" || $packet[0] !== self::MCPE_RAKNET_PACKET_ID){ $this->sessions[$sessionId]->getLogger()->debug("Non-FE packet received: " . base64_encode($packet)); return; } diff --git a/src/network/mcpe/raklib/RakLibServer.php b/src/network/mcpe/raklib/RakLibServer.php index 94ea2c973..e7ee44d2c 100644 --- a/src/network/mcpe/raklib/RakLibServer.php +++ b/src/network/mcpe/raklib/RakLibServer.php @@ -129,7 +129,7 @@ class RakLibServer extends Thread{ public function startAndWait(int $options = PTHREADS_INHERIT_NONE) : void{ $this->start($options); $this->synchronized(function() : void{ - while(!$this->ready and $this->crashInfo === null){ + while(!$this->ready && $this->crashInfo === null){ $this->wait(); } $crashInfo = $this->crashInfo; diff --git a/src/network/query/QueryHandler.php b/src/network/query/QueryHandler.php index 1fe207969..06b3c5ab0 100644 --- a/src/network/query/QueryHandler.php +++ b/src/network/query/QueryHandler.php @@ -104,7 +104,7 @@ class QueryHandler implements RawPacketHandler{ return true; case self::STATISTICS: //Stat $token = $stream->getInt(); - if($token !== ($t1 = self::getTokenString($this->token, $address)) and $token !== ($t2 = self::getTokenString($this->lastToken, $address))){ + if($token !== ($t1 = self::getTokenString($this->token, $address)) && $token !== ($t2 = self::getTokenString($this->lastToken, $address))){ $this->logger->debug("Bad token $token from $address $port, expected $t1 or $t2"); return true; diff --git a/src/network/query/QueryInfo.php b/src/network/query/QueryInfo.php index 559f9a653..5275edba7 100644 --- a/src/network/query/QueryInfo.php +++ b/src/network/query/QueryInfo.php @@ -204,7 +204,7 @@ final class QueryInfo{ $query = ""; $plist = $this->server_engine; - if(count($this->plugins) > 0 and $this->listPlugins){ + if(count($this->plugins) > 0 && $this->listPlugins){ $plist .= ":"; foreach($this->plugins as $p){ $d = $p->getDescription(); From 8f525ab3998e708ec298c95e436dec70b35a47a2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:14:28 +0000 Subject: [PATCH 659/710] Replace disallowed operators in src/entity/ --- src/entity/Attribute.php | 8 +-- src/entity/AttributeMap.php | 2 +- src/entity/Entity.php | 68 +++++++++++++------------- src/entity/EntityDataHelper.php | 6 +-- src/entity/ExperienceManager.php | 6 +-- src/entity/Human.php | 12 ++--- src/entity/HungerManager.php | 8 +-- src/entity/Living.php | 26 +++++----- src/entity/Location.php | 2 +- src/entity/Skin.php | 2 +- src/entity/Squid.php | 2 +- src/entity/Villager.php | 2 +- src/entity/effect/EffectInstance.php | 4 +- src/entity/effect/EffectManager.php | 6 +-- src/entity/effect/PoisonEffect.php | 2 +- src/entity/object/ExperienceOrb.php | 6 +-- src/entity/object/FallingBlock.php | 4 +- src/entity/object/ItemEntity.php | 14 +++--- src/entity/object/Painting.php | 4 +- src/entity/object/PrimedTNT.php | 4 +- src/entity/projectile/Arrow.php | 6 +-- src/entity/projectile/Projectile.php | 10 ++-- src/entity/projectile/SplashPotion.php | 6 +-- 23 files changed, 105 insertions(+), 105 deletions(-) diff --git a/src/entity/Attribute.php b/src/entity/Attribute.php index 589a5da47..3f9bc7faf 100644 --- a/src/entity/Attribute.php +++ b/src/entity/Attribute.php @@ -65,7 +65,7 @@ class Attribute{ protected $desynchronized = true; public function __construct(string $id, float $minValue, float $maxValue, float $defaultValue, bool $shouldSend = true){ - if($minValue > $maxValue or $defaultValue > $maxValue or $defaultValue < $minValue){ + if($minValue > $maxValue || $defaultValue > $maxValue || $defaultValue < $minValue){ throw new \InvalidArgumentException("Invalid ranges: min value: $minValue, max value: $maxValue, $defaultValue: $defaultValue"); } $this->id = $id; @@ -123,7 +123,7 @@ class Attribute{ * @return $this */ public function setDefaultValue(float $defaultValue){ - if($defaultValue > $this->getMaxValue() or $defaultValue < $this->getMinValue()){ + if($defaultValue > $this->getMaxValue() || $defaultValue < $this->getMinValue()){ throw new \InvalidArgumentException("Default $defaultValue is outside the range " . $this->getMinValue() . " - " . $this->getMaxValue()); } @@ -146,7 +146,7 @@ class Attribute{ * @return $this */ public function setValue(float $value, bool $fit = false, bool $forceSend = false){ - if($value > $this->getMaxValue() or $value < $this->getMinValue()){ + if($value > $this->getMaxValue() || $value < $this->getMinValue()){ if(!$fit){ throw new \InvalidArgumentException("Value $value is outside the range " . $this->getMinValue() . " - " . $this->getMaxValue()); } @@ -172,7 +172,7 @@ class Attribute{ } public function isDesynchronized() : bool{ - return $this->shouldSend and $this->desynchronized; + return $this->shouldSend && $this->desynchronized; } public function markSynchronized(bool $synced = true) : void{ diff --git a/src/entity/AttributeMap.php b/src/entity/AttributeMap.php index 0a4a11d3d..cc427d929 100644 --- a/src/entity/AttributeMap.php +++ b/src/entity/AttributeMap.php @@ -49,7 +49,7 @@ class AttributeMap{ */ public function needSend() : array{ return array_filter($this->attributes, function(Attribute $attribute) : bool{ - return $attribute->isSyncable() and $attribute->isDesynchronized(); + return $attribute->isSyncable() && $attribute->isDesynchronized(); }); } } diff --git a/src/entity/Entity.php b/src/entity/Entity.php index d720a3a13..417253b98 100644 --- a/src/entity/Entity.php +++ b/src/entity/Entity.php @@ -227,9 +227,9 @@ abstract class Entity{ $this->location = $location->asLocation(); assert( - !is_nan($this->location->x) and !is_infinite($this->location->x) and - !is_nan($this->location->y) and !is_infinite($this->location->y) and - !is_nan($this->location->z) and !is_infinite($this->location->z) + !is_nan($this->location->x) && !is_infinite($this->location->x) && + !is_nan($this->location->y) && !is_infinite($this->location->y) && + !is_nan($this->location->z) && !is_infinite($this->location->z) ); $this->boundingBox = new AxisAlignedBB(0, 0, 0, 0, 0, 0); @@ -590,7 +590,7 @@ abstract class Entity{ $this->health = 0; } } - }elseif($amount <= $this->getMaxHealth() or $amount < $this->health){ + }elseif($amount <= $this->getMaxHealth() || $amount < $this->health){ $this->health = $amount; }else{ $this->health = $this->getMaxHealth(); @@ -641,13 +641,13 @@ abstract class Entity{ $this->checkBlockIntersections(); - if($this->location->y <= World::Y_MIN - 16 and $this->isAlive()){ + if($this->location->y <= World::Y_MIN - 16 && $this->isAlive()){ $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_VOID, 10); $this->attack($ev); $hasUpdate = true; } - if($this->isOnFire() and $this->doOnFireTick($tickDiff)){ + if($this->isOnFire() && $this->doOnFireTick($tickDiff)){ $hasUpdate = true; } @@ -683,7 +683,7 @@ abstract class Entity{ * @throws \InvalidArgumentException */ public function setFireTicks(int $fireTicks) : void{ - if($fireTicks < 0 or $fireTicks > 0x7fff){ + if($fireTicks < 0 || $fireTicks > 0x7fff){ throw new \InvalidArgumentException("Fire ticks must be in range 0 ... " . 0x7fff . ", got $fireTicks"); } $this->fireTicks = $fireTicks; @@ -700,13 +700,13 @@ abstract class Entity{ } protected function doOnFireTick(int $tickDiff = 1) : bool{ - if($this->isFireProof() and $this->fireTicks > 1){ + if($this->isFireProof() && $this->fireTicks > 1){ $this->fireTicks = 1; }else{ $this->fireTicks -= $tickDiff; } - if(($this->fireTicks % 20 === 0) or $tickDiff > 20){ + if(($this->fireTicks % 20 === 0) || $tickDiff > 20){ $this->dealFireDamage(); } @@ -728,7 +728,7 @@ abstract class Entity{ } public function canCollideWith(Entity $entity) : bool{ - return !$this->justCreated and $entity !== $this; + return !$this->justCreated && $entity !== $this; } public function canBeCollidedWith() : bool{ @@ -748,13 +748,13 @@ abstract class Entity{ $this->setImmobile($still); } - if($teleport or $diffPosition > 0.0001 or $diffRotation > 1.0 or (!$wasStill and $still)){ + if($teleport || $diffPosition > 0.0001 || $diffRotation > 1.0 || (!$wasStill && $still)){ $this->lastLocation = $this->location->asLocation(); $this->broadcastMovement($teleport); } - if($diffMotion > 0.0025 or $wasStill !== $still){ //0.05 ** 2 + if($diffMotion > 0.0025 || $wasStill !== $still){ //0.05 ** 2 $this->lastMotion = clone $this->motion; $this->broadcastMotion(); @@ -853,27 +853,27 @@ abstract class Entity{ $direction = Facing::WEST; } - if($eastNonSolid and 1 - $diffX < $limit){ + if($eastNonSolid && 1 - $diffX < $limit){ $limit = 1 - $diffX; $direction = Facing::EAST; } - if($downNonSolid and $diffY < $limit){ + if($downNonSolid && $diffY < $limit){ $limit = $diffY; $direction = Facing::DOWN; } - if($upNonSolid and 1 - $diffY < $limit){ + if($upNonSolid && 1 - $diffY < $limit){ $limit = 1 - $diffY; $direction = Facing::UP; } - if($northNonSolid and $diffZ < $limit){ + if($northNonSolid && $diffZ < $limit){ $limit = $diffZ; $direction = Facing::NORTH; } - if($southNonSolid and 1 - $diffZ < $limit){ + if($southNonSolid && 1 - $diffZ < $limit){ $direction = Facing::SOUTH; } @@ -903,13 +903,13 @@ abstract class Entity{ $angle += 360.0; } - if((0 <= $angle and $angle < 45) or (315 <= $angle and $angle < 360)){ + if((0 <= $angle && $angle < 45) || (315 <= $angle && $angle < 360)){ return Facing::SOUTH; } - if(45 <= $angle and $angle < 135){ + if(45 <= $angle && $angle < 135){ return Facing::WEST; } - if(135 <= $angle and $angle < 225){ + if(135 <= $angle && $angle < 225){ return Facing::NORTH; } @@ -964,7 +964,7 @@ abstract class Entity{ abs($this->motion->z) <= self::MOTION_THRESHOLD ? 0 : null ); - if($this->motion->x != 0 or $this->motion->y != 0 or $this->motion->z != 0){ + if($this->motion->x != 0 || $this->motion->y != 0 || $this->motion->z != 0){ $this->move($this->motion->x, $this->motion->y, $this->motion->z); } @@ -980,7 +980,7 @@ abstract class Entity{ $this->timings->stopTiming(); //if($this->isStatic()) - return ($hasUpdate or $this->hasMovementUpdate()); + return ($hasUpdate || $this->hasMovementUpdate()); //return !($this instanceof Player); } @@ -1019,10 +1019,10 @@ abstract class Entity{ */ public function hasMovementUpdate() : bool{ return ( - $this->forceMovementUpdate or - $this->motion->x != 0 or - $this->motion->y != 0 or - $this->motion->z != 0 or + $this->forceMovementUpdate || + $this->motion->x != 0 || + $this->motion->y != 0 || + $this->motion->z != 0 || !$this->onGround ); } @@ -1095,7 +1095,7 @@ abstract class Entity{ public function isInsideOfSolid() : bool{ $block = $this->getWorld()->getBlockAt((int) floor($this->location->x), (int) floor($y = ($this->location->y + $this->getEyeHeight())), (int) floor($this->location->z)); - return $block->isSolid() and !$block->isTransparent() and $block->collidesWithBB($this->getBoundingBox()); + return $block->isSolid() && !$block->isTransparent() && $block->collidesWithBB($this->getBoundingBox()); } protected function move(float $dx, float $dy, float $dz) : void{ @@ -1114,7 +1114,7 @@ abstract class Entity{ $moveBB = clone $this->boundingBox; - assert(abs($dx) <= 20 and abs($dy) <= 20 and abs($dz) <= 20, "Movement distance is excessive: dx=$dx, dy=$dy, dz=$dz"); + assert(abs($dx) <= 20 && abs($dy) <= 20 && abs($dz) <= 20, "Movement distance is excessive: dx=$dx, dy=$dy, dz=$dz"); $list = $this->getWorld()->getCollisionBoxes($this, $moveBB->addCoord($dx, $dy, $dz), false); @@ -1124,7 +1124,7 @@ abstract class Entity{ $moveBB->offset(0, $dy, 0); - $fallingFlag = ($this->onGround or ($dy != $wantedY and $wantedY < 0)); + $fallingFlag = ($this->onGround || ($dy != $wantedY && $wantedY < 0)); foreach($list as $bb){ $dx = $bb->calculateXOffset($moveBB, $dx); @@ -1138,7 +1138,7 @@ abstract class Entity{ $moveBB->offset(0, 0, $dz); - if($this->stepHeight > 0 and $fallingFlag and ($wantedX != $dx or $wantedZ != $dz)){ + if($this->stepHeight > 0 && $fallingFlag && ($wantedX != $dx || $wantedZ != $dz)){ $cx = $dx; $cy = $dy; $cz = $dz; @@ -1214,9 +1214,9 @@ abstract class Entity{ protected function checkGroundState(float $wantedX, float $wantedY, float $wantedZ, float $dx, float $dy, float $dz) : void{ $this->isCollidedVertically = $wantedY != $dy; - $this->isCollidedHorizontally = ($wantedX != $dx or $wantedZ != $dz); - $this->isCollided = ($this->isCollidedHorizontally or $this->isCollidedVertically); - $this->onGround = ($wantedY != $dy and $wantedY < 0); + $this->isCollidedHorizontally = ($wantedX != $dx || $wantedZ != $dz); + $this->isCollided = ($this->isCollidedHorizontally || $this->isCollidedVertically); + $this->onGround = ($wantedY != $dy && $wantedY < 0); } /** @@ -1455,7 +1455,7 @@ abstract class Entity{ //TODO: this will cause some visible lag during chunk resends; if the player uses a spawn egg in a chunk, the //created entity won't be visible until after the resend arrives. However, this is better than possibly crashing //the player by sending them entities too early. - if(!isset($this->hasSpawned[$id]) and $player->getWorld() === $this->getWorld() and $player->hasReceivedChunk($this->location->getFloorX() >> Chunk::COORD_BIT_SIZE, $this->location->getFloorZ() >> Chunk::COORD_BIT_SIZE)){ + if(!isset($this->hasSpawned[$id]) && $player->getWorld() === $this->getWorld() && $player->hasReceivedChunk($this->location->getFloorX() >> Chunk::COORD_BIT_SIZE, $this->location->getFloorZ() >> Chunk::COORD_BIT_SIZE)){ $this->hasSpawned[$id] = $player; $this->sendSpawnPacket($player); diff --git a/src/entity/EntityDataHelper.php b/src/entity/EntityDataHelper.php index 928ebcdc4..f01a10bb7 100644 --- a/src/entity/EntityDataHelper.php +++ b/src/entity/EntityDataHelper.php @@ -46,7 +46,7 @@ final class EntityDataHelper{ $pos = self::parseVec3($nbt, "Pos", false); $yawPitch = $nbt->getTag("Rotation"); - if(!($yawPitch instanceof ListTag) or $yawPitch->getTagType() !== NBT::TAG_Float){ + if(!($yawPitch instanceof ListTag) || $yawPitch->getTagType() !== NBT::TAG_Float){ throw new SavedDataLoadingException("'Rotation' should be a List"); } /** @var FloatTag[] $values */ @@ -63,10 +63,10 @@ final class EntityDataHelper{ */ public static function parseVec3(CompoundTag $nbt, string $tagName, bool $optional) : Vector3{ $pos = $nbt->getTag($tagName); - if($pos === null and $optional){ + if($pos === null && $optional){ return new Vector3(0, 0, 0); } - if(!($pos instanceof ListTag) or ($pos->getTagType() !== NBT::TAG_Double && $pos->getTagType() !== NBT::TAG_Float)){ + if(!($pos instanceof ListTag) || ($pos->getTagType() !== NBT::TAG_Double && $pos->getTagType() !== NBT::TAG_Float)){ throw new SavedDataLoadingException("'$tagName' should be a List or List"); } /** @var DoubleTag[]|FloatTag[] $values */ diff --git a/src/entity/ExperienceManager.php b/src/entity/ExperienceManager.php index c91f9ffee..4ed1c5486 100644 --- a/src/entity/ExperienceManager.php +++ b/src/entity/ExperienceManager.php @@ -252,14 +252,14 @@ class ExperienceManager{ /** @var Durable[] $equipment */ $equipment = []; - if(($item = $this->entity->getInventory()->getItemInHand()) instanceof Durable and $item->hasEnchantment(VanillaEnchantments::MENDING())){ + if(($item = $this->entity->getInventory()->getItemInHand()) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){ $equipment[$mainHandIndex] = $item; } - if(($item = $this->entity->getOffHandInventory()->getItem(0)) instanceof Durable and $item->hasEnchantment(VanillaEnchantments::MENDING())){ + if(($item = $this->entity->getOffHandInventory()->getItem(0)) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){ $equipment[$offHandIndex] = $item; } foreach($this->entity->getArmorInventory()->getContents() as $k => $armorItem){ - if($armorItem instanceof Durable and $armorItem->hasEnchantment(VanillaEnchantments::MENDING())){ + if($armorItem instanceof Durable && $armorItem->hasEnchantment(VanillaEnchantments::MENDING())){ $equipment[$k] = $armorItem; } } diff --git a/src/entity/Human.php b/src/entity/Human.php index 7aebc89c3..56da6570e 100644 --- a/src/entity/Human.php +++ b/src/entity/Human.php @@ -166,7 +166,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ } public function consumeObject(Consumable $consumable) : bool{ - if($consumable instanceof FoodSource && $consumable->requiresHunger() and !$this->hungerManager->isHungry()){ + if($consumable instanceof FoodSource && $consumable->requiresHunger() && !$this->hungerManager->isHungry()){ return false; } @@ -266,11 +266,11 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ /** @var CompoundTag $item */ foreach($inventoryTag as $i => $item){ $slot = $item->getByte("Slot"); - if($slot >= 0 and $slot < 9){ //Hotbar + if($slot >= 0 && $slot < 9){ //Hotbar //Old hotbar saving stuff, ignore it - }elseif($slot >= 100 and $slot < 104){ //Armor + }elseif($slot >= 100 && $slot < 104){ //Armor $armorInventoryItems[$slot - 100] = Item::nbtDeserialize($item); - }elseif($slot >= 9 and $slot < $this->inventory->getSize() + 9){ + }elseif($slot >= 9 && $slot < $this->inventory->getSize() + 9){ $inventoryItems[$slot - 9] = Item::nbtDeserialize($item); } } @@ -340,8 +340,8 @@ class Human extends Living implements ProjectileSource, InventoryHolder{ parent::applyDamageModifiers($source); $type = $source->getCause(); - if($type !== EntityDamageEvent::CAUSE_SUICIDE and $type !== EntityDamageEvent::CAUSE_VOID - and ($this->inventory->getItemInHand() instanceof Totem || $this->offHandInventory->getItem(0) instanceof Totem)){ + if($type !== EntityDamageEvent::CAUSE_SUICIDE && $type !== EntityDamageEvent::CAUSE_VOID + && ($this->inventory->getItemInHand() instanceof Totem || $this->offHandInventory->getItem(0) instanceof Totem)){ $compensation = $this->getHealth() - $source->getFinalDamage() - 1; if($compensation < 0){ diff --git a/src/entity/HungerManager.php b/src/entity/HungerManager.php index f0e0e9d8e..4b95751a0 100644 --- a/src/entity/HungerManager.php +++ b/src/entity/HungerManager.php @@ -182,7 +182,7 @@ class HungerManager{ } public function tick(int $tickDiff = 1) : void{ - if(!$this->entity->isAlive() or !$this->enabled){ + if(!$this->entity->isAlive() || !$this->enabled){ return; } $food = $this->getFood(); @@ -194,12 +194,12 @@ class HungerManager{ $this->foodTickTimer = 0; } - if($difficulty === World::DIFFICULTY_PEACEFUL and $this->foodTickTimer % 10 === 0){ + if($difficulty === World::DIFFICULTY_PEACEFUL && $this->foodTickTimer % 10 === 0){ if($food < $this->getMaxFood()){ $this->addFood(1.0); $food = $this->getFood(); } - if($this->foodTickTimer % 20 === 0 and $health < $this->entity->getMaxHealth()){ + if($this->foodTickTimer % 20 === 0 && $health < $this->entity->getMaxHealth()){ $this->entity->heal(new EntityRegainHealthEvent($this->entity, 1, EntityRegainHealthEvent::CAUSE_SATURATION)); } } @@ -211,7 +211,7 @@ class HungerManager{ $this->exhaust(3.0, PlayerExhaustEvent::CAUSE_HEALTH_REGEN); } }elseif($food <= 0){ - if(($difficulty === World::DIFFICULTY_EASY and $health > 10) or ($difficulty === World::DIFFICULTY_NORMAL and $health > 1) or $difficulty === World::DIFFICULTY_HARD){ + if(($difficulty === World::DIFFICULTY_EASY && $health > 10) || ($difficulty === World::DIFFICULTY_NORMAL && $health > 1) || $difficulty === World::DIFFICULTY_HARD){ $this->entity->attack(new EntityDamageEvent($this->entity, EntityDamageEvent::CAUSE_STARVATION, 1)); } } diff --git a/src/entity/Living.php b/src/entity/Living.php index a5b6101c9..d5f169b11 100644 --- a/src/entity/Living.php +++ b/src/entity/Living.php @@ -187,7 +187,7 @@ abstract class Living extends Entity{ $wasAlive = $this->isAlive(); parent::setHealth($amount); $this->healthAttr->setValue(ceil($this->getHealth()), true); - if($this->isAlive() and !$wasAlive){ + if($this->isAlive() && !$wasAlive){ $this->broadcastAnimation(new RespawnAnimation($this)); } } @@ -407,7 +407,7 @@ abstract class Living extends Entity{ * to effects or armour. */ public function applyDamageModifiers(EntityDamageEvent $source) : void{ - if($this->lastDamageCause !== null and $this->attackTime > 0){ + if($this->lastDamageCause !== null && $this->attackTime > 0){ if($this->lastDamageCause->getBaseDamage() >= $source->getBaseDamage()){ $source->cancel(); } @@ -419,7 +419,7 @@ abstract class Living extends Entity{ } $cause = $source->getCause(); - if(($resistance = $this->effectManager->get(VanillaEffects::RESISTANCE())) !== null and $cause !== EntityDamageEvent::CAUSE_VOID and $cause !== EntityDamageEvent::CAUSE_SUICIDE){ + if(($resistance = $this->effectManager->get(VanillaEffects::RESISTANCE())) !== null && $cause !== EntityDamageEvent::CAUSE_VOID && $cause !== EntityDamageEvent::CAUSE_SUICIDE){ $source->setModifier(-$source->getFinalDamage() * min(1, 0.2 * $resistance->getEffectLevel()), EntityDamageEvent::MODIFIER_RESISTANCE); } @@ -443,10 +443,10 @@ abstract class Living extends Entity{ $this->setAbsorption(max(0, $this->getAbsorption() + $source->getModifier(EntityDamageEvent::MODIFIER_ABSORPTION))); $this->damageArmor($source->getBaseDamage()); - if($source instanceof EntityDamageByEntityEvent and ($attacker = $source->getDamager()) !== null){ + if($source instanceof EntityDamageByEntityEvent && ($attacker = $source->getDamager()) !== null){ $damage = 0; foreach($this->armorInventory->getContents() as $k => $item){ - if($item instanceof Armor and ($thornsLevel = $item->getEnchantmentLevel(VanillaEnchantments::THORNS())) > 0){ + if($item instanceof Armor && ($thornsLevel = $item->getEnchantmentLevel(VanillaEnchantments::THORNS())) > 0){ if(mt_rand(0, 99) < $thornsLevel * 15){ $this->damageItem($item, 3); $damage += ($thornsLevel > 10 ? $thornsLevel - 10 : 1 + mt_rand(0, 3)); @@ -493,10 +493,10 @@ abstract class Living extends Entity{ $source->cancel(); } - if($this->effectManager->has(VanillaEffects::FIRE_RESISTANCE()) and ( + if($this->effectManager->has(VanillaEffects::FIRE_RESISTANCE()) && ( $source->getCause() === EntityDamageEvent::CAUSE_FIRE - or $source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK - or $source->getCause() === EntityDamageEvent::CAUSE_LAVA + || $source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK + || $source->getCause() === EntityDamageEvent::CAUSE_LAVA ) ){ $source->cancel(); @@ -504,8 +504,8 @@ abstract class Living extends Entity{ $this->applyDamageModifiers($source); - if($source instanceof EntityDamageByEntityEvent and ( - $source->getCause() === EntityDamageEvent::CAUSE_BLOCK_EXPLOSION or + if($source instanceof EntityDamageByEntityEvent && ( + $source->getCause() === EntityDamageEvent::CAUSE_BLOCK_EXPLOSION || $source->getCause() === EntityDamageEvent::CAUSE_ENTITY_EXPLOSION) ){ //TODO: knockback should not just apply for entity damage sources @@ -642,7 +642,7 @@ abstract class Living extends Entity{ if(!$this->canBreathe()){ $this->setBreathing(false); - if(($respirationLevel = $this->armorInventory->getHelmet()->getEnchantmentLevel(VanillaEnchantments::RESPIRATION())) <= 0 or + if(($respirationLevel = $this->armorInventory->getHelmet()->getEnchantmentLevel(VanillaEnchantments::RESPIRATION())) <= 0 || lcg_value() <= (1 / ($respirationLevel + 1)) ){ $ticks -= $tickDiff; @@ -672,7 +672,7 @@ abstract class Living extends Entity{ * Returns whether the entity can currently breathe. */ public function canBreathe() : bool{ - return $this->effectManager->has(VanillaEffects::WATER_BREATHING()) or $this->effectManager->has(VanillaEffects::CONDUIT_POWER()) or !$this->isUnderwater(); + return $this->effectManager->has(VanillaEffects::WATER_BREATHING()) || $this->effectManager->has(VanillaEffects::CONDUIT_POWER()) || !$this->isUnderwater(); } /** @@ -767,7 +767,7 @@ abstract class Living extends Entity{ $block = $this->getWorld()->getBlockAt($vector3->x, $vector3->y, $vector3->z); $blocks[$nextIndex++] = $block; - if($maxLength !== 0 and count($blocks) > $maxLength){ + if($maxLength !== 0 && count($blocks) > $maxLength){ array_shift($blocks); --$nextIndex; } diff --git a/src/entity/Location.php b/src/entity/Location.php index c04ac9acb..2ebbb2661 100644 --- a/src/entity/Location.php +++ b/src/entity/Location.php @@ -68,7 +68,7 @@ class Location extends Position{ public function equals(Vector3 $v) : bool{ if($v instanceof Location){ - return parent::equals($v) and $v->yaw == $this->yaw and $v->pitch == $this->pitch; + return parent::equals($v) && $v->yaw == $this->yaw && $v->pitch == $this->pitch; } return parent::equals($v); } diff --git a/src/entity/Skin.php b/src/entity/Skin.php index 604d6f6a2..786a6e711 100644 --- a/src/entity/Skin.php +++ b/src/entity/Skin.php @@ -68,7 +68,7 @@ final class Skin{ if(!in_array($len, self::ACCEPTED_SKIN_SIZES, true)){ throw new InvalidSkinException("Invalid skin data size $len bytes (allowed sizes: " . implode(", ", self::ACCEPTED_SKIN_SIZES) . ")"); } - if($capeData !== "" and strlen($capeData) !== 8192){ + if($capeData !== "" && strlen($capeData) !== 8192){ throw new InvalidSkinException("Invalid cape data size " . strlen($capeData) . " bytes (must be exactly 8192 bytes)"); } diff --git a/src/entity/Squid.php b/src/entity/Squid.php index 1010c5d78..063e87b16 100644 --- a/src/entity/Squid.php +++ b/src/entity/Squid.php @@ -95,7 +95,7 @@ class Squid extends WaterAnimal{ if($this->isAlive()){ - if($this->location->y > 62 and $this->swimDirection !== null){ + if($this->location->y > 62 && $this->swimDirection !== null){ $this->swimDirection = $this->swimDirection->withComponents(null, -0.5, null); } diff --git a/src/entity/Villager.php b/src/entity/Villager.php index d43e4faf9..7e1c081cc 100644 --- a/src/entity/Villager.php +++ b/src/entity/Villager.php @@ -57,7 +57,7 @@ class Villager extends Living implements Ageable{ /** @var int $profession */ $profession = $nbt->getInt("Profession", self::PROFESSION_FARMER); - if($profession > 4 or $profession < 0){ + if($profession > 4 || $profession < 0){ $profession = self::PROFESSION_FARMER; } diff --git a/src/entity/effect/EffectInstance.php b/src/entity/effect/EffectInstance.php index c908c7ec7..566ca1e5e 100644 --- a/src/entity/effect/EffectInstance.php +++ b/src/entity/effect/EffectInstance.php @@ -77,7 +77,7 @@ class EffectInstance{ * @return $this */ public function setDuration(int $duration) : EffectInstance{ - if($duration < 0 or $duration > Limits::INT32_MAX){ + if($duration < 0 || $duration > Limits::INT32_MAX){ throw new \InvalidArgumentException("Effect duration must be in range 0 - " . Limits::INT32_MAX . ", got $duration"); } $this->duration = $duration; @@ -118,7 +118,7 @@ class EffectInstance{ * @return $this */ public function setAmplifier(int $amplifier) : EffectInstance{ - if($amplifier < 0 or $amplifier > 255){ + if($amplifier < 0 || $amplifier > 255){ throw new \InvalidArgumentException("Amplifier must be in range 0 - 255, got $amplifier"); } $this->amplifier = $amplifier; diff --git a/src/entity/effect/EffectManager.php b/src/entity/effect/EffectManager.php index 17bdb8947..ee561229f 100644 --- a/src/entity/effect/EffectManager.php +++ b/src/entity/effect/EffectManager.php @@ -91,7 +91,7 @@ class EffectManager{ $ev = new EntityEffectRemoveEvent($this->entity, $effect); $ev->call(); if($ev->isCancelled()){ - if($hasExpired and !$ev->getEffect()->hasExpired()){ //altered duration of an expired effect to make it not get removed + if($hasExpired && !$ev->getEffect()->hasExpired()){ //altered duration of an expired effect to make it not get removed foreach($this->effectAddHooks as $hook){ $hook($ev->getEffect(), true); } @@ -140,7 +140,7 @@ class EffectManager{ $oldEffect = $this->effects[$index]; if( abs($effect->getAmplifier()) < $oldEffect->getAmplifier() - or (abs($effect->getAmplifier()) === abs($oldEffect->getAmplifier()) and $effect->getDuration() < $oldEffect->getDuration()) + || (abs($effect->getAmplifier()) === abs($oldEffect->getAmplifier()) && $effect->getDuration() < $oldEffect->getDuration()) ){ $cancelled = true; } @@ -180,7 +180,7 @@ class EffectManager{ $colors = []; $ambient = true; foreach($this->effects as $effect){ - if($effect->isVisible() and $effect->getType()->hasBubbles()){ + if($effect->isVisible() && $effect->getType()->hasBubbles()){ $level = $effect->getEffectLevel(); $color = $effect->getColor(); for($i = 0; $i < $level; ++$i){ diff --git a/src/entity/effect/PoisonEffect.php b/src/entity/effect/PoisonEffect.php index e3b1618b5..166be76c6 100644 --- a/src/entity/effect/PoisonEffect.php +++ b/src/entity/effect/PoisonEffect.php @@ -47,7 +47,7 @@ class PoisonEffect extends Effect{ } public function applyEffect(Living $entity, EffectInstance $instance, float $potency = 1.0, ?Entity $source = null) : void{ - if($entity->getHealth() > 1 or $this->fatal){ + if($entity->getHealth() > 1 || $this->fatal){ $ev = new EntityDamageEvent($entity, EntityDamageEvent::CAUSE_MAGIC, 1); $entity->attack($ev); } diff --git a/src/entity/object/ExperienceOrb.php b/src/entity/object/ExperienceOrb.php index ef26ffb0e..274abf379 100644 --- a/src/entity/object/ExperienceOrb.php +++ b/src/entity/object/ExperienceOrb.php @@ -166,7 +166,7 @@ class ExperienceOrb extends Entity{ } $currentTarget = $this->getTargetPlayer(); - if($currentTarget !== null and (!$currentTarget->isAlive() or !$currentTarget->getXpManager()->canAttractXpOrbs() or $currentTarget->location->distanceSquared($this->location) > self::MAX_TARGET_DISTANCE ** 2)){ + if($currentTarget !== null && (!$currentTarget->isAlive() || !$currentTarget->getXpManager()->canAttractXpOrbs() || $currentTarget->location->distanceSquared($this->location) > self::MAX_TARGET_DISTANCE ** 2)){ $currentTarget = null; } @@ -174,7 +174,7 @@ class ExperienceOrb extends Entity{ if($currentTarget === null){ $newTarget = $this->getWorld()->getNearestEntity($this->location, self::MAX_TARGET_DISTANCE, Human::class); - if($newTarget instanceof Human and !($newTarget instanceof Player and $newTarget->isSpectator()) and $newTarget->getXpManager()->canAttractXpOrbs()){ + if($newTarget instanceof Human && !($newTarget instanceof Player && $newTarget->isSpectator()) && $newTarget->getXpManager()->canAttractXpOrbs()){ $currentTarget = $newTarget; } } @@ -194,7 +194,7 @@ class ExperienceOrb extends Entity{ $this->motion = $this->motion->addVector($vector->normalize()->multiply(0.2 * (1 - sqrt($distance)) ** 2)); } - if($currentTarget->getXpManager()->canPickupXp() and $this->boundingBox->intersectsWith($currentTarget->getBoundingBox())){ + if($currentTarget->getXpManager()->canPickupXp() && $this->boundingBox->intersectsWith($currentTarget->getBoundingBox())){ $this->flagForDespawn(); $currentTarget->getXpManager()->onPickupXp($this->getXpValue()); diff --git a/src/entity/object/FallingBlock.php b/src/entity/object/FallingBlock.php index 9957453b6..cb2551349 100644 --- a/src/entity/object/FallingBlock.php +++ b/src/entity/object/FallingBlock.php @@ -112,11 +112,11 @@ class FallingBlock extends Entity{ $blockTarget = $this->block->tickFalling(); } - if($this->onGround or $blockTarget !== null){ + if($this->onGround || $blockTarget !== null){ $this->flagForDespawn(); $block = $world->getBlock($pos); - if(!$block->canBeReplaced() or !$world->isInWorld($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ()) or ($this->onGround and abs($this->location->y - $this->location->getFloorY()) > 0.001)){ + if(!$block->canBeReplaced() || !$world->isInWorld($pos->getFloorX(), $pos->getFloorY(), $pos->getFloorZ()) || ($this->onGround && abs($this->location->y - $this->location->getFloorY()) > 0.001)){ //FIXME: anvils are supposed to destroy torches $world->dropItem($this->location, $this->block->asItem()); }else{ diff --git a/src/entity/object/ItemEntity.php b/src/entity/object/ItemEntity.php index 248b09d1e..73d67a192 100644 --- a/src/entity/object/ItemEntity.php +++ b/src/entity/object/ItemEntity.php @@ -103,16 +103,16 @@ class ItemEntity extends Entity{ $hasUpdate = parent::entityBaseTick($tickDiff); - if(!$this->isFlaggedForDespawn() and $this->pickupDelay !== self::NEVER_DESPAWN){ //Infinite delay + if(!$this->isFlaggedForDespawn() && $this->pickupDelay !== self::NEVER_DESPAWN){ //Infinite delay $this->pickupDelay -= $tickDiff; if($this->pickupDelay < 0){ $this->pickupDelay = 0; } - if($this->hasMovementUpdate() and $this->despawnDelay % self::MERGE_CHECK_PERIOD === 0){ + if($this->hasMovementUpdate() && $this->despawnDelay % self::MERGE_CHECK_PERIOD === 0){ $mergeable = [$this]; //in case the merge target ends up not being this $mergeTarget = $this; foreach($this->getWorld()->getNearbyEntities($this->boundingBox->expandedCopy(0.5, 0.5, 0.5), $this) as $entity){ - if(!$entity instanceof ItemEntity or $entity->isFlaggedForDespawn()){ + if(!$entity instanceof ItemEntity || $entity->isFlaggedForDespawn()){ continue; } @@ -151,7 +151,7 @@ class ItemEntity extends Entity{ */ public function isMergeable(ItemEntity $entity) : bool{ $item = $entity->item; - return $entity !== $this && $entity->pickupDelay !== self::NEVER_DESPAWN and $item->canStackWith($this->item) and $item->getCount() + $this->item->getCount() <= $item->getMaxStackSize(); + return $entity !== $this && $entity->pickupDelay !== self::NEVER_DESPAWN && $item->canStackWith($this->item) && $item->getCount() + $this->item->getCount() <= $item->getMaxStackSize(); } /** @@ -238,7 +238,7 @@ class ItemEntity extends Entity{ * @throws \InvalidArgumentException */ public function setDespawnDelay(int $despawnDelay) : void{ - if(($despawnDelay < 0 or $despawnDelay > self::MAX_DESPAWN_DELAY) and $despawnDelay !== self::NEVER_DESPAWN){ + if(($despawnDelay < 0 || $despawnDelay > self::MAX_DESPAWN_DELAY) && $despawnDelay !== self::NEVER_DESPAWN){ throw new \InvalidArgumentException("Despawn ticker must be in range 0 ... " . self::MAX_DESPAWN_DELAY . " or " . self::NEVER_DESPAWN . ", got $despawnDelay"); } $this->despawnDelay = $despawnDelay; @@ -291,13 +291,13 @@ class ItemEntity extends Entity{ $item = $this->getItem(); $playerInventory = match(true){ - $player->getOffHandInventory()->getItem(0)->canStackWith($item) and $player->getOffHandInventory()->getAddableItemQuantity($item) > 0 => $player->getOffHandInventory(), + $player->getOffHandInventory()->getItem(0)->canStackWith($item) && $player->getOffHandInventory()->getAddableItemQuantity($item) > 0 => $player->getOffHandInventory(), $player->getInventory()->getAddableItemQuantity($item) > 0 => $player->getInventory(), default => null }; $ev = new EntityItemPickupEvent($player, $this, $item, $playerInventory); - if($player->hasFiniteResources() and $playerInventory === null){ + if($player->hasFiniteResources() && $playerInventory === null){ $ev->cancel(); } diff --git a/src/entity/object/Painting.php b/src/entity/object/Painting.php index a95560e24..ff59de043 100644 --- a/src/entity/object/Painting.php +++ b/src/entity/object/Painting.php @@ -107,7 +107,7 @@ class Painting extends Entity{ if($this->lastDamageCause instanceof EntityDamageByEntityEvent){ $killer = $this->lastDamageCause->getDamager(); - if($killer instanceof Player and !$killer->hasFiniteResources()){ + if($killer instanceof Player && !$killer->hasFiniteResources()){ $drops = false; } } @@ -212,7 +212,7 @@ class Painting extends Entity{ $pos = $startPos->getSide($rotatedFace, $w)->getSide(Facing::UP, $h); $block = $world->getBlockAt($pos->x, $pos->y, $pos->z); - if($block->isSolid() or !$block->getSide($oppositeSide)->isSolid()){ + if($block->isSolid() || !$block->getSide($oppositeSide)->isSolid()){ return false; } } diff --git a/src/entity/object/PrimedTNT.php b/src/entity/object/PrimedTNT.php index f3ed921b8..70d58dafa 100644 --- a/src/entity/object/PrimedTNT.php +++ b/src/entity/object/PrimedTNT.php @@ -58,7 +58,7 @@ class PrimedTNT extends Entity implements Explosive{ } public function setFuse(int $fuse) : void{ - if($fuse < 0 or $fuse > 32767){ + if($fuse < 0 || $fuse > 32767){ throw new \InvalidArgumentException("Fuse must be in the range 0-32767"); } $this->fuse = $fuse; @@ -112,7 +112,7 @@ class PrimedTNT extends Entity implements Explosive{ } } - return $hasUpdate or $this->fuse >= 0; + return $hasUpdate || $this->fuse >= 0; } public function explode() : void{ diff --git a/src/entity/projectile/Arrow.php b/src/entity/projectile/Arrow.php index ca194d2c5..47924c8cb 100644 --- a/src/entity/projectile/Arrow.php +++ b/src/entity/projectile/Arrow.php @@ -176,16 +176,16 @@ class Arrow extends Projectile{ $item = VanillaItems::ARROW(); $playerInventory = match(true){ !$player->hasFiniteResources() => null, //arrows are not picked up in creative - $player->getOffHandInventory()->getItem(0)->canStackWith($item) and $player->getOffHandInventory()->canAddItem($item) => $player->getOffHandInventory(), + $player->getOffHandInventory()->getItem(0)->canStackWith($item) && $player->getOffHandInventory()->canAddItem($item) => $player->getOffHandInventory(), $player->getInventory()->canAddItem($item) => $player->getInventory(), default => null }; $ev = new EntityItemPickupEvent($player, $this, $item, $playerInventory); - if($player->hasFiniteResources() and $playerInventory === null){ + if($player->hasFiniteResources() && $playerInventory === null){ $ev->cancel(); } - if($this->pickupMode === self::PICKUP_NONE or ($this->pickupMode === self::PICKUP_CREATIVE and !$player->isCreative())){ + if($this->pickupMode === self::PICKUP_NONE || ($this->pickupMode === self::PICKUP_CREATIVE && !$player->isCreative())){ $ev->cancel(); } diff --git a/src/entity/projectile/Projectile.php b/src/entity/projectile/Projectile.php index cf700b052..1fa1071f9 100644 --- a/src/entity/projectile/Projectile.php +++ b/src/entity/projectile/Projectile.php @@ -78,7 +78,7 @@ abstract class Projectile extends Entity{ $this->damage = $nbt->getDouble("damage", $this->damage); (function() use ($nbt) : void{ - if(($tileXTag = $nbt->getTag("tileX")) instanceof IntTag and ($tileYTag = $nbt->getTag("tileY")) instanceof IntTag and ($tileZTag = $nbt->getTag("tileZ")) instanceof IntTag){ + if(($tileXTag = $nbt->getTag("tileX")) instanceof IntTag && ($tileYTag = $nbt->getTag("tileY")) instanceof IntTag && ($tileZTag = $nbt->getTag("tileZ")) instanceof IntTag){ $blockPos = new Vector3($tileXTag->getValue(), $tileYTag->getValue(), $tileZTag->getValue()); }else{ return; @@ -102,7 +102,7 @@ abstract class Projectile extends Entity{ } public function canCollideWith(Entity $entity) : bool{ - return $entity instanceof Living and !$this->onGround; + return $entity instanceof Living && !$this->onGround; } public function canBeCollidedWith() : bool{ @@ -155,7 +155,7 @@ abstract class Projectile extends Entity{ } public function onNearbyBlockChange() : void{ - if($this->blockHit !== null and $this->getWorld()->isInLoadedTerrain($this->blockHit->getPosition()) and !$this->blockHit->isSameState($this->getWorld()->getBlock($this->blockHit->getPosition()))){ + if($this->blockHit !== null && $this->getWorld()->isInLoadedTerrain($this->blockHit->getPosition()) && !$this->blockHit->isSameState($this->getWorld()->getBlock($this->blockHit->getPosition()))){ $this->blockHit = null; } @@ -163,7 +163,7 @@ abstract class Projectile extends Entity{ } public function hasMovementUpdate() : bool{ - return $this->blockHit === null and parent::hasMovementUpdate(); + return $this->blockHit === null && parent::hasMovementUpdate(); } protected function move(float $dx, float $dy, float $dz) : void{ @@ -194,7 +194,7 @@ abstract class Projectile extends Entity{ $newDiff = $end->subtractVector($start); foreach($this->getWorld()->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){ - if($entity->getId() === $this->getOwningEntityId() and $this->ticksLived < 5){ + if($entity->getId() === $this->getOwningEntityId() && $this->ticksLived < 5){ continue; } diff --git a/src/entity/projectile/SplashPotion.php b/src/entity/projectile/SplashPotion.php index a7ecfa47a..364ded7c2 100644 --- a/src/entity/projectile/SplashPotion.php +++ b/src/entity/projectile/SplashPotion.php @@ -99,14 +99,14 @@ class SplashPotion extends Throwable{ if($hasEffects){ if(!$this->willLinger()){ foreach($this->getWorld()->getNearbyEntities($this->boundingBox->expandedCopy(4.125, 2.125, 4.125), $this) as $entity){ - if($entity instanceof Living and $entity->isAlive()){ + if($entity instanceof Living && $entity->isAlive()){ $distanceSquared = $entity->getEyePos()->distanceSquared($this->location); if($distanceSquared > 16){ //4 blocks continue; } $distanceMultiplier = 1 - (sqrt($distanceSquared) / 4); - if($event instanceof ProjectileHitEntityEvent and $entity === $event->getEntityHit()){ + if($event instanceof ProjectileHitEntityEvent && $entity === $event->getEntityHit()){ $distanceMultiplier = 1.0; } @@ -129,7 +129,7 @@ class SplashPotion extends Throwable{ }else{ //TODO: lingering potions } - }elseif($event instanceof ProjectileHitBlockEvent and $this->getPotionType()->equals(PotionType::WATER())){ + }elseif($event instanceof ProjectileHitBlockEvent && $this->getPotionType()->equals(PotionType::WATER())){ $blockIn = $event->getBlockHit()->getSide($event->getRayTraceResult()->getHitFace()); if($blockIn->getId() === BlockLegacyIds::FIRE){ From 373880e5825f95dac0c90787ffcd71d11c68c81a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:16:00 +0000 Subject: [PATCH 660/710] Replace disallowed operators in src/player/ --- src/player/OfflinePlayer.php | 4 +- src/player/Player.php | 94 ++++++++++++------------ src/player/SurvivalBlockBreakHandler.php | 2 +- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/player/OfflinePlayer.php b/src/player/OfflinePlayer.php index a90047b5d..1a9955413 100644 --- a/src/player/OfflinePlayer.php +++ b/src/player/OfflinePlayer.php @@ -43,11 +43,11 @@ class OfflinePlayer implements IPlayer{ } public function getFirstPlayed() : ?int{ - return ($this->namedtag !== null and ($firstPlayedTag = $this->namedtag->getTag("firstPlayed")) instanceof LongTag) ? $firstPlayedTag->getValue() : null; + return ($this->namedtag !== null && ($firstPlayedTag = $this->namedtag->getTag("firstPlayed")) instanceof LongTag) ? $firstPlayedTag->getValue() : null; } public function getLastPlayed() : ?int{ - return ($this->namedtag !== null and ($lastPlayedTag = $this->namedtag->getTag("lastPlayed")) instanceof LongTag) ? $lastPlayedTag->getValue() : null; + return ($this->namedtag !== null && ($lastPlayedTag = $this->namedtag->getTag("lastPlayed")) instanceof LongTag) ? $lastPlayedTag->getValue() : null; } public function hasPlayedBefore() : bool{ diff --git a/src/player/Player.php b/src/player/Player.php index 19ee8cc6e..014f4b79e 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -182,7 +182,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $lname = strtolower($name); $len = strlen($name); - return $lname !== "rcon" and $lname !== "console" and $len >= 1 and $len <= 16 and preg_match("/[^A-Za-z0-9_ ]/", $name) === 0; + return $lname !== "rcon" && $lname !== "console" && $len >= 1 && $len <= 16 && preg_match("/[^A-Za-z0-9_ ]/", $name) === 0; } protected ?NetworkSession $networkSession; @@ -329,7 +329,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->firstPlayed = $nbt->getLong("firstPlayed", $now = (int) (microtime(true) * 1000)); $this->lastPlayed = $nbt->getLong("lastPlayed", $now); - if(!$this->server->getForceGamemode() and ($gameModeTag = $nbt->getTag("playerGameType")) instanceof IntTag){ + if(!$this->server->getForceGamemode() && ($gameModeTag = $nbt->getTag("playerGameType")) instanceof IntTag){ $this->internalSetGameMode(GameModeIdMap::getInstance()->fromId($gameModeTag->getValue()) ?? GameMode::SURVIVAL()); //TODO: bad hack here to avoid crashes on corrupted data }else{ $this->internalSetGameMode($this->server->getGamemode()); @@ -447,7 +447,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function spawnTo(Player $player) : void{ - if($this->isAlive() and $player->isAlive() and $player->canSee($this) and !$this->isSpectator()){ + if($this->isAlive() && $player->isAlive() && $player->canSee($this) && !$this->isSpectator()){ parent::spawnTo($player); } } @@ -461,7 +461,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function setScreenLineHeight(?int $height) : void{ - if($height !== null and $height < 1){ + if($height !== null && $height < 1){ throw new \InvalidArgumentException("Line height must be at least 1"); } $this->lineHeight = $height; @@ -494,7 +494,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function canBeCollidedWith() : bool{ - return !$this->isSpectator() and parent::canBeCollidedWith(); + return !$this->isSpectator() && parent::canBeCollidedWith(); } public function resetFallDistance() : void{ @@ -523,7 +523,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function isConnected() : bool{ - return $this->networkSession !== null and $this->networkSession->isConnected(); + return $this->networkSession !== null && $this->networkSession->isConnected(); } public function getNetworkSession() : NetworkSession{ @@ -699,7 +699,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ protected function spawnEntitiesOnChunk(int $chunkX, int $chunkZ) : void{ foreach($this->getWorld()->getChunkEntities($chunkX, $chunkZ) as $entity){ - if($entity !== $this and !$entity->isFlaggedForDespawn()){ + if($entity !== $this && !$entity->isFlaggedForDespawn()){ $entity->spawnTo($this); } } @@ -728,7 +728,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $X = null; $Z = null; World::getXZ($index, $X, $Z); - assert(is_int($X) and is_int($Z)); + assert(is_int($X) && is_int($Z)); ++$count; @@ -826,7 +826,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * This is based on factors including the player's current render radius and current position. */ protected function orderChunks() : void{ - if(!$this->isConnected() or $this->viewDistance === -1){ + if(!$this->isConnected() || $this->viewDistance === -1){ return; } @@ -840,7 +840,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->location->getFloorX() >> Chunk::COORD_BIT_SIZE, $this->location->getFloorZ() >> Chunk::COORD_BIT_SIZE ) as $hash){ - if(!isset($this->usedChunks[$hash]) or $this->usedChunks[$hash]->equals(UsedChunkStatus::NEEDED())){ + if(!isset($this->usedChunks[$hash]) || $this->usedChunks[$hash]->equals(UsedChunkStatus::NEEDED())){ $newOrder[$hash] = true; } unset($unloadChunks[$hash]); @@ -852,7 +852,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } $this->loadQueue = $newOrder; - if(count($this->loadQueue) > 0 or count($unloadChunks) > 0){ + if(count($this->loadQueue) > 0 || count($unloadChunks) > 0){ $this->chunkLoader->setCurrentLocation($this->location); $this->getNetworkSession()->syncViewAreaCenterPoint($this->location, $this->viewDistance); } @@ -888,14 +888,14 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ */ public function hasReceivedChunk(int $chunkX, int $chunkZ) : bool{ $status = $this->usedChunks[World::chunkHash($chunkX, $chunkZ)] ?? null; - return $status !== null and $status->equals(UsedChunkStatus::SENT()); + return $status !== null && $status->equals(UsedChunkStatus::SENT()); } /** * Ticks the chunk-requesting mechanism. */ public function doChunkRequests() : void{ - if($this->nextChunkOrderRun !== PHP_INT_MAX and $this->nextChunkOrderRun-- <= 0){ + if($this->nextChunkOrderRun !== PHP_INT_MAX && $this->nextChunkOrderRun-- <= 0){ $this->nextChunkOrderRun = PHP_INT_MAX; $this->orderChunks(); } @@ -919,7 +919,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function hasValidCustomSpawn() : bool{ - return $this->spawnPosition !== null and $this->spawnPosition->isValid(); + return $this->spawnPosition !== null && $this->spawnPosition->isValid(); } /** @@ -1051,7 +1051,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * @param bool $literal whether a literal check should be performed */ public function isSurvival(bool $literal = false) : bool{ - return $this->gamemode->equals(GameMode::SURVIVAL()) or (!$literal and $this->gamemode->equals(GameMode::ADVENTURE())); + return $this->gamemode->equals(GameMode::SURVIVAL()) || (!$literal && $this->gamemode->equals(GameMode::ADVENTURE())); } /** @@ -1061,7 +1061,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * @param bool $literal whether a literal check should be performed */ public function isCreative(bool $literal = false) : bool{ - return $this->gamemode->equals(GameMode::CREATIVE()) or (!$literal and $this->gamemode->equals(GameMode::SPECTATOR())); + return $this->gamemode->equals(GameMode::CREATIVE()) || (!$literal && $this->gamemode->equals(GameMode::SPECTATOR())); } /** @@ -1071,7 +1071,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * @param bool $literal whether a literal check should be performed */ public function isAdventure(bool $literal = false) : bool{ - return $this->gamemode->equals(GameMode::ADVENTURE()) or (!$literal and $this->gamemode->equals(GameMode::SPECTATOR())); + return $this->gamemode->equals(GameMode::ADVENTURE()) || (!$literal && $this->gamemode->equals(GameMode::SPECTATOR())); } public function isSpectator() : bool{ @@ -1082,7 +1082,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * TODO: make this a dynamic ability instead of being hardcoded */ public function hasFiniteResources() : bool{ - return $this->gamemode->equals(GameMode::SURVIVAL()) or $this->gamemode->equals(GameMode::ADVENTURE()); + return $this->gamemode->equals(GameMode::SURVIVAL()) || $this->gamemode->equals(GameMode::ADVENTURE()); } public function isFireProof() : bool{ @@ -1129,7 +1129,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ foreach($this->getWorld()->getNearbyEntities($this->boundingBox->expandedCopy(1, 0.5, 1), $this) as $entity){ $entity->scheduleUpdate(); - if(!$entity->isAlive() or $entity->isFlaggedForDespawn()){ + if(!$entity->isAlive() || $entity->isFlaggedForDespawn()){ continue; } @@ -1180,7 +1180,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->nextChunkOrderRun = 0; } - if(!$revert and $distanceSquared != 0){ + if(!$revert && $distanceSquared != 0){ $dx = $newPos->x - $this->location->x; $dy = $newPos->y - $this->location->y; $dz = $newPos->z - $this->location->z; @@ -1209,7 +1209,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $delta = $to->distanceSquared($from); $deltaAngle = abs($this->lastLocation->yaw - $to->yaw) + abs($this->lastLocation->pitch - $to->pitch); - if($delta > 0.0001 or $deltaAngle > 1.0){ + if($delta > 0.0001 || $deltaAngle > 1.0){ $ev = new PlayerMoveEvent($this, $from, $to); $ev->call(); @@ -1291,7 +1291,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->lastUpdate = $currentTick; - if(!$this->isAlive() and $this->spawned){ + if(!$this->isAlive() && $this->spawned){ $this->onDeathUpdate($tickDiff); return true; } @@ -1311,13 +1311,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $this->entityBaseTick($tickDiff); Timings::$entityBaseTick->stopTiming(); - if(!$this->isSpectator() and $this->isAlive()){ + if(!$this->isSpectator() && $this->isAlive()){ Timings::$playerCheckNearEntities->startTiming(); $this->checkNearEntities(); Timings::$playerCheckNearEntities->stopTiming(); } - if($this->blockBreakHandler !== null and !$this->blockBreakHandler->update()){ + if($this->blockBreakHandler !== null && !$this->blockBreakHandler->update()){ $this->blockBreakHandler = null; } } @@ -1328,7 +1328,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function canBreathe() : bool{ - return $this->isCreative() or parent::canBreathe(); + return $this->isCreative() || parent::canBreathe(); } /** @@ -1357,7 +1357,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $message = TextFormat::clean($message, false); foreach(explode("\n", $message) as $messagePart){ - if(trim($messagePart) !== "" and strlen($messagePart) <= self::MAX_CHAT_BYTE_LENGTH and mb_strlen($messagePart, 'UTF-8') <= self::MAX_CHAT_CHAR_LENGTH and $this->messageCounter-- > 0){ + if(trim($messagePart) !== "" && strlen($messagePart) <= self::MAX_CHAT_BYTE_LENGTH && mb_strlen($messagePart, 'UTF-8') <= self::MAX_CHAT_CHAR_LENGTH && $this->messageCounter-- > 0){ if(strpos($messagePart, './') === 0){ $messagePart = substr($messagePart, 1); } @@ -1417,7 +1417,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $oldItem = clone $item; $ev = new PlayerItemUseEvent($this, $item, $directionVector); - if($this->hasItemCooldown($item) or $this->isSpectator()){ + if($this->hasItemCooldown($item) || $this->isSpectator()){ $ev->cancel(); } @@ -1433,7 +1433,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } $this->resetItemCooldown($item); - if($this->hasFiniteResources() and !$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){ + if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->inventory->getItemInHand())){ if($item instanceof Durable && $item->isBroken()){ $this->broadcastSound(new ItemBreakSound()); } @@ -1461,7 +1461,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } $ev->call(); - if($ev->isCancelled() or !$this->consumeObject($slot)){ + if($ev->isCancelled() || !$this->consumeObject($slot)){ return false; } @@ -1488,7 +1488,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ public function releaseHeldItem() : bool{ try{ $item = $this->inventory->getItemInHand(); - if(!$this->isUsingItem() or $this->hasItemCooldown($item)){ + if(!$this->isUsingItem() || $this->hasItemCooldown($item)){ return false; } @@ -1497,7 +1497,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $result = $item->onReleaseUsing($this); if($result->equals(ItemUseResult::SUCCESS())){ $this->resetItemCooldown($item); - if(!$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){ + if(!$item->equalsExact($oldItem) && $oldItem->equalsExact($this->inventory->getItemInHand())){ if($item instanceof Durable && $item->isBroken()){ $this->broadcastSound(new ItemBreakSound()); } @@ -1522,7 +1522,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $ev = new PlayerBlockPickEvent($this, $block, $item); $existingSlot = $this->inventory->first($item); - if($existingSlot === -1 and $this->hasFiniteResources()){ + if($existingSlot === -1 && $this->hasFiniteResources()){ $ev->cancel(); } $ev->call(); @@ -1591,13 +1591,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function continueBreakBlock(Vector3 $pos, int $face) : void{ - if($this->blockBreakHandler !== null and $this->blockBreakHandler->getBlockPos()->distanceSquared($pos) < 0.0001){ + if($this->blockBreakHandler !== null && $this->blockBreakHandler->getBlockPos()->distanceSquared($pos) < 0.0001){ $this->blockBreakHandler->setTargetedFace($face); } } public function stopBreakBlock(Vector3 $pos) : void{ - if($this->blockBreakHandler !== null and $this->blockBreakHandler->getBlockPos()->distanceSquared($pos) < 0.0001){ + if($this->blockBreakHandler !== null && $this->blockBreakHandler->getBlockPos()->distanceSquared($pos) < 0.0001){ $this->blockBreakHandler = null; } } @@ -1616,7 +1616,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $item = $this->inventory->getItemInHand(); $oldItem = clone $item; if($this->getWorld()->useBreakOn($pos, $item, $this, true)){ - if($this->hasFiniteResources() and !$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){ + if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->inventory->getItemInHand())){ if($item instanceof Durable && $item->isBroken()){ $this->broadcastSound(new ItemBreakSound()); } @@ -1645,7 +1645,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $item = $this->inventory->getItemInHand(); //this is a copy of the real item $oldItem = clone $item; if($this->getWorld()->useItemOn($pos, $item, $face, $clickOffset, $this, true)){ - if($this->hasFiniteResources() and !$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){ + if($this->hasFiniteResources() && !$item->equalsExact($oldItem) && $oldItem->equalsExact($this->inventory->getItemInHand())){ if($item instanceof Durable && $item->isBroken()){ $this->broadcastSound(new ItemBreakSound()); } @@ -1670,7 +1670,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if(!$entity->isAlive()){ return false; } - if($entity instanceof ItemEntity or $entity instanceof Arrow){ + if($entity instanceof ItemEntity || $entity instanceof Arrow){ $this->logger->debug("Attempted to attack non-attackable entity " . get_class($entity)); return false; } @@ -1682,7 +1682,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if(!$this->canInteract($entity->getLocation(), self::MAX_REACH_DISTANCE_ENTITY_INTERACTION)){ $this->logger->debug("Cancelled attack of entity " . $entity->getId() . " due to not currently being interactable"); $ev->cancel(); - }elseif($this->isSpectator() or ($entity instanceof Player and !$this->server->getConfigGroup()->getConfigBool("pvp"))){ + }elseif($this->isSpectator() || ($entity instanceof Player && !$this->server->getConfigGroup()->getConfigBool("pvp"))){ $ev->cancel(); } @@ -1691,14 +1691,14 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ $meleeEnchantments = []; foreach($heldItem->getEnchantments() as $enchantment){ $type = $enchantment->getType(); - if($type instanceof MeleeWeaponEnchantment and $type->isApplicableTo($entity)){ + if($type instanceof MeleeWeaponEnchantment && $type->isApplicableTo($entity)){ $meleeEnchantmentDamage += $type->getDamageBonus($enchantment->getLevel()); $meleeEnchantments[] = $enchantment; } } $ev->setModifier($meleeEnchantmentDamage, EntityDamageEvent::MODIFIER_WEAPON_ENCHANTMENTS); - if(!$this->isSprinting() and !$this->isFlying() and $this->fallDistance > 0 and !$this->effectManager->has(VanillaEffects::BLINDNESS()) and !$this->isUnderwater()){ + if(!$this->isSprinting() && !$this->isFlying() && $this->fallDistance > 0 && !$this->effectManager->has(VanillaEffects::BLINDNESS()) && !$this->isUnderwater()){ $ev->setModifier($ev->getFinalDamage() / 2, EntityDamageEvent::MODIFIER_CRITICAL); } @@ -1712,7 +1712,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } $this->getWorld()->addSound($soundPos, new EntityAttackSound()); - if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0 and $entity instanceof Living){ + if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0 && $entity instanceof Living){ $entity->broadcastAnimation(new CriticalHitAnimation($entity)); } @@ -1725,7 +1725,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ if($this->isAlive()){ //reactive damage like thorns might cause us to be killed by attacking another mob, which //would mean we'd already have dropped the inventory by the time we reached here - if($heldItem->onAttackEntity($entity) and $this->hasFiniteResources() and $oldItem->equalsExact($this->inventory->getItemInHand())){ //always fire the hook, even if we are survival + if($heldItem->onAttackEntity($entity) && $this->hasFiniteResources() && $oldItem->equalsExact($this->inventory->getItemInHand())){ //always fire the hook, even if we are survival if($heldItem instanceof Durable && $heldItem->isBroken()){ $this->broadcastSound(new ItemBreakSound()); } @@ -1899,7 +1899,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ * @param int $fadeOut Title fade-out time in ticks. */ public function setTitleDuration(int $fadeIn, int $stay, int $fadeOut) : void{ - if($fadeIn >= 0 and $stay >= 0 and $fadeOut >= 0){ + if($fadeIn >= 0 && $stay >= 0 && $fadeOut >= 0){ $this->getNetworkSession()->onTitleDuration($fadeIn, $stay, $fadeOut); } } @@ -2286,11 +2286,11 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } if($this->isCreative() - and $source->getCause() !== EntityDamageEvent::CAUSE_SUICIDE - and $source->getCause() !== EntityDamageEvent::CAUSE_VOID + && $source->getCause() !== EntityDamageEvent::CAUSE_SUICIDE + && $source->getCause() !== EntityDamageEvent::CAUSE_VOID ){ $source->cancel(); - }elseif($this->allowFlight and $source->getCause() === EntityDamageEvent::CAUSE_FALL){ + }elseif($this->allowFlight && $source->getCause() === EntityDamageEvent::CAUSE_FALL){ $source->cancel(); } @@ -2315,7 +2315,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function broadcastAnimation(Animation $animation, ?array $targets = null) : void{ - if($this->spawned and $targets === null){ + if($this->spawned && $targets === null){ $targets = $this->getViewers(); $targets[] = $this; } diff --git a/src/player/SurvivalBlockBreakHandler.php b/src/player/SurvivalBlockBreakHandler.php index 5e27392cf..197d31215 100644 --- a/src/player/SurvivalBlockBreakHandler.php +++ b/src/player/SurvivalBlockBreakHandler.php @@ -105,7 +105,7 @@ final class SurvivalBlockBreakHandler{ $this->breakProgress += $this->breakSpeed; - if(($this->fxTicker++ % $this->fxTickInterval) === 0 and $this->breakProgress < 1){ + if(($this->fxTicker++ % $this->fxTickInterval) === 0 && $this->breakProgress < 1){ $this->player->getWorld()->addParticle($this->blockPos, new BlockPunchParticle($this->block, $this->targetedFace)); $this->player->getWorld()->addSound($this->blockPos, new BlockPunchSound($this->block)); $this->player->broadcastAnimation(new ArmSwingAnimation($this->player), $this->player->getViewers()); From 22fb02c4e67e83d7bd1d86799cfc8ecab5a69c49 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:16:50 +0000 Subject: [PATCH 661/710] Replace disallowed operators in src/item/ --- src/item/Armor.php | 4 ++-- src/item/Bow.php | 4 ++-- src/item/Bucket.php | 2 +- src/item/ChorusFruit.php | 4 ++-- src/item/Durable.php | 4 ++-- src/item/Item.php | 16 ++++++++-------- src/item/ItemEnchantmentHandlingTrait.php | 4 ++-- src/item/ItemFactory.php | 6 +++--- src/item/ItemIdentifier.php | 2 +- src/item/WrittenBook.php | 2 +- src/item/enchantment/ProtectionEnchantment.php | 2 +- 11 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/item/Armor.php b/src/item/Armor.php index 39ced43e3..cd3d6bd55 100644 --- a/src/item/Armor.php +++ b/src/item/Armor.php @@ -96,7 +96,7 @@ class Armor extends Durable{ foreach($this->getEnchantments() as $enchantment){ $type = $enchantment->getType(); - if($type instanceof ProtectionEnchantment and $type->isApplicable($event)){ + if($type instanceof ProtectionEnchantment && $type->isApplicable($event)){ $epf += $type->getProtectionFactor($enchantment->getLevel()); } } @@ -110,7 +110,7 @@ class Armor extends Durable{ $chance = 1 / ($unbreakingLevel + 1); for($i = 0; $i < $amount; ++$i){ - if(mt_rand(1, 100) > 60 and lcg_value() > $chance){ //unbreaking only applies to armor 40% of the time at best + if(mt_rand(1, 100) > 60 && lcg_value() > $chance){ //unbreaking only applies to armor 40% of the time at best $negated++; } } diff --git a/src/item/Bow.php b/src/item/Bow.php index 41777e0a6..c74b91f4f 100644 --- a/src/item/Bow.php +++ b/src/item/Bow.php @@ -52,7 +52,7 @@ class Bow extends Tool implements Releasable{ default => null }; - if($player->hasFiniteResources() and $inventory === null){ + if($player->hasFiniteResources() && $inventory === null){ return ItemUseResult::FAIL(); } @@ -85,7 +85,7 @@ class Bow extends Tool implements Releasable{ } $ev = new EntityShootBowEvent($player, $this, $entity, $baseForce * 3); - if($baseForce < 0.1 or $diff < 5 or $player->isSpectator()){ + if($baseForce < 0.1 || $diff < 5 || $player->isSpectator()){ $ev->cancel(); } diff --git a/src/item/Bucket.php b/src/item/Bucket.php index b7fd2a19f..3d6c818a1 100644 --- a/src/item/Bucket.php +++ b/src/item/Bucket.php @@ -38,7 +38,7 @@ class Bucket extends Item{ public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : ItemUseResult{ //TODO: move this to generic placement logic - if($blockClicked instanceof Liquid and $blockClicked->isSource()){ + if($blockClicked instanceof Liquid && $blockClicked->isSource()){ $stack = clone $this; $stack->pop(); diff --git a/src/item/ChorusFruit.php b/src/item/ChorusFruit.php index 7cf621e67..51364b15b 100644 --- a/src/item/ChorusFruit.php +++ b/src/item/ChorusFruit.php @@ -61,7 +61,7 @@ class ChorusFruit extends Food{ $y = mt_rand($minY, $maxY); $z = mt_rand($minZ, $maxZ); - while($y >= 0 and !$world->getBlockAt($x, $y, $z)->isSolid()){ + while($y >= 0 && !$world->getBlockAt($x, $y, $z)->isSolid()){ $y--; } if($y < 0){ @@ -70,7 +70,7 @@ class ChorusFruit extends Food{ $blockUp = $world->getBlockAt($x, $y + 1, $z); $blockUp2 = $world->getBlockAt($x, $y + 2, $z); - if($blockUp->isSolid() or $blockUp instanceof Liquid or $blockUp2->isSolid() or $blockUp2 instanceof Liquid){ + if($blockUp->isSolid() || $blockUp instanceof Liquid || $blockUp2->isSolid() || $blockUp2 instanceof Liquid){ continue; } diff --git a/src/item/Durable.php b/src/item/Durable.php index 004525808..9d4a2d044 100644 --- a/src/item/Durable.php +++ b/src/item/Durable.php @@ -62,7 +62,7 @@ abstract class Durable extends Item{ * @return bool if any damage was applied to the item */ public function applyDamage(int $amount) : bool{ - if($this->isUnbreakable() or $this->isBroken()){ + if($this->isUnbreakable() || $this->isBroken()){ return false; } @@ -81,7 +81,7 @@ abstract class Durable extends Item{ } public function setDamage(int $damage) : Item{ - if($damage < 0 or $damage > $this->getMaxDurability()){ + if($damage < 0 || $damage > $this->getMaxDurability()){ throw new \InvalidArgumentException("Damage must be in range 0 - " . $this->getMaxDurability()); } $this->damage = $damage; diff --git a/src/item/Item.php b/src/item/Item.php index a1a3b8c89..a1b2a6eab 100644 --- a/src/item/Item.php +++ b/src/item/Item.php @@ -277,7 +277,7 @@ class Item implements \JsonSerializable{ if($display !== null){ $this->customName = $display->getString(self::TAG_DISPLAY_NAME, $this->customName); $lore = $display->getListTag(self::TAG_DISPLAY_LORE); - if($lore !== null and $lore->getTagType() === NBT::TAG_String){ + if($lore !== null && $lore->getTagType() === NBT::TAG_String){ /** @var StringTag $t */ foreach($lore as $t){ $this->lore[] = $t->getValue(); @@ -287,7 +287,7 @@ class Item implements \JsonSerializable{ $this->removeEnchantments(); $enchantments = $tag->getListTag(self::TAG_ENCH); - if($enchantments !== null and $enchantments->getTagType() === NBT::TAG_Compound){ + if($enchantments !== null && $enchantments->getTagType() === NBT::TAG_Compound){ /** @var CompoundTag $enchantment */ foreach($enchantments as $enchantment){ $magicNumber = $enchantment->getShort("id", -1); @@ -412,7 +412,7 @@ class Item implements \JsonSerializable{ } public function isNull() : bool{ - return $this->count <= 0 or $this->getId() === ItemIds::AIR; + return $this->count <= 0 || $this->getId() === ItemIds::AIR; } /** @@ -568,9 +568,9 @@ class Item implements \JsonSerializable{ * @param bool $checkCompound Whether to verify that the items' NBT match. */ final public function equals(Item $item, bool $checkDamage = true, bool $checkCompound = true) : bool{ - return $this->getId() === $item->getId() and - (!$checkDamage or $this->getMeta() === $item->getMeta()) and - (!$checkCompound or $this->getNamedTag()->equals($item->getNamedTag())); + return $this->getId() === $item->getId() && + (!$checkDamage || $this->getMeta() === $item->getMeta()) && + (!$checkCompound || $this->getNamedTag()->equals($item->getNamedTag())); } /** @@ -584,7 +584,7 @@ class Item implements \JsonSerializable{ * Returns whether the specified item stack has the same ID, damage, NBT and count as this item stack. */ final public function equalsExact(Item $other) : bool{ - return $this->equals($other, true, true) and $this->count === $other->count; + return $this->equals($other, true, true) && $this->count === $other->count; } final public function __toString() : string{ @@ -676,7 +676,7 @@ class Item implements \JsonSerializable{ * @throws SavedDataLoadingException */ public static function nbtDeserialize(CompoundTag $tag) : Item{ - if($tag->getTag("id") === null or $tag->getTag("Count") === null){ + if($tag->getTag("id") === null || $tag->getTag("Count") === null){ return ItemFactory::getInstance()->get(0); } diff --git a/src/item/ItemEnchantmentHandlingTrait.php b/src/item/ItemEnchantmentHandlingTrait.php index 927509a41..9ba344139 100644 --- a/src/item/ItemEnchantmentHandlingTrait.php +++ b/src/item/ItemEnchantmentHandlingTrait.php @@ -42,7 +42,7 @@ trait ItemEnchantmentHandlingTrait{ public function hasEnchantment(Enchantment $enchantment, int $level = -1) : bool{ $id = spl_object_id($enchantment); - return isset($this->enchantments[$id]) and ($level === -1 or $this->enchantments[$id]->getLevel() === $level); + return isset($this->enchantments[$id]) && ($level === -1 || $this->enchantments[$id]->getLevel() === $level); } public function getEnchantment(Enchantment $enchantment) : ?EnchantmentInstance{ @@ -54,7 +54,7 @@ trait ItemEnchantmentHandlingTrait{ */ public function removeEnchantment(Enchantment $enchantment, int $level = -1) : self{ $instance = $this->getEnchantment($enchantment); - if($instance !== null and ($level === -1 or $instance->getLevel() === $level)){ + if($instance !== null && ($level === -1 || $instance->getLevel() === $level)){ unset($this->enchantments[spl_object_id($enchantment)]); } diff --git a/src/item/ItemFactory.php b/src/item/ItemFactory.php index ae6a596fb..dbceea1b0 100644 --- a/src/item/ItemFactory.php +++ b/src/item/ItemFactory.php @@ -418,7 +418,7 @@ class ItemFactory{ $id = $item->getId(); $variant = $item->getMeta(); - if(!$override and $this->isRegistered($id, $variant)){ + if(!$override && $this->isRegistered($id, $variant)){ throw new \RuntimeException("Trying to overwrite an already registered item"); } @@ -453,7 +453,7 @@ class ItemFactory{ if($meta !== -1){ if(isset($this->list[$offset = self::getListOffset($id, $meta)])){ $item = clone $this->list[$offset]; - }elseif(isset($this->list[$zero = self::getListOffset($id, 0)]) and $this->list[$zero] instanceof Durable){ + }elseif(isset($this->list[$zero = self::getListOffset($id, 0)]) && $this->list[$zero] instanceof Durable){ if($meta <= $this->list[$zero]->getMaxDurability()){ $item = clone $this->list[$zero]; $item->setDamage($meta); @@ -498,7 +498,7 @@ class ItemFactory{ } private static function getListOffset(int $id, int $variant) : int{ - if($id < -0x8000 or $id > 0x7fff){ + if($id < -0x8000 || $id > 0x7fff){ throw new \InvalidArgumentException("ID must be in range " . -0x8000 . " - " . 0x7fff); } return (($id & 0xffff) << 16) | ($variant & 0xffff); diff --git a/src/item/ItemIdentifier.php b/src/item/ItemIdentifier.php index 0242706f4..414cd5e0e 100644 --- a/src/item/ItemIdentifier.php +++ b/src/item/ItemIdentifier.php @@ -31,7 +31,7 @@ final class ItemIdentifier{ private $meta; public function __construct(int $id, int $meta){ - if($id < -0x8000 or $id > 0x7fff){ //signed short range + if($id < -0x8000 || $id > 0x7fff){ //signed short range throw new \InvalidArgumentException("ID must be in range " . -0x8000 . " - " . 0x7fff); } $this->id = $id; diff --git a/src/item/WrittenBook.php b/src/item/WrittenBook.php index 88352cdd1..129dfec3b 100644 --- a/src/item/WrittenBook.php +++ b/src/item/WrittenBook.php @@ -65,7 +65,7 @@ class WrittenBook extends WritableBookBase{ * @return $this */ public function setGeneration(int $generation) : self{ - if($generation < 0 or $generation > 3){ + if($generation < 0 || $generation > 3){ throw new \InvalidArgumentException("Generation \"$generation\" is out of range"); } diff --git a/src/item/enchantment/ProtectionEnchantment.php b/src/item/enchantment/ProtectionEnchantment.php index 30312ce34..b6f6a91be 100644 --- a/src/item/enchantment/ProtectionEnchantment.php +++ b/src/item/enchantment/ProtectionEnchantment.php @@ -66,6 +66,6 @@ class ProtectionEnchantment extends Enchantment{ * Returns whether this enchantment type offers protection from the specified damage source's cause. */ public function isApplicable(EntityDamageEvent $event) : bool{ - return $this->applicableDamageTypes === null or isset($this->applicableDamageTypes[$event->getCause()]); + return $this->applicableDamageTypes === null || isset($this->applicableDamageTypes[$event->getCause()]); } } From aa6bd4438aba09a8c083a9eb236dc79cd1d4d4dc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:17:17 +0000 Subject: [PATCH 662/710] Replace disallowed operators in src/event/ --- src/event/HandlerList.php | 6 +++--- src/event/HandlerListManager.php | 2 +- src/event/RegisteredListener.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/event/HandlerList.php b/src/event/HandlerList.php index b135a53cd..71b159ca5 100644 --- a/src/event/HandlerList.php +++ b/src/event/HandlerList.php @@ -65,11 +65,11 @@ class HandlerList{ * @param RegisteredListener|Listener|Plugin $object */ public function unregister($object) : void{ - if($object instanceof Plugin or $object instanceof Listener){ + if($object instanceof Plugin || $object instanceof Listener){ foreach($this->handlerSlots as $priority => $list){ foreach($list as $hash => $listener){ - if(($object instanceof Plugin and $listener->getPlugin() === $object) - or ($object instanceof Listener and (new \ReflectionFunction($listener->getHandler()))->getClosureThis() === $object) //this doesn't even need to be a listener :D + if(($object instanceof Plugin && $listener->getPlugin() === $object) + || ($object instanceof Listener && (new \ReflectionFunction($listener->getHandler()))->getClosureThis() === $object) //this doesn't even need to be a listener :D ){ unset($this->handlerSlots[$priority][$hash]); } diff --git a/src/event/HandlerListManager.php b/src/event/HandlerListManager.php index 0859b1e5e..864b639d7 100644 --- a/src/event/HandlerListManager.php +++ b/src/event/HandlerListManager.php @@ -45,7 +45,7 @@ class HandlerListManager{ * @param Plugin|Listener|RegisteredListener|null $object */ public function unregisterAll($object = null) : void{ - if($object instanceof Listener or $object instanceof Plugin or $object instanceof RegisteredListener){ + if($object instanceof Listener || $object instanceof Plugin || $object instanceof RegisteredListener){ foreach($this->allLists as $h){ $h->unregister($object); } diff --git a/src/event/RegisteredListener.php b/src/event/RegisteredListener.php index cc22a0511..d0732bc99 100644 --- a/src/event/RegisteredListener.php +++ b/src/event/RegisteredListener.php @@ -68,7 +68,7 @@ class RegisteredListener{ } public function callEvent(Event $event) : void{ - if($event instanceof Cancellable and $event->isCancelled() and !$this->isHandlingCancelled()){ + if($event instanceof Cancellable && $event->isCancelled() && !$this->isHandlingCancelled()){ return; } $this->timings->startTiming(); From 3f8f5cd2007e21201ec16cd004b024d1cbeed2a1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:18:26 +0000 Subject: [PATCH 663/710] Replace disallowed operators in src/crafting/ --- src/crafting/CraftingGrid.php | 2 +- src/crafting/ShapedRecipe.php | 12 ++++++------ src/crafting/ShapelessRecipe.php | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/crafting/CraftingGrid.php b/src/crafting/CraftingGrid.php index eb3ea5f25..b72392016 100644 --- a/src/crafting/CraftingGrid.php +++ b/src/crafting/CraftingGrid.php @@ -96,7 +96,7 @@ abstract class CraftingGrid extends SimpleInventory{ * Returns the item at offset x,y, offset by where the starts of the recipe rectangle are. */ public function getIngredient(int $x, int $y) : Item{ - if($this->startX !== null and $this->startY !== null){ + if($this->startX !== null && $this->startY !== null){ return $this->getItem(($y + $this->startY) * $this->gridWidth + ($x + $this->startX)); } diff --git a/src/crafting/ShapedRecipe.php b/src/crafting/ShapedRecipe.php index 5fc881a97..fc02224a9 100644 --- a/src/crafting/ShapedRecipe.php +++ b/src/crafting/ShapedRecipe.php @@ -62,14 +62,14 @@ class ShapedRecipe implements CraftingRecipe{ */ public function __construct(array $shape, array $ingredients, array $results){ $this->height = count($shape); - if($this->height > 3 or $this->height <= 0){ + if($this->height > 3 || $this->height <= 0){ throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 rows, not $this->height"); } $shape = array_values($shape); $this->width = strlen($shape[0]); - if($this->width > 3 or $this->width <= 0){ + if($this->width > 3 || $this->width <= 0){ throw new \InvalidArgumentException("Shaped recipes may only have 1, 2 or 3 columns, not $this->width"); } @@ -79,7 +79,7 @@ class ShapedRecipe implements CraftingRecipe{ } for($x = 0; $x < $this->width; ++$x){ - if($row[$x] !== ' ' and !isset($ingredients[$row[$x]])){ + if($row[$x] !== ' ' && !isset($ingredients[$row[$x]])){ throw new \InvalidArgumentException("No item specified for symbol '" . $row[$x] . "'"); } } @@ -172,7 +172,7 @@ class ShapedRecipe implements CraftingRecipe{ $given = $grid->getIngredient($reverse ? $this->width - $x - 1 : $x, $y); $required = $this->getIngredient($x, $y); - if(!$required->equals($given, !$required->hasAnyDamageValue(), $required->hasNamedTag()) or $required->getCount() > $given->getCount()){ + if(!$required->equals($given, !$required->hasAnyDamageValue(), $required->hasNamedTag()) || $required->getCount() > $given->getCount()){ return false; } } @@ -182,10 +182,10 @@ class ShapedRecipe implements CraftingRecipe{ } public function matchesCraftingGrid(CraftingGrid $grid) : bool{ - if($this->width !== $grid->getRecipeWidth() or $this->height !== $grid->getRecipeHeight()){ + if($this->width !== $grid->getRecipeWidth() || $this->height !== $grid->getRecipeHeight()){ return false; } - return $this->matchInputMap($grid, false) or $this->matchInputMap($grid, true); + return $this->matchInputMap($grid, false) || $this->matchInputMap($grid, true); } } diff --git a/src/crafting/ShapelessRecipe.php b/src/crafting/ShapelessRecipe.php index 195b917fa..4ef3bfc1a 100644 --- a/src/crafting/ShapelessRecipe.php +++ b/src/crafting/ShapelessRecipe.php @@ -85,7 +85,7 @@ class ShapelessRecipe implements CraftingRecipe{ foreach($this->ingredients as $needItem){ foreach($input as $j => $haveItem){ - if($haveItem->equals($needItem, !$needItem->hasAnyDamageValue(), $needItem->hasNamedTag()) and $haveItem->getCount() >= $needItem->getCount()){ + if($haveItem->equals($needItem, !$needItem->hasAnyDamageValue(), $needItem->hasNamedTag()) && $haveItem->getCount() >= $needItem->getCount()){ unset($input[$j]); continue 2; } From 03f47d0a782478a9706f3429b71b201b5ef6d0df Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:19:20 +0000 Subject: [PATCH 664/710] Replace disallowed operators in src/plugin/ --- src/plugin/ApiVersion.php | 2 +- src/plugin/PharPluginLoader.php | 2 +- src/plugin/PluginBase.php | 6 +++--- src/plugin/PluginDescription.php | 2 +- src/plugin/PluginLoadabilityChecker.php | 4 ++-- src/plugin/PluginManager.php | 14 +++++++------- src/plugin/ScriptPluginLoader.php | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/plugin/ApiVersion.php b/src/plugin/ApiVersion.php index 5a2bb035b..3842c1af5 100644 --- a/src/plugin/ApiVersion.php +++ b/src/plugin/ApiVersion.php @@ -53,7 +53,7 @@ final class ApiVersion{ continue; } - if($version->getMinor() === $myVersion->getMinor() and $version->getPatch() > $myVersion->getPatch()){ //If the plugin requires bug fixes in patches, being backwards compatible + if($version->getMinor() === $myVersion->getMinor() && $version->getPatch() > $myVersion->getPatch()){ //If the plugin requires bug fixes in patches, being backwards compatible continue; } } diff --git a/src/plugin/PharPluginLoader.php b/src/plugin/PharPluginLoader.php index d42fa0b5e..e036099e8 100644 --- a/src/plugin/PharPluginLoader.php +++ b/src/plugin/PharPluginLoader.php @@ -41,7 +41,7 @@ class PharPluginLoader implements PluginLoader{ public function canLoadPlugin(string $path) : bool{ $ext = ".phar"; - return is_file($path) and substr($path, -strlen($ext)) === $ext; + return is_file($path) && substr($path, -strlen($ext)) === $ext; } /** diff --git a/src/plugin/PluginBase.php b/src/plugin/PluginBase.php index 32b30794e..fdf47d39c 100644 --- a/src/plugin/PluginBase.php +++ b/src/plugin/PluginBase.php @@ -209,11 +209,11 @@ abstract class PluginBase implements Plugin, CommandExecutor{ */ public function getCommand(string $name){ $command = $this->getServer()->getPluginCommand($name); - if($command === null or $command->getOwningPlugin() !== $this){ + if($command === null || $command->getOwningPlugin() !== $this){ $command = $this->getServer()->getPluginCommand(strtolower($this->description->getName()) . ":" . $name); } - if($command instanceof PluginOwned and $command->getOwningPlugin() === $this){ + if($command instanceof PluginOwned && $command->getOwningPlugin() === $this){ return $command; }else{ return null; @@ -254,7 +254,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{ mkdir(dirname($out), 0755, true); } - if(file_exists($out) and !$replace){ + if(file_exists($out) && !$replace){ return false; } diff --git a/src/plugin/PluginDescription.php b/src/plugin/PluginDescription.php index 22949e673..0bd7587bb 100644 --- a/src/plugin/PluginDescription.php +++ b/src/plugin/PluginDescription.php @@ -124,7 +124,7 @@ class PluginDescription{ $this->compatibleMcpeProtocols = array_map("\intval", (array) ($plugin["mcpe-protocol"] ?? [])); $this->compatibleOperatingSystems = array_map("\strval", (array) ($plugin["os"] ?? [])); - if(isset($plugin["commands"]) and is_array($plugin["commands"])){ + if(isset($plugin["commands"]) && is_array($plugin["commands"])){ foreach($plugin["commands"] as $commandName => $commandData){ if(!is_string($commandName)){ throw new PluginDescriptionParseException("Invalid Plugin commands, key must be the name of the command"); diff --git a/src/plugin/PluginLoadabilityChecker.php b/src/plugin/PluginLoadabilityChecker.php index 4451cc6f1..216f70129 100644 --- a/src/plugin/PluginLoadabilityChecker.php +++ b/src/plugin/PluginLoadabilityChecker.php @@ -47,7 +47,7 @@ final class PluginLoadabilityChecker{ public function check(PluginDescription $description) : Translatable|null{ $name = $description->getName(); - if(stripos($name, "pocketmine") !== false or stripos($name, "minecraft") !== false or stripos($name, "mojang") !== false){ + if(stripos($name, "pocketmine") !== false || stripos($name, "minecraft") !== false || stripos($name, "mojang") !== false){ return KnownTranslationFactory::pocketmine_plugin_restrictedName(); } @@ -66,7 +66,7 @@ final class PluginLoadabilityChecker{ return KnownTranslationFactory::pocketmine_plugin_ambiguousMinAPI(implode(", ", $ambiguousVersions)); } - if(count($description->getCompatibleOperatingSystems()) > 0 and !in_array(Utils::getOS(), $description->getCompatibleOperatingSystems(), true)) { + if(count($description->getCompatibleOperatingSystems()) > 0 && !in_array(Utils::getOS(), $description->getCompatibleOperatingSystems(), true)) { return KnownTranslationFactory::pocketmine_plugin_incompatibleOS(implode(", ", $description->getCompatibleOperatingSystems())); } diff --git a/src/plugin/PluginManager.php b/src/plugin/PluginManager.php index 49f8ed06b..529fe5bbe 100644 --- a/src/plugin/PluginManager.php +++ b/src/plugin/PluginManager.php @@ -137,7 +137,7 @@ class PluginManager{ $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName()))); $dataFolder = $this->getDataDirectory($path, $description->getName()); - if(file_exists($dataFolder) and !is_dir($dataFolder)){ + if(file_exists($dataFolder) && !is_dir($dataFolder)){ $this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError( $description->getName(), KnownTranslationFactory::pocketmine_plugin_badDataFolder($dataFolder) @@ -274,7 +274,7 @@ class PluginManager{ continue; } - if(isset($triage->plugins[$name]) or $this->getPlugin($name) instanceof Plugin){ + if(isset($triage->plugins[$name]) || $this->getPlugin($name) instanceof Plugin){ $this->server->getLogger()->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_duplicateError($name))); continue; } @@ -283,7 +283,7 @@ class PluginManager{ $this->server->getLogger()->warning($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_spacesDiscouraged($name))); } - if($this->graylist !== null and !$this->graylist->isAllowed($name)){ + if($this->graylist !== null && !$this->graylist->isAllowed($name)){ $this->server->getLogger()->notice($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_loadError( $name, $this->graylist->isWhitelist() ? KnownTranslationFactory::pocketmine_plugin_disallowedByWhitelist() : KnownTranslationFactory::pocketmine_plugin_disallowedByBlacklist() @@ -314,7 +314,7 @@ class PluginManager{ private function checkDepsForTriage(string $pluginName, string $dependencyType, array &$dependencyLists, array $loadedPlugins, PluginLoadTriage $triage) : void{ if(isset($dependencyLists[$pluginName])){ foreach($dependencyLists[$pluginName] as $key => $dependency){ - if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ + if(isset($loadedPlugins[$dependency]) || $this->getPlugin($dependency) instanceof Plugin){ $this->server->getLogger()->debug("Successfully resolved $dependencyType dependency \"$dependency\" for plugin \"$pluginName\""); unset($dependencyLists[$pluginName][$key]); }elseif(array_key_exists($dependency, $triage->plugins)){ @@ -348,7 +348,7 @@ class PluginManager{ $this->checkDepsForTriage($name, "hard", $triage->dependencies, $loadedPlugins, $triage); $this->checkDepsForTriage($name, "soft", $triage->softDependencies, $loadedPlugins, $triage); - if(!isset($triage->dependencies[$name]) and !isset($triage->softDependencies[$name])){ + if(!isset($triage->dependencies[$name]) && !isset($triage->softDependencies[$name])){ unset($triage->plugins[$name]); $loadedThisLoop++; @@ -426,7 +426,7 @@ class PluginManager{ } public function isPluginEnabled(Plugin $plugin) : bool{ - return isset($this->plugins[$plugin->getDescription()->getName()]) and $plugin->isEnabled(); + return isset($this->plugins[$plugin->getDescription()->getName()]) && $plugin->isEnabled(); } public function enablePlugin(Plugin $plugin) : void{ @@ -485,7 +485,7 @@ class PluginManager{ * @phpstan-return class-string|null */ private function getEventsHandledBy(\ReflectionMethod $method) : ?string{ - if($method->isStatic() or !$method->getDeclaringClass()->implementsInterface(Listener::class)){ + if($method->isStatic() || !$method->getDeclaringClass()->implementsInterface(Listener::class)){ return null; } $tags = Utils::parseDocComment((string) $method->getDocComment()); diff --git a/src/plugin/ScriptPluginLoader.php b/src/plugin/ScriptPluginLoader.php index f446be72c..ccf4c8a01 100644 --- a/src/plugin/ScriptPluginLoader.php +++ b/src/plugin/ScriptPluginLoader.php @@ -42,7 +42,7 @@ class ScriptPluginLoader implements PluginLoader{ public function canLoadPlugin(string $path) : bool{ $ext = ".php"; - return is_file($path) and substr($path, -strlen($ext)) === $ext; + return is_file($path) && substr($path, -strlen($ext)) === $ext; } /** From b85fe0e72af867798c0393cc65d2ceb03ec56073 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:20:03 +0000 Subject: [PATCH 665/710] Replace disallowed operators in src/scheduler/ --- src/scheduler/AsyncPool.php | 6 +++--- src/scheduler/AsyncTask.php | 8 ++++---- src/scheduler/Task.php | 2 +- src/scheduler/TaskScheduler.php | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/scheduler/AsyncPool.php b/src/scheduler/AsyncPool.php index 047488ee3..645dfc24c 100644 --- a/src/scheduler/AsyncPool.php +++ b/src/scheduler/AsyncPool.php @@ -163,7 +163,7 @@ class AsyncPool{ * Submits an AsyncTask to an arbitrary worker. */ public function submitTaskToWorker(AsyncTask $task, int $worker) : void{ - if($worker < 0 or $worker >= $this->size){ + if($worker < 0 || $worker >= $this->size){ throw new \InvalidArgumentException("Invalid worker $worker"); } if($task->isSubmitted()){ @@ -197,7 +197,7 @@ class AsyncPool{ } } } - if($worker === null or ($minUsage > 0 and count($this->workers) < $this->size)){ + if($worker === null || ($minUsage > 0 && count($this->workers) < $this->size)){ //select a worker to start on the fly for($i = 0; $i < $this->size; ++$i){ if(!isset($this->workers[$i])){ @@ -297,7 +297,7 @@ class AsyncPool{ $ret = 0; $time = time(); foreach($this->taskQueues as $i => $queue){ - if((!isset($this->workerLastUsed[$i]) or $this->workerLastUsed[$i] + 300 < $time) and $queue->isEmpty()){ + if((!isset($this->workerLastUsed[$i]) || $this->workerLastUsed[$i] + 300 < $time) && $queue->isEmpty()){ $this->workers[$i]->quit(); $this->eventLoop->removeNotifier($this->workers[$i]->getNotifier()); unset($this->workers[$i], $this->taskQueues[$i], $this->workerLastUsed[$i]); diff --git a/src/scheduler/AsyncTask.php b/src/scheduler/AsyncTask.php index 2f1bedc6b..ea70364b9 100644 --- a/src/scheduler/AsyncTask.php +++ b/src/scheduler/AsyncTask.php @@ -93,7 +93,7 @@ abstract class AsyncTask extends \Threaded{ } public function isCrashed() : bool{ - return $this->crashed or $this->isTerminated(); + return $this->crashed || $this->isTerminated(); } /** @@ -101,7 +101,7 @@ abstract class AsyncTask extends \Threaded{ * because it is not true prior to task execution. */ public function isFinished() : bool{ - return $this->finished or $this->isCrashed(); + return $this->finished || $this->isCrashed(); } public function hasResult() : bool{ @@ -236,7 +236,7 @@ abstract class AsyncTask extends \Threaded{ */ protected function fetchLocal(string $key){ $id = spl_object_id($this); - if(self::$threadLocalStorage === null or !isset(self::$threadLocalStorage[$id][$key])){ + if(self::$threadLocalStorage === null || !isset(self::$threadLocalStorage[$id][$key])){ throw new \InvalidArgumentException("No matching thread-local data found on this thread"); } @@ -245,7 +245,7 @@ abstract class AsyncTask extends \Threaded{ final public function __destruct(){ $this->reallyDestruct(); - if(self::$threadLocalStorage !== null and isset(self::$threadLocalStorage[$h = spl_object_id($this)])){ + if(self::$threadLocalStorage !== null && isset(self::$threadLocalStorage[$h = spl_object_id($this)])){ unset(self::$threadLocalStorage[$h]); if(self::$threadLocalStorage->count() === 0){ self::$threadLocalStorage = null; diff --git a/src/scheduler/Task.php b/src/scheduler/Task.php index 0c4ea4469..4ad4c7e39 100644 --- a/src/scheduler/Task.php +++ b/src/scheduler/Task.php @@ -42,7 +42,7 @@ abstract class Task{ } final public function setHandler(?TaskHandler $taskHandler) : void{ - if($this->taskHandler === null or $taskHandler === null){ + if($this->taskHandler === null || $taskHandler === null){ $this->taskHandler = $taskHandler; } } diff --git a/src/scheduler/TaskScheduler.php b/src/scheduler/TaskScheduler.php index a1ed6a261..f66bd857a 100644 --- a/src/scheduler/TaskScheduler.php +++ b/src/scheduler/TaskScheduler.php @@ -150,6 +150,6 @@ class TaskScheduler{ } private function isReady(int $currentTick) : bool{ - return !$this->queue->isEmpty() and $this->queue->current()->getNextRun() <= $currentTick; + return !$this->queue->isEmpty() && $this->queue->current()->getNextRun() <= $currentTick; } } From e986a0a4f2b0ef2aaa0dd762011cc8422304bdc6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:20:32 +0000 Subject: [PATCH 666/710] Replace disallowed operators in src/inventory/ --- src/inventory/BaseInventory.php | 6 +++--- src/inventory/PlayerInventory.php | 2 +- src/inventory/transaction/CraftingTransaction.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/inventory/BaseInventory.php b/src/inventory/BaseInventory.php index 589254d85..5700923ac 100644 --- a/src/inventory/BaseInventory.php +++ b/src/inventory/BaseInventory.php @@ -146,7 +146,7 @@ abstract class BaseInventory implements Inventory{ $checkTags = $exact || $item->hasNamedTag(); foreach($this->getContents() as $index => $i){ - if($item->equals($i, $checkDamage, $checkTags) and ($i->getCount() === $count or (!$exact and $i->getCount() > $count))){ + if($item->equals($i, $checkDamage, $checkTags) && ($i->getCount() === $count || (!$exact && $i->getCount() > $count))){ return $index; } } @@ -224,7 +224,7 @@ abstract class BaseInventory implements Inventory{ $emptySlots[] = $i; } - if($slot->canStackWith($item) and $item->getCount() < $item->getMaxStackSize()){ + if($slot->canStackWith($item) && $item->getCount() < $item->getMaxStackSize()){ $amount = min($item->getMaxStackSize() - $item->getCount(), $slot->getCount(), $this->getMaxStackSize()); if($amount > 0){ $slot->setCount($slot->getCount() - $amount); @@ -367,7 +367,7 @@ abstract class BaseInventory implements Inventory{ } public function slotExists(int $slot) : bool{ - return $slot >= 0 and $slot < $this->getSize(); + return $slot >= 0 && $slot < $this->getSize(); } public function getListeners() : ObjectSet{ diff --git a/src/inventory/PlayerInventory.php b/src/inventory/PlayerInventory.php index 253ddfdea..1da30d2e9 100644 --- a/src/inventory/PlayerInventory.php +++ b/src/inventory/PlayerInventory.php @@ -49,7 +49,7 @@ class PlayerInventory extends SimpleInventory{ } public function isHotbarSlot(int $slot) : bool{ - return $slot >= 0 and $slot <= $this->getHotbarSize(); + return $slot >= 0 && $slot <= $this->getHotbarSize(); } /** diff --git a/src/inventory/transaction/CraftingTransaction.php b/src/inventory/transaction/CraftingTransaction.php index 0d13ccbed..953199089 100644 --- a/src/inventory/transaction/CraftingTransaction.php +++ b/src/inventory/transaction/CraftingTransaction.php @@ -92,7 +92,7 @@ class CraftingTransaction extends InventoryTransaction{ $haveCount = 0; foreach($txItems as $j => $txItem){ - if($txItem->equals($recipeItem, !$wildcards or !$recipeItem->hasAnyDamageValue(), !$wildcards or $recipeItem->hasNamedTag())){ + if($txItem->equals($recipeItem, !$wildcards || !$recipeItem->hasAnyDamageValue(), !$wildcards || $recipeItem->hasNamedTag())){ $haveCount += $txItem->getCount(); unset($txItems[$j]); } From ae03c70dfc2a59edbce1e8ae52261f5a6a92e541 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:20:51 +0000 Subject: [PATCH 667/710] Replace disallowed operators in src/permission/ --- src/permission/BanEntry.php | 2 +- src/permission/PermissibleInternal.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/permission/BanEntry.php b/src/permission/BanEntry.php index 596edfeb5..d0d200eac 100644 --- a/src/permission/BanEntry.php +++ b/src/permission/BanEntry.php @@ -168,7 +168,7 @@ class BanEntry{ } if(count($parts) > 0){ $expire = trim(array_shift($parts)); - if($expire !== "" and strtolower($expire) !== "forever"){ + if($expire !== "" && strtolower($expire) !== "forever"){ $entry->setExpires(self::parseDate($expire)); } } diff --git a/src/permission/PermissibleInternal.php b/src/permission/PermissibleInternal.php index 14cb0ba1a..23d0b3b0c 100644 --- a/src/permission/PermissibleInternal.php +++ b/src/permission/PermissibleInternal.php @@ -114,7 +114,7 @@ class PermissibleInternal implements Permissible{ $result = new PermissionAttachment($plugin); $this->attachments[spl_object_id($result)] = $result; - if($name !== null and $value !== null){ + if($name !== null && $value !== null){ $result->setPermission($name, $value); } From 61f81442802358250254ac491d6b11526f575844 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:21:04 +0000 Subject: [PATCH 668/710] Replace disallowed operators in src/updater/ --- src/updater/UpdateCheckTask.php | 2 +- src/updater/UpdateChecker.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/updater/UpdateCheckTask.php b/src/updater/UpdateCheckTask.php index 6b571b2fe..fb308eec3 100644 --- a/src/updater/UpdateCheckTask.php +++ b/src/updater/UpdateCheckTask.php @@ -53,7 +53,7 @@ class UpdateCheckTask extends AsyncTask{ if($response !== null){ $response = json_decode($response->getBody(), true); if(is_array($response)){ - if(isset($response["error"]) and is_string($response["error"])){ + if(isset($response["error"]) && is_string($response["error"])){ $this->error = $response["error"]; }else{ $mapper = new \JsonMapper(); diff --git a/src/updater/UpdateChecker.php b/src/updater/UpdateChecker.php index 6edced2e0..9c530dedb 100644 --- a/src/updater/UpdateChecker.php +++ b/src/updater/UpdateChecker.php @@ -68,9 +68,9 @@ class UpdateChecker{ $this->showConsoleUpdate(); } }else{ - if(!VersionInfo::IS_DEVELOPMENT_BUILD and $this->getChannel() !== "stable"){ + if(!VersionInfo::IS_DEVELOPMENT_BUILD && $this->getChannel() !== "stable"){ $this->showChannelSuggestionStable(); - }elseif(VersionInfo::IS_DEVELOPMENT_BUILD and $this->getChannel() === "stable"){ + }elseif(VersionInfo::IS_DEVELOPMENT_BUILD && $this->getChannel() === "stable"){ $this->showChannelSuggestionBeta(); } } From 4e956d5d1d7ae9cb5cc16d5d8b1f19399bcc9537 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:23:19 +0000 Subject: [PATCH 669/710] Replace remaining disallowed operators --- src/MemoryManager.php | 16 +++++------ src/PocketMine.php | 2 +- src/Server.php | 28 +++++++++---------- src/crash/CrashDump.php | 4 +-- .../LegacyToStringBidirectionalIdMap.php | 2 +- src/lang/Language.php | 14 +++++----- src/resourcepacks/ZippedResourcePack.php | 4 +-- src/thread/ThreadManager.php | 4 +-- src/wizard/SetupWizard.php | 4 +-- 9 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/MemoryManager.php b/src/MemoryManager.php index 2ddfbffbe..b24853317 100644 --- a/src/MemoryManager.php +++ b/src/MemoryManager.php @@ -168,14 +168,14 @@ class MemoryManager{ } public function canUseChunkCache() : bool{ - return !$this->lowMemory or !$this->lowMemDisableChunkCache; + return !$this->lowMemory || !$this->lowMemDisableChunkCache; } /** * Returns the allowed chunk radius based on the current memory usage. */ public function getViewDistance(int $distance) : int{ - return ($this->lowMemory and $this->lowMemChunkRadiusOverride > 0) ? min($this->lowMemChunkRadiusOverride, $distance) : $distance; + return ($this->lowMemory && $this->lowMemChunkRadiusOverride > 0) ? min($this->lowMemChunkRadiusOverride, $distance) : $distance; } /** @@ -214,18 +214,18 @@ class MemoryManager{ public function check() : void{ Timings::$memoryManager->startTiming(); - if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){ + if(($this->memoryLimit > 0 || $this->globalMemoryLimit > 0) && ++$this->checkTicker >= $this->checkRate){ $this->checkTicker = 0; $memory = Process::getAdvancedMemoryUsage(); $trigger = false; - if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){ + if($this->memoryLimit > 0 && $memory[0] > $this->memoryLimit){ $trigger = 0; - }elseif($this->globalMemoryLimit > 0 and $memory[1] > $this->globalMemoryLimit){ + }elseif($this->globalMemoryLimit > 0 && $memory[1] > $this->globalMemoryLimit){ $trigger = 1; } if($trigger !== false){ - if($this->lowMemory and $this->continuousTrigger){ + if($this->lowMemory && $this->continuousTrigger){ if(++$this->continuousTriggerTicker >= $this->continuousTriggerRate){ $this->continuousTriggerTicker = 0; $this->trigger($memory[$trigger], $this->memoryLimit, $trigger > 0, ++$this->continuousTriggerCount); @@ -240,7 +240,7 @@ class MemoryManager{ } } - if($this->garbageCollectionPeriod > 0 and ++$this->garbageCollectionTicker >= $this->garbageCollectionPeriod){ + if($this->garbageCollectionPeriod > 0 && ++$this->garbageCollectionTicker >= $this->garbageCollectionPeriod){ $this->garbageCollectionTicker = 0; $this->triggerGarbageCollector(); } @@ -317,7 +317,7 @@ class MemoryManager{ $reflection = new \ReflectionClass($className); $staticProperties[$className] = []; foreach($reflection->getProperties() as $property){ - if(!$property->isStatic() or $property->getDeclaringClass()->getName() !== $className){ + if(!$property->isStatic() || $property->getDeclaringClass()->getName() !== $className){ continue; } diff --git a/src/PocketMine.php b/src/PocketMine.php index 3c38639ed..9cb8eedf8 100644 --- a/src/PocketMine.php +++ b/src/PocketMine.php @@ -287,7 +287,7 @@ JIT_WARNING $exitCode = 0; do{ - if(!file_exists(Path::join($dataPath, "server.properties")) and !isset($opts["no-wizard"])){ + if(!file_exists(Path::join($dataPath, "server.properties")) && !isset($opts["no-wizard"])){ $installer = new SetupWizard($dataPath); if(!$installer->run()){ $exitCode = -1; diff --git a/src/Server.php b/src/Server.php index 48ff55861..8b484a9f1 100644 --- a/src/Server.php +++ b/src/Server.php @@ -561,7 +561,7 @@ class Server{ $ev->call(); $class = $ev->getPlayerClass(); - if($offlinePlayerData !== null and ($world = $this->worldManager->getWorldByName($offlinePlayerData->getString("Level", ""))) !== null){ + if($offlinePlayerData !== null && ($world = $this->worldManager->getWorldByName($offlinePlayerData->getString("Level", ""))) !== null){ $playerPos = EntityDataHelper::parseLocation($offlinePlayerData, $world); $spawn = $playerPos->asVector3(); }else{ @@ -721,7 +721,7 @@ class Server{ } public function isWhitelisted(string $name) : bool{ - return !$this->hasWhitelist() or $this->operators->exists($name, true) or $this->whitelist->exists($name, true); + return !$this->hasWhitelist() || $this->operators->exists($name, true) || $this->whitelist->exists($name, true); } public function isOp(string $name) : bool{ @@ -895,7 +895,7 @@ class Server{ } $netCompressionLevel = $this->configGroup->getPropertyInt("network.compression-level", 6); - if($netCompressionLevel < 1 or $netCompressionLevel > 9){ + if($netCompressionLevel < 1 || $netCompressionLevel > 9){ $this->logger->warning("Invalid network compression level $netCompressionLevel set, setting to default 6"); $netCompressionLevel = 6; } @@ -912,7 +912,7 @@ class Server{ $bannedTxt = Path::join($this->dataPath, "banned.txt"); $bannedPlayersTxt = Path::join($this->dataPath, "banned-players.txt"); - if(file_exists($bannedTxt) and !file_exists($bannedPlayersTxt)){ + if(file_exists($bannedTxt) && !file_exists($bannedPlayersTxt)){ @rename($bannedTxt, $bannedPlayersTxt); } @touch($bannedPlayersTxt); @@ -934,7 +934,7 @@ class Server{ $this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled())); } - if($this->configGroup->getConfigBool("hardcore", false) and $this->getDifficulty() < World::DIFFICULTY_HARD){ + if($this->configGroup->getConfigBool("hardcore", false) && $this->getDifficulty() < World::DIFFICULTY_HARD){ $this->configGroup->setConfigInt("difficulty", World::DIFFICULTY_HARD); } @@ -984,7 +984,7 @@ class Server{ $providerManager = new WorldProviderManager(); if( - ($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString("level-settings.default-format", ""))) !== null and + ($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString("level-settings.default-format", ""))) !== null && $format instanceof WritableWorldProviderManagerEntry ){ $providerManager->setDefault($format); @@ -1381,7 +1381,7 @@ class Server{ public function enablePlugins(PluginEnableOrder $type) : void{ foreach($this->pluginManager->getPlugins() as $plugin){ - if(!$plugin->isEnabled() and $plugin->getDescription()->getOrder()->equals($type)){ + if(!$plugin->isEnabled() && $plugin->getDescription()->getOrder()->equals($type)){ $this->pluginManager->enablePlugin($plugin); } } @@ -1572,7 +1572,7 @@ class Server{ $stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash"); $crashInterval = 120; //2 minutes - if(($lastReportTime = @filemtime($stamp)) !== false and $lastReportTime + $crashInterval >= time()){ + if(($lastReportTime = @filemtime($stamp)) !== false && $lastReportTime + $crashInterval >= time()){ $report = false; $this->logger->debug("Not sending crashdump due to last crash less than $crashInterval seconds ago"); } @@ -1581,7 +1581,7 @@ class Server{ $plugin = $dump->getData()->plugin; if($plugin !== ""){ $p = $this->pluginManager->getPlugin($plugin); - if($p instanceof Plugin and !($p->getPluginLoader() instanceof PharPluginLoader)){ + if($p instanceof Plugin && !($p->getPluginLoader() instanceof PharPluginLoader)){ $this->logger->debug("Not sending crashdump due to caused by non-phar plugin"); $report = false; } @@ -1591,7 +1591,7 @@ class Server{ $report = false; } - if(strrpos(VersionInfo::GIT_HASH(), "-dirty") !== false or VersionInfo::GIT_HASH() === str_repeat("00", 20)){ + if(strrpos(VersionInfo::GIT_HASH(), "-dirty") !== false || VersionInfo::GIT_HASH() === str_repeat("00", 20)){ $this->logger->debug("Not sending crashdump due to locally modified"); $report = false; //Don't send crashdumps for locally modified builds } @@ -1606,8 +1606,8 @@ class Server{ "reportPaste" => base64_encode($dump->getEncodedData()) ], 10, [], $postUrlError); - if($reply !== null and ($data = json_decode($reply->getBody())) !== null){ - if(isset($data->crashId) and isset($data->crashUrl)){ + if($reply !== null && ($data = json_decode($reply->getBody())) !== null){ + if(isset($data->crashId) && isset($data->crashUrl)){ $reportId = $data->crashId; $reportUrl = $data->crashUrl; $this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId))); @@ -1664,7 +1664,7 @@ class Server{ public function addOnlinePlayer(Player $player) : bool{ $ev = new PlayerLoginEvent($player, "Plugin reason"); $ev->call(); - if($ev->isCancelled() or !$player->isConnected()){ + if($ev->isCancelled() || !$player->isConnected()){ $player->disconnect($ev->getKickMessage()); return false; @@ -1793,7 +1793,7 @@ class Server{ $this->network->getBandwidthTracker()->rotateAverageHistory(); } - if($this->sendUsageTicker > 0 and --$this->sendUsageTicker === 0){ + if($this->sendUsageTicker > 0 && --$this->sendUsageTicker === 0){ $this->sendUsageTicker = 6000; $this->sendUsage(SendUsageTask::TYPE_STATUS); } diff --git a/src/crash/CrashDump.php b/src/crash/CrashDump.php index c2979e53b..395f11a3f 100644 --- a/src/crash/CrashDump.php +++ b/src/crash/CrashDump.php @@ -222,10 +222,10 @@ class CrashDump{ } } - if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-code", true) and file_exists($error["fullFile"])){ + if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-code", true) && file_exists($error["fullFile"])){ $file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES); if($file !== false){ - for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 and isset($file[$l]); ++$l){ + for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 && isset($file[$l]); ++$l){ $this->data->code[$l + 1] = $file[$l]; } } diff --git a/src/data/bedrock/LegacyToStringBidirectionalIdMap.php b/src/data/bedrock/LegacyToStringBidirectionalIdMap.php index a7ce83b1f..1bf1d76d9 100644 --- a/src/data/bedrock/LegacyToStringBidirectionalIdMap.php +++ b/src/data/bedrock/LegacyToStringBidirectionalIdMap.php @@ -50,7 +50,7 @@ abstract class LegacyToStringBidirectionalIdMap{ throw new AssumptionFailedError("Invalid format of ID map"); } foreach($stringToLegacyId as $stringId => $legacyId){ - if(!is_string($stringId) or !is_int($legacyId)){ + if(!is_string($stringId) || !is_int($legacyId)){ throw new AssumptionFailedError("ID map should have string keys and int values"); } $this->legacyToString[$legacyId] = $stringId; diff --git a/src/lang/Language.php b/src/lang/Language.php index f86b1bba5..bce7c5c69 100644 --- a/src/lang/Language.php +++ b/src/lang/Language.php @@ -135,7 +135,7 @@ class Language{ */ public function translateString(string $str, array $params = [], ?string $onlyPrefix = null) : string{ $baseText = $this->get($str); - $baseText = $this->parseTranslation(($onlyPrefix === null or strpos($str, $onlyPrefix) === 0) ? $baseText : $str, $onlyPrefix); + $baseText = $this->parseTranslation(($onlyPrefix === null || strpos($str, $onlyPrefix) === 0) ? $baseText : $str, $onlyPrefix); foreach($params as $i => $p){ $replacement = $p instanceof Translatable ? $this->translate($p) : (string) $p; @@ -176,14 +176,14 @@ class Language{ if($replaceString !== null){ $ord = ord($c); if( - ($ord >= 0x30 and $ord <= 0x39) // 0-9 - or ($ord >= 0x41 and $ord <= 0x5a) // A-Z - or ($ord >= 0x61 and $ord <= 0x7a) or // a-z - $c === "." or $c === "-" + ($ord >= 0x30 && $ord <= 0x39) // 0-9 + || ($ord >= 0x41 && $ord <= 0x5a) // A-Z + || ($ord >= 0x61 && $ord <= 0x7a) || // a-z + $c === "." || $c === "-" ){ $replaceString .= $c; }else{ - if(($t = $this->internalGet(substr($replaceString, 1))) !== null and ($onlyPrefix === null or strpos($replaceString, $onlyPrefix) === 1)){ + if(($t = $this->internalGet(substr($replaceString, 1))) !== null && ($onlyPrefix === null || strpos($replaceString, $onlyPrefix) === 1)){ $newString .= $t; }else{ $newString .= $replaceString; @@ -204,7 +204,7 @@ class Language{ } if($replaceString !== null){ - if(($t = $this->internalGet(substr($replaceString, 1))) !== null and ($onlyPrefix === null or strpos($replaceString, $onlyPrefix) === 1)){ + if(($t = $this->internalGet(substr($replaceString, 1))) !== null && ($onlyPrefix === null || strpos($replaceString, $onlyPrefix) === 1)){ $newString .= $t; }else{ $newString .= $replaceString; diff --git a/src/resourcepacks/ZippedResourcePack.php b/src/resourcepacks/ZippedResourcePack.php index 3642f657e..347a197dd 100644 --- a/src/resourcepacks/ZippedResourcePack.php +++ b/src/resourcepacks/ZippedResourcePack.php @@ -76,7 +76,7 @@ class ZippedResourcePack implements ResourcePack{ for($i = 0; $i < $archive->numFiles; ++$i){ $name = Utils::assumeNotFalse($archive->getNameIndex($i), "This index should be valid"); if( - ($manifestPath === null or strlen($name) < strlen($manifestPath)) and + ($manifestPath === null || strlen($name) < strlen($manifestPath)) && preg_match('#.*/manifest.json$#', $name) === 1 ){ $manifestPath = $name; @@ -146,7 +146,7 @@ class ZippedResourcePack implements ResourcePack{ } public function getSha256(bool $cached = true) : string{ - if($this->sha256 === null or !$cached){ + if($this->sha256 === null || !$cached){ $this->sha256 = hash_file("sha256", $this->path, true); } return $this->sha256; diff --git a/src/thread/ThreadManager.php b/src/thread/ThreadManager.php index 56f36c8f0..2b1ca58cc 100644 --- a/src/thread/ThreadManager.php +++ b/src/thread/ThreadManager.php @@ -45,7 +45,7 @@ class ThreadManager extends \Volatile{ * @param Worker|Thread $thread */ public function add($thread) : void{ - if($thread instanceof Thread or $thread instanceof Worker){ + if($thread instanceof Thread || $thread instanceof Worker){ $this[spl_object_id($thread)] = $thread; } } @@ -54,7 +54,7 @@ class ThreadManager extends \Volatile{ * @param Worker|Thread $thread */ public function remove($thread) : void{ - if($thread instanceof Thread or $thread instanceof Worker){ + if($thread instanceof Thread || $thread instanceof Worker){ unset($this[spl_object_id($thread)]); } } diff --git a/src/wizard/SetupWizard.php b/src/wizard/SetupWizard.php index a0261501d..ae0ecb17d 100644 --- a/src/wizard/SetupWizard.php +++ b/src/wizard/SetupWizard.php @@ -145,7 +145,7 @@ LICENSE; private function askPort(Translatable $prompt, int $default) : int{ while(true){ $port = (int) $this->getInput($this->lang->translate($prompt), (string) $default); - if($port <= 0 or $port > 65535){ + if($port <= 0 || $port > 65535){ $this->error($this->lang->translate(KnownTranslationFactory::invalid_port())); continue; } @@ -264,7 +264,7 @@ LICENSE; private function getInput(string $message, string $default = "", string $options = "") : string{ $message = "[?] " . $message; - if($options !== "" or $default !== ""){ + if($options !== "" || $default !== ""){ $message .= " (" . ($options === "" ? $default : $options) . ")"; } $message .= ": "; From 32db27af78a7ea0774a75a5e2386083a3eae0bf3 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:23:33 +0000 Subject: [PATCH 670/710] php-cs-fixer: add logical_operators rule --- .php-cs-fixer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index 35102be7d..3fbdf33bb 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -43,6 +43,7 @@ return (new PhpCsFixer\Config) 'import_classes' => null, ], 'indentation_type' => true, + 'logical_operators' => true, 'native_function_invocation' => [ 'scope' => 'namespaced', 'include' => ['@all'], From 345ac75aacbc692043306646ef519ae219dea99f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 19:25:34 +0000 Subject: [PATCH 671/710] Remove PHPStan rules (no longer needed) this is enforced by php-cs-fixer now instead. --- phpstan.neon.dist | 3 - tests/phpstan/configs/and-or-logical.neon | 577 ------------------ .../rules/DisallowLogicalAndOperatorRule.php | 44 -- .../rules/DisallowLogicalOrOperatorRule.php | 44 -- 4 files changed, 668 deletions(-) delete mode 100644 tests/phpstan/configs/and-or-logical.neon delete mode 100644 tests/phpstan/rules/DisallowLogicalAndOperatorRule.php delete mode 100644 tests/phpstan/rules/DisallowLogicalOrOperatorRule.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 28e70f224..9ebc98502 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,6 +1,5 @@ includes: - tests/phpstan/configs/actual-problems.neon - - tests/phpstan/configs/and-or-logical.neon - tests/phpstan/configs/gc-hacks.neon - tests/phpstan/configs/impossible-generics.neon - tests/phpstan/configs/php-bugs.neon @@ -13,8 +12,6 @@ includes: rules: - pocketmine\phpstan\rules\DisallowEnumComparisonRule - - pocketmine\phpstan\rules\DisallowLogicalAndOperatorRule - - pocketmine\phpstan\rules\DisallowLogicalOrOperatorRule - pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule # - pocketmine\phpstan\rules\ThreadedSupportedTypesRule diff --git a/tests/phpstan/configs/and-or-logical.neon b/tests/phpstan/configs/and-or-logical.neon deleted file mode 100644 index 3c3e513bf..000000000 --- a/tests/phpstan/configs/and-or-logical.neon +++ /dev/null @@ -1,577 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 6 - path: ../../../src/MemoryManager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/MemoryManager.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/PocketMine.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 10 - path: ../../../src/Server.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 5 - path: ../../../src/Server.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/crafting/CraftingGrid.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/crafting/ShapedRecipe.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 5 - path: ../../../src/crafting/ShapedRecipe.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/crafting/ShapelessRecipe.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/crash/CrashDump.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/data/bedrock/LegacyToStringBidirectionalIdMap.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/entity/Attribute.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 4 - path: ../../../src/entity/Attribute.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/entity/AttributeMap.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 29 - path: ../../../src/entity/Entity.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 19 - path: ../../../src/entity/Entity.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/entity/EntityDataHelper.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/entity/EntityDataHelper.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/entity/ExperienceManager.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 6 - path: ../../../src/entity/Human.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 4 - path: ../../../src/entity/HungerManager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/entity/HungerManager.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 9 - path: ../../../src/entity/Living.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 6 - path: ../../../src/entity/Living.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/entity/Location.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/entity/Skin.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/entity/Squid.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/entity/Villager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/entity/effect/EffectInstance.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/entity/effect/EffectManager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/entity/effect/EffectManager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/entity/effect/PoisonEffect.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 5 - path: ../../../src/entity/object/ExperienceOrb.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/entity/object/ExperienceOrb.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/entity/object/FallingBlock.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/entity/object/FallingBlock.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 7 - path: ../../../src/entity/object/ItemEntity.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/entity/object/ItemEntity.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/entity/object/Painting.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/entity/object/Painting.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/entity/object/PrimedTNT.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/entity/projectile/Arrow.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/entity/projectile/Arrow.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 7 - path: ../../../src/entity/projectile/Projectile.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 3 - path: ../../../src/entity/projectile/SplashPotion.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/event/HandlerList.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/event/HandlerList.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/event/HandlerListManager.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/event/RegisteredListener.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 4 - path: ../../../src/inventory/BaseInventory.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/inventory/BaseInventory.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/inventory/PlayerInventory.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/inventory/transaction/CraftingTransaction.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/item/Armor.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/item/Bow.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/item/Bow.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/item/Bucket.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/item/ChorusFruit.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/item/ChorusFruit.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/item/Durable.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 7 - path: ../../../src/item/Item.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 6 - path: ../../../src/item/Item.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/item/ItemFactory.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/item/ItemFactory.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/item/ItemIdentifier.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/item/WrittenBook.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/item/enchantment/ProtectionEnchantment.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 5 - path: ../../../src/lang/Language.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 7 - path: ../../../src/lang/Language.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/network/Network.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/network/mcpe/InventoryManager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/network/mcpe/InventoryManager.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 6 - path: ../../../src/network/mcpe/NetworkSession.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 5 - path: ../../../src/network/mcpe/NetworkSession.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/network/mcpe/auth/ProcessLoginTask.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/network/mcpe/cache/ChunkCache.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/network/mcpe/compression/ZlibCompressor.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/network/mcpe/convert/ItemTranslator.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/network/mcpe/convert/TypeConverter.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 8 - path: ../../../src/network/mcpe/handler/InGamePacketHandler.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 4 - path: ../../../src/network/mcpe/handler/InGamePacketHandler.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/network/mcpe/handler/LoginPacketHandler.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/network/mcpe/handler/ResourcePacksPacketHandler.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/network/mcpe/raklib/RakLibInterface.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/network/mcpe/raklib/RakLibServer.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/network/query/QueryHandler.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/network/query/QueryInfo.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/permission/BanEntry.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/permission/PermissibleInternal.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/player/OfflinePlayer.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 51 - path: ../../../src/player/Player.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 15 - path: ../../../src/player/Player.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/player/SurvivalBlockBreakHandler.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/plugin/ApiVersion.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/plugin/PharPluginLoader.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/plugin/PluginBase.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/plugin/PluginBase.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/plugin/PluginDescription.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/plugin/PluginLoadabilityChecker.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/plugin/PluginLoadabilityChecker.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 4 - path: ../../../src/plugin/PluginManager.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/plugin/PluginManager.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/plugin/ScriptPluginLoader.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/resourcepacks/ZippedResourcePack.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/resourcepacks/ZippedResourcePack.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/scheduler/AsyncPool.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/scheduler/AsyncPool.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/scheduler/AsyncTask.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 3 - path: ../../../src/scheduler/AsyncTask.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 1 - path: ../../../src/scheduler/Task.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/scheduler/TaskScheduler.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/thread/ThreadManager.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 1 - path: ../../../src/updater/UpdateCheckTask.php - - - - message: "#^Use of the \"and\" operator is discouraged\\. Use && instead\\.$#" - count: 2 - path: ../../../src/updater/UpdateChecker.php - - - - message: "#^Use of the \"or\" operator is discouraged\\. Use \\|\\| instead\\.$#" - count: 2 - path: ../../../src/wizard/SetupWizard.php - diff --git a/tests/phpstan/rules/DisallowLogicalAndOperatorRule.php b/tests/phpstan/rules/DisallowLogicalAndOperatorRule.php deleted file mode 100644 index 49e6bbcc4..000000000 --- a/tests/phpstan/rules/DisallowLogicalAndOperatorRule.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ -final class DisallowLogicalAndOperatorRule implements Rule{ - - public function getNodeType() : string{ - return LogicalAnd::class; - } - - public function processNode(Node $node, Scope $scope) : array{ - return [RuleErrorBuilder::message('Use of the "and" operator is discouraged. Use && instead.')->build()]; - } -} diff --git a/tests/phpstan/rules/DisallowLogicalOrOperatorRule.php b/tests/phpstan/rules/DisallowLogicalOrOperatorRule.php deleted file mode 100644 index 7aa43c706..000000000 --- a/tests/phpstan/rules/DisallowLogicalOrOperatorRule.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ -final class DisallowLogicalOrOperatorRule implements Rule{ - - public function getNodeType() : string{ - return LogicalOr::class; - } - - public function processNode(Node $node, Scope $scope) : array{ - return [RuleErrorBuilder::message('Use of the "or" operator is discouraged. Use || instead.')->build()]; - } -} From fc53f3721ac45c372b546eeda4244c934199453b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 20 Jan 2022 21:49:14 +0000 Subject: [PATCH 672/710] Avoid direct mutations of Entity->location --- src/entity/Living.php | 11 +++++++---- src/entity/Squid.php | 6 ++++-- src/entity/projectile/Projectile.php | 6 ++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/entity/Living.php b/src/entity/Living.php index d5f169b11..889e55fa2 100644 --- a/src/entity/Living.php +++ b/src/entity/Living.php @@ -808,14 +808,17 @@ abstract class Living extends Entity{ public function lookAt(Vector3 $target) : void{ $horizontal = sqrt(($target->x - $this->location->x) ** 2 + ($target->z - $this->location->z) ** 2); $vertical = $target->y - ($this->location->y + $this->getEyeHeight()); - $this->location->pitch = -atan2($vertical, $horizontal) / M_PI * 180; //negative is up, positive is down + $pitch = -atan2($vertical, $horizontal) / M_PI * 180; //negative is up, positive is down $xDist = $target->x - $this->location->x; $zDist = $target->z - $this->location->z; - $this->location->yaw = atan2($zDist, $xDist) / M_PI * 180 - 90; - if($this->location->yaw < 0){ - $this->location->yaw += 360.0; + + $yaw = atan2($zDist, $xDist) / M_PI * 180 - 90; + if($yaw < 0){ + $yaw += 360.0; } + + $this->setRotation($yaw, $pitch); } protected function sendSpawnPacket(Player $player) : void{ diff --git a/src/entity/Squid.php b/src/entity/Squid.php index 063e87b16..39e2a3637 100644 --- a/src/entity/Squid.php +++ b/src/entity/Squid.php @@ -113,8 +113,10 @@ class Squid extends WaterAnimal{ } $f = sqrt(($this->motion->x ** 2) + ($this->motion->z ** 2)); - $this->location->yaw = (-atan2($this->motion->x, $this->motion->z) * 180 / M_PI); - $this->location->pitch = (-atan2($f, $this->motion->y) * 180 / M_PI); + $this->setRotation( + -atan2($this->motion->x, $this->motion->z) * 180 / M_PI, + -atan2($f, $this->motion->y) * 180 / M_PI + ); } return $hasUpdate; diff --git a/src/entity/projectile/Projectile.php b/src/entity/projectile/Projectile.php index 1fa1071f9..1f652bda4 100644 --- a/src/entity/projectile/Projectile.php +++ b/src/entity/projectile/Projectile.php @@ -253,8 +253,10 @@ abstract class Projectile extends Entity{ //recompute angles... $f = sqrt(($this->motion->x ** 2) + ($this->motion->z ** 2)); - $this->location->yaw = (atan2($this->motion->x, $this->motion->z) * 180 / M_PI); - $this->location->pitch = (atan2($this->motion->y, $f) * 180 / M_PI); + $this->setRotation( + atan2($this->motion->x, $this->motion->z) * 180 / M_PI, + atan2($this->motion->y, $f) * 180 / M_PI + ); } $this->getWorld()->onEntityMoved($this); From 73d8c87b7677625f619d547a7e9873cae5719938 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jan 2022 14:53:03 +0000 Subject: [PATCH 673/710] Bump phpunit/phpunit from 9.5.11 to 9.5.12 (#4748) Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.11 to 9.5.12. - [Release notes](https://github.com/sebastianbergmann/phpunit/releases) - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.11...9.5.12) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/composer.lock b/composer.lock index 771a72cf9..7fa306c76 100644 --- a/composer.lock +++ b/composer.lock @@ -1466,9 +1466,6 @@ "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" - }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", @@ -2391,16 +2388,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.11", + "version": "9.5.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "2406855036db1102126125537adb1406f7242fdd" + "reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2406855036db1102126125537adb1406f7242fdd", - "reference": "2406855036db1102126125537adb1406f7242fdd", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/93d4bf4c37aec6384bb9e5d390d9049a463a7256", + "reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256", "shasum": "" }, "require": { @@ -2478,7 +2475,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.11" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.12" }, "funding": [ { @@ -2490,7 +2487,7 @@ "type": "github" } ], - "time": "2021-12-25T07:07:57+00:00" + "time": "2022-01-21T05:54:47+00:00" }, { "name": "sebastian/cli-parser", From 56fe71d939c38fe14e18a31a673a9331bcc0e4ca Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 17:34:13 +0000 Subject: [PATCH 674/710] InGamePacketHandler: fixed crash in form handling when invalid JSON is given --- src/network/mcpe/handler/InGamePacketHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 947e29042..045c8a5ed 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -880,7 +880,7 @@ class InGamePacketHandler extends PacketHandler{ $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)"); + throw new PacketHandlingException("Failed to fix JSON: " . json_last_error_msg() . "(original: $json, modified: $fixed)"); } return $ret; From 387c13beffce3a15632c2931dc1ca2e5e51d3ce9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 18:32:58 +0000 Subject: [PATCH 675/710] InGamePacketHandler: fixed invalid JSON being treated as form close --- src/network/mcpe/handler/InGamePacketHandler.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 045c8a5ed..29822374a 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -110,7 +110,6 @@ use function is_infinite; use function is_nan; use function json_decode; use function json_encode; -use function json_last_error_msg; use function max; use function mb_strlen; use function microtime; @@ -120,6 +119,7 @@ use function strlen; use function strpos; use function substr; use function trim; +use const JSON_THROW_ON_ERROR; /** * This handler handles packets related to general gameplay. @@ -879,14 +879,18 @@ class InGamePacketHandler extends PacketHandler{ } $fixed = "[" . implode(",", $newParts) . "]"; - if(($ret = json_decode($fixed, $assoc)) === null){ - throw new PacketHandlingException("Failed to fix JSON: " . json_last_error_msg() . "(original: $json, modified: $fixed)"); + try{ + return json_decode($fixed, $assoc, flags: JSON_THROW_ON_ERROR); + }catch(\JsonException $e){ + throw PacketHandlingException::wrap($e, "Failed to fix JSON (original: $json, modified: $fixed)"); } - - return $ret; } - return json_decode($json, $assoc); + try{ + return json_decode($json, $assoc, flags: JSON_THROW_ON_ERROR); + }catch(\JsonException $e){ + throw PacketHandlingException::wrap($e); + } } public function handleServerSettingsRequest(ServerSettingsRequestPacket $packet) : bool{ From ed312863a75b80439355564095bf958eb949ef5e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 18:43:53 +0000 Subject: [PATCH 676/710] ignore phpstan bug --- tests/phpstan/configs/phpstan-bugs.neon | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 6ca48d1b5..6c960f845 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -20,6 +20,11 @@ parameters: count: 1 path: ../../../src/entity/projectile/Projectile.php + - + message: "#^Dead catch \\- JsonException is never thrown in the try block\\.$#" + count: 2 + path: ../../../src/network/mcpe/handler/InGamePacketHandler.php + - message: "#^Dead catch \\- RuntimeException is never thrown in the try block\\.$#" count: 1 From c10eda5eae6c0421f678b8e687b3879d1c8c1635 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 18:47:34 +0000 Subject: [PATCH 677/710] InGamePacketHandler: limit depth of form responses to 2 form responses should only contain string|int|float|bool|null. Arrays or objects appearing in here are likely malicious. --- src/network/mcpe/handler/InGamePacketHandler.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index 29822374a..5ce75f1da 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -125,6 +125,7 @@ use const JSON_THROW_ON_ERROR; * This handler handles packets related to general gameplay. */ class InGamePacketHandler extends PacketHandler{ + private const MAX_FORM_RESPONSE_DEPTH = 2; //modal/simple will be 1, custom forms 2 - they will never contain anything other than string|int|float|bool|null /** @var Player */ private $player; @@ -880,14 +881,14 @@ class InGamePacketHandler extends PacketHandler{ $fixed = "[" . implode(",", $newParts) . "]"; try{ - return json_decode($fixed, $assoc, flags: JSON_THROW_ON_ERROR); + return json_decode($fixed, $assoc, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR); }catch(\JsonException $e){ throw PacketHandlingException::wrap($e, "Failed to fix JSON (original: $json, modified: $fixed)"); } } try{ - return json_decode($json, $assoc, flags: JSON_THROW_ON_ERROR); + return json_decode($json, $assoc, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR); }catch(\JsonException $e){ throw PacketHandlingException::wrap($e); } From 94c4f58667eda7ff785dbc8add442eddcadb84d5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 19:13:36 +0000 Subject: [PATCH 678/710] Fixed bogus test --- tests/phpunit/network/mcpe/handler/StupidJsonDecodeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/network/mcpe/handler/StupidJsonDecodeTest.php b/tests/phpunit/network/mcpe/handler/StupidJsonDecodeTest.php index 3e49e8265..e5756aad6 100644 --- a/tests/phpunit/network/mcpe/handler/StupidJsonDecodeTest.php +++ b/tests/phpunit/network/mcpe/handler/StupidJsonDecodeTest.php @@ -45,7 +45,7 @@ class StupidJsonDecodeTest extends TestCase{ ["[\n \"a\",\"b,c,d,e\\\" \",,0,1,2, false, 0.001]", ['a', 'b,c,d,e" ', '', 0, 1, 2, false, 0.001]], ["0", 0], ["false", false], - ["NULL", null], + ["null", null], ['["\",,\"word","a\",,\"word2",]', ['",,"word', 'a",,"word2', '']], ['["\",,\"word","a\",,\"word2",""]', ['",,"word', 'a",,"word2', '']], ['["Hello,, PocketMine"]', ['Hello,, PocketMine']], From 8c5cc67e074d6fa9ca9772416a82d842bb93f800 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 19:38:59 +0000 Subject: [PATCH 679/710] Updated baseline --- tests/phpstan/configs/phpstan-bugs.neon | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index 6c960f845..6ca48d1b5 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -20,11 +20,6 @@ parameters: count: 1 path: ../../../src/entity/projectile/Projectile.php - - - message: "#^Dead catch \\- JsonException is never thrown in the try block\\.$#" - count: 2 - path: ../../../src/network/mcpe/handler/InGamePacketHandler.php - - message: "#^Dead catch \\- RuntimeException is never thrown in the try block\\.$#" count: 1 From 58ba4f680f50634de9be7f0475b8072722b1b3d0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 19:39:30 +0000 Subject: [PATCH 680/710] Release 4.0.7 --- changelogs/4.0.md | 13 +++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 0cd3c2a25..38c7cbfec 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1607,3 +1607,16 @@ Released 13th January 2022. ## Fixes - Fixed server crash on invalid facing values provided by the client when placing or breaking blocks. - Fixed documentation link to AsyncTask in Worker. + +# 4.0.7 +Released 21st January 2022. + +## General +- Max nesting of form responses is now limited to 2. +- Updated outdated documentation of `PlayerInteractEvent`. + +## Fixes +- Fixed server crash on invalid JSON provided by the client in `ModalFormResponsePacket`. +- Fixed ender pearls teleporting players when thrown by a player directly against a wall when cancelling `ProjectileLaunchEvent`. +- Fixed collision box of brewing stand. +- Fixed break times and tool types of bamboo, nether wart blocks, infested stone and leaves. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 44e0baf24..0d9ac7794 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.7"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; private function __construct(){ From f9c8c0e34df0c311d8e79992b79de54989b302f1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 19:39:31 +0000 Subject: [PATCH 681/710] 4.0.8 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 0d9ac7794..5071c9a2c 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.7"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.8"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From b33a75a6d121bdbdd23765795a375f1ec1a5f7c9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 20:45:36 +0000 Subject: [PATCH 682/710] Updated transient dependency junk --- composer.lock | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/composer.lock b/composer.lock index f3dbc58ba..f98e641d5 100644 --- a/composer.lock +++ b/composer.lock @@ -575,9 +575,6 @@ "require": { "php": "^7.1 || ^8.0" }, - "replace": { - "myclabs/deep-copy": "self.version" - }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", @@ -1500,16 +1497,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.11", + "version": "9.5.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "2406855036db1102126125537adb1406f7242fdd" + "reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2406855036db1102126125537adb1406f7242fdd", - "reference": "2406855036db1102126125537adb1406f7242fdd", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/93d4bf4c37aec6384bb9e5d390d9049a463a7256", + "reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256", "shasum": "" }, "require": { @@ -1587,7 +1584,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.11" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.12" }, "funding": [ { @@ -1599,7 +1596,7 @@ "type": "github" } ], - "time": "2021-12-25T07:07:57+00:00" + "time": "2022-01-21T05:54:47+00:00" }, { "name": "sebastian/cli-parser", @@ -2788,5 +2785,5 @@ "platform-overrides": { "php": "8.0.0" }, - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.2.0" } From d28be4eaf24a890f7ef110a51181a3d806a6acca Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 23:05:21 +0000 Subject: [PATCH 683/710] Quick and dirty backport of encryption, preserving BC --- composer.json | 2 + composer.lock | 78 ++++++- src/pocketmine/Player.php | 57 ++++- src/pocketmine/Server.php | 3 + src/pocketmine/network/mcpe/JwtException.php | 28 +++ src/pocketmine/network/mcpe/JwtUtils.php | 211 ++++++++++++++++++ .../mcpe/PlayerNetworkSessionAdapter.php | 2 +- .../network/mcpe/RakLibInterface.php | 22 +- .../mcpe/encryption/DecryptionException.php | 28 +++ .../mcpe/encryption/EncryptionContext.php | 119 ++++++++++ .../mcpe/encryption/EncryptionUtils.php | 68 ++++++ .../mcpe/encryption/PrepareEncryptionTask.php | 96 ++++++++ src/pocketmine/resources/pocketmine.yml | 3 + 13 files changed, 711 insertions(+), 6 deletions(-) create mode 100644 src/pocketmine/network/mcpe/JwtException.php create mode 100644 src/pocketmine/network/mcpe/JwtUtils.php create mode 100644 src/pocketmine/network/mcpe/encryption/DecryptionException.php create mode 100644 src/pocketmine/network/mcpe/encryption/EncryptionContext.php create mode 100644 src/pocketmine/network/mcpe/encryption/EncryptionUtils.php create mode 100644 src/pocketmine/network/mcpe/encryption/PrepareEncryptionTask.php diff --git a/composer.json b/composer.json index 4c8b68e82..5f5bebb3f 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "php": "^8.0", "php-64bit": "*", "ext-chunkutils2": "^0.3.1", + "ext-crypto": "^0.3.1", "ext-ctype": "*", "ext-curl": "*", "ext-date": "*", @@ -27,6 +28,7 @@ "ext-zlib": ">=1.2.11", "composer-runtime-api": "^2.0", "adhocore/json-comment": "^1.1", + "fgrosse/phpasn1": "^2.3", "pocketmine/binaryutils": "^0.1.9", "pocketmine/callback-validator": "^1.0.2", "pocketmine/classloader": "^0.1.0", diff --git a/composer.lock b/composer.lock index f98e641d5..5711dc22f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9fe058549206174b6c62b2a41685083c", + "content-hash": "4ee772232d0936f6f9eda5d54ec2462d", "packages": [ { "name": "adhocore/json-comment", @@ -61,6 +61,81 @@ ], "time": "2021-04-09T03:06:06+00:00" }, + { + "name": "fgrosse/phpasn1", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/fgrosse/PHPASN1.git", + "reference": "eef488991d53e58e60c9554b09b1201ca5ba9296" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/eef488991d53e58e60c9554b09b1201ca5ba9296", + "reference": "eef488991d53e58e60c9554b09b1201ca5ba9296", + "shasum": "" + }, + "require": { + "php": "~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "~2.0", + "phpunit/phpunit": "^6.3 || ^7.0 || ^8.0" + }, + "suggest": { + "ext-bcmath": "BCmath is the fallback extension for big integer calculations", + "ext-curl": "For loading OID information from the web if they have not bee defined statically", + "ext-gmp": "GMP is the preferred extension for big integer calculations", + "phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "FG\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Friedrich Große", + "email": "friedrich.grosse@gmail.com", + "homepage": "https://github.com/FGrosse", + "role": "Author" + }, + { + "name": "All contributors", + "homepage": "https://github.com/FGrosse/PHPASN1/contributors" + } + ], + "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", + "homepage": "https://github.com/FGrosse/PHPASN1", + "keywords": [ + "DER", + "asn.1", + "asn1", + "ber", + "binary", + "decoding", + "encoding", + "x.509", + "x.690", + "x509", + "x690" + ], + "support": { + "issues": "https://github.com/fgrosse/PHPASN1/issues", + "source": "https://github.com/fgrosse/PHPASN1/tree/v2.4.0" + }, + "time": "2021-12-11T12:41:06+00:00" + }, { "name": "pocketmine/binaryutils", "version": "0.1.13", @@ -2762,6 +2837,7 @@ "php": "^8.0", "php-64bit": "*", "ext-chunkutils2": "^0.3.1", + "ext-crypto": "^0.3.1", "ext-ctype": "*", "ext-curl": "*", "ext-date": "*", diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 1bf11b1d6..ac8d4ba35 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -102,6 +102,8 @@ use pocketmine\nbt\tag\DoubleTag; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\StringTag; use pocketmine\network\mcpe\convert\ItemTypeDictionary; +use pocketmine\network\mcpe\encryption\EncryptionContext; +use pocketmine\network\mcpe\encryption\PrepareEncryptionTask; use pocketmine\network\mcpe\PlayerNetworkSessionAdapter; use pocketmine\network\mcpe\protocol\ActorEventPacket; use pocketmine\network\mcpe\protocol\AdventureSettingsPacket; @@ -139,6 +141,7 @@ use pocketmine\network\mcpe\protocol\ResourcePackDataInfoPacket; use pocketmine\network\mcpe\protocol\ResourcePacksInfoPacket; use pocketmine\network\mcpe\protocol\ResourcePackStackPacket; use pocketmine\network\mcpe\protocol\RespawnPacket; +use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket; use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket; use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket; use pocketmine\network\mcpe\protocol\SetTitlePacket; @@ -184,6 +187,7 @@ use pocketmine\tile\ItemFrame; use pocketmine\tile\Spawnable; use pocketmine\tile\Tile; use pocketmine\timings\Timings; +use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\TextFormat; use pocketmine\utils\UUID; use function abs; @@ -285,6 +289,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** @var DataPacket[] */ private $batchedPackets = []; + private ?EncryptionContext $cipher = null; + /** * @var int * Last measurement of player's latency in milliseconds. @@ -300,6 +306,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** @var bool */ private $seenLoginPacket = false; /** @var bool */ + private $awaitingEncryptionHandshake = false; + /** @var bool */ private $resourcePacksDone = false; /** @var bool */ @@ -2073,9 +2081,49 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->xuid = $xuid; } - //TODO: encryption + $identityPublicKey = base64_decode($packet->identityPublicKey, true); + if($identityPublicKey === false){ + //if this is invalid it should have borked VerifyLoginTask + throw new AssumptionFailedError("We should never have reached here if the key is invalid"); + } + + if(EncryptionContext::$ENABLED){ + $this->server->getAsyncPool()->submitTask(new PrepareEncryptionTask( + $identityPublicKey, + function(string $encryptionKey, string $handshakeJwt) : void{ + if(!$this->isConnected()){ + return; + } + + $pk = new ServerToClientHandshakePacket(); + $pk->jwt = $handshakeJwt; + $this->sendDataPacket($pk, false, true); //make sure this gets sent before encryption is enabled + + $this->awaitingEncryptionHandshake = true; + + $this->cipher = EncryptionContext::fakeGCM($encryptionKey); + + $this->server->getLogger()->debug("Enabled encryption for " . $this->username); + } + )); + }else{ + $this->processLogin(); + } + } + + /** + * @internal + */ + public function onEncryptionHandshake() : bool{ + if(!$this->awaitingEncryptionHandshake){ + return false; + } + $this->awaitingEncryptionHandshake = false; + + $this->server->getLogger()->debug("Encryption handshake completed for " . $this->username); $this->processLogin(); + return true; } /** @@ -3434,6 +3482,13 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } } + /** + * @internal + */ + public function getCipher() : ?EncryptionContext{ + return $this->cipher; + } + /** * @return bool|int */ diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 48e598a8a..6cb0b3566 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -71,6 +71,7 @@ use pocketmine\nbt\tag\ShortTag; use pocketmine\nbt\tag\StringTag; use pocketmine\network\AdvancedSourceInterface; use pocketmine\network\CompressBatchedTask; +use pocketmine\network\mcpe\encryption\EncryptionContext; use pocketmine\network\mcpe\protocol\BatchPacket; use pocketmine\network\mcpe\protocol\DataPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; @@ -1406,6 +1407,8 @@ class Server{ } $this->networkCompressionAsync = (bool) $this->getProperty("network.async-compression", true); + EncryptionContext::$ENABLED = (bool) $this->getProperty("network.enable-encryption", true); + $this->doTitleTick = ((bool) $this->getProperty("console.title-tick", true)) && Terminal::hasFormattingCodes(); $consoleSender = new ConsoleCommandSender(); diff --git a/src/pocketmine/network/mcpe/JwtException.php b/src/pocketmine/network/mcpe/JwtException.php new file mode 100644 index 000000000..14a3c21a2 --- /dev/null +++ b/src/pocketmine/network/mcpe/JwtException.php @@ -0,0 +1,28 @@ + gmp_strval(gmp_import($str, 1, GMP_BIG_ENDIAN | GMP_MSW_FIRST), 10); + + $sequence = new Sequence( + new Integer($convert($rString)), + new Integer($convert($sString)) + ); + + $v = openssl_verify( + $header . '.' . $body, + $sequence->getBinary(), + $signingKey, + OPENSSL_ALGO_SHA384 + ); + switch($v){ + case 0: return false; + case 1: return true; + case -1: throw new JwtException("Error verifying JWT signature: " . openssl_error_string()); + default: throw new AssumptionFailedError("openssl_verify() should only return -1, 0 or 1"); + } + } + + /** + * @phpstan-param array $header + * @phpstan-param array $claims + */ + public static function create(array $header, array $claims, \OpenSSLAsymmetricKey $signingKey) : string{ + $jwtBody = JwtUtils::b64UrlEncode(json_encode($header, JSON_THROW_ON_ERROR)) . "." . JwtUtils::b64UrlEncode(json_encode($claims, JSON_THROW_ON_ERROR)); + + openssl_sign( + $jwtBody, + $rawDerSig, + $signingKey, + OPENSSL_ALGO_SHA384 + ); + + try{ + $asnObject = Sequence::fromBinary($rawDerSig); + }catch(ParserException $e){ + throw new AssumptionFailedError("Failed to parse OpenSSL signature: " . $e->getMessage(), 0, $e); + } + if(count($asnObject) !== 2){ + throw new AssumptionFailedError("OpenSSL produced invalid signature, expected exactly 2 parts"); + } + [$r, $s] = [$asnObject[0], $asnObject[1]]; + if(!($r instanceof Integer) || !($s instanceof Integer)){ + throw new AssumptionFailedError("OpenSSL produced invalid signature, expected 2 INTEGER parts"); + } + $rString = $r->getContent(); + $sString = $s->getContent(); + + $toBinary = fn($str) => str_pad( + gmp_export(gmp_init($str, 10), 1, GMP_BIG_ENDIAN | GMP_MSW_FIRST), + 48, + "\x00", + STR_PAD_LEFT + ); + $jwtSig = JwtUtils::b64UrlEncode($toBinary($rString) . $toBinary($sString)); + + return "$jwtBody.$jwtSig"; + } + + public static function b64UrlEncode(string $str) : string{ + return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); + } + + public static function b64UrlDecode(string $str) : string{ + if(($len = strlen($str) % 4) !== 0){ + $str .= str_repeat('=', 4 - $len); + } + $decoded = base64_decode(strtr($str, '-_', '+/'), true); + if($decoded === false){ + throw new JwtException("Malformed base64url encoded payload could not be decoded"); + } + return $decoded; + } + + public static function emitDerPublicKey(\OpenSSLAsymmetricKey $opensslKey) : string{ + $details = openssl_pkey_get_details($opensslKey); + if($details === false){ + throw new AssumptionFailedError("Failed to get details from OpenSSL key resource"); + } + + /** @var string $pemKey */ + $pemKey = $details['key']; + if(preg_match("@^-----BEGIN[A-Z\d ]+PUBLIC KEY-----\n([A-Za-z\d+/\n]+)\n-----END[A-Z\d ]+PUBLIC KEY-----\n$@", $pemKey, $matches) === 1){ + $derKey = base64_decode(str_replace("\n", "", $matches[1]), true); + if($derKey !== false){ + return $derKey; + } + } + throw new AssumptionFailedError("OpenSSL resource contains invalid public key"); + } + + public static function parseDerPublicKey(string $derKey) : \OpenSSLAsymmetricKey{ + $signingKeyOpenSSL = openssl_pkey_get_public(sprintf("-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n", base64_encode($derKey))); + if($signingKeyOpenSSL === false){ + throw new JwtException("OpenSSL failed to parse key: " . openssl_error_string()); + } + return $signingKeyOpenSSL; + } +} diff --git a/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php b/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php index b300d3142..a56fb2ba2 100644 --- a/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php +++ b/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php @@ -118,7 +118,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{ } public function handleClientToServerHandshake(ClientToServerHandshakePacket $packet) : bool{ - return false; //TODO + return $this->player->onEncryptionHandshake(); } public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{ diff --git a/src/pocketmine/network/mcpe/RakLibInterface.php b/src/pocketmine/network/mcpe/RakLibInterface.php index 4097340b4..16bfcea37 100644 --- a/src/pocketmine/network/mcpe/RakLibInterface.php +++ b/src/pocketmine/network/mcpe/RakLibInterface.php @@ -45,6 +45,7 @@ use function get_class; use function implode; use function rtrim; use function spl_object_hash; +use function substr; use function unserialize; use const PTHREADS_INHERIT_CONSTANTS; @@ -55,6 +56,8 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{ */ private const MCPE_RAKNET_PROTOCOL_VERSION = 10; + private const MCPE_RAKNET_PACKET_ID = "\xfe"; + /** @var Server */ private $server; @@ -163,9 +166,18 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{ //get this now for blocking in case the player was closed before the exception was raised $player = $this->players[$identifier]; $address = $player->getAddress(); + try{ if($packet->buffer !== ""){ - $pk = new BatchPacket($packet->buffer); + if($packet->buffer[0] !== self::MCPE_RAKNET_PACKET_ID){ + throw new \UnexpectedValueException("Unexpected non-FE packet"); + } + + $cipher = $player->getCipher(); + $buffer = substr($packet->buffer, 1); + $buffer = $cipher !== null ? $cipher->decrypt($buffer) : $buffer; + + $pk = new BatchPacket(self::MCPE_RAKNET_PACKET_ID . $buffer); $player->handleDataPacket($pk); } }catch(\Throwable $e){ @@ -245,17 +257,21 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{ } if($packet instanceof BatchPacket){ + $cipher = $player->getCipher(); + $rawBuffer = substr($packet->buffer, 1); + $buffer = self::MCPE_RAKNET_PACKET_ID . ($cipher !== null ? $cipher->encrypt($rawBuffer) : $rawBuffer); + if($needACK){ $pk = new EncapsulatedPacket(); $pk->identifierACK = $this->identifiersACK[$identifier]++; - $pk->buffer = $packet->buffer; + $pk->buffer = $buffer; $pk->reliability = PacketReliability::RELIABLE_ORDERED; $pk->orderChannel = 0; }else{ if(!isset($packet->__encapsulatedPacket)){ $packet->__encapsulatedPacket = new CachedEncapsulatedPacket; $packet->__encapsulatedPacket->identifierACK = null; - $packet->__encapsulatedPacket->buffer = $packet->buffer; + $packet->__encapsulatedPacket->buffer = $buffer; $packet->__encapsulatedPacket->reliability = PacketReliability::RELIABLE_ORDERED; $packet->__encapsulatedPacket->orderChannel = 0; } diff --git a/src/pocketmine/network/mcpe/encryption/DecryptionException.php b/src/pocketmine/network/mcpe/encryption/DecryptionException.php new file mode 100644 index 000000000..1a5e7e690 --- /dev/null +++ b/src/pocketmine/network/mcpe/encryption/DecryptionException.php @@ -0,0 +1,28 @@ +key = $encryptionKey; + + $this->decryptCipher = new Cipher($algorithm); + $this->decryptCipher->decryptInit($this->key, $iv); + + $this->encryptCipher = new Cipher($algorithm); + $this->encryptCipher->encryptInit($this->key, $iv); + } + + /** + * Returns an EncryptionContext suitable for decrypting Minecraft packets from 1.16.200 and up. + * + * MCPE uses GCM, but without the auth tag, which defeats the whole purpose of using GCM. + * GCM is just a wrapper around CTR which adds the auth tag, so CTR can replace GCM for this case. + * However, since GCM passes only the first 12 bytes of the IV followed by 0002, we must do the same for + * compatibility with MCPE. + * In PM, we could skip this and just use GCM directly (since we use OpenSSL), but this way is more portable, and + * better for developers who come digging in the PM code looking for answers. + */ + public static function fakeGCM(string $encryptionKey) : self{ + return new EncryptionContext( + $encryptionKey, + "AES-256-CTR", + substr($encryptionKey, 0, 12) . "\x00\x00\x00\x02" + ); + } + + public static function cfb8(string $encryptionKey) : self{ + return new EncryptionContext( + $encryptionKey, + "AES-256-CFB8", + substr($encryptionKey, 0, 16) + ); + } + + /** + * @throws DecryptionException + */ + public function decrypt(string $encrypted) : string{ + if(strlen($encrypted) < 9){ + throw new DecryptionException("Payload is too short"); + } + $decrypted = $this->decryptCipher->decryptUpdate($encrypted); + $payload = substr($decrypted, 0, -8); + + $packetCounter = $this->decryptCounter++; + + if(($expected = $this->calculateChecksum($packetCounter, $payload)) !== ($actual = substr($decrypted, -8))){ + throw new DecryptionException("Encrypted packet $packetCounter has invalid checksum (expected " . bin2hex($expected) . ", got " . bin2hex($actual) . ")"); + } + + return $payload; + } + + public function encrypt(string $payload) : string{ + return $this->encryptCipher->encryptUpdate($payload . $this->calculateChecksum($this->encryptCounter++, $payload)); + } + + private function calculateChecksum(int $counter, string $payload) : string{ + $hash = openssl_digest(Binary::writeLLong($counter) . $payload . $this->key, self::CHECKSUM_ALGO, true); + if($hash === false){ + throw new \RuntimeException("openssl_digest() error: " . openssl_error_string()); + } + return substr($hash, 0, 8); + } +} diff --git a/src/pocketmine/network/mcpe/encryption/EncryptionUtils.php b/src/pocketmine/network/mcpe/encryption/EncryptionUtils.php new file mode 100644 index 000000000..0ad2ebfee --- /dev/null +++ b/src/pocketmine/network/mcpe/encryption/EncryptionUtils.php @@ -0,0 +1,68 @@ + base64_encode($derPublicKey), + "alg" => "ES384" + ], + [ + "salt" => base64_encode($salt) + ], + $serverPriv + ); + } +} diff --git a/src/pocketmine/network/mcpe/encryption/PrepareEncryptionTask.php b/src/pocketmine/network/mcpe/encryption/PrepareEncryptionTask.php new file mode 100644 index 000000000..1a4b6dd2e --- /dev/null +++ b/src/pocketmine/network/mcpe/encryption/PrepareEncryptionTask.php @@ -0,0 +1,96 @@ + ["curve_name" => "secp384r1"]]); + if($serverPrivateKey === false){ + throw new \RuntimeException("openssl_pkey_new() failed: " . openssl_error_string()); + } + self::$SERVER_PRIVATE_KEY = $serverPrivateKey; + } + + $this->serverPrivateKey = igbinary_serialize(openssl_pkey_get_details(self::$SERVER_PRIVATE_KEY)); + $this->clientPub = $clientPub; + $this->storeLocal($onCompletion); + } + + public function onRun() : void{ + /** @var mixed[] $serverPrivDetails */ + $serverPrivDetails = igbinary_unserialize($this->serverPrivateKey); + $serverPriv = openssl_pkey_new($serverPrivDetails); + if($serverPriv === false) throw new AssumptionFailedError("Failed to restore server signing key from details"); + $clientPub = JwtUtils::parseDerPublicKey($this->clientPub); + $sharedSecret = EncryptionUtils::generateSharedSecret($serverPriv, $clientPub); + + $salt = random_bytes(16); + $this->aesKey = EncryptionUtils::generateKey($sharedSecret, $salt); + $this->handshakeJwt = EncryptionUtils::generateServerHandshakeJwt($serverPriv, $salt); + + @openssl_free_key($serverPriv); + @openssl_free_key($clientPub); + } + + public function onCompletion(Server $server) : void{ + /** + * @var \Closure $callback + * @phpstan-var \Closure(string $encryptionKey, string $handshakeJwt) : void $callback + */ + $callback = $this->fetchLocal(); + if($this->aesKey === null || $this->handshakeJwt === null){ + throw new AssumptionFailedError("Something strange happened here ..."); + } + $callback($this->aesKey, $this->handshakeJwt); + } +} diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index f12769bdf..68a00bd73 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -92,6 +92,9 @@ network: #Maximum size in bytes of packets sent over the network (default 1492 bytes). Packets larger than this will be #fragmented or split into smaller parts. Clients can request MTU sizes up to but not more than this number. max-mtu-size: 1492 + #Enable encryption of Minecraft network traffic. This has an impact on performance, but prevents hackers from stealing sessions and pretending to be other players. + #DO NOT DISABLE THIS unless you understand the risks involved. + enable-encryption: true debug: #If > 1, it will show debug messages in the console From 1eae133118ac9e36f031a71b9d59593deceec13a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 23:39:37 +0000 Subject: [PATCH 684/710] fixed PHPStan build --- phpstan.neon.dist | 1 + tests/phpstan/configs/actual-problems.neon | 10 ++++++++++ tests/phpstan/stubs/phpasn1.stub | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 tests/phpstan/stubs/phpasn1.stub diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 8ad20ab63..dcb2292c3 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -39,6 +39,7 @@ parameters: stubFiles: - tests/phpstan/stubs/chunkutils.stub - tests/phpstan/stubs/leveldb.stub + - tests/phpstan/stubs/phpasn1.stub - tests/phpstan/stubs/pthreads.stub reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings staticReflectionClassNamePatterns: diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 7ee1e46ed..3c3c68ec2 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -3410,6 +3410,16 @@ parameters: count: 1 path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php + - + message: "#^Method pocketmine\\\\network\\\\mcpe\\\\encryption\\\\EncryptionUtils\\:\\:generateKey\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/encryption/EncryptionUtils.php + + - + message: "#^Property pocketmine\\\\network\\\\mcpe\\\\encryption\\\\PrepareEncryptionTask\\:\\:\\$serverPrivateKey \\(string\\) does not accept string\\|null\\.$#" + count: 1 + path: ../../../src/pocketmine/network/mcpe/encryption/PrepareEncryptionTask.php + - message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddActorPacket\\:\\:\\$metadata \\(array\\\\) does not accept array\\\\.$#" count: 1 diff --git a/tests/phpstan/stubs/phpasn1.stub b/tests/phpstan/stubs/phpasn1.stub new file mode 100644 index 000000000..b459289ef --- /dev/null +++ b/tests/phpstan/stubs/phpasn1.stub @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace FG\ASN1\Universal; + +class Integer +{ + /** + * @param int|string $value + */ + public function __construct($value){} + + /** @return int|string */ + public function getContent(){} +} From 0697c7d3164b079be93b653a77caab963a56c281 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 21 Jan 2022 23:45:49 +0000 Subject: [PATCH 685/710] Clean up according to newer php-cs-fixer --- src/pocketmine/event/block/BlockBreakEvent.php | 2 -- src/pocketmine/inventory/Inventory.php | 4 ---- src/pocketmine/level/Level.php | 4 ---- src/pocketmine/network/mcpe/NetworkBinaryStream.php | 2 -- src/pocketmine/plugin/PluginManager.php | 2 -- src/pocketmine/utils/Color.php | 2 -- src/pocketmine/utils/UUID.php | 2 -- 7 files changed, 18 deletions(-) diff --git a/src/pocketmine/event/block/BlockBreakEvent.php b/src/pocketmine/event/block/BlockBreakEvent.php index df821ee85..5c9bfefa1 100644 --- a/src/pocketmine/event/block/BlockBreakEvent.php +++ b/src/pocketmine/event/block/BlockBreakEvent.php @@ -100,8 +100,6 @@ class BlockBreakEvent extends BlockEvent implements Cancellable{ /** * Variadic hack for easy array member type enforcement. - * - * @param Item ...$drops */ public function setDropsVariadic(Item ...$drops) : void{ $this->blockDrops = $drops; diff --git a/src/pocketmine/inventory/Inventory.php b/src/pocketmine/inventory/Inventory.php index f950b73af..e7e69815e 100644 --- a/src/pocketmine/inventory/Inventory.php +++ b/src/pocketmine/inventory/Inventory.php @@ -58,8 +58,6 @@ interface Inventory{ * * Returns the Items that did not fit. * - * @param Item ...$slots - * * @return Item[] */ public function addItem(Item ...$slots) : array; @@ -73,8 +71,6 @@ interface Inventory{ * Removes the given Item from the inventory. * It will return the Items that couldn't be removed. * - * @param Item ...$slots - * * @return Item[] */ public function removeItem(Item ...$slots) : array; diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 2c503ea0d..a400221d6 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -761,8 +761,6 @@ class Level implements ChunkManager, Metadatable{ /** * @internal * - * @param Player ...$targets If empty, will send to all players in the level. - * * @return void */ public function sendTime(Player ...$targets){ @@ -2929,8 +2927,6 @@ class Level implements ChunkManager, Metadatable{ } /** - * @param Player ...$targets - * * @return void */ public function sendDifficulty(Player ...$targets){ diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php index d07644f5f..3dfcfea6a 100644 --- a/src/pocketmine/network/mcpe/NetworkBinaryStream.php +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -540,8 +540,6 @@ class NetworkBinaryStream extends BinaryStream{ /** * Writes a list of Attributes to the packet buffer using the standard format. - * - * @param Attribute ...$attributes */ public function putAttributeList(Attribute ...$attributes) : void{ $this->putUnsignedVarInt(count($attributes)); diff --git a/src/pocketmine/plugin/PluginManager.php b/src/pocketmine/plugin/PluginManager.php index 6ee6fa1ec..6bbf131fd 100644 --- a/src/pocketmine/plugin/PluginManager.php +++ b/src/pocketmine/plugin/PluginManager.php @@ -365,8 +365,6 @@ class PluginManager{ /** * Returns whether a specified API version string is considered compatible with the server's API version. - * - * @param string ...$versions */ public function isCompatibleApi(string ...$versions) : bool{ $serverString = $this->server->getApiVersion(); diff --git a/src/pocketmine/utils/Color.php b/src/pocketmine/utils/Color.php index 1522c20c1..b6f36fafa 100644 --- a/src/pocketmine/utils/Color.php +++ b/src/pocketmine/utils/Color.php @@ -109,8 +109,6 @@ class Color{ /** * Mixes the supplied list of colours together to produce a result colour. - * - * @param Color ...$colors */ public static function mix(Color ...$colors) : Color{ $count = count($colors); diff --git a/src/pocketmine/utils/UUID.php b/src/pocketmine/utils/UUID.php index b6d725d39..05b31f8b7 100644 --- a/src/pocketmine/utils/UUID.php +++ b/src/pocketmine/utils/UUID.php @@ -84,8 +84,6 @@ class UUID{ /** * Creates an UUIDv3 from binary data or list of binary data - * - * @param string ...$data */ public static function fromData(string ...$data) : UUID{ $hash = hash("md5", implode($data), true); From 09201ac14bcb876867a3fd64d904e0c21bd40a38 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 22 Jan 2022 00:24:31 +0000 Subject: [PATCH 686/710] Fixed chunk sending we can't cache the encapsulated stuff anymore because of encryption. --- .../network/mcpe/RakLibInterface.php | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/pocketmine/network/mcpe/RakLibInterface.php b/src/pocketmine/network/mcpe/RakLibInterface.php index 16bfcea37..8772a79f8 100644 --- a/src/pocketmine/network/mcpe/RakLibInterface.php +++ b/src/pocketmine/network/mcpe/RakLibInterface.php @@ -261,22 +261,11 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{ $rawBuffer = substr($packet->buffer, 1); $buffer = self::MCPE_RAKNET_PACKET_ID . ($cipher !== null ? $cipher->encrypt($rawBuffer) : $rawBuffer); - if($needACK){ - $pk = new EncapsulatedPacket(); - $pk->identifierACK = $this->identifiersACK[$identifier]++; - $pk->buffer = $buffer; - $pk->reliability = PacketReliability::RELIABLE_ORDERED; - $pk->orderChannel = 0; - }else{ - if(!isset($packet->__encapsulatedPacket)){ - $packet->__encapsulatedPacket = new CachedEncapsulatedPacket; - $packet->__encapsulatedPacket->identifierACK = null; - $packet->__encapsulatedPacket->buffer = $buffer; - $packet->__encapsulatedPacket->reliability = PacketReliability::RELIABLE_ORDERED; - $packet->__encapsulatedPacket->orderChannel = 0; - } - $pk = $packet->__encapsulatedPacket; - } + $pk = new EncapsulatedPacket(); + $pk->identifierACK = $needACK ? $this->identifiersACK[$identifier]++ : null; + $pk->buffer = $buffer; + $pk->reliability = PacketReliability::RELIABLE_ORDERED; + $pk->orderChannel = 0; $this->interface->sendEncapsulated($identifier, $pk, ($needACK ? RakLib::FLAG_NEED_ACK : 0) | ($immediate ? RakLib::PRIORITY_IMMEDIATE : RakLib::PRIORITY_NORMAL)); return $pk->identifierACK; From e5a9123522e409749addb1fc845960970d62cb9f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 22 Jan 2022 00:30:05 +0000 Subject: [PATCH 687/710] PocketMine.php: require ext-crypto --- src/pocketmine/PocketMine.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index bb162ec13..55d328ef2 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -76,6 +76,7 @@ namespace pocketmine { $extensions = [ "chunkutils2" => "PocketMine ChunkUtils v2", "curl" => "cURL", + "crypto" => "php-crypto", "ctype" => "ctype", "date" => "Date", "hash" => "Hash", From e21446e5832060066099d93f9822f2ecfe8d59ad Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 22 Jan 2022 00:36:47 +0000 Subject: [PATCH 688/710] Release 3.27.0 --- changelogs/3.27.md | 15 +++++++++++++++ src/pocketmine/VersionInfo.php | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 changelogs/3.27.md diff --git a/changelogs/3.27.md b/changelogs/3.27.md new file mode 100644 index 000000000..58ed8925a --- /dev/null +++ b/changelogs/3.27.md @@ -0,0 +1,15 @@ +**For Minecraft: Bedrock Edition 1.18.0** + +### Note about API versions +Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps. +Plugin developers should **only** update their required API to this version if you need the changes in this build. + +**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do. + +# 3.27.0 +- Introduced support for protocol encryption. + - Encryption is enabled by default. + - Fixes login replay attacks. + - This may cause some performance degradation. + - Encryption can be disabled by setting `network.enable-encryption` to `false` in `pocketmine.yml`. DO NOT do this unless you understand the risks involved. +- An obsoletion notice has been added to the console during server startup. \ No newline at end of file diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index d2c0036be..164f4cab5 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.26.6"; -const IS_DEVELOPMENT_BUILD = true; +const BASE_VERSION = "3.27.0"; +const IS_DEVELOPMENT_BUILD = false; const BUILD_CHANNEL = "pm3"; From 60ef2db892da66f99d66ecf1ea218c7ec878ddd4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 22 Jan 2022 00:36:48 +0000 Subject: [PATCH 689/710] 3.27.1 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 164f4cab5..ba505addd 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.27.0"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.27.1"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_CHANNEL = "pm3"; From 419bb9eba69d05c6959606915280fcb6be945828 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 22 Jan 2022 01:33:31 +0000 Subject: [PATCH 690/710] Player: fixed parameter name inconsistency --- src/player/Player.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/player/Player.php b/src/player/Player.php index 014f4b79e..b2cc1f687 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -1812,16 +1812,16 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ return true; } - public function toggleSwim(bool $swimming) : bool{ - if($swimming === $this->swimming){ + public function toggleSwim(bool $swim) : bool{ + if($swim === $this->swimming){ return true; } - $ev = new PlayerToggleSwimEvent($this, $swimming); + $ev = new PlayerToggleSwimEvent($this, $swim); $ev->call(); if($ev->isCancelled()){ return false; } - $this->setSwimming($swimming); + $this->setSwimming($swim); return true; } From 587da478a69ef89fe22b97ffb1b151bdf6220b7c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 22 Jan 2022 02:23:06 +0000 Subject: [PATCH 691/710] Release 4.1.0-BETA1 --- changelogs/4.1.md | 117 ++++++++++++++++++++++++++++++++++++++++++++ src/VersionInfo.php | 6 +-- 2 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 changelogs/4.1.md diff --git a/changelogs/4.1.md b/changelogs/4.1.md new file mode 100644 index 000000000..8565f6909 --- /dev/null +++ b/changelogs/4.1.md @@ -0,0 +1,117 @@ +**For Minecraft: Bedrock Edition 1.18.0** + +### Note about API versions +Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps. +Plugin developers should **only** update their required API to this version if you need the changes in this build. + +**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do. + +# 4.1.0-BETA1 +Released 22nd January 2022. + +## General +- Game mode names (e.g. `survival`, `creative`) may now be used for the `gamemode` property in `server.properties`. +- Increased default maximum render distance to 16 chunks. Players with a render distance smaller than this will notice no difference. +- The setup wizard now prompts for a maximum render distance value. +- The setup wizard now prompts for an IPv6 port selection. Previously it would always use 19133. +- `chunk-ticking.disable-block-ticking` now accepts block names like those used in the `/give` command. +- The `/clear` command now behaves more like vanilla: + - The order of inventories is now the same as Bedrock. + - The cursor and offhand inventories are now cleared if necessary. + +## Technical +- `PlayerAuthInputPacket` is now used instead of `MovePlayerPacket` for processing movements. This improves position and rotation accuracy. +- `&&` and `||` are now always used instead of `and` and `or`. +- New version of `pocketmine/errorhandler` is used by this version, adding support for `ErrorToExceptionHandler::trap()`. This enables reliably capturing `E_WARNING` and `E_NOTICE` from functions such as `yaml_parse()` and friends. +- New dependency versions are required by this version: + - `pocketmine/bedrock-protocol` has been updated from 7.1.0 to [7.3.0](https://github.com/pmmp/BedrockProtocol/releases/tag/7.3.0%2Bbedrock-1.18.0). + - `pocketmine/errorhandler` has been updated from 0.3.0 to [0.6.0](https://github.com/pmmp/ErrorHandler/releases/tag/0.6.0). + +## API +### Block +- The following classes have been added: + - `Lectern` + - `Pumpkin` +- The following public API methods have been added: + - `Block->getTypeId() : int` - returns an integer which uniquely identifies the block type, ignoring things like facing, colour etc. + - `VanillaBlocks::LECTERN()` + +### Entity +- The following classes have been added: + - `animation\ItemEntityStackSizeChangeAnimation` +- The following public API methods have been added: + - `object\ItemEntity->isMergeable(object\ItemEntity $other) : bool` + - `object\ItemEntity->setStackSize(int $size) : void` + - `object\ItemEntity->tryMergeInto(object\ItemEntity $other) : bool` + - `ExperienceManager->canAttractXpOrbs() : bool` + - `ExperienceManager->setCanAttractXpOrbs(bool $v = true) : void` + - `Entity->getSize() : EntitySizeInfo` + - `Living->isGliding() : bool` + - `Living->isSwimming() : bool` + - `Living->setGliding(bool $value = true) : void` + - `Living->setSwimming(bool $value = true) : void` +- The following protected API methods have been added: + - `Entity->getBlocksIntersected(float $inset) : \Generator` + +### Event +- `BlockSpreadEvent` is now called when fire spreads to the positions of blocks it burns away. +- `BlockFormEvent` is now called when concrete powder turns into concrete due to contact with water. +- The following classes have been added: + - `BlockMeltEvent` - called when ice or snow melts + - `ChestPairEvent` - called when two chests try to form a pair + - `PlayerToggleGlideEvent` - called when a player starts or stops gliding + - `PlayerToggleSwimEvent` - called when a player starts or stops swimming + +### Item +- The following public API methods have been added: + - `SplashPotion->getType() : PotionType` + - `VanillaItems::AIR()` +- The following API methods have been deprecated: + - `ItemFactory::air()` - use `VanillaItems::AIR()` instead + +### Player +- The following public API methods have been added: + - `Player->hasBlockCollision() : bool` + - `Player->setHasBlockCollision(bool $value)` - allows controlling spectator-like no-clip behaviour without changing game mode + - `Player->toggleSwim(bool $swim) : bool` - called by the network system when the client tries to start/stop swimming + - `Player->toggleGlide(bool $glide) : bool` - called by the network system when the client tries to start/stop gliding + +### Server +- The following public API constants have been added: + - `Server::DEFAULT_SERVER_NAME` + - `Server::DEFAULT_MAX_PLAYERS` + - `Server::DEFAULT_PORT_IPV4` + - `Server::DEFAULT_PORT_IPV6` + - `Server::DEFAULT_MAX_VIEW_DISTANCE` + +### Utils +- Config parsing errors are now always represented by `ConfigLoadException` and include the path to the file in the message. +- Added `TextFormat::MINECOIN_GOLD`, and support for it to the various `TextFormat` methods. +- The following public API methods have been added: + - `Utils::assumeNotFalse()` - static analysis crutch to silence PHPStan errors without using `ignoreErrors` or `@phpstan-ignore-line`, which are both too coarse. +- The following public API properties have been added: + - `Terminal::$COLOR_MINECOIN_GOLD` +- The following classes have been added: + - `ConfigLoadException` +- Fixed `Random->nextSignedInt()` to actually return a signed int. Previously it would return any integer value between 0 and 4,294,957,295. +- Fixed `Random->nextSignedFloat()` to return a float between `-1.0` and `1.0`. Previously it would return any value between `0.0` and `2.0`. +- `VersionString->getNumber()` output is now structured differently to fix overflow issues caused by the old format. + +### World +- The following classes have been added: + - `sound\ItemUseOnBlockSound` + - `sound\LecternPlaceBookSound` + +## Gameplay +### Blocks +- Fire now spreads. +- Implemented lectern blocks. +- Added missing sounds for hoeing grass and dirt. +- Added missing sounds for using a shovel on grass to create grass path. +- Pumpkins can now be carved using shears. + +### Items +- Dropped items of the same type now merge with each other. + +### Misc +- Implemented player swimming. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 94b8dabda..2e5e7bad3 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,9 +31,9 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.1.0"; - public const IS_DEVELOPMENT_BUILD = true; - public const BUILD_CHANNEL = "stable"; + public const BASE_VERSION = "4.1.0-BETA1"; + public const IS_DEVELOPMENT_BUILD = false; + public const BUILD_CHANNEL = "beta"; private function __construct(){ //NOOP From 5ae20459dd4b05665c4d776e408a9eecf6f184ae Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 22 Jan 2022 02:23:09 +0000 Subject: [PATCH 692/710] 4.1.0-BETA2 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 2e5e7bad3..fe97175aa 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.1.0-BETA1"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.1.0-BETA2"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "beta"; private function __construct(){ From 67a0ae02469c3d116d30f872a6333dda40d9e00c Mon Sep 17 00:00:00 2001 From: Leo Lee Date: Sat, 22 Jan 2022 22:01:56 +0800 Subject: [PATCH 693/710] Fixed incorrect drops for ender chest (#4751) --- src/block/EnderChest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/block/EnderChest.php b/src/block/EnderChest.php index e37632008..8734b04fb 100644 --- a/src/block/EnderChest.php +++ b/src/block/EnderChest.php @@ -66,4 +66,8 @@ class EnderChest extends Transparent{ VanillaBlocks::OBSIDIAN()->asItem()->setCount(8) ]; } + + public function isAffectedBySilkTouch() : bool{ + return true; + } } From e0da99a973f3da66b6c7f76e3900302e5e62c5ab Mon Sep 17 00:00:00 2001 From: VixikHD Date: Sat, 22 Jan 2022 17:54:58 +0100 Subject: [PATCH 694/710] feat: Implement Brewing (#4413) The following API constants have been added: - tile\BrewingStand::BREW_TIME_TICKS The following public API methods have been added: - utils\BrewingStandSlot->getSlotNumber() : int - CraftingManager->getPotionTypeRecipes() : array> - CraftingManager->getPotionContainerChangeRecipes() : array> - CraftingManager->registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void - CraftingManager->registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void The following classes have been added: - BrewingRecipe - PotionTypeRecipe - PotionContainerChangeRecipe - BrewItemEvent - BrewingFuelUseEvent - PotionFinishBrewingSound --- src/block/BrewingStand.php | 20 ++- src/block/tile/BrewingStand.php | 168 ++++++++++++++++-- src/block/utils/BrewingStandSlot.php | 20 ++- src/crafting/BrewingRecipe.php | 30 ++++ src/crafting/CraftingManager.php | 54 ++++++ .../CraftingManagerFromDataHelper.php | 14 ++ src/crafting/PotionContainerChangeRecipe.php | 54 ++++++ src/crafting/PotionTypeRecipe.php | 55 ++++++ src/event/block/BrewItemEvent.php | 71 ++++++++ src/event/block/BrewingFuelUseEvent.php | 64 +++++++ src/network/mcpe/cache/CraftingDataCache.php | 37 +++- src/world/sound/PotionFinishBrewingSound.php | 35 ++++ 12 files changed, 606 insertions(+), 16 deletions(-) create mode 100644 src/crafting/BrewingRecipe.php create mode 100644 src/crafting/PotionContainerChangeRecipe.php create mode 100644 src/crafting/PotionTypeRecipe.php create mode 100644 src/event/block/BrewItemEvent.php create mode 100644 src/event/block/BrewingFuelUseEvent.php create mode 100644 src/world/sound/PotionFinishBrewingSound.php diff --git a/src/block/BrewingStand.php b/src/block/BrewingStand.php index e0366b7d3..fd763a3f0 100644 --- a/src/block/BrewingStand.php +++ b/src/block/BrewingStand.php @@ -125,6 +125,24 @@ class BrewingStand extends Transparent{ } public function onScheduledUpdate() : void{ - //TODO + $brewing = $this->position->getWorld()->getTile($this->position); + if($brewing instanceof TileBrewingStand){ + if($brewing->onUpdate()){ + $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); + } + + $changed = false; + foreach(BrewingStandSlot::getAll() as $slot){ + $occupied = !$brewing->getInventory()->isSlotEmpty($slot->getSlotNumber()); + if($occupied !== $this->hasSlot($slot)){ + $this->setSlot($slot, $occupied); + $changed = true; + } + } + + if($changed){ + $this->position->getWorld()->setBlock($this->position, $this); + } + } } } diff --git a/src/block/tile/BrewingStand.php b/src/block/tile/BrewingStand.php index 450a52125..e008c7fda 100644 --- a/src/block/tile/BrewingStand.php +++ b/src/block/tile/BrewingStand.php @@ -24,16 +24,29 @@ declare(strict_types=1); namespace pocketmine\block\tile; use pocketmine\block\inventory\BrewingStandInventory; +use pocketmine\crafting\BrewingRecipe; +use pocketmine\event\block\BrewingFuelUseEvent; +use pocketmine\event\block\BrewItemEvent; use pocketmine\inventory\CallbackInventoryListener; use pocketmine\inventory\Inventory; +use pocketmine\item\Item; +use pocketmine\item\VanillaItems; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; +use pocketmine\network\mcpe\protocol\ContainerSetDataPacket; +use pocketmine\player\Player; +use pocketmine\world\sound\PotionFinishBrewingSound; use pocketmine\world\World; +use function array_map; +use function count; class BrewingStand extends Spawnable implements Container, Nameable{ - + use NameableTrait { + addAdditionalSpawnData as addNameSpawnData; + } use ContainerTrait; - use NameableTrait; + + public const BREW_TIME_TICKS = 400; // Brew time in ticks private const TAG_BREW_TIME = "BrewTime"; //TAG_Short private const TAG_BREW_TIME_PE = "CookTime"; //TAG_Short @@ -41,15 +54,11 @@ class BrewingStand extends Spawnable implements Container, Nameable{ private const TAG_REMAINING_FUEL_TIME = "Fuel"; //TAG_Byte private const TAG_REMAINING_FUEL_TIME_PE = "FuelAmount"; //TAG_Short - /** @var BrewingStandInventory */ - private $inventory; + private BrewingStandInventory $inventory; - /** @var int */ - private $brewTime = 0; - /** @var int */ - private $maxFuelTime = 0; - /** @var int */ - private $remainingFuelTime = 0; + private int $brewTime = 0; + private int $maxFuelTime = 0; + private int $remainingFuelTime = 0; public function __construct(World $world, Vector3 $pos){ parent::__construct($world, $pos); @@ -83,6 +92,14 @@ class BrewingStand extends Spawnable implements Container, Nameable{ $nbt->setShort(self::TAG_REMAINING_FUEL_TIME_PE, $this->remainingFuelTime); } + protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ + $this->addNameSpawnData($nbt); + + $nbt->setShort(self::TAG_BREW_TIME_PE, $this->brewTime); + $nbt->setShort(self::TAG_MAX_FUEL_TIME, $this->maxFuelTime); + $nbt->setShort(self::TAG_REMAINING_FUEL_TIME_PE, $this->remainingFuelTime); + } + public function getDefaultName() : string{ return "Brewing Stand"; } @@ -108,4 +125,135 @@ class BrewingStand extends Spawnable implements Container, Nameable{ public function getRealInventory(){ return $this->inventory; } + + private function checkFuel(Item $item) : void{ + $ev = new BrewingFuelUseEvent($this); + if(!$item->equals(VanillaItems::BLAZE_POWDER(), true, false)){ + $ev->cancel(); + } + + $ev->call(); + if($ev->isCancelled()){ + return; + } + + $item->pop(); + $this->inventory->setItem(BrewingStandInventory::SLOT_FUEL, $item); + + $this->maxFuelTime = $this->remainingFuelTime = $ev->getFuelTime(); + } + + /** + * @return BrewingRecipe[] + * @phpstan-return array + */ + private function getBrewableRecipes() : array{ + if($this->inventory->getItem(BrewingStandInventory::SLOT_INGREDIENT)->isNull()){ + return []; + } + + $recipes = []; + foreach([BrewingStandInventory::SLOT_BOTTLE_LEFT, BrewingStandInventory::SLOT_BOTTLE_MIDDLE, BrewingStandInventory::SLOT_BOTTLE_RIGHT] as $slot){ + $input = $this->inventory->getItem($slot); + if($input->isNull()){ + continue; + } + + if(($recipe = $this->position->getWorld()->getServer()->getCraftingManager()->matchBrewingRecipe($input, $this->inventory->getItem(BrewingStandInventory::SLOT_INGREDIENT))) !== null){ + $recipes[$slot] = $recipe; + } + } + + return $recipes; + } + + public function onUpdate() : bool{ + if($this->closed){ + return false; + } + + $this->timings->startTiming(); + + $prevBrewTime = $this->brewTime; + $prevRemainingFuelTime = $this->remainingFuelTime; + $prevMaxFuelTime = $this->maxFuelTime; + + $ret = false; + + $fuel = $this->inventory->getItem(BrewingStandInventory::SLOT_FUEL); + $ingredient = $this->inventory->getItem(BrewingStandInventory::SLOT_INGREDIENT); + + $recipes = $this->getBrewableRecipes(); + $canBrew = count($recipes) !== 0; + + if($this->remainingFuelTime <= 0 && $canBrew){ + $this->checkFuel($fuel); + } + + if($this->remainingFuelTime > 0){ + if($canBrew){ + if($this->brewTime === 0){ + $this->brewTime = self::BREW_TIME_TICKS; + --$this->remainingFuelTime; + } + + --$this->brewTime; + + if($this->brewTime <= 0){ + $anythingBrewed = false; + foreach($recipes as $slot => $recipe){ + $input = $this->inventory->getItem($slot); + $output = $recipe->getResultFor($input); + if($output === null){ + continue; + } + + $ev = new BrewItemEvent($this, $slot, $input, $output, $recipe); + $ev->call(); + if($ev->isCancelled()){ + continue; + } + + $this->inventory->setItem($slot, $ev->getResult()); + $anythingBrewed = true; + } + + if($anythingBrewed){ + $this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new PotionFinishBrewingSound()); + } + + $ingredient->pop(); + $this->inventory->setItem(BrewingStandInventory::SLOT_INGREDIENT, $ingredient); + + $this->brewTime = 0; + }else{ + $ret = true; + } + }else{ + $this->brewTime = 0; + } + }else{ + $this->brewTime = $this->remainingFuelTime = $this->maxFuelTime = 0; + } + + $viewers = array_map(fn(Player $p) => $p->getNetworkSession()->getInvManager(), $this->inventory->getViewers()); + foreach($viewers as $v){ + if($v === null){ + continue; + } + if($prevBrewTime !== $this->brewTime){ + $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_BREWING_STAND_BREW_TIME, $this->brewTime); + } + if($prevRemainingFuelTime !== $this->remainingFuelTime){ + $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_BREWING_STAND_FUEL_AMOUNT, $this->remainingFuelTime); + } + if($prevMaxFuelTime !== $this->maxFuelTime){ + $v->syncData($this->inventory, ContainerSetDataPacket::PROPERTY_BREWING_STAND_FUEL_TOTAL, $this->maxFuelTime); + } + } + + $this->timings->stopTiming(); + + return $ret; + } } diff --git a/src/block/utils/BrewingStandSlot.php b/src/block/utils/BrewingStandSlot.php index c5b14af1b..37182693e 100644 --- a/src/block/utils/BrewingStandSlot.php +++ b/src/block/utils/BrewingStandSlot.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block\utils; +use pocketmine\block\inventory\BrewingStandInventory; use pocketmine\utils\EnumTrait; /** @@ -36,13 +37,24 @@ use pocketmine\utils\EnumTrait; * @method static BrewingStandSlot SOUTHWEST() */ final class BrewingStandSlot{ - use EnumTrait; + use EnumTrait { + __construct as Enum___construct; + } protected static function setup() : void{ self::registerAll( - new self("east"), - new self("northwest"), - new self("southwest") + new self("east", BrewingStandInventory::SLOT_BOTTLE_LEFT), + new self("northwest", BrewingStandInventory::SLOT_BOTTLE_MIDDLE), + new self("southwest", BrewingStandInventory::SLOT_BOTTLE_RIGHT) ); } + + private function __construct(string $enumName, private int $slotNumber){ + $this->Enum___construct($enumName); + } + + /** + * Returns the brewing stand inventory slot number associated with this visual slot. + */ + public function getSlotNumber() : int{ return $this->slotNumber; } } diff --git a/src/crafting/BrewingRecipe.php b/src/crafting/BrewingRecipe.php new file mode 100644 index 000000000..e903f0c3c --- /dev/null +++ b/src/crafting/BrewingRecipe.php @@ -0,0 +1,30 @@ +> + */ + protected $potionTypeRecipes = []; + + /** + * @var PotionContainerChangeRecipe[][] + * @phpstan-var array> + */ + protected $potionContainerChangeRecipes = []; + /** * @var ObjectSet * @phpstan-var ObjectSet<\Closure() : void> @@ -140,6 +152,22 @@ class CraftingManager{ return $this->furnaceRecipeManagers[$furnaceType->id()]; } + /** + * @return PotionTypeRecipe[][] + * @phpstan-return array> + */ + public function getPotionTypeRecipes() : array{ + return $this->potionTypeRecipes; + } + + /** + * @return PotionContainerChangeRecipe[][] + * @phpstan-return array> + */ + public function getPotionContainerChangeRecipes() : array{ + return $this->potionContainerChangeRecipes; + } + public function registerShapedRecipe(ShapedRecipe $recipe) : void{ $this->shapedRecipes[self::hashOutputs($recipe->getResults())][] = $recipe; @@ -156,6 +184,25 @@ class CraftingManager{ } } + public function registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void{ + $input = $recipe->getInput(); + $ingredient = $recipe->getIngredient(); + $this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":" . ($ingredient->hasAnyDamageValue() ? "?" : $ingredient->getMeta())] = $recipe; + + foreach($this->recipeRegisteredCallbacks as $callback){ + $callback(); + } + } + + public function registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void{ + $ingredient = $recipe->getIngredient(); + $this->potionContainerChangeRecipes[$recipe->getInputItemId()][$ingredient->getId() . ":" . ($ingredient->hasAnyDamageValue() ? "?" : $ingredient->getMeta())] = $recipe; + + foreach($this->recipeRegisteredCallbacks as $callback){ + $callback(); + } + } + /** * @param Item[] $outputs */ @@ -206,4 +253,11 @@ class CraftingManager{ } } } + + public function matchBrewingRecipe(Item $input, Item $ingredient) : ?BrewingRecipe{ + return $this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":" . $ingredient->getMeta()] ?? + $this->potionTypeRecipes[$input->getId() . ":" . $input->getMeta()][$ingredient->getId() . ":?"] ?? + $this->potionContainerChangeRecipes[$input->getId()][$ingredient->getId() . ":" . $ingredient->getMeta()] ?? + $this->potionContainerChangeRecipes[$input->getId()][$ingredient->getId() . ":?"] ?? null; + } } diff --git a/src/crafting/CraftingManagerFromDataHelper.php b/src/crafting/CraftingManagerFromDataHelper.php index bd8465b1b..b5c485ab2 100644 --- a/src/crafting/CraftingManagerFromDataHelper.php +++ b/src/crafting/CraftingManagerFromDataHelper.php @@ -77,6 +77,20 @@ final class CraftingManagerFromDataHelper{ Item::jsonDeserialize($recipe["input"])) ); } + foreach($recipes["potion_type"] as $recipe){ + $result->registerPotionTypeRecipe(new PotionTypeRecipe( + Item::jsonDeserialize($recipe["input"]), + Item::jsonDeserialize($recipe["ingredient"]), + Item::jsonDeserialize($recipe["output"]) + )); + } + foreach($recipes["potion_container_change"] as $recipe){ + $result->registerPotionContainerChangeRecipe(new PotionContainerChangeRecipe( + $recipe["input_item_id"], + Item::jsonDeserialize($recipe["ingredient"]), + $recipe["output_item_id"] + )); + } return $result; } diff --git a/src/crafting/PotionContainerChangeRecipe.php b/src/crafting/PotionContainerChangeRecipe.php new file mode 100644 index 000000000..4f4ec2cde --- /dev/null +++ b/src/crafting/PotionContainerChangeRecipe.php @@ -0,0 +1,54 @@ +ingredient = clone $ingredient; + } + + public function getInputItemId() : int{ + return $this->inputItemId; + } + + public function getIngredient() : Item{ + return clone $this->ingredient; + } + + public function getOutputItemId() : int{ + return $this->outputItemId; + } + + public function getResultFor(Item $input) : ?Item{ + return $input->getId() === $this->getInputItemId() ? ItemFactory::getInstance()->get($this->getOutputItemId(), $input->getMeta()) : null; + } +} diff --git a/src/crafting/PotionTypeRecipe.php b/src/crafting/PotionTypeRecipe.php new file mode 100644 index 000000000..aa1604d6f --- /dev/null +++ b/src/crafting/PotionTypeRecipe.php @@ -0,0 +1,55 @@ +input = clone $input; + $this->ingredient = clone $ingredient; + $this->output = clone $output; + } + + public function getInput() : Item{ + return clone $this->input; + } + + public function getIngredient() : Item{ + return clone $this->ingredient; + } + + public function getOutput() : Item{ + return clone $this->output; + } + + public function getResultFor(Item $input) : ?Item{ + return $input->equals($this->input, true, false) ? $this->getOutput() : null; + } +} diff --git a/src/event/block/BrewItemEvent.php b/src/event/block/BrewItemEvent.php new file mode 100644 index 000000000..44df0047a --- /dev/null +++ b/src/event/block/BrewItemEvent.php @@ -0,0 +1,71 @@ +getBlock()); + } + + public function getBrewingStand() : BrewingStand{ + return $this->brewingStand; + } + + /** + * Returns which slot of the brewing stand's inventory the potion is in. + */ + public function getSlot() : int{ + return $this->slot; + } + + public function getInput() : Item{ + return clone $this->input; + } + + public function getResult() : Item{ + return clone $this->result; + } + + public function setResult(Item $result) : void{ + $this->result = clone $result; + } + + public function getRecipe() : BrewingRecipe{ + return $this->recipe; + } +} diff --git a/src/event/block/BrewingFuelUseEvent.php b/src/event/block/BrewingFuelUseEvent.php new file mode 100644 index 000000000..25b2c105c --- /dev/null +++ b/src/event/block/BrewingFuelUseEvent.php @@ -0,0 +1,64 @@ +getBlock()); + } + + public function getBrewingStand() : BrewingStand{ + return $this->brewingStand; + } + + /** + * Returns how many times the fuel can be used for potion brewing before it runs out. + */ + public function getFuelTime() : int{ + return $this->fuelTime; + } + + /** + * Sets how many times the fuel can be used for potion brewing before it runs out. + */ + public function setFuelTime(int $fuelTime) : void{ + if($fuelTime <= 0){ + throw new \InvalidArgumentException("Fuel time must be positive"); + } + $this->fuelTime = $fuelTime; + } +} diff --git a/src/network/mcpe/cache/CraftingDataCache.php b/src/network/mcpe/cache/CraftingDataCache.php index 369a45039..2b2d1968e 100644 --- a/src/network/mcpe/cache/CraftingDataCache.php +++ b/src/network/mcpe/cache/CraftingDataCache.php @@ -26,12 +26,15 @@ namespace pocketmine\network\mcpe\cache; use pocketmine\crafting\CraftingManager; use pocketmine\crafting\FurnaceType; use pocketmine\item\Item; +use pocketmine\network\mcpe\convert\ItemTranslator; use pocketmine\network\mcpe\convert\TypeConverter; use pocketmine\network\mcpe\protocol\CraftingDataPacket; use pocketmine\network\mcpe\protocol\types\inventory\ItemStack; use pocketmine\network\mcpe\protocol\types\recipe\CraftingRecipeBlockName; use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipe as ProtocolFurnaceRecipe; use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipeBlockName; +use pocketmine\network\mcpe\protocol\types\recipe\PotionContainerChangeRecipe as ProtocolPotionContainerChangeRecipe; +use pocketmine\network\mcpe\protocol\types\recipe\PotionTypeRecipe as ProtocolPotionTypeRecipe; use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient; use pocketmine\network\mcpe\protocol\types\recipe\ShapedRecipe as ProtocolShapedRecipe; use pocketmine\network\mcpe\protocol\types\recipe\ShapelessRecipe as ProtocolShapelessRecipe; @@ -137,7 +140,39 @@ final class CraftingDataCache{ } } + $potionTypeRecipes = []; + foreach($manager->getPotionTypeRecipes() as $recipes){ + foreach($recipes as $recipe){ + $input = $converter->coreItemStackToNet($recipe->getInput()); + $ingredient = $converter->coreItemStackToNet($recipe->getIngredient()); + $output = $converter->coreItemStackToNet($recipe->getOutput()); + $potionTypeRecipes[] = new ProtocolPotionTypeRecipe( + $input->getId(), + $input->getMeta(), + $ingredient->getId(), + $ingredient->getMeta(), + $output->getId(), + $output->getMeta() + ); + } + } + + $potionContainerChangeRecipes = []; + $itemTranslator = ItemTranslator::getInstance(); + foreach($manager->getPotionContainerChangeRecipes() as $recipes){ + foreach($recipes as $recipe){ + $input = $itemTranslator->toNetworkId($recipe->getInputItemId(), 0); + $ingredient = $itemTranslator->toNetworkId($recipe->getIngredient()->getId(), 0); + $output = $itemTranslator->toNetworkId($recipe->getOutputItemId(), 0); + $potionContainerChangeRecipes[] = new ProtocolPotionContainerChangeRecipe( + $input[0], + $ingredient[0], + $output[0] + ); + } + } + Timings::$craftingDataCacheRebuild->stopTiming(); - return CraftingDataPacket::create($recipesWithTypeIds, [], [], [], true); + return CraftingDataPacket::create($recipesWithTypeIds, $potionTypeRecipes, $potionContainerChangeRecipes, [], true); } } diff --git a/src/world/sound/PotionFinishBrewingSound.php b/src/world/sound/PotionFinishBrewingSound.php new file mode 100644 index 000000000..5f292687b --- /dev/null +++ b/src/world/sound/PotionFinishBrewingSound.php @@ -0,0 +1,35 @@ + Date: Sat, 22 Jan 2022 21:26:34 +0000 Subject: [PATCH 695/710] HayBale: fixed fall damage --- src/block/HayBale.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/block/HayBale.php b/src/block/HayBale.php index abf25e8a1..92df9a5fb 100644 --- a/src/block/HayBale.php +++ b/src/block/HayBale.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\PillarRotationInMetadataTrait; +use pocketmine\entity\Entity; class HayBale extends Opaque{ use PillarRotationInMetadataTrait; @@ -35,4 +36,9 @@ class HayBale extends Opaque{ public function getFlammability() : int{ return 20; } + + public function onEntityLand(Entity $entity) : ?float{ + $entity->fallDistance *= 0.2; + return null; + } } From 99f087e5e18236afd9ddd5e208d8d61ecba52de1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jan 2022 14:21:49 +0000 Subject: [PATCH 696/710] Bump phpunit/phpunit from 9.5.12 to 9.5.13 (#4767) Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.12 to 9.5.13. - [Release notes](https://github.com/sebastianbergmann/phpunit/releases) - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md) - [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.12...9.5.13) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 7fa306c76..267df8983 100644 --- a/composer.lock +++ b/composer.lock @@ -2388,16 +2388,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.12", + "version": "9.5.13", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256" + "reference": "597cb647654ede35e43b137926dfdfef0fb11743" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/93d4bf4c37aec6384bb9e5d390d9049a463a7256", - "reference": "93d4bf4c37aec6384bb9e5d390d9049a463a7256", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/597cb647654ede35e43b137926dfdfef0fb11743", + "reference": "597cb647654ede35e43b137926dfdfef0fb11743", "shasum": "" }, "require": { @@ -2475,7 +2475,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.12" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.13" }, "funding": [ { @@ -2487,7 +2487,7 @@ "type": "github" } ], - "time": "2022-01-21T05:54:47+00:00" + "time": "2022-01-24T07:33:35+00:00" }, { "name": "sebastian/cli-parser", From 32b07e094055c42859e6ac9d937b4b055063cf3a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 24 Jan 2022 21:07:51 +0000 Subject: [PATCH 697/710] World: avoid repeated getInstance() calls in hot paths --- src/world/World.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/world/World.php b/src/world/World.php index 8fff731dd..1707e8e17 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -947,6 +947,8 @@ class World implements ChunkManager{ public function createBlockUpdatePackets(array $blocks) : array{ $packets = []; + $blockMapping = RuntimeBlockMapping::getInstance(); + foreach($blocks as $b){ if(!($b instanceof Vector3)){ throw new \TypeError("Expected Vector3 in blocks array, got " . (is_object($b) ? get_class($b) : gettype($b))); @@ -956,7 +958,7 @@ class World implements ChunkManager{ $blockPosition = BlockPosition::fromVector3($b); $packets[] = UpdateBlockPacket::create( $blockPosition, - RuntimeBlockMapping::getInstance()->toRuntimeId($fullBlock->getFullId()), + $blockMapping->toRuntimeId($fullBlock->getFullId()), UpdateBlockPacket::FLAG_NETWORK, UpdateBlockPacket::DATA_LAYER_NORMAL ); @@ -1105,6 +1107,7 @@ class World implements ChunkManager{ $entity->onRandomUpdate(); } + $blockFactory = BlockFactory::getInstance(); foreach($chunk->getSubChunks() as $Y => $subChunk){ if(!$subChunk->isEmptyFast()){ $k = 0; @@ -1121,8 +1124,7 @@ class World implements ChunkManager{ $state = $subChunk->getFullBlock($x, $y, $z); if(isset($this->randomTickBlocks[$state])){ - /** @var Block $block */ - $block = BlockFactory::getInstance()->fromFullBlock($state); + $block = $blockFactory->fromFullBlock($state); $block->position($this, $chunkX * Chunk::EDGE_LENGTH + $x, ($Y << SubChunk::COORD_BIT_SIZE) + $y, $chunkZ * Chunk::EDGE_LENGTH + $z); $block->onRandomTick(); } From b9f1bcf0e4cc0d889ca842bc96e282cb67acecad Mon Sep 17 00:00:00 2001 From: ShockedPlot7560 <66992287+ShockedPlot7560@users.noreply.github.com> Date: Tue, 25 Jan 2022 19:00:26 +0100 Subject: [PATCH 698/710] Implement PlayerViewDistanceChangeEvent (#4749) closes #4550 --- .../player/PlayerViewDistanceChangeEvent.php | 55 +++++++++++++++++++ src/player/Player.php | 10 +++- 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/event/player/PlayerViewDistanceChangeEvent.php diff --git a/src/event/player/PlayerViewDistanceChangeEvent.php b/src/event/player/PlayerViewDistanceChangeEvent.php new file mode 100644 index 000000000..0048672ab --- /dev/null +++ b/src/event/player/PlayerViewDistanceChangeEvent.php @@ -0,0 +1,55 @@ +player = $player; + $this->oldDistance = $oldDistance; + $this->newDistance = $newDistance; + } + + /** + * Returns the new view radius, measured in chunks. + */ + public function getNewDistance() : int{ + return $this->newDistance; + } + + /** + * Returns the old view radius, measured in chunks. + * A value of -1 means that the player has just connected and did not have a view distance before this event. + */ + public function getOldDistance() : int{ + return $this->oldDistance; + } +} diff --git a/src/player/Player.php b/src/player/Player.php index b2cc1f687..7cf4388d1 100644 --- a/src/player/Player.php +++ b/src/player/Player.php @@ -73,6 +73,7 @@ use pocketmine\event\player\PlayerToggleSneakEvent; use pocketmine\event\player\PlayerToggleSprintEvent; use pocketmine\event\player\PlayerToggleSwimEvent; use pocketmine\event\player\PlayerTransferEvent; +use pocketmine\event\player\PlayerViewDistanceChangeEvent; use pocketmine\form\Form; use pocketmine\form\FormValidationException; use pocketmine\inventory\CallbackInventoryListener; @@ -507,7 +508,14 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{ } public function setViewDistance(int $distance) : void{ - $this->viewDistance = $this->server->getAllowedViewDistance($distance); + $newViewDistance = $this->server->getAllowedViewDistance($distance); + + if($newViewDistance !== $this->viewDistance){ + $ev = new PlayerViewDistanceChangeEvent($this, $this->viewDistance, $newViewDistance); + $ev->call(); + } + + $this->viewDistance = $newViewDistance; $this->spawnThreshold = (int) (min($this->viewDistance, $this->server->getConfigGroup()->getPropertyInt("chunk-sending.spawn-radius", 4)) ** 2 * M_PI); From 0bf5f97fe9c0ecff2b1042437be99fc769533f0c Mon Sep 17 00:00:00 2001 From: ShockedPlot7560 <66992287+ShockedPlot7560@users.noreply.github.com> Date: Tue, 25 Jan 2022 19:52:31 +0100 Subject: [PATCH 699/710] Implement furnace sound (#4755) closes #4363 The following classes have been added: - BlastFurnaceSound - SmokerSound - FurnaceSound --- src/block/Furnace.php | 14 +++++++++++ src/world/sound/BlastFurnaceSound.php | 35 +++++++++++++++++++++++++++ src/world/sound/FurnaceSound.php | 35 +++++++++++++++++++++++++++ src/world/sound/SmokerSound.php | 35 +++++++++++++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 src/world/sound/BlastFurnaceSound.php create mode 100644 src/world/sound/FurnaceSound.php create mode 100644 src/world/sound/SmokerSound.php diff --git a/src/block/Furnace.php b/src/block/Furnace.php index d4b74ea7c..60352585b 100644 --- a/src/block/Furnace.php +++ b/src/block/Furnace.php @@ -26,9 +26,15 @@ namespace pocketmine\block; use pocketmine\block\tile\Furnace as TileFurnace; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait; +use pocketmine\crafting\FurnaceType; use pocketmine\item\Item; use pocketmine\math\Vector3; use pocketmine\player\Player; +use pocketmine\utils\AssumptionFailedError; +use pocketmine\world\sound\BlastFurnaceSound; +use pocketmine\world\sound\FurnaceSound; +use pocketmine\world\sound\SmokerSound; +use function mt_rand; class Furnace extends Opaque{ use FacesOppositePlacingPlayerTrait; @@ -84,6 +90,14 @@ class Furnace extends Opaque{ public function onScheduledUpdate() : void{ $furnace = $this->position->getWorld()->getTile($this->position); if($furnace instanceof TileFurnace && $furnace->onUpdate()){ + if(mt_rand(1, 60) === 1){ //in vanilla this is between 1 and 5 seconds; try to average about 3 + $this->position->getWorld()->addSound($this->position, match($furnace->getFurnaceType()->id()){ + FurnaceType::FURNACE()->id() => new FurnaceSound(), + FurnaceType::BLAST_FURNACE()->id() => new BlastFurnaceSound(), + FurnaceType::SMOKER()->id() => new SmokerSound(), + default => throw new AssumptionFailedError("Unreachable") + }); + } $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); //TODO: check this } } diff --git a/src/world/sound/BlastFurnaceSound.php b/src/world/sound/BlastFurnaceSound.php new file mode 100644 index 000000000..c7846e6c5 --- /dev/null +++ b/src/world/sound/BlastFurnaceSound.php @@ -0,0 +1,35 @@ + Date: Tue, 25 Jan 2022 19:01:49 +0000 Subject: [PATCH 700/710] Added FurnaceType->getCookSound() --- src/block/Furnace.php | 12 +----------- src/crafting/FurnaceType.php | 14 ++++++++++---- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/block/Furnace.php b/src/block/Furnace.php index 60352585b..ff96d0b27 100644 --- a/src/block/Furnace.php +++ b/src/block/Furnace.php @@ -26,14 +26,9 @@ namespace pocketmine\block; use pocketmine\block\tile\Furnace as TileFurnace; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait; -use pocketmine\crafting\FurnaceType; use pocketmine\item\Item; use pocketmine\math\Vector3; use pocketmine\player\Player; -use pocketmine\utils\AssumptionFailedError; -use pocketmine\world\sound\BlastFurnaceSound; -use pocketmine\world\sound\FurnaceSound; -use pocketmine\world\sound\SmokerSound; use function mt_rand; class Furnace extends Opaque{ @@ -91,12 +86,7 @@ class Furnace extends Opaque{ $furnace = $this->position->getWorld()->getTile($this->position); if($furnace instanceof TileFurnace && $furnace->onUpdate()){ if(mt_rand(1, 60) === 1){ //in vanilla this is between 1 and 5 seconds; try to average about 3 - $this->position->getWorld()->addSound($this->position, match($furnace->getFurnaceType()->id()){ - FurnaceType::FURNACE()->id() => new FurnaceSound(), - FurnaceType::BLAST_FURNACE()->id() => new BlastFurnaceSound(), - FurnaceType::SMOKER()->id() => new SmokerSound(), - default => throw new AssumptionFailedError("Unreachable") - }); + $this->position->getWorld()->addSound($this->position, $furnace->getFurnaceType()->getCookSound()); } $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); //TODO: check this } diff --git a/src/crafting/FurnaceType.php b/src/crafting/FurnaceType.php index 889150c45..079066b97 100644 --- a/src/crafting/FurnaceType.php +++ b/src/crafting/FurnaceType.php @@ -24,6 +24,10 @@ declare(strict_types=1); namespace pocketmine\crafting; use pocketmine\utils\EnumTrait; +use pocketmine\world\sound\BlastFurnaceSound; +use pocketmine\world\sound\FurnaceSound; +use pocketmine\world\sound\SmokerSound; +use pocketmine\world\sound\Sound; /** * This doc-block is generated automatically, do not modify it manually. @@ -42,15 +46,17 @@ final class FurnaceType{ protected static function setup() : void{ self::registerAll( - new self("furnace", 200), - new self("blast_furnace", 100), - new self("smoker", 100), + new self("furnace", 200, new FurnaceSound()), + new self("blast_furnace", 100, new BlastFurnaceSound()), + new self("smoker", 100, new SmokerSound()), ); } - private function __construct(string $enumName, private int $cookDurationTicks){ + private function __construct(string $enumName, private int $cookDurationTicks, private Sound $cookSound){ $this->Enum___construct($enumName); } public function getCookDurationTicks() : int{ return $this->cookDurationTicks; } + + public function getCookSound() : Sound{ return $this->cookSound; } } From 75d0fc4749466d9c702f0192e128392e6e52d6de Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 25 Jan 2022 19:23:04 +0000 Subject: [PATCH 701/710] BlockFactory: Make stone slab registration a little less unpleasant to read --- src/block/BlockFactory.php | 65 +++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index 914e1edca..14d37d72d 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -398,35 +398,42 @@ class BlockFactory{ //TODO: in the future this won't be the same for all the types $stoneSlabBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_BRICK), "Brick", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_COBBLESTONE), "Cobblestone", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_FAKE_WOODEN), "Fake Wooden", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_NETHER_BRICK), "Nether Brick", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_QUARTZ), "Quartz", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_SANDSTONE), "Sandstone", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_SMOOTH_STONE), "Smooth Stone", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(1, Meta::STONE_SLAB_STONE_BRICK), "Stone Brick", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_DARK_PRISMARINE), "Dark Prismarine", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_MOSSY_COBBLESTONE), "Mossy Cobblestone", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_PRISMARINE), "Prismarine", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_PRISMARINE_BRICKS), "Prismarine Bricks", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_PURPUR), "Purpur", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_RED_NETHER_BRICK), "Red Nether Brick", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_RED_SANDSTONE), "Red Sandstone", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(2, Meta::STONE_SLAB2_SMOOTH_SANDSTONE), "Smooth Sandstone", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_ANDESITE), "Andesite", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_DIORITE), "Diorite", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_END_STONE_BRICK), "End Stone Brick", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_GRANITE), "Granite", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_POLISHED_ANDESITE), "Polished Andesite", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_POLISHED_DIORITE), "Polished Diorite", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_POLISHED_GRANITE), "Polished Granite", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(3, Meta::STONE_SLAB3_SMOOTH_RED_SANDSTONE), "Smooth Red Sandstone", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_CUT_RED_SANDSTONE), "Cut Red Sandstone", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_CUT_SANDSTONE), "Cut Sandstone", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_MOSSY_STONE_BRICK), "Mossy Stone Brick", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_SMOOTH_QUARTZ), "Smooth Quartz", $stoneSlabBreakInfo)); - $this->registerSlabWithDoubleHighBitsRemapping(new Slab(BlockLegacyIdHelper::getStoneSlabIdentifier(4, Meta::STONE_SLAB4_STONE), "Stone", $stoneSlabBreakInfo)); + + $getStoneSlabId = static fn(int $stoneSlabId, int $meta) => BlockLegacyIdHelper::getStoneSlabIdentifier($stoneSlabId, $meta); + foreach([ + new Slab($getStoneSlabId(1, Meta::STONE_SLAB_BRICK), "Brick", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(1, Meta::STONE_SLAB_COBBLESTONE), "Cobblestone", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(1, Meta::STONE_SLAB_FAKE_WOODEN), "Fake Wooden", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(1, Meta::STONE_SLAB_NETHER_BRICK), "Nether Brick", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(1, Meta::STONE_SLAB_QUARTZ), "Quartz", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(1, Meta::STONE_SLAB_SANDSTONE), "Sandstone", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(1, Meta::STONE_SLAB_SMOOTH_STONE), "Smooth Stone", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(1, Meta::STONE_SLAB_STONE_BRICK), "Stone Brick", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_DARK_PRISMARINE), "Dark Prismarine", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_MOSSY_COBBLESTONE), "Mossy Cobblestone", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_PRISMARINE), "Prismarine", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_PRISMARINE_BRICKS), "Prismarine Bricks", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_PURPUR), "Purpur", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_RED_NETHER_BRICK), "Red Nether Brick", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_RED_SANDSTONE), "Red Sandstone", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(2, Meta::STONE_SLAB2_SMOOTH_SANDSTONE), "Smooth Sandstone", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_ANDESITE), "Andesite", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_DIORITE), "Diorite", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_END_STONE_BRICK), "End Stone Brick", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_GRANITE), "Granite", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_POLISHED_ANDESITE), "Polished Andesite", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_POLISHED_DIORITE), "Polished Diorite", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_POLISHED_GRANITE), "Polished Granite", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(3, Meta::STONE_SLAB3_SMOOTH_RED_SANDSTONE), "Smooth Red Sandstone", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_CUT_RED_SANDSTONE), "Cut Red Sandstone", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_CUT_SANDSTONE), "Cut Sandstone", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_MOSSY_STONE_BRICK), "Mossy Stone Brick", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_SMOOTH_QUARTZ), "Smooth Quartz", $stoneSlabBreakInfo), + new Slab($getStoneSlabId(4, Meta::STONE_SLAB4_STONE), "Stone", $stoneSlabBreakInfo), + ] as $slabType){ + $this->registerSlabWithDoubleHighBitsRemapping($slabType); + } + $this->registerAllMeta(new Opaque(new BID(Ids::STONECUTTER, 0), "Stonecutter", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel()))); $this->registerAllMeta(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BlockBreakInfo::instant())); $this->registerAllMeta(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant())); From 6cbc14f2b23976dc1c3c07188648785a1f5470fb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 25 Jan 2022 21:53:15 +0000 Subject: [PATCH 702/710] World: fixed block update bug introduced by 3faeb5a5568566bccc449855b54495f88473f7fc --- src/world/World.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/World.php b/src/world/World.php index 65ded6fa4..382a3479a 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -493,7 +493,7 @@ class World implements ChunkManager{ foreach(BlockFactory::getInstance()->getAllKnownStates() as $state){ $dontTickName = $dontTickBlocks[$state->getTypeId()] ?? null; - if($dontTickName === null && !$state->ticksRandomly()){ + if($dontTickName === null && $state->ticksRandomly()){ $this->randomTickBlocks[$state->getFullId()] = true; } } From 8a4bc72b3443a61db9a58c51f7aeac14c3d6e42d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 25 Jan 2022 23:33:20 +0000 Subject: [PATCH 703/710] Release 4.0.8 --- changelogs/4.0.md | 7 +++++++ src/VersionInfo.php | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/changelogs/4.0.md b/changelogs/4.0.md index 38c7cbfec..ec6f7fa60 100644 --- a/changelogs/4.0.md +++ b/changelogs/4.0.md @@ -1620,3 +1620,10 @@ Released 21st January 2022. - Fixed ender pearls teleporting players when thrown by a player directly against a wall when cancelling `ProjectileLaunchEvent`. - Fixed collision box of brewing stand. - Fixed break times and tool types of bamboo, nether wart blocks, infested stone and leaves. + +# 4.0.8 +Released 25th January 2022. + +## Fixes +- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe. +- The correct amount of fall damage is now taken when falling from a height onto hay bales. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index 5071c9a2c..f576c457b 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.0.8"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 3ab5b5a79d6363c5781b681e1f3b1b8e79957f2b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 25 Jan 2022 23:33:24 +0000 Subject: [PATCH 704/710] 4.0.9 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index f576c457b..cce49cbb1 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.0.8"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.0.9"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "stable"; private function __construct(){ From 1dbfedce4c8be4d8a6c78906cfd3208994f0b9da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Jan 2022 00:19:02 +0000 Subject: [PATCH 705/710] Bump pocketmine/locale-data from 2.3.33 to 2.4.2 (#4769) Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.3.33 to 2.4.2. - [Release notes](https://github.com/pmmp/Language/releases) - [Commits](https://github.com/pmmp/Language/compare/2.3.33...2.4.2) --- updated-dependencies: - dependency-name: pocketmine/locale-data dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 8eecd762e..0d92365c0 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "pocketmine/classloader": "^0.2.0", "pocketmine/color": "^0.2.0", "pocketmine/errorhandler": "^0.3.0", - "pocketmine/locale-data": "~2.3.0", + "pocketmine/locale-data": "~2.4.2", "pocketmine/log": "^0.4.0", "pocketmine/log-pthreads": "^0.4.0", "pocketmine/math": "^0.4.0", diff --git a/composer.lock b/composer.lock index 267df8983..9ae9291c5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "055bec16a9bbc839f4410d09b09f2703", + "content-hash": "aabbf0c3280f590f48d2edb622747341", "packages": [ { "name": "adhocore/json-comment", @@ -535,16 +535,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.3.33", + "version": "2.4.2", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "44998ca9c055f872a33e59cd4d2736d081ba84b5" + "reference": "235694bfbef1343d7a7934974bca0726d9fdc4d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/44998ca9c055f872a33e59cd4d2736d081ba84b5", - "reference": "44998ca9c055f872a33e59cd4d2736d081ba84b5", + "url": "https://api.github.com/repos/pmmp/Language/zipball/235694bfbef1343d7a7934974bca0726d9fdc4d2", + "reference": "235694bfbef1343d7a7934974bca0726d9fdc4d2", "shasum": "" }, "type": "library", @@ -552,9 +552,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.3.33" + "source": "https://github.com/pmmp/Language/tree/2.4.2" }, - "time": "2022-01-16T22:08:04+00:00" + "time": "2022-01-24T17:00:08+00:00" }, { "name": "pocketmine/log", From 3155c9039631eb84b521ca9cac210e5ed2d719ee Mon Sep 17 00:00:00 2001 From: Rush2929 <76860328+Rush2929@users.noreply.github.com> Date: Wed, 26 Jan 2022 09:25:00 +0900 Subject: [PATCH 706/710] Fixed incorrect drops for Cobweb (#4759) --- src/block/Cobweb.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/block/Cobweb.php b/src/block/Cobweb.php index 680af1595..785db721d 100644 --- a/src/block/Cobweb.php +++ b/src/block/Cobweb.php @@ -39,6 +39,9 @@ class Cobweb extends Flowable{ } public function getDropsForCompatibleTool(Item $item) : array{ + if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0){ + return [$this->asItem()]; + } return [ VanillaItems::STRING() ]; From 822af4f7f5f9459c7d390e787c3cc6cb9d1b0b98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Jan 2022 00:45:05 +0000 Subject: [PATCH 707/710] Bump pocketmine/locale-data from 2.4.2 to 2.4.3 (#4773) Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.4.2 to 2.4.3. - [Release notes](https://github.com/pmmp/Language/releases) - [Commits](https://github.com/pmmp/Language/compare/2.4.2...2.4.3) --- updated-dependencies: - dependency-name: pocketmine/locale-data dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 9ae9291c5..9339809ec 100644 --- a/composer.lock +++ b/composer.lock @@ -535,16 +535,16 @@ }, { "name": "pocketmine/locale-data", - "version": "2.4.2", + "version": "2.4.3", "source": { "type": "git", "url": "https://github.com/pmmp/Language.git", - "reference": "235694bfbef1343d7a7934974bca0726d9fdc4d2" + "reference": "4d0b081f1a79407e087968ea76aaf330db6ea2b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Language/zipball/235694bfbef1343d7a7934974bca0726d9fdc4d2", - "reference": "235694bfbef1343d7a7934974bca0726d9fdc4d2", + "url": "https://api.github.com/repos/pmmp/Language/zipball/4d0b081f1a79407e087968ea76aaf330db6ea2b5", + "reference": "4d0b081f1a79407e087968ea76aaf330db6ea2b5", "shasum": "" }, "type": "library", @@ -552,9 +552,9 @@ "description": "Language resources used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/Language/issues", - "source": "https://github.com/pmmp/Language/tree/2.4.2" + "source": "https://github.com/pmmp/Language/tree/2.4.3" }, - "time": "2022-01-24T17:00:08+00:00" + "time": "2022-01-25T23:18:24+00:00" }, { "name": "pocketmine/log", From d9ea6479258277bd71138f70b0aac0ea4fc99614 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 27 Jan 2022 00:28:54 +0000 Subject: [PATCH 708/710] InGamePacketHandler: add a hack for swimming AABB client bug --- src/network/mcpe/handler/InGamePacketHandler.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index dc2a5e468..97d45ee89 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -90,6 +90,8 @@ use pocketmine\network\mcpe\protocol\SubClientLoginPacket; use pocketmine\network\mcpe\protocol\TextPacket; use pocketmine\network\mcpe\protocol\types\ActorEvent; use pocketmine\network\mcpe\protocol\types\BlockPosition; +use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties; +use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty; use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds; use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\NetworkInventoryAction; @@ -222,6 +224,11 @@ class InGamePacketHandler extends PacketHandler{ ($gliding !== null && !$this->player->toggleGlide($gliding)); if((bool) $mismatch){ $this->player->sendData([$this->player]); + }elseif($packet->hasFlag(PlayerAuthInputFlags::STOP_SWIMMING) || $packet->hasFlag(PlayerAuthInputFlags::STOP_GLIDING)){ + //TODO: HACK! workaround for a client bug where the AABB doesn't change back properly when stopping swimming or gliding + $this->player->sendData([$this->player], [ + EntityMetadataProperties::BOUNDING_BOX_HEIGHT => new FloatMetadataProperty($this->player->getSize()->getHeight()) + ]); } if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){ From 1d2593208a81970a3ab9aa8d8cfd03764b0dae74 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 27 Jan 2022 00:55:02 +0000 Subject: [PATCH 709/710] Release 4.1.0-BETA2 --- changelogs/4.1.md | 49 +++++++++++++++++++++++++++++++++++++++++++++ src/VersionInfo.php | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/changelogs/4.1.md b/changelogs/4.1.md index 8565f6909..56829b49d 100644 --- a/changelogs/4.1.md +++ b/changelogs/4.1.md @@ -115,3 +115,52 @@ Released 22nd January 2022. ### Misc - Implemented player swimming. + +# 4.1.0-BETA2 +Released 27th January 2022. + +## API +### Block +- The following API methods have been added: + - `utils\BrewingStandSlot->getSlotNumber() : int` + - `utils\FurnaceType->getCookSound() : Sound` +- The following API constants have been added: + - `tile\BrewingStand::BREW_TIME_TICKS` + +### Crafting +- The following API methods have been added: + - `CraftingManager->getPotionContainerChangeRecipes() : array>` + - `CraftingManager->getPotionTypeRecipes() : array>` + - `CraftingManager->registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void` + - `CraftingManager->registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void` +- The following classes have been added: + - `BrewingRecipe` + - `PotionContainerChangeRecipe` + - `PotionTypeRecipe` + +### Event +- The following classes have been added: + - `BrewItemEvent` - called when a brewing stand finishes brewing potions; this is called up to 3 times (once for each brewing slot, as needed) + - `BrewingFuelUseEvent` - called when a brewing stand consumes blaze powder + - `PlayerViewDistanceChangeEvent` - called whenever a player alters their render distance or requests one for the first time when connecting + +### World +#### Sound +- The following classes have been added: + - `BlastFurnaceSound` - the sound made by a blast furnace during smelting + - `FurnaceSound` - the sound made by a regular furnace during cooking or smelting + - `PotionFinishBrewingSound` - the sound made by a brewing stand when a potion finishes being brewed + - `SmokerSound` - the sound made by a smoker during cooking + +## Gameplay +### Blocks +- Brewing stands can now be used for brewing potions. +- The visual appearance of a brewing stand now updates correctly when the contents of its inventory changes (adding/removing potions). +- Added missing sounds for furnace, blast furnace and smoker. +- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe. +- Cobwebs now drop themselves when mined using shears. +- The correct amount of fall damage is now taken when falling from a height onto hay bales. +- Fixed block updating bug introduced by beta1 which caused crops and other plants to never grow. + +### Misc +- Added a workaround for client hitbox size bug after swimming which caused the player to be able to fit into one-block-tall gaps. diff --git a/src/VersionInfo.php b/src/VersionInfo.php index fe97175aa..cc9d8f975 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -32,7 +32,7 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; public const BASE_VERSION = "4.1.0-BETA2"; - public const IS_DEVELOPMENT_BUILD = true; + public const IS_DEVELOPMENT_BUILD = false; public const BUILD_CHANNEL = "beta"; private function __construct(){ From 6ccb1ff114ce161ff9b9a2d3741502fe7747988d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 27 Jan 2022 00:55:09 +0000 Subject: [PATCH 710/710] 4.1.0-BETA3 is next --- src/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VersionInfo.php b/src/VersionInfo.php index cc9d8f975..4848849e0 100644 --- a/src/VersionInfo.php +++ b/src/VersionInfo.php @@ -31,8 +31,8 @@ use function str_repeat; final class VersionInfo{ public const NAME = "PocketMine-MP"; - public const BASE_VERSION = "4.1.0-BETA2"; - public const IS_DEVELOPMENT_BUILD = false; + public const BASE_VERSION = "4.1.0-BETA3"; + public const IS_DEVELOPMENT_BUILD = true; public const BUILD_CHANNEL = "beta"; private function __construct(){