Compare commits

..

73 Commits

Author SHA1 Message Date
c32c21464c Release 3.22.0 2021-07-13 18:31:28 +01:00
16faafa1ef Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2021-07-13 18:11:03 +01:00
4d6ac57a26 Fixed particle IDs 2021-07-13 17:54:40 +01:00
73ba1ba224 Bump phpstan/phpstan from 0.12.91 to 0.12.92 (#4309)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 0.12.91 to 0.12.92.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/0.12.91...0.12.92)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-12 12:35:35 +01:00
8b79253d3b Protocol changes for 1.17.10 2021-07-09 19:29:34 +01:00
1122131c8d 3.21.2 is next 2021-07-05 18:49:26 +01:00
a50ef2af6f Release 3.21.1 2021-07-05 18:49:26 +01:00
72e4660800 Updated build/php submodule to pmmp/php-build-scripts@4bf8ec1ad0 2021-07-05 18:42:35 +01:00
e6285a0312 Update composer transitive dependencies 2021-07-05 17:22:32 +01:00
5420e76a9a Bump phpstan/phpstan-strict-rules from 0.12.9 to 0.12.10 (#4295) 2021-07-05 13:20:03 +00:00
de46a81cf4 Bump phpstan/phpstan from 0.12.90 to 0.12.91 (#4296)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 0.12.90 to 0.12.91.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/0.12.90...0.12.91)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-05 14:07:49 +01:00
0cdc04f9b5 Player: Fixed so-called 'pot lag'
this occurred because of transactions arriving before MobEquipmentPacket updating the player's own held item slot. This was only a problem while rapidly changing hotbar slots and simultaneously using items, like projectiles.
closes #4168
2021-06-26 18:56:30 +01:00
8b1a84f2bf Bump phpunit/phpunit from 9.5.5 to 9.5.6 (#4282)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.5 to 9.5.6.
- [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.5...9.5.6)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-26 16:49:19 +01:00
155e516f74 phpstan 0.12.90 2021-06-18 18:46:30 +01:00
ea0a47dff7 Updated transitive composer dependency junk 2021-06-18 18:42:08 +01:00
0a6ce18322 CrashDump: Sort plugins list 2021-06-17 20:56:49 +01:00
11d73e5bb8 Bump phpstan/phpstan-phpunit from 0.12.19 to 0.12.20 (#4273)
Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 0.12.19 to 0.12.20.
- [Release notes](https://github.com/phpstan/phpstan-phpunit/releases)
- [Commits](https://github.com/phpstan/phpstan-phpunit/compare/0.12.19...0.12.20)

---
updated-dependencies:
- dependency-name: phpstan/phpstan-phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-17 15:30:01 +01:00
492ad6bb66 3.21.1 is next 2021-06-13 15:38:22 +01:00
82e8eb46ac Release 3.21.0 2021-06-13 15:38:22 +01:00
c7868a810d Move PHP minimum to 7.4
7.3 isn't actively tested anymore, and since 7.4 has been out for so long already, it doesn't make sense to keep pandering to users who can't be bothered to update their PHP binaries.
In most cases, these users are also experiencing problems caused by older versions of pthreads that were long since fixed.
In addition, pthreads is no longer tested or supported on 7.3, so users can't get newer bug fixes even if they wanted to.
2021-06-13 15:34:24 +01:00
2cc22a29c1 Update composer dependencies 2021-06-13 14:40:46 +01:00
8e2829bdd4 Remove movement workaround from 1.14.30 (#4246) 2021-06-13 14:32:40 +01:00
af79e787ea Bump phpstan/phpstan from 0.12.88 to 0.12.89 (#4262)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 0.12.88 to 0.12.89.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/0.12.88...0.12.89)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-10 15:10:45 +01:00
65c53e6512 actions: use PHP 7.4.20 2021-06-09 13:44:00 +01:00
5503fadf13 3.20.1 is next 2021-06-08 20:21:55 +01:00
99964709c9 Release 3.20.0 2021-06-08 20:21:55 +01:00
b85f3bd149 make-release: abort on no changelog changes 2021-06-08 20:20:30 +01:00
57d274901d Protocol changes for 1.17.0 2021-06-08 19:40:28 +01:00
f3e1c82246 this again :thonkingtempered: 2021-06-08 19:27:49 +01:00
908b627846 3.19.4 is next 2021-06-08 18:52:01 +01:00
afb21c1df2 Release 3.19.3 2021-06-08 18:51:48 +01:00
988be2a96b Bump phpunit/phpunit from 9.5.4 to 9.5.5 (#4247)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.4 to 9.5.5.
- [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.4...9.5.5)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-07 21:57:21 +01:00
afe67f7502 Updated build/php submodule to pmmp/php-build-scripts@0a0ac2abb3 2021-06-05 20:18:58 +01:00
b257348a3a Renamed fields of AddEntityPacket and RemoveEntityPacket 2021-06-04 17:18:24 +01:00
12c66d3362 CraftingDataPacket: fixed assert failure on debug builds 2021-06-04 17:13:50 +01:00
92fd2d35a4 SetDisplayObjectivePacket: added order and display slot constants (#4232) 2021-05-24 20:33:24 +01:00
61077c48f1 Worker: fixed quit() usually being useless
Worker::isRunning() returns false after it exits the run() function, even if tasks are stacked and it isn't shutdown.
While this is mostly harmless (since the internal destructor will join the thread anyway), this should be fixed anyway.
2021-05-21 01:24:07 +01:00
e0c61071e1 3.19.3 is next 2021-05-19 22:53:31 +01:00
813d431208 Release 3.19.2 2021-05-19 22:53:30 +01:00
ee112b992d Bump phpstan/phpstan from 0.12.87 to 0.12.88 (#4222)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 0.12.87 to 0.12.88.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/0.12.87...0.12.88)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-19 00:18:48 +01:00
c9b33e2b9f Bump phpstan/phpstan-phpunit from 0.12.18 to 0.12.19 (#4214)
Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 0.12.18 to 0.12.19.
- [Release notes](https://github.com/phpstan/phpstan-phpunit/releases)
- [Commits](https://github.com/phpstan/phpstan-phpunit/compare/0.12.18...0.12.19)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-13 15:17:18 +01:00
2f2be84b12 Bump phpstan/phpstan from 0.12.86 to 0.12.87 (#4217)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 0.12.86 to 0.12.87.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/0.12.86...0.12.87)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-13 12:25:25 +01:00
5a7736b179 actions: go with PHP 7.4.19 2021-05-10 20:30:08 +01:00
e648f1c91e Remove unnecessary script copy 2021-05-10 17:55:52 +01:00
5116e11cea Only install the stuff we need to run PHP, not to build it 2021-05-10 17:55:52 +01:00
9c05e37fbe Bump phpstan/phpstan from 0.12.85 to 0.12.86 (#4212)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 0.12.85 to 0.12.86.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/0.12.85...0.12.86)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-10 16:53:43 +01:00
fb4796f35e Added PhpStorm code style and file templates 2021-05-07 20:44:46 +01:00
0c2ba66078 Updated build/php submodule to pmmp/php-build-scripts@07129c61d6 2021-05-05 22:15:48 +01:00
c29cd8e2eb actions: added PHP script to update versions 2021-05-04 22:21:45 +01:00
a13b0c98a1 Updated to PHP-CS-Fixer 3.0.0 2021-05-04 22:18:18 +01:00
e6ff908e18 actions: update PHP versions 2021-05-04 21:52:17 +01:00
c47ecb55c0 Sign: Do not allow edits by any player except the one who placed it, and only while that player is online
signs now become finalized if:
- the player quits and rejoins (because the entity runtime ID of the player will not be the same)
- the chunk is unloaded and reloaded (because the tagged entity runtime ID is not saved).

closes #4198
2021-05-02 13:22:31 +01:00
c19d2fe891 Bump phpstan/phpstan from 0.12.84 to 0.12.85 (#4199)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 0.12.84 to 0.12.85.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Commits](https://github.com/phpstan/phpstan/compare/0.12.84...0.12.85)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-05-01 23:24:49 +01:00
f195f24f4f Upgrade to GitHub-native Dependabot (#4201) 2021-05-01 23:24:35 +01:00
4b5f279a3e UseItemOnEntityTransactionData: added missing type 2021-04-29 19:13:52 +01:00
89260d788c 3.19.2 is next 2021-04-25 20:34:13 +01:00
a7cd081002 Release 3.19.1 2021-04-25 20:34:13 +01:00
361be8fe36 Normal: drop MOUNTAINS and SMALL_MOUNTAINS from biome selection
this would cause disruption to generation on a patch release, which is unacceptable.
This would be better for 3.20 or 4.0.
2021-04-25 20:27:19 +01:00
b01e4ab417 Bump phpstan/phpstan from 0.12.83 to 0.12.84 (#4189) 2021-04-21 18:49:08 +00:00
177b963d8e TaskScheduler: do not push cancelled repeating tasks back onto the queue 2021-04-19 13:23:31 +01:00
8d1a1628de Item: Remove "ench" tag when all enchantments are removed from an item (#4184)
fixes #4144
2021-04-18 20:56:07 +01:00
6f80b8979d Particle: added some missing IDs 2021-04-16 18:20:47 +01:00
3c8eb29d4e Limit blockitem metadata hack to just blockitems
for some reason putting NBT on some items makes the creative inventory go haywire. Sadly, we currently need this hack, so I limit it to only stuff which actually needs it (blockitems).
closes #4159
2021-04-16 00:41:19 +01:00
b94bbf6f5e Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2021-04-16 00:11:01 +01:00
314a8a1297 protocol: updated particle type constants
closes #4173
2021-04-16 00:10:48 +01:00
547503e8f4 Normal: Fixed bug that never lets mountainous terrain generate (#4170) 2021-04-13 17:56:57 +01:00
f74ff1fcd4 Bump adhocore/json-comment from 1.1.0 to 1.1.2 (#4158)
Bumps [adhocore/json-comment](https://github.com/adhocore/php-json-comment) from 1.1.0 to 1.1.2.
- [Release notes](https://github.com/adhocore/php-json-comment/releases)
- [Changelog](https://github.com/adhocore/php-json-comment/blob/main/CHANGELOG.md)
- [Commits](https://github.com/adhocore/php-json-comment/compare/1.1.0...1.1.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2021-04-11 16:03:41 +01:00
6c351357ab NetworkBinaryStream: bail if finding unexpected trailing data on item extradata
this may help to discover additional bugs and/or missing data on items that we don't know about yet.
2021-04-11 16:02:41 +01:00
3433406cff 3.19.1 is next 2021-04-07 19:03:36 +01:00
b307cd0aa1 Release 3.19.0 2021-04-07 19:03:36 +01:00
c9b83d7276 Protocol changes for 1.16.220 2021-04-07 18:59:01 +01:00
e22b6ff566 Revert "Revert "Backport InventoryTransactionPacket impl from PM4""
This reverts commit c7cdaeae85.
2021-04-07 18:42:07 +01:00
af88f49a21 3.18.3 is next 2021-04-07 18:32:14 +01:00
89 changed files with 2013 additions and 743 deletions

8
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: composer
directory: "/"
schedule:
interval: daily
time: "10:00"
open-pull-requests-limit: 10

View File

@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
php: [7.4.20]
steps:
- uses: actions/checkout@v2 #needed for build.sh
@ -37,7 +37,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
php: [7.4.20]
steps:
- uses: actions/checkout@v2
@ -55,7 +55,7 @@ jobs:
- name: Install cached PHP's dependencies
if: steps.php-build-cache.outputs.cache-hit == 'true'
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
run: ./tests/gh-actions/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
@ -87,7 +87,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
php: [7.4.20]
steps:
- uses: actions/checkout@v2
@ -105,7 +105,7 @@ jobs:
- name: Install cached PHP's dependencies
if: steps.php-build-cache.outputs.cache-hit == 'true'
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
run: ./tests/gh-actions/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
@ -137,7 +137,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
php: [7.4.20]
steps:
- uses: actions/checkout@v2
@ -157,7 +157,7 @@ jobs:
- name: Install cached PHP's dependencies
if: steps.php-build-cache.outputs.cache-hit == 'true'
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
run: ./tests/gh-actions/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
@ -189,7 +189,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [7.3.27, 7.4.16]
php: [7.4.20]
steps:
- uses: actions/checkout@v2
@ -209,7 +209,7 @@ jobs:
- name: Install cached PHP's dependencies
if: steps.php-build-cache.outputs.cache-hit == 'true'
run: chmod +x ./bin/php7/install-dependencies.sh && ./bin/php7/install-dependencies.sh
run: ./tests/gh-actions/install-dependencies.sh
- name: Prefix PHP to PATH
run: echo "$(pwd)/bin/php7/bin" >> $GITHUB_PATH
@ -278,4 +278,4 @@ jobs:
tools: php-cs-fixer
- name: Run PHP-CS-Fixer
run: php-cs-fixer fix --dry-run --diff --diff-format=udiff
run: php-cs-fixer fix --dry-run --diff

View File

@ -0,0 +1,51 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
const VERSIONS = [
"7.3",
"7.4",
"8.0"
];
$workflowFile = file_get_contents(__DIR__ . '/main.yml');
$newWorkflowFile = $workflowFile;
foreach(VERSIONS as $v){
$releaseInfo = file_get_contents("https://secure.php.net/releases?json&version=$v");
if($releaseInfo === false){
throw new \RuntimeException("Failed to contact php.net API");
}
$data = json_decode($releaseInfo, true);
if(!is_array($data) || !isset($data["version"]) || !is_string($data["version"]) || preg_match('/^\d+\.\d+\.\d+(-[A-Za-z\d]+)?$/', $data["version"]) === 0){
throw new \RuntimeException("Invalid data returned by API");
}
$updated = preg_replace("/$v\.\d+/", $data["version"], $newWorkflowFile);
if($updated !== $newWorkflowFile){
echo "Updated $v revision to " . $data["version"] . "\n";
}
$newWorkflowFile = $updated;
}
if($workflowFile !== $newWorkflowFile){
echo "Writing modified workflow file\n";
file_put_contents(__DIR__ . '/main.yml', $newWorkflowFile);
}

5
.gitignore vendored
View File

@ -16,7 +16,9 @@ server.lock
/phpstan.neon
# Common IDEs
.idea/
.idea/*
!.idea/codeStyles/
!.idea/fileTemplates/
nbproject/*
# Windows image file caches
@ -47,3 +49,4 @@ Documentation/*
# php-cs-fixer
/.php_cs.cache
/.php-cs-fixer.cache

71
.idea/codeStyles/Project.xml generated Normal file
View File

@ -0,0 +1,71 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<HTMLCodeStyleSettings>
<option name="HTML_TEXT_WRAP" value="0" />
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="thead,tbody,tfoot" />
</HTMLCodeStyleSettings>
<PHPCodeStyleSettings>
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="true" />
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
<option name="LOWER_CASE_NULL_CONST" value="true" />
<option name="VARIABLE_NAMING_STYLE" value="CAMEL_CASE" />
<option name="SPACES_WITHIN_SHORT_ECHO_TAGS" value="false" />
<option name="SPACE_BEFORE_CLOSURE_LEFT_PARENTHESIS" value="false" />
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
<option name="SPACE_BEFORE_COLON_IN_RETURN_TYPE" value="true" />
</PHPCodeStyleSettings>
<editorconfig>
<option name="ENABLED" value="false" />
</editorconfig>
<codeStyleSettings language="HTML">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JSON">
<indentOptions>
<option name="INDENT_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PHP">
<option name="CLASS_BRACE_STYLE" value="1" />
<option name="METHOD_BRACE_STYLE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
<option name="SPACE_AFTER_TYPE_CAST" value="true" />
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_CLASS_LBRACE" value="false" />
<option name="SPACE_BEFORE_METHOD_LBRACE" value="false" />
<option name="SPACE_BEFORE_IF_LBRACE" value="false" />
<option name="SPACE_BEFORE_ELSE_LBRACE" value="false" />
<option name="SPACE_BEFORE_WHILE_LBRACE" value="false" />
<option name="SPACE_BEFORE_FOR_LBRACE" value="false" />
<option name="SPACE_BEFORE_DO_LBRACE" value="false" />
<option name="SPACE_BEFORE_SWITCH_LBRACE" value="false" />
<option name="SPACE_BEFORE_TRY_LBRACE" value="false" />
<option name="SPACE_BEFORE_CATCH_LBRACE" value="false" />
<option name="SPACE_BEFORE_FINALLY_LBRACE" value="false" />
<option name="SPACE_BEFORE_ELSE_KEYWORD" value="false" />
<option name="SPACE_BEFORE_WHILE_KEYWORD" value="false" />
<option name="SPACE_BEFORE_CATCH_KEYWORD" value="false" />
<option name="SPACE_BEFORE_FINALLY_KEYWORD" value="false" />
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="neon">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -0,0 +1,8 @@
#if(${THROWS_DOC} != "")
/**
${THROWS_DOC}
*/
#end
public function __construct(${PARAM_LIST}) {
${BODY}
}

View File

@ -0,0 +1,6 @@
/** @return $this */
public function set${NAME}(#if (${SCALAR_TYPE_HINT})${SCALAR_TYPE_HINT} #else#end$${PARAM_NAME})#if(${RETURN_TYPE}): self#else#end
{
$this->${FIELD_NAME} = $${PARAM_NAME};
return $this;
}

View File

@ -0,0 +1,3 @@
#if(${TYPE_HINT} != ${RETURN_TYPE} && ${TYPE_HINT} != "")/** @return ${TYPE_HINT} */#end
public ${STATIC} function ${GET_OR_IS}${NAME}()#if(${RETURN_TYPE}): ${RETURN_TYPE}#else#end
{ return #if(${STATIC} == "static")self::$${FIELD_NAME};#else$this->${FIELD_NAME};#end }

View File

@ -0,0 +1,2 @@
public ${STATIC} function set${NAME}(#if (${SCALAR_TYPE_HINT})${SCALAR_TYPE_HINT} #end$${PARAM_NAME})#if (${VOID_RETURN_TYPE}):void #end
{#if (${STATIC} == "static") self::$${FIELD_NAME} = $${PARAM_NAME}; #else $this->${FIELD_NAME} = $${PARAM_NAME}; #end}

View File

View File

@ -0,0 +1,21 @@
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);

View File

@ -0,0 +1,5 @@
#if (${THROWS_DOC} != "")
/**
${THROWS_DOC}
*/
#end

View File

@ -0,0 +1 @@
/** @var ${TYPE_HINT} */

View File

View File

@ -0,0 +1,10 @@
<?php
#parse("PHP File Header.php")
#if (${NAMESPACE})
namespace ${NAMESPACE};
#end
final class ${NAME} {
}

View File

@ -0,0 +1,4 @@
<?php
#parse("PHP File Header.php")

View File

@ -0,0 +1,10 @@
<?php
#parse("PHP File Header.php")
#if (${NAMESPACE})
namespace ${NAMESPACE};
#end
interface ${NAME} {
}

View File

@ -0,0 +1,10 @@
<?php
#parse("PHP File Header.php")
#if (${NAMESPACE})
namespace ${NAMESPACE};
#end
trait ${NAME} {
}

View File

@ -9,7 +9,7 @@ $finder = PhpCsFixer\Finder::create()
->notContains('#ifndef COMPILE') //preprocessor will break if these are changed
->notName('PocketMine.php');
return PhpCsFixer\Config::create()
return (new PhpCsFixer\Config)
->setRiskyAllowed(true)
->setRules([
'align_multiline_comment' => [

View File

@ -69,12 +69,16 @@ function main(array $argv) : void{
$currentVer->getPatch() + 1
));
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
echo "please add appropriate notes to the changelog and press enter...";
fgets(STDIN);
system('git add "' . dirname(__DIR__) . '/changelogs"');
system('git diff --cached --quiet "' . dirname(__DIR__) . '/changelogs"', $result);
if($result === 0){
echo "error: no changelog changes detected; aborting\n";
exit(1);
}
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false);
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
system('git tag ' . $currentVer->getBaseVersion());
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true);

31
changelogs/3.19.md Normal file
View File

@ -0,0 +1,31 @@
**For Minecraft: Bedrock Edition 1.16.220**
### 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.19.0
- Added support for Minecraft: Bedrock Edition 1.16.220.
- Removed compatibility with earlier versions.
## Known issues (please don't open issues for these)
- Walls don't connect to each other
- Pumpkin and melon stems may not connect to their corresponding pumpkin/melon
- New blocks, items & mobs aren't implemented
- Nether doesn't exist
# 3.19.1
- Fixed some particles not working since 1.16.220.
- Fixed issues with creative inventory items appearing in the wrong places since 1.16.220.
- `Item->removeEnchantment()` now removes the `ench` tag from item NBT when removing the only enchantment on an item.
- Fixed temporary memory leak of repeating tasks which cancelled themselves during their `onRun()` handler (they were pushed back onto the task queue even though cancelled, and only removed at their next attempted repeat).
# 3.19.2
- Signs can now only be edited by the player who placed them. They will become finalized if the chunk containing them is unloaded and reloaded, or if the creating player quits the server.
# 3.19.3
- Fixed `Worker->quit()` returning without stopping the thread.
- Added some protocol constants in `SetDisplayObjectivePacket`.
- Fixed possible client crash caused by `CraftingDataPacket`.

11
changelogs/3.20.md Normal file
View File

@ -0,0 +1,11 @@
**For Minecraft: Bedrock Edition 1.17.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.20.0
- Added support for Minecraft: Bedrock Edition 1.17.0
- Removed compatibility with earlier versions.

15
changelogs/3.21.md Normal file
View File

@ -0,0 +1,15 @@
**For Minecraft: Bedrock Edition 1.17.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.21.0
- PHP 7.4 is now required as a minimum.
- A workaround for player movement added in 1.14.30 has been removed.
# 3.21.1
- Fixed so-called 'pot lag' - a bug that could occur when using items while rapidly switching hotbar slots.
- Plugins in crashdumps are now ordered alphabetically for easier reading.

11
changelogs/3.22.md Normal file
View File

@ -0,0 +1,11 @@
**For Minecraft: Bedrock Edition 1.17.10**
### 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.22.0
- Added support for Minecraft: Bedrock Edition 1.17.10.
- Removed compatibility with earlier versions.

View File

@ -5,7 +5,7 @@
"homepage": "https://pmmp.io",
"license": "LGPL-3.0",
"require": {
"php": "^7.3 || ^8.0",
"php": "^7.4 || ^8.0",
"php-64bit": "*",
"ext-ctype": "*",
"ext-curl": "*",
@ -38,7 +38,7 @@
"pocketmine/spl": "^0.4.0"
},
"require-dev": {
"phpstan/phpstan": "0.12.83",
"phpstan/phpstan": "0.12.92",
"phpstan/phpstan-phpunit": "^0.12.6",
"phpstan/phpstan-strict-rules": "^0.12.2",
"phpunit/phpunit": "^9.2"
@ -60,7 +60,7 @@
},
"config": {
"platform": {
"php": "7.3.0"
"php": "7.4.0"
},
"sort-packages": true
},

132
composer.lock generated
View File

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c07802390fc058bf06b3a1741ef7c08e",
"content-hash": "79b082334bd3930d7eef49be9b70e59f",
"packages": [
{
"name": "adhocore/json-comment",
"version": "1.1.0",
"version": "1.1.2",
"source": {
"type": "git",
"url": "https://github.com/adhocore/php-json-comment.git",
"reference": "cf7998124d1050b83d7d985447fefd630e09c1a2"
"reference": "fc2f76979f0a44a5f5bc2a2b600d0762fe0e78e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/cf7998124d1050b83d7d985447fefd630e09c1a2",
"reference": "cf7998124d1050b83d7d985447fefd630e09c1a2",
"url": "https://api.github.com/repos/adhocore/php-json-comment/zipball/fc2f76979f0a44a5f5bc2a2b600d0762fe0e78e7",
"reference": "fc2f76979f0a44a5f5bc2a2b600d0762fe0e78e7",
"shasum": ""
},
"require": {
@ -51,7 +51,7 @@
],
"support": {
"issues": "https://github.com/adhocore/php-json-comment/issues",
"source": "https://github.com/adhocore/php-json-comment/tree/1.1.0"
"source": "https://github.com/adhocore/php-json-comment/tree/1.1.2"
},
"funding": [
{
@ -59,7 +59,7 @@
"type": "custom"
}
],
"time": "2021-04-05T13:11:13+00:00"
"time": "2021-04-09T03:06:06+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -617,16 +617,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.10.4",
"version": "v4.11.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e"
"reference": "fe14cf3672a149364fb66dfe11bf6549af899f94"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e",
"reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/fe14cf3672a149364fb66dfe11bf6549af899f94",
"reference": "fe14cf3672a149364fb66dfe11bf6549af899f94",
"shasum": ""
},
"require": {
@ -667,9 +667,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.11.0"
},
"time": "2020-12-20T10:01:03+00:00"
"time": "2021-07-03T13:36:55+00:00"
},
{
"name": "phar-io/manifest",
@ -1009,16 +1009,16 @@
},
{
"name": "phpstan/phpstan",
"version": "0.12.83",
"version": "0.12.92",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "4a967cec6efb46b500dd6d768657336a3ffe699f"
"reference": "64d4c5dc8ea96972bc18432d137a330239a5d2b2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/4a967cec6efb46b500dd6d768657336a3ffe699f",
"reference": "4a967cec6efb46b500dd6d768657336a3ffe699f",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/64d4c5dc8ea96972bc18432d137a330239a5d2b2",
"reference": "64d4c5dc8ea96972bc18432d137a330239a5d2b2",
"shasum": ""
},
"require": {
@ -1049,13 +1049,17 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/0.12.83"
"source": "https://github.com/phpstan/phpstan/tree/0.12.92"
},
"funding": [
{
"url": "https://github.com/ondrejmirtes",
"type": "github"
},
{
"url": "https://github.com/phpstan",
"type": "github"
},
{
"url": "https://www.patreon.com/phpstan",
"type": "patreon"
@ -1065,34 +1069,33 @@
"type": "tidelift"
}
],
"time": "2021-04-03T15:35:45+00:00"
"time": "2021-07-10T13:53:49+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "0.12.18",
"version": "0.12.20",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72"
"reference": "efc009981af383eb3303f0ca9868c29acad7ce74"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72",
"reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/efc009981af383eb3303f0ca9868c29acad7ce74",
"reference": "efc009981af383eb3303f0ca9868c29acad7ce74",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"phpstan/phpstan": "^0.12.60"
"phpstan/phpstan": "^0.12.86"
},
"conflict": {
"phpunit/phpunit": "<7.0"
},
"require-dev": {
"phing/phing": "^2.16.3",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-strict-rules": "^0.12.6",
"phpunit/phpunit": "^7.5.20"
"phpunit/phpunit": "^9.5"
},
"type": "phpstan-extension",
"extra": {
@ -1118,22 +1121,22 @@
"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.18"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.20"
},
"time": "2021-03-06T11:51:27+00:00"
"time": "2021-06-17T08:28:30+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "0.12.9",
"version": "0.12.10",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "0705fefc7c9168529fd130e341428f5f10f4f01d"
"reference": "ce82a050f9da4a32e438272907e38cdd04806223"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/0705fefc7c9168529fd130e341428f5f10f4f01d",
"reference": "0705fefc7c9168529fd130e341428f5f10f4f01d",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/ce82a050f9da4a32e438272907e38cdd04806223",
"reference": "ce82a050f9da4a32e438272907e38cdd04806223",
"shasum": ""
},
"require": {
@ -1141,10 +1144,9 @@
"phpstan/phpstan": "^0.12.66"
},
"require-dev": {
"phing/phing": "^2.16.3",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-phpunit": "^0.12.16",
"phpunit/phpunit": "^7.5.20"
"phpunit/phpunit": "^9.5"
},
"type": "phpstan-extension",
"extra": {
@ -1169,9 +1171,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.9"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/0.12.10"
},
"time": "2021-01-13T08:50:28+00:00"
"time": "2021-07-04T14:57:39+00:00"
},
{
"name": "phpunit/php-code-coverage",
@ -1493,16 +1495,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.4",
"version": "9.5.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741"
"reference": "fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c73c6737305e779771147af66c96ca6a7ed8a741",
"reference": "c73c6737305e779771147af66c96ca6a7ed8a741",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb",
"reference": "fb9b8333f14e3dce976a60ef6a7e05c7c7ed8bfb",
"shasum": ""
},
"require": {
@ -1532,7 +1534,7 @@
"sebastian/global-state": "^5.0.1",
"sebastian/object-enumerator": "^4.0.3",
"sebastian/resource-operations": "^3.0.3",
"sebastian/type": "^2.3",
"sebastian/type": "^2.3.4",
"sebastian/version": "^3.0.2"
},
"require-dev": {
@ -1580,7 +1582,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.4"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.6"
},
"funding": [
{
@ -1592,7 +1594,7 @@
"type": "github"
}
],
"time": "2021-03-23T07:16:29+00:00"
"time": "2021-06-23T05:14:38+00:00"
},
{
"name": "sebastian/cli-parser",
@ -2100,16 +2102,16 @@
},
{
"name": "sebastian/global-state",
"version": "5.0.2",
"version": "5.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "a90ccbddffa067b51f574dea6eb25d5680839455"
"reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455",
"reference": "a90ccbddffa067b51f574dea6eb25d5680839455",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49",
"reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49",
"shasum": ""
},
"require": {
@ -2152,7 +2154,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2"
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3"
},
"funding": [
{
@ -2160,7 +2162,7 @@
"type": "github"
}
],
"time": "2020-10-26T15:55:19+00:00"
"time": "2021-06-11T13:31:12+00:00"
},
{
"name": "sebastian/lines-of-code",
@ -2451,16 +2453,16 @@
},
{
"name": "sebastian/type",
"version": "2.3.1",
"version": "2.3.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
"reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2"
"reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2",
"reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8cd8a1c753c90bc1a0f5372170e3e489136f914",
"reference": "b8cd8a1c753c90bc1a0f5372170e3e489136f914",
"shasum": ""
},
"require": {
@ -2495,7 +2497,7 @@
"homepage": "https://github.com/sebastianbergmann/type",
"support": {
"issues": "https://github.com/sebastianbergmann/type/issues",
"source": "https://github.com/sebastianbergmann/type/tree/2.3.1"
"source": "https://github.com/sebastianbergmann/type/tree/2.3.4"
},
"funding": [
{
@ -2503,7 +2505,7 @@
"type": "github"
}
],
"time": "2020-10-26T13:18:59+00:00"
"time": "2021-06-15T12:49:02+00:00"
},
{
"name": "sebastian/version",
@ -2560,16 +2562,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.22.1",
"version": "v1.23.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e"
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e",
"reference": "c6c942b1ac76c82448322025e084cadc56048b4e",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce",
"reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce",
"shasum": ""
},
"require": {
@ -2581,7 +2583,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.22-dev"
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -2619,7 +2621,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0"
},
"funding": [
{
@ -2635,7 +2637,7 @@
"type": "tidelift"
}
],
"time": "2021-01-07T16:49:33+00:00"
"time": "2021-02-19T12:13:01+00:00"
},
{
"name": "theseer/tokenizer",
@ -2752,7 +2754,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": "^7.3 || ^8.0",
"php": "^7.4 || ^8.0",
"php-64bit": "*",
"ext-ctype": "*",
"ext-curl": "*",
@ -2775,7 +2777,7 @@
},
"platform-dev": [],
"platform-overrides": {
"php": "7.3.0"
"php": "7.4.0"
},
"plugin-api-version": "2.0.0"
"plugin-api-version": "2.1.0"
}

View File

@ -46,6 +46,7 @@ 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 microtime;
use function mkdir;
@ -81,6 +82,7 @@ use const FILE_IGNORE_NEW_LINES;
use const JSON_UNESCAPED_SLASHES;
use const PHP_EOL;
use const PHP_OS;
use const SORT_STRING;
class CrashDump{
@ -182,7 +184,9 @@ class CrashDump{
$this->addLine();
$this->addLine("Loaded plugins:");
$this->data["plugins"] = [];
foreach($this->server->getPluginManager()->getPlugins() as $p){
$plugins = $this->server->getPluginManager()->getPlugins();
ksort($plugins, SORT_STRING);
foreach($plugins as $p){
$d = $p->getDescription();
$this->data["plugins"][$d->getName()] = [
"name" => $d->getName(),

View File

@ -152,7 +152,12 @@ use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\DimensionIds;
use pocketmine\network\mcpe\protocol\types\Experiments;
use pocketmine\network\mcpe\protocol\types\GameMode;
use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData;
use pocketmine\network\mcpe\protocol\types\inventory\NormalTransactionData;
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\NetworkInventoryAction;
use pocketmine\network\mcpe\protocol\types\PersonaPieceTintColor;
use pocketmine\network\mcpe\protocol\types\PersonaSkinPiece;
@ -210,6 +215,7 @@ use function min;
use function preg_match;
use function round;
use function spl_object_hash;
use function sprintf;
use function sqrt;
use function strlen;
use function strpos;
@ -413,7 +419,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/** @var float */
protected $lastRightClickTime = 0.0;
/** @var \stdClass|null */
/** @var UseItemTransactionData|null */
protected $lastRightClickData = null;
/**
@ -2274,6 +2280,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$pk->experiments = new Experiments([], false);
$pk->itemTable = ItemTypeDictionary::getInstance()->getEntries();
$pk->playerMovementSettings = new PlayerMovementSettings(PlayerMovementType::LEGACY, 0, false);
$pk->serverSoftwareVersion = sprintf("%s %s", \pocketmine\NAME, \pocketmine\VERSION);
$this->dataPacket($pk);
$this->sendDataPacket(new AvailableActorIdentifiersPacket());
@ -2435,14 +2442,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
/** @var InventoryAction[] $actions */
$actions = [];
$isCraftingPart = false;
foreach($packet->actions as $networkInventoryAction){
foreach($packet->trData->getActions() as $networkInventoryAction){
if(
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_TODO and (
$networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT or
$networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_USE_INGREDIENT
) or (
$this->craftingTransaction !== null &&
!$networkInventoryAction->oldItem->equalsExact($networkInventoryAction->newItem) &&
!$networkInventoryAction->oldItem->getItemStack()->equalsExact($networkInventoryAction->newItem->getItemStack()) &&
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER &&
$networkInventoryAction->windowId === ContainerIds::UI &&
$networkInventoryAction->inventorySlot === UIInventorySlotOffset::CREATED_ITEM_OUTPUT
@ -2493,321 +2500,325 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->craftingTransaction = null;
}
switch($packet->transactionType){
case InventoryTransactionPacket::TYPE_NORMAL:
$this->setUsingItem(false);
$transaction = new InventoryTransaction($this, $actions);
if($packet->trData instanceof NormalTransactionData){
$this->setUsingItem(false);
$transaction = new InventoryTransaction($this, $actions);
try{
$transaction->execute();
}catch(TransactionValidationException $e){
$this->server->getLogger()->debug("Failed to execute inventory transaction from " . $this->getName() . ": " . $e->getMessage());
$this->server->getLogger()->debug("Actions: " . json_encode($packet->actions));
try{
$transaction->execute();
}catch(TransactionValidationException $e){
$this->server->getLogger()->debug("Failed to execute inventory transaction from " . $this->getName() . ": " . $e->getMessage());
$this->server->getLogger()->debug("Actions: " . json_encode($packet->trData->getActions()));
return false;
}
return false;
}
//TODO: fix achievement for getting iron from furnace
//TODO: fix achievement for getting iron from furnace
return true;
case InventoryTransactionPacket::TYPE_MISMATCH:
if(count($packet->actions) > 0){
$this->server->getLogger()->debug("Expected 0 actions for mismatch, got " . count($packet->actions) . ", " . json_encode($packet->actions));
}
$this->setUsingItem(false);
$this->sendAllInventories();
return true;
}elseif($packet->trData instanceof MismatchTransactionData){
if(count($packet->trData->getActions()) > 0){
$this->server->getLogger()->debug("Expected 0 actions for mismatch, got " . count($packet->trData->getActions()) . ", " . json_encode($packet->trData->getActions()));
}
$this->setUsingItem(false);
$this->sendAllInventories();
return true;
case InventoryTransactionPacket::TYPE_USE_ITEM:
$blockVector = new Vector3($packet->trData->x, $packet->trData->y, $packet->trData->z);
$face = $packet->trData->face;
return true;
}elseif($packet->trData instanceof UseItemTransactionData){
$type = $packet->trData->actionType;
switch($type){
case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_BLOCK:
//TODO: start hack for client spam bug
$spamBug = ($this->lastRightClickData !== null and
microtime(true) - $this->lastRightClickTime < 0.1 and //100ms
$this->lastRightClickData->playerPos->distanceSquared($packet->trData->playerPos) < 0.00001 and
$this->lastRightClickData->x === $packet->trData->x and
$this->lastRightClickData->y === $packet->trData->y and
$this->lastRightClickData->z === $packet->trData->z and
$this->lastRightClickData->clickPos->distanceSquared($packet->trData->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 = $packet->trData;
$this->lastRightClickTime = microtime(true);
if($spamBug){
return true;
}
//TODO: end hack for client spam bug
$blockVector = $packet->trData->getBlockPos();
$face = $packet->trData->getFace();
$this->setUsingItem(false);
if(!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13)){
}elseif($this->isCreative()){
$item = $this->inventory->getItemInHand();
if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->clickPos, $this, true)){
return true;
}
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->itemInHand)){
$this->inventory->sendHeldItem($this);
}else{
$item = $this->inventory->getItemInHand();
$oldItem = clone $item;
if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->clickPos, $this, true)){
if(!$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){
$this->inventory->setItemInHand($item);
$this->inventory->sendHeldItem($this->hasSpawned);
}
return true;
}
}
$this->inventory->sendHeldItem($this);
if($blockVector->distanceSquared($this) > 10000){
return true;
}
$target = $this->level->getBlock($blockVector);
$block = $target->getSide($face);
/** @var Block[] $blocks */
$blocks = array_merge($target->getAllSides(), $block->getAllSides()); //getAllSides() on each of these will include $target and $block because they are next to each other
$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);
if($this->inventory->getHeldItemIndex() !== $packet->trData->getHotbarSlot()){
$this->inventory->equipItem($packet->trData->getHotbarSlot());
}
switch($packet->trData->getActionType()){
case UseItemTransactionData::ACTION_CLICK_BLOCK:
//TODO: start hack for client spam bug
$spamBug = ($this->lastRightClickData !== null and
microtime(true) - $this->lastRightClickTime < 0.1 and //100ms
$this->lastRightClickData->getPlayerPos()->distanceSquared($packet->trData->getPlayerPos()) < 0.00001 and
$this->lastRightClickData->getBlockPos()->equals($packet->trData->getBlockPos()) and
$this->lastRightClickData->getClickPos()->distanceSquared($packet->trData->getClickPos()) < 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 = $packet->trData;
$this->lastRightClickTime = microtime(true);
if($spamBug){
return true;
case InventoryTransactionPacket::USE_ITEM_ACTION_BREAK_BLOCK:
$this->doCloseInventory();
}
//TODO: end hack for client spam bug
$this->setUsingItem(false);
if(!$this->canInteract($blockVector->add(0.5, 0.5, 0.5), 13)){
}elseif($this->isCreative()){
$item = $this->inventory->getItemInHand();
if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->getClickPos(), $this, true)){
return true;
}
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->getItemInHand()->getItemStack())){
$this->inventory->sendHeldItem($this);
}else{
$item = $this->inventory->getItemInHand();
$oldItem = clone $item;
if($this->canInteract($blockVector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 7) and $this->level->useBreakOn($blockVector, $item, $this, true)){
if($this->isSurvival()){
if(!$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){
$this->inventory->setItemInHand($item);
$this->inventory->sendHeldItem($this->hasSpawned);
}
$this->exhaust(0.025, PlayerExhaustEvent::CAUSE_MINING);
if($this->level->useItemOn($blockVector, $item, $face, $packet->trData->getClickPos(), $this, true)){
if(!$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){
$this->inventory->setItemInHand($item);
$this->inventory->sendHeldItem($this->hasSpawned);
}
return true;
}
}
$this->inventory->sendContents($this);
$this->inventory->sendHeldItem($this);
$target = $this->level->getBlock($blockVector);
/** @var Block[] $blocks */
$blocks = $target->getAllSides();
$blocks[] = $target;
$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);
foreach($blocks as $b){
$tile = $this->level->getTile($b);
if($tile instanceof Spawnable){
$tile->spawnTo($this);
}
}
$this->inventory->sendHeldItem($this);
if($blockVector->distanceSquared($this) > 10000){
return true;
case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_AIR:
if($this->isUsingItem()){
$slot = $this->inventory->getItemInHand();
if($slot instanceof Consumable and !($slot instanceof MaybeConsumable and !$slot->canBeConsumed())){
$ev = new PlayerItemConsumeEvent($this, $slot);
if($this->hasItemCooldown($slot)){
$ev->setCancelled();
}
$ev->call();
if($ev->isCancelled() or !$this->consumeObject($slot)){
$this->inventory->sendContents($this);
return true;
}
$this->resetItemCooldown($slot);
if($this->isSurvival()){
$slot->pop();
$this->inventory->setItemInHand($slot);
$this->inventory->addItem($slot->getResidue());
}
$this->setUsingItem(false);
}
$target = $this->level->getBlock($blockVector);
$block = $target->getSide($face);
/** @var Block[] $blocks */
$blocks = array_merge($target->getAllSides(), $block->getAllSides()); //getAllSides() on each of these will include $target and $block because they are next to each other
$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);
return true;
case UseItemTransactionData::ACTION_BREAK_BLOCK:
$this->doCloseInventory();
$item = $this->inventory->getItemInHand();
$oldItem = clone $item;
if($this->canInteract($blockVector->add(0.5, 0.5, 0.5), $this->isCreative() ? 13 : 7) and $this->level->useBreakOn($blockVector, $item, $this, true)){
if($this->isSurvival()){
if(!$item->equalsExact($oldItem) and $oldItem->equalsExact($this->inventory->getItemInHand())){
$this->inventory->setItemInHand($item);
$this->inventory->sendHeldItem($this->hasSpawned);
}
}
$directionVector = $this->getDirectionVector();
if($this->isCreative()){
$item = $this->inventory->getItemInHand();
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->itemInHand)){
$this->inventory->sendHeldItem($this);
return true;
}else{
$item = $this->inventory->getItemInHand();
$this->exhaust(0.025, PlayerExhaustEvent::CAUSE_MINING);
}
return true;
}
$ev = new PlayerInteractEvent($this, $item, null, $directionVector, $face, PlayerInteractEvent::RIGHT_CLICK_AIR);
if($this->hasItemCooldown($item) or $this->isSpectator()){
$ev->setCancelled();
$this->inventory->sendContents($this);
$this->inventory->sendHeldItem($this);
$target = $this->level->getBlock($blockVector);
/** @var Block[] $blocks */
$blocks = $target->getAllSides();
$blocks[] = $target;
$this->level->sendBlocks([$this], $blocks, UpdateBlockPacket::FLAG_ALL_PRIORITY);
foreach($blocks as $b){
$tile = $this->level->getTile($b);
if($tile instanceof Spawnable){
$tile->spawnTo($this);
}
}
$ev->call();
if($ev->isCancelled()){
$this->inventory->sendHeldItem($this);
return true;
}
if($item->onClickAir($this, $directionVector)){
$this->resetItemCooldown($item);
return true;
case UseItemTransactionData::ACTION_CLICK_AIR:
if($this->isUsingItem()){
$slot = $this->inventory->getItemInHand();
if($slot instanceof Consumable and !($slot instanceof MaybeConsumable and !$slot->canBeConsumed())){
$ev = new PlayerItemConsumeEvent($this, $slot);
if($this->hasItemCooldown($slot)){
$ev->setCancelled();
}
$ev->call();
if($ev->isCancelled() or !$this->consumeObject($slot)){
$this->inventory->sendContents($this);
return true;
}
$this->resetItemCooldown($slot);
if($this->isSurvival()){
$slot->pop();
$this->inventory->setItemInHand($slot);
$this->inventory->addItem($slot->getResidue());
}
$this->setUsingItem(false);
}
}
$directionVector = $this->getDirectionVector();
if($this->isCreative()){
$item = $this->inventory->getItemInHand();
}elseif(!$this->inventory->getItemInHand()->equals($packet->trData->getItemInHand()->getItemStack())){
$this->inventory->sendHeldItem($this);
return true;
}else{
$item = $this->inventory->getItemInHand();
}
$ev = new PlayerInteractEvent($this, $item, null, $directionVector, $face, PlayerInteractEvent::RIGHT_CLICK_AIR);
if($this->hasItemCooldown($item) or $this->isSpectator()){
$ev->setCancelled();
}
$ev->call();
if($ev->isCancelled()){
$this->inventory->sendHeldItem($this);
return true;
}
if($item->onClickAir($this, $directionVector)){
$this->resetItemCooldown($item);
if($this->isSurvival()){
$this->inventory->setItemInHand($item);
}
}
$this->setUsingItem(true);
return true;
default:
//unknown
break;
}
$this->inventory->sendContents($this);
return false;
}elseif($packet->trData instanceof UseItemOnEntityTransactionData){
$target = $this->level->getEntity($packet->trData->getEntityRuntimeId());
if($target === null){
return false;
}
if($this->inventory->getHeldItemIndex() !== $packet->trData->getHotbarSlot()){
$this->inventory->equipItem($packet->trData->getHotbarSlot());
}
switch($packet->trData->getActionType()){
case UseItemOnEntityTransactionData::ACTION_INTERACT:
break; //TODO
case UseItemOnEntityTransactionData::ACTION_ATTACK:
if(!$target->isAlive()){
return true;
}
if($target instanceof ItemEntity or $target instanceof Arrow){
$this->kick("Attempting to attack an invalid entity");
$this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidEntity", [$this->getName()]));
return false;
}
$cancelled = false;
$heldItem = $this->inventory->getItemInHand();
$oldItem = clone $heldItem;
if(!$this->canInteract($target, 8) or $this->isSpectator()){
$cancelled = true;
}elseif($target instanceof Player){
if(!$this->server->getConfigBool("pvp")){
$cancelled = true;
}
}
$ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints());
$meleeEnchantmentDamage = 0;
/** @var EnchantmentInstance[] $meleeEnchantments */
$meleeEnchantments = [];
foreach($heldItem->getEnchantments() as $enchantment){
$type = $enchantment->getType();
if($type instanceof MeleeWeaponEnchantment and $type->isApplicableTo($target)){
$meleeEnchantmentDamage += $type->getDamageBonus($enchantment->getLevel());
$meleeEnchantments[] = $enchantment;
}
}
$ev->setModifier($meleeEnchantmentDamage, EntityDamageEvent::MODIFIER_WEAPON_ENCHANTMENTS);
if($cancelled){
$ev->setCancelled();
}
if(!$this->isSprinting() and !$this->isFlying() and $this->fallDistance > 0 and !$this->hasEffect(Effect::BLINDNESS) and !$this->isUnderwater()){
$ev->setModifier($ev->getFinalDamage() / 2, EntityDamageEvent::MODIFIER_CRITICAL);
}
$target->attack($ev);
if($ev->isCancelled()){
if($heldItem instanceof Durable and $this->isSurvival()){
$this->inventory->sendContents($this);
}
return true;
}
if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0){
$pk = new AnimatePacket();
$pk->action = AnimatePacket::ACTION_CRITICAL_HIT;
$pk->entityRuntimeId = $target->getId();
$this->server->broadcastPacket($target->getViewers(), $pk);
if($target instanceof Player){
$target->dataPacket($pk);
}
}
foreach($meleeEnchantments as $enchantment){
$type = $enchantment->getType();
assert($type instanceof MeleeWeaponEnchantment);
$type->onPostAttack($this, $target, $enchantment->getLevel());
}
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($target) and $this->isSurvival() and $oldItem->equalsExact($this->inventory->getItemInHand())){ //always fire the hook, even if we are survival
$this->inventory->setItemInHand($heldItem);
}
$this->exhaust(0.3, PlayerExhaustEvent::CAUSE_ATTACK);
}
return true;
default:
break; //unknown
}
$this->inventory->sendContents($this);
return false;
}elseif($packet->trData instanceof ReleaseItemTransactionData){
if($this->inventory->getHeldItemIndex() !== $packet->trData->getHotbarSlot()){
$this->inventory->equipItem($packet->trData->getHotbarSlot());
}
try{
switch($packet->trData->getActionType()){
case ReleaseItemTransactionData::ACTION_RELEASE:
if($this->isUsingItem()){
$item = $this->inventory->getItemInHand();
if($this->hasItemCooldown($item)){
$this->inventory->sendContents($this);
return false;
}
if($item->onReleaseUsing($this)){
$this->resetItemCooldown($item);
$this->inventory->setItemInHand($item);
}
return true;
}
$this->setUsingItem(true);
return true;
break;
default:
//unknown
break;
}
break;
case InventoryTransactionPacket::TYPE_USE_ITEM_ON_ENTITY:
$target = $this->level->getEntity($packet->trData->entityRuntimeId);
if($target === null){
return false;
}
$type = $packet->trData->actionType;
switch($type){
case InventoryTransactionPacket::USE_ITEM_ON_ENTITY_ACTION_INTERACT:
break; //TODO
case InventoryTransactionPacket::USE_ITEM_ON_ENTITY_ACTION_ATTACK:
if(!$target->isAlive()){
return true;
}
if($target instanceof ItemEntity or $target instanceof Arrow){
$this->kick("Attempting to attack an invalid entity");
$this->server->getLogger()->warning($this->getServer()->getLanguage()->translateString("pocketmine.player.invalidEntity", [$this->getName()]));
return false;
}
$cancelled = false;
$heldItem = $this->inventory->getItemInHand();
$oldItem = clone $heldItem;
if(!$this->canInteract($target, 8) or $this->isSpectator()){
$cancelled = true;
}elseif($target instanceof Player){
if(!$this->server->getConfigBool("pvp")){
$cancelled = true;
}
}
$ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints());
$meleeEnchantmentDamage = 0;
/** @var EnchantmentInstance[] $meleeEnchantments */
$meleeEnchantments = [];
foreach($heldItem->getEnchantments() as $enchantment){
$type = $enchantment->getType();
if($type instanceof MeleeWeaponEnchantment and $type->isApplicableTo($target)){
$meleeEnchantmentDamage += $type->getDamageBonus($enchantment->getLevel());
$meleeEnchantments[] = $enchantment;
}
}
$ev->setModifier($meleeEnchantmentDamage, EntityDamageEvent::MODIFIER_WEAPON_ENCHANTMENTS);
if($cancelled){
$ev->setCancelled();
}
if(!$this->isSprinting() and !$this->isFlying() and $this->fallDistance > 0 and !$this->hasEffect(Effect::BLINDNESS) and !$this->isUnderwater()){
$ev->setModifier($ev->getFinalDamage() / 2, EntityDamageEvent::MODIFIER_CRITICAL);
}
$target->attack($ev);
if($ev->isCancelled()){
if($heldItem instanceof Durable and $this->isSurvival()){
$this->inventory->sendContents($this);
}
return true;
}
if($ev->getModifier(EntityDamageEvent::MODIFIER_CRITICAL) > 0){
$pk = new AnimatePacket();
$pk->action = AnimatePacket::ACTION_CRITICAL_HIT;
$pk->entityRuntimeId = $target->getId();
$this->server->broadcastPacket($target->getViewers(), $pk);
if($target instanceof Player){
$target->dataPacket($pk);
}
}
foreach($meleeEnchantments as $enchantment){
$type = $enchantment->getType();
assert($type instanceof MeleeWeaponEnchantment);
$type->onPostAttack($this, $target, $enchantment->getLevel());
}
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($target) and $this->isSurvival() and $oldItem->equalsExact($this->inventory->getItemInHand())){ //always fire the hook, even if we are survival
$this->inventory->setItemInHand($heldItem);
}
$this->exhaust(0.3, PlayerExhaustEvent::CAUSE_ATTACK);
}
return true;
default:
break; //unknown
}
break;
case InventoryTransactionPacket::TYPE_RELEASE_ITEM:
try{
$type = $packet->trData->actionType;
switch($type){
case InventoryTransactionPacket::RELEASE_ITEM_ACTION_RELEASE:
if($this->isUsingItem()){
$item = $this->inventory->getItemInHand();
if($this->hasItemCooldown($item)){
$this->inventory->sendContents($this);
return false;
}
if($item->onReleaseUsing($this)){
$this->resetItemCooldown($item);
$this->inventory->setItemInHand($item);
}
}else{
break;
}
return true;
default:
break;
}
}finally{
$this->setUsingItem(false);
}
$this->inventory->sendContents($this);
break;
default:
$this->inventory->sendContents($this);
break;
}finally{
$this->setUsingItem(false);
}
$this->inventory->sendContents($this);
return false;
}else{
$this->inventory->sendContents($this);
return false;
}
return false; //TODO
}
public function handleMobEquipment(MobEquipmentPacket $packet) : bool{
@ -2817,8 +2828,8 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$item = $this->inventory->getItem($packet->hotbarSlot);
if(!$item->equals($packet->item)){
$this->server->getLogger()->debug("Tried to equip " . $packet->item . " but have " . $item . " in target slot");
if(!$item->equals($packet->item->getItemStack())){
$this->server->getLogger()->debug("Tried to equip " . $packet->item->getItemStack() . " but have " . $item . " in target slot");
$this->inventory->sendContents($this);
return false;
}

View File

@ -36,7 +36,7 @@ namespace pocketmine {
require_once __DIR__ . '/VersionInfo.php';
const MIN_PHP_VERSION = "7.3.0";
const MIN_PHP_VERSION = "7.4.0";
/**
* @param string $message

View File

@ -33,6 +33,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
const _VERSION_INFO_INCLUDED = true;
const NAME = "PocketMine-MP";
const BASE_VERSION = "3.18.2";
const BASE_VERSION = "3.22.0";
const IS_DEVELOPMENT_BUILD = false;
const BUILD_NUMBER = 0;

View File

@ -95,7 +95,7 @@ abstract class Worker extends \Worker{
public function quit(){
$this->isKilled = true;
if($this->isRunning()){
if(!$this->isShutdown()){
while($this->unstack() !== null);
$this->notify();
$this->shutdown();

View File

@ -68,7 +68,10 @@ class SignPost extends Transparent{
$this->getLevelNonNull()->setBlock($blockReplace, BlockFactory::get(Block::WALL_SIGN, $this->meta), true);
}
Tile::createTile(Tile::SIGN, $this->getLevelNonNull(), TileSign::createNBT($this, $face, $item, $player));
$sign = Tile::createTile(Tile::SIGN, $this->getLevelNonNull(), TileSign::createNBT($this, $face, $item, $player));
if($player !== null && $sign instanceof TileSign){
$sign->setEditorEntityRuntimeId($player->getId());
}
return true;
}

View File

@ -51,9 +51,9 @@ use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
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;
@ -813,7 +813,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
$pk->motion = $this->getMotion();
$pk->yaw = $this->yaw;
$pk->pitch = $this->pitch;
$pk->item = $this->getInventory()->getItemInHand();
$pk->item = ItemStackWrapper::legacy($this->getInventory()->getItemInHand());
$pk->metadata = $this->propertyManager->getAll();
$player->dataPacket($pk);
@ -830,23 +830,6 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
}
}
public function broadcastMovement(bool $teleport = false) : void{
//TODO: workaround 1.14.30 bug: MoveActor(Absolute|Delta)Packet don't work on players anymore :(
$pk = new MovePlayerPacket();
$pk->entityRuntimeId = $this->getId();
$pk->position = $this->getOffsetPosition($this);
$pk->yaw = $this->yaw;
$pk->pitch = $this->pitch;
$pk->headYaw = $this->yaw;
$pk->mode = $teleport ? MovePlayerPacket::MODE_TELEPORT : MovePlayerPacket::MODE_NORMAL;
//we can't assume that everyone who is using our chunk wants to see this movement,
//because this human might be a player who shouldn't be receiving his own movement.
//this didn't matter when we were able to use MoveActorPacket because
//the client just ignored MoveActor for itself, but it doesn't ignore MovePlayer for itself.
$this->server->broadcastPacket($this->hasSpawned, $pk);
}
public function close() : void{
if(!$this->closed){
if($this->inventory !== null){

View File

@ -30,6 +30,7 @@ use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\Player;
use function get_class;
@ -173,7 +174,7 @@ class ItemEntity extends Entity{
$pk->entityRuntimeId = $this->getId();
$pk->position = $this->asVector3();
$pk->motion = $this->getMotion();
$pk->item = $this->getItem();
$pk->item = ItemStackWrapper::legacy($this->getItem());
$pk->metadata = $this->propertyManager->getAll();
$player->dataPacket($pk);

View File

@ -98,10 +98,10 @@ class ArmorInventory extends BaseInventory{
$pk = new MobArmorEquipmentPacket();
$pk->entityRuntimeId = $this->getHolder()->getId();
$pk->head = $this->getHelmet();
$pk->chest = $this->getChestplate();
$pk->legs = $this->getLeggings();
$pk->feet = $this->getBoots();
$pk->head = ItemStackWrapper::legacy($this->getHelmet());
$pk->chest = ItemStackWrapper::legacy($this->getChestplate());
$pk->legs = ItemStackWrapper::legacy($this->getLeggings());
$pk->feet = ItemStackWrapper::legacy($this->getBoots());
$pk->encode();
foreach($target as $player){
@ -126,10 +126,10 @@ class ArmorInventory extends BaseInventory{
$pk = new MobArmorEquipmentPacket();
$pk->entityRuntimeId = $this->getHolder()->getId();
$pk->head = $this->getHelmet();
$pk->chest = $this->getChestplate();
$pk->legs = $this->getLeggings();
$pk->feet = $this->getBoots();
$pk->head = ItemStackWrapper::legacy($this->getHelmet());
$pk->chest = ItemStackWrapper::legacy($this->getChestplate());
$pk->legs = ItemStackWrapper::legacy($this->getLeggings());
$pk->feet = ItemStackWrapper::legacy($this->getBoots());
$pk->encode();
foreach($target as $player){

View File

@ -30,6 +30,7 @@ use pocketmine\network\mcpe\protocol\CreativeContentPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\Player;
use function array_map;
use function in_array;
@ -165,7 +166,7 @@ class PlayerInventory extends BaseInventory{
$pk = new MobEquipmentPacket();
$pk->entityRuntimeId = $this->getHolder()->getId();
$pk->item = $item;
$pk->item = ItemStackWrapper::legacy($item);
$pk->inventorySlot = $pk->hotbarSlot = $this->getHeldItemIndex();
$pk->windowId = ContainerIds::INVENTORY;

View File

@ -339,7 +339,11 @@ class Item implements ItemIds, \JsonSerializable{
}
}
$this->setNamedTagEntry($ench);
if($ench->getCount() > 0){
$this->setNamedTagEntry($ench);
}else{
$this->removeNamedTagEntry(self::TAG_ENCH);
}
}
public function removeEnchantments() : void{

View File

@ -144,16 +144,9 @@ class Normal extends Generator{
return Biome::BIRCH_FOREST;
}
}else{
//FIXME: This will always cause River to be used since the rainfall is always greater than 0.8 if we
//reached this branch. However I don't think that substituting temperature for rainfall is correct given
//that mountain biomes are supposed to be pretty cold.
if($rainfall < 0.25){
return Biome::MOUNTAINS;
}elseif($rainfall < 0.70){
return Biome::SMALL_MOUNTAINS;
}else{
return Biome::RIVER;
}
//Previously here, we had a (broken) condition to generate mountains, but fixing it would have
//caused generation changes on a patch release, so we can't keep it here for now.
return Biome::RIVER;
}
}
};

View File

@ -31,6 +31,7 @@ use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\utils\UUID;
@ -104,7 +105,7 @@ class FloatingTextParticle extends Particle{
$pk->username = $name;
$pk->entityRuntimeId = $this->entityId;
$pk->position = $this->asVector3(); //TODO: check offset
$pk->item = ItemFactory::get(Item::AIR, 0, 0);
$pk->item = ItemStackWrapper::legacy(ItemFactory::get(Item::AIR, 0, 0));
$flags = (
1 << Entity::DATA_FLAG_IMMOBILE

View File

@ -36,65 +36,79 @@ abstract class Particle extends Vector3{
public const TYPE_EXPLODE = 6;
public const TYPE_EVAPORATION = 7;
public const TYPE_FLAME = 8;
public const TYPE_LAVA = 9;
public const TYPE_LARGE_SMOKE = 10;
public const TYPE_REDSTONE = 11;
public const TYPE_RISING_RED_DUST = 12;
public const TYPE_ITEM_BREAK = 13;
public const TYPE_SNOWBALL_POOF = 14;
public const TYPE_HUGE_EXPLODE = 15;
public const TYPE_HUGE_EXPLODE_SEED = 16;
public const TYPE_MOB_FLAME = 17;
public const TYPE_HEART = 18;
public const TYPE_TERRAIN = 19;
public const TYPE_SUSPENDED_TOWN = 20, TYPE_TOWN_AURA = 20;
public const TYPE_PORTAL = 21;
//22 same as 21
public const TYPE_SPLASH = 23, TYPE_WATER_SPLASH = 23;
public const TYPE_WATER_SPLASH_MANUAL = 24;
public const TYPE_WATER_WAKE = 25;
public const TYPE_DRIP_WATER = 26;
public const TYPE_DRIP_LAVA = 27;
public const TYPE_DRIP_HONEY = 28;
public const TYPE_FALLING_DUST = 29, TYPE_DUST = 29;
public const TYPE_MOB_SPELL = 30;
public const TYPE_MOB_SPELL_AMBIENT = 31;
public const TYPE_MOB_SPELL_INSTANTANEOUS = 32;
public const TYPE_INK = 33;
public const TYPE_SLIME = 34;
public const TYPE_RAIN_SPLASH = 35;
public const TYPE_VILLAGER_ANGRY = 36;
public const TYPE_VILLAGER_HAPPY = 37;
public const TYPE_ENCHANTMENT_TABLE = 38;
public const TYPE_TRACKING_EMITTER = 39;
public const TYPE_NOTE = 40;
public const TYPE_WITCH_SPELL = 41;
public const TYPE_CARROT = 42;
public const TYPE_MOB_APPEARANCE = 43;
public const TYPE_END_ROD = 44;
public const TYPE_DRAGONS_BREATH = 45;
public const TYPE_SPIT = 46;
public const TYPE_TOTEM = 47;
public const TYPE_FOOD = 48;
public const TYPE_FIREWORKS_STARTER = 49;
public const TYPE_FIREWORKS_SPARK = 50;
public const TYPE_FIREWORKS_OVERLAY = 51;
public const TYPE_BALLOON_GAS = 52;
public const TYPE_COLORED_FLAME = 53;
public const TYPE_SPARKLER = 54;
public const TYPE_CONDUIT = 55;
public const TYPE_BUBBLE_COLUMN_UP = 56;
public const TYPE_BUBBLE_COLUMN_DOWN = 57;
public const TYPE_SNEEZE = 58;
public const TYPE_SHULKER_BULLET = 59;
public const TYPE_BLEACH = 60;
public const TYPE_DRAGON_DESTROY_BLOCK = 61;
public const TYPE_MYCELIUM_DUST = 62;
public const TYPE_FALLING_RED_DUST = 63;
public const TYPE_CAMPFIRE_SMOKE = 64;
public const TYPE_TALL_CAMPFIRE_SMOKE = 65;
public const TYPE_DRAGON_BREATH_FIRE = 66;
public const TYPE_DRAGON_BREATH_TRAIL = 67;
public const TYPE_CANDLE_FLAME = 9;
public const TYPE_LAVA = 10;
public const TYPE_LARGE_SMOKE = 11;
public const TYPE_REDSTONE = 12;
public const TYPE_RISING_RED_DUST = 13;
public const TYPE_ITEM_BREAK = 14;
public const TYPE_SNOWBALL_POOF = 15;
public const TYPE_HUGE_EXPLODE = 16;
public const TYPE_HUGE_EXPLODE_SEED = 17;
public const TYPE_MOB_FLAME = 18;
public const TYPE_HEART = 19;
public const TYPE_TERRAIN = 20;
public const TYPE_SUSPENDED_TOWN = 21, TYPE_TOWN_AURA = 21;
public const TYPE_PORTAL = 22;
//23 same as 22
public const TYPE_SPLASH = 24, TYPE_WATER_SPLASH = 24;
public const TYPE_WATER_SPLASH_MANUAL = 25;
public const TYPE_WATER_WAKE = 26;
public const TYPE_DRIP_WATER = 27;
public const TYPE_DRIP_LAVA = 28;
public const TYPE_DRIP_HONEY = 29;
public const TYPE_STALACTITE_DRIP_WATER = 30;
public const TYPE_STALACTITE_DRIP_LAVA = 31;
public const TYPE_FALLING_DUST = 32, TYPE_DUST = 32;
public const TYPE_MOB_SPELL = 33;
public const TYPE_MOB_SPELL_AMBIENT = 34;
public const TYPE_MOB_SPELL_INSTANTANEOUS = 35;
public const TYPE_INK = 36;
public const TYPE_SLIME = 37;
public const TYPE_RAIN_SPLASH = 38;
public const TYPE_VILLAGER_ANGRY = 39;
public const TYPE_VILLAGER_HAPPY = 40;
public const TYPE_ENCHANTMENT_TABLE = 41;
public const TYPE_TRACKING_EMITTER = 42;
public const TYPE_NOTE = 43;
public const TYPE_WITCH_SPELL = 44;
public const TYPE_CARROT = 45;
public const TYPE_MOB_APPEARANCE = 46;
public const TYPE_END_ROD = 47;
public const TYPE_DRAGONS_BREATH = 48;
public const TYPE_SPIT = 49;
public const TYPE_TOTEM = 50;
public const TYPE_FOOD = 51;
public const TYPE_FIREWORKS_STARTER = 52;
public const TYPE_FIREWORKS_SPARK = 53;
public const TYPE_FIREWORKS_OVERLAY = 54;
public const TYPE_BALLOON_GAS = 55;
public const TYPE_COLORED_FLAME = 56;
public const TYPE_SPARKLER = 57;
public const TYPE_CONDUIT = 58;
public const TYPE_BUBBLE_COLUMN_UP = 59;
public const TYPE_BUBBLE_COLUMN_DOWN = 60;
public const TYPE_SNEEZE = 61;
public const TYPE_SHULKER_BULLET = 62;
public const TYPE_BLEACH = 63;
public const TYPE_DRAGON_DESTROY_BLOCK = 64;
public const TYPE_MYCELIUM_DUST = 65;
public const TYPE_FALLING_RED_DUST = 66;
public const TYPE_CAMPFIRE_SMOKE = 67;
public const TYPE_TALL_CAMPFIRE_SMOKE = 68;
public const TYPE_DRAGON_BREATH_FIRE = 69;
public const TYPE_DRAGON_BREATH_TRAIL = 70;
public const TYPE_BLUE_FLAME = 71;
public const TYPE_SOUL = 72;
public const TYPE_OBSIDIAN_TEAR = 73;
public const TYPE_PORTAL_REVERSE = 74;
public const TYPE_SNOWFLAKE = 75;
public const TYPE_VIBRATION_SIGNAL = 76;
public const TYPE_SCULK_SENSOR_REDSTONE = 77;
public const TYPE_SPORE_BLOSSOM_SHOWER = 78;
public const TYPE_SPORE_BLOSSOM_AMBIENT = 79;
public const TYPE_WAX = 80;
public const TYPE_ELECTRIC_SPARK = 81;
/**
* @return DataPacket|DataPacket[]

View File

@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe;
#include <rules/DataPacket.h>
use pocketmine\block\BlockIds;
use pocketmine\entity\Attribute;
use pocketmine\entity\Entity;
use pocketmine\item\Durable;
@ -32,12 +33,14 @@ use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\ItemIds;
use pocketmine\math\Vector3;
use pocketmine\nbt\LittleEndianNBTStream;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\NamedTag;
use pocketmine\network\mcpe\convert\ItemTranslator;
use pocketmine\network\mcpe\convert\ItemTypeDictionary;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\network\mcpe\protocol\types\GameRuleType;
@ -58,6 +61,7 @@ class NetworkBinaryStream extends BinaryStream{
private const DAMAGE_TAG = "Damage"; //TAG_Int
private const DAMAGE_TAG_CONFLICT_RESOLUTION = "___Damage_ProtocolCollisionResolution___";
private const PM_META_TAG = "___Meta___";
public function getString() : string{
return $this->get($this->getUnsignedVarInt());
@ -193,83 +197,134 @@ class NetworkBinaryStream extends BinaryStream{
$this->putString($image->getData());
}
public function getSlot() : Item{
public function getItemStackWithoutStackId() : Item{
return $this->getItemStack(function() : void{
//NOOP
});
}
public function putItemStackWithoutStackId(Item $item) : void{
$this->putItemStack($item, function() : void{
//NOOP
});
}
/**
* @phpstan-param \Closure(NetworkBinaryStream) : void $readExtraCrapInTheMiddle
*/
public function getItemStack(\Closure $readExtraCrapInTheMiddle) : Item{
$netId = $this->getVarInt();
if($netId === 0){
return ItemFactory::get(0, 0, 0);
}
$auxValue = $this->getVarInt();
$netData = $auxValue >> 8;
$cnt = $auxValue & 0xff;
$cnt = $this->getLShort();
$netData = $this->getUnsignedVarInt();
[$id, $meta] = ItemTranslator::getInstance()->fromNetworkId($netId, $netData);
$nbtLen = $this->getLShort();
$readExtraCrapInTheMiddle($this);
/** @var CompoundTag|null $nbt */
$nbt = null;
if($nbtLen === 0xffff){
$nbtDataVersion = $this->getByte();
if($nbtDataVersion !== 1){
throw new \UnexpectedValueException("Unexpected NBT data version $nbtDataVersion");
$this->getVarInt();
$extraData = new NetworkBinaryStream($this->getString());
return (static function() use ($extraData, $netId, $id, $meta, $cnt) : Item{
$nbtLen = $extraData->getLShort();
/** @var CompoundTag|null $nbt */
$nbt = null;
if($nbtLen === 0xffff){
$nbtDataVersion = $extraData->getByte();
if($nbtDataVersion !== 1){
throw new \UnexpectedValueException("Unexpected NBT data version $nbtDataVersion");
}
$decodedNBT = (new LittleEndianNBTStream())->read($extraData->buffer, false, $extraData->offset, 512);
if(!($decodedNBT instanceof CompoundTag)){
throw new \UnexpectedValueException("Unexpected root tag type for itemstack");
}
$nbt = $decodedNBT;
}elseif($nbtLen !== 0){
throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen");
}
$decodedNBT = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512);
if(!($decodedNBT instanceof CompoundTag)){
throw new \UnexpectedValueException("Unexpected root tag type for itemstack");
//TODO
for($i = 0, $canPlaceOn = $extraData->getLInt(); $i < $canPlaceOn; ++$i){
$extraData->get($extraData->getLShort());
}
$nbt = $decodedNBT;
}elseif($nbtLen !== 0){
throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen");
}
//TODO
for($i = 0, $canPlaceOn = $this->getVarInt(); $i < $canPlaceOn; ++$i){
$this->getString();
}
//TODO
for($i = 0, $canDestroy = $extraData->getLInt(); $i < $canDestroy; ++$i){
$extraData->get($extraData->getLShort());
}
//TODO
for($i = 0, $canDestroy = $this->getVarInt(); $i < $canDestroy; ++$i){
$this->getString();
}
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
$extraData->getLLong(); //"blocking tick" (ffs mojang)
}
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
$this->getVarLong(); //"blocking tick" (ffs mojang)
}
if($nbt !== null){
if($nbt->hasTag(self::DAMAGE_TAG, IntTag::class)){
$meta = $nbt->getInt(self::DAMAGE_TAG);
$nbt->removeTag(self::DAMAGE_TAG);
if(($conflicted = $nbt->getTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION)) !== null){
$nbt->removeTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
$conflicted->setName(self::DAMAGE_TAG);
$nbt->setTag($conflicted);
}elseif($nbt->count() === 0){
$nbt = null;
if(!$extraData->feof()){
throw new \UnexpectedValueException("Unexpected trailing extradata for network item $netId");
}
if($nbt !== null){
if($nbt->hasTag(self::DAMAGE_TAG, IntTag::class)){
$meta = $nbt->getInt(self::DAMAGE_TAG);
$nbt->removeTag(self::DAMAGE_TAG);
if(($conflicted = $nbt->getTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION)) !== null){
$nbt->removeTag(self::DAMAGE_TAG_CONFLICT_RESOLUTION);
$conflicted->setName(self::DAMAGE_TAG);
$nbt->setTag($conflicted);
}elseif($nbt->count() === 0){
$nbt = null;
}
}elseif(($metaTag = $nbt->getTag(self::PM_META_TAG)) instanceof IntTag){
//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.
$meta = $metaTag->getValue();
$nbt->removeTag(self::PM_META_TAG);
if($nbt->count() === 0){
$nbt = null;
}
}
}
}
return ItemFactory::get($id, $meta, $cnt, $nbt);
return ItemFactory::get($id, $meta, $cnt, $nbt);
})();
}
public function putSlot(Item $item) : void{
/**
* @phpstan-param \Closure(NetworkBinaryStream) : void $writeExtraCrapInTheMiddle
*/
public function putItemStack(Item $item, \Closure $writeExtraCrapInTheMiddle) : void{
if($item->getId() === 0){
$this->putVarInt(0);
return;
}
[$netId, $netData] = ItemTranslator::getInstance()->toNetworkId($item->getId(), $item->getDamage());
$coreData = $item->getDamage();
[$netId, $netData] = ItemTranslator::getInstance()->toNetworkId($item->getId(), $coreData);
$this->putVarInt($netId);
$auxValue = (($netData & 0x7fff) << 8) | $item->getCount();
$this->putVarInt($auxValue);
$this->putLShort($item->getCount());
$this->putUnsignedVarInt($netData);
$writeExtraCrapInTheMiddle($this);
$blockRuntimeId = 0;
$isBlockItem = $item->getId() < 256;
if($isBlockItem){
$block = $item->getBlock();
if($block->getId() !== BlockIds::AIR){
$blockRuntimeId = RuntimeBlockMapping::toStaticRuntimeId($block->getId(), $block->getDamage());
}
}
$this->putVarInt($blockRuntimeId);
$nbt = null;
if($item->hasCompoundTag()){
$nbt = clone $item->getNamedTag();
}
if($item instanceof Durable and $item->getDamage() > 0){
if($item instanceof Durable and $coreData > 0){
if($nbt !== null){
if(($existing = $nbt->getTag(self::DAMAGE_TAG)) !== null){
$nbt->removeTag(self::DAMAGE_TAG);
@ -279,23 +334,37 @@ class NetworkBinaryStream extends BinaryStream{
}else{
$nbt = new CompoundTag();
}
$nbt->setInt(self::DAMAGE_TAG, $item->getDamage());
$nbt->setInt(self::DAMAGE_TAG, $coreData);
}elseif($isBlockItem && $coreData !== 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, $coreData);
}
if($nbt !== null){
$this->putLShort(0xffff);
$this->putByte(1); //TODO: NBT data version (?)
$this->put((new NetworkLittleEndianNBTStream())->write($nbt));
}else{
$this->putLShort(0);
}
$this->putString(
(static function() use ($nbt, $netId) : string{
$extraData = new NetworkBinaryStream();
$this->putVarInt(0); //CanPlaceOn entry count (TODO)
$this->putVarInt(0); //CanDestroy entry count (TODO)
if($nbt !== null){
$extraData->putLShort(0xffff);
$extraData->putByte(1); //TODO: NBT data version (?)
$extraData->put((new LittleEndianNBTStream())->write($nbt));
}else{
$extraData->putLShort(0);
}
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
$this->putVarLong(0); //"blocking tick" (ffs mojang)
}
$extraData->putLInt(0); //CanPlaceOn entry count (TODO)
$extraData->putLInt(0); //CanDestroy entry count (TODO)
if($netId === ItemTypeDictionary::getInstance()->fromStringId("minecraft:shield")){
$extraData->putLLong(0); //"blocking tick" (ffs mojang)
}
return $extraData->getBuffer();
})());
}
public function getRecipeIngredient() : Item{
@ -602,14 +671,15 @@ class NetworkBinaryStream extends BinaryStream{
* Reads gamerules
* TODO: implement this properly
*
* @return mixed[][], members are in the structure [name => [type, value]]
* @phpstan-return array<string, array{0: int, 1: bool|int|float}>
* @return mixed[][], members are in the structure [name => [type, value, isPlayerModifiable]]
* @phpstan-return array<string, array{0: int, 1: bool|int|float, 2: bool}>
*/
public function getGameRules() : array{
$count = $this->getUnsignedVarInt();
$rules = [];
for($i = 0; $i < $count; ++$i){
$name = $this->getString();
$isPlayerModifiable = $this->getBool();
$type = $this->getUnsignedVarInt();
$value = null;
switch($type){
@ -624,23 +694,24 @@ class NetworkBinaryStream extends BinaryStream{
break;
}
$rules[$name] = [$type, $value];
$rules[$name] = [$type, $value, $isPlayerModifiable];
}
return $rules;
}
/**
* Writes a gamerule array, members should be in the structure [name => [type, value]]
* Writes a gamerule array, members should be in the structure [name => [type, value, isPlayerModifiable]]
* TODO: implement this properly
*
* @param mixed[][] $rules
* @phpstan-param array<string, array{0: int, 1: bool|int|float}> $rules
* @phpstan-param array<string, array{0: int, 1: bool|int|float, 2: bool}> $rules
*/
public function putGameRules(array $rules) : void{
$this->putUnsignedVarInt(count($rules));
foreach($rules as $name => $rule){
$this->putString($name);
$this->putBool($rule[2]);
$this->putUnsignedVarInt($rule[0]);
switch($rule[0]){
case GameRuleType::BOOL:

View File

@ -31,6 +31,7 @@ use pocketmine\network\mcpe\protocol\AddEntityPacket;
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
use pocketmine\network\mcpe\protocol\AddPaintingPacket;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\AddVolumeEntityPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimateEntityPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
@ -109,6 +110,7 @@ use pocketmine\network\mcpe\protocol\MultiplayerSettingsPacket;
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
use pocketmine\network\mcpe\protocol\NetworkSettingsPacket;
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
use pocketmine\network\mcpe\protocol\NpcDialoguePacket;
use pocketmine\network\mcpe\protocol\NpcRequestPacket;
use pocketmine\network\mcpe\protocol\OnScreenTextureAnimationPacket;
use pocketmine\network\mcpe\protocol\PacketViolationWarningPacket;
@ -130,6 +132,7 @@ use pocketmine\network\mcpe\protocol\PurchaseReceiptPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\RemoveEntityPacket;
use pocketmine\network\mcpe\protocol\RemoveObjectivePacket;
use pocketmine\network\mcpe\protocol\RemoveVolumeEntityPacket;
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
use pocketmine\network\mcpe\protocol\ResourcePackChunkDataPacket;
use pocketmine\network\mcpe\protocol\ResourcePackChunkRequestPacket;
@ -164,6 +167,7 @@ use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
use pocketmine\network\mcpe\protocol\ShowProfilePacket;
use pocketmine\network\mcpe\protocol\ShowStoreOfferPacket;
use pocketmine\network\mcpe\protocol\SimpleEventPacket;
use pocketmine\network\mcpe\protocol\SimulationTypePacket;
use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket;
use pocketmine\network\mcpe\protocol\SpawnParticleEffectPacket;
use pocketmine\network\mcpe\protocol\StartGamePacket;
@ -172,6 +176,7 @@ use pocketmine\network\mcpe\protocol\StructureBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataRequestPacket;
use pocketmine\network\mcpe\protocol\StructureTemplateDataResponsePacket;
use pocketmine\network\mcpe\protocol\SubClientLoginPacket;
use pocketmine\network\mcpe\protocol\SyncActorPropertyPacket;
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\TickSyncPacket;
@ -826,4 +831,24 @@ abstract class NetworkSession{
public function handleClientboundDebugRenderer(ClientboundDebugRendererPacket $packet) : bool{
return false;
}
public function handleSyncActorProperty(SyncActorPropertyPacket $packet) : bool{
return false;
}
public function handleAddVolumeEntity(AddVolumeEntityPacket $packet) : bool{
return false;
}
public function handleRemoveVolumeEntity(RemoveVolumeEntityPacket $packet) : bool{
return false;
}
public function handleSimulationType(SimulationTypePacket $packet) : bool{
return false;
}
public function handleNpcDialogue(NpcDialoguePacket $packet) : bool{
return false;
}
}

View File

@ -85,6 +85,10 @@ final class ItemTranslator{
if(!is_string($oldId) || !is_string($newId)){
throw new AssumptionFailedError("Invalid item table format");
}
if(!isset($legacyStringToIntMap[$oldId])){
//new item without a fixed legacy ID - we can't handle this right now
continue;
}
$simpleMappings[$newId] = $legacyStringToIntMap[$oldId];
}
foreach($legacyStringToIntMap as $stringId => $intId){
@ -128,8 +132,9 @@ final class ItemTranslator{
}elseif(isset($simpleMappings[$stringId])){
$this->simpleCoreToNetMapping[$simpleMappings[$stringId]] = $netId;
$this->simpleNetToCoreMapping[$netId] = $simpleMappings[$stringId];
}elseif($stringId !== "minecraft:unknown"){
throw new \InvalidArgumentException("Unmapped entry " . $stringId);
}else{
//not all items have a legacy mapping - for now, we only support the ones that do
continue;
}
}
}

View File

@ -31,24 +31,24 @@ class AddEntityPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::ADD_ENTITY_PACKET;
/** @var int */
private $uvarint1;
private $entityNetId;
public static function create(int $uvarint1) : self{
public static function create(int $entityNetId) : self{
$result = new self;
$result->uvarint1 = $uvarint1;
$result->entityNetId = $entityNetId;
return $result;
}
public function getUvarint1() : int{
return $this->uvarint1;
public function getEntityNetId() : int{
return $this->entityNetId;
}
protected function decodePayload() : void{
$this->uvarint1 = $this->getUnsignedVarInt();
$this->entityNetId = $this->getUnsignedVarInt();
}
protected function encodePayload() : void{
$this->putUnsignedVarInt($this->uvarint1);
$this->putUnsignedVarInt($this->entityNetId);
}
public function handle(NetworkSession $handler) : bool{

View File

@ -25,9 +25,9 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
class AddItemActorPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ADD_ITEM_ACTOR_PACKET;
@ -36,7 +36,7 @@ class AddItemActorPacket extends DataPacket{
public $entityUniqueId = null; //TODO
/** @var int */
public $entityRuntimeId;
/** @var Item */
/** @var ItemStackWrapper */
public $item;
/** @var Vector3 */
public $position;
@ -53,7 +53,7 @@ class AddItemActorPacket extends DataPacket{
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->item = $this->getSlot();
$this->item = ItemStackWrapper::read($this);
$this->position = $this->getVector3();
$this->motion = $this->getVector3();
$this->metadata = $this->getEntityMetadata();
@ -63,7 +63,7 @@ class AddItemActorPacket extends DataPacket{
protected function encodePayload(){
$this->putEntityUniqueId($this->entityUniqueId ?? $this->entityRuntimeId);
$this->putEntityRuntimeId($this->entityRuntimeId);
$this->putSlot($this->item);
$this->item->write($this);
$this->putVector3($this->position);
$this->putVector3Nullable($this->motion);
$this->putEntityMetadata($this->metadata);

View File

@ -25,11 +25,11 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\DeviceOS;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\utils\UUID;
use function count;
@ -56,7 +56,7 @@ class AddPlayerPacket extends DataPacket{
public $yaw = 0.0;
/** @var float|null */
public $headYaw = null; //TODO
/** @var Item */
/** @var ItemStackWrapper */
public $item;
/**
* @var mixed[][]
@ -98,7 +98,7 @@ class AddPlayerPacket extends DataPacket{
$this->pitch = $this->getLFloat();
$this->yaw = $this->getLFloat();
$this->headYaw = $this->getLFloat();
$this->item = $this->getSlot();
$this->item = ItemStackWrapper::read($this);
$this->metadata = $this->getEntityMetadata();
$this->uvarint1 = $this->getUnsignedVarInt();
@ -129,7 +129,7 @@ class AddPlayerPacket extends DataPacket{
$this->putLFloat($this->pitch);
$this->putLFloat($this->yaw);
$this->putLFloat($this->headYaw ?? $this->yaw);
$this->putSlot($this->item);
$this->item->write($this);
$this->putEntityMetadata($this->metadata);
$this->putUnsignedVarInt($this->uvarint1);

View File

@ -0,0 +1,64 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\NetworkSession;
class AddVolumeEntityPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::ADD_VOLUME_ENTITY_PACKET;
/** @var int */
private $entityNetId;
/** @var CompoundTag */
private $data;
public static function create(int $entityNetId, CompoundTag $data) : self{
$result = new self;
$result->entityNetId = $entityNetId;
$result->data = $data;
return $result;
}
public function getEntityNetId() : int{ return $this->entityNetId; }
public function getData() : CompoundTag{ return $this->data; }
protected function decodePayload() : void{
$this->entityNetId = $this->getUnsignedVarInt();
$this->data = $this->getNbtCompoundRoot();
}
protected function encodePayload() : void{
$this->putUnsignedVarInt($this->entityNetId);
$this->put((new NetworkLittleEndianNBTStream())->write($this->data));
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleAddVolumeEntity($this);
}
}

View File

@ -281,7 +281,7 @@ class AvailableCommandsPacket extends DataPacket{
$retval = new CommandData();
$retval->commandName = $this->getString();
$retval->commandDescription = $this->getString();
$retval->flags = $this->getByte();
$retval->flags = $this->getLShort();
$retval->permission = $this->getByte();
$retval->aliases = $enums[$this->getLInt()] ?? null;
@ -324,7 +324,7 @@ class AvailableCommandsPacket extends DataPacket{
protected function putCommandData(CommandData $data, array $enumIndexes, array $postfixIndexes) : void{
$this->putString($data->commandName);
$this->putString($data->commandDescription);
$this->putByte($data->flags);
$this->putLShort($data->flags);
$this->putByte($data->permission);
if($data->aliases !== null){

View File

@ -91,7 +91,7 @@ class CraftingDataPacket extends DataPacket{
$resultCount = $this->getUnsignedVarInt();
$entry["output"] = [];
for($k = 0; $k < $resultCount; ++$k){
$entry["output"][] = $this->getSlot();
$entry["output"][] = $this->getItemStackWithoutStackId();
}
$entry["uuid"] = $this->getUUID()->toString();
$entry["block"] = $this->getString();
@ -113,7 +113,7 @@ class CraftingDataPacket extends DataPacket{
$resultCount = $this->getUnsignedVarInt();
$entry["output"] = [];
for($k = 0; $k < $resultCount; ++$k){
$entry["output"][] = $this->getSlot();
$entry["output"][] = $this->getItemStackWithoutStackId();
}
$entry["uuid"] = $this->getUUID()->toString();
$entry["block"] = $this->getString();
@ -131,7 +131,7 @@ class CraftingDataPacket extends DataPacket{
[$inputId, $inputData] = ItemTranslator::getInstance()->fromNetworkIdWithWildcardHandling($inputIdNet, $inputMetaNet);
}
$entry["input"] = ItemFactory::get($inputId, $inputData);
$entry["output"] = $out = $this->getSlot();
$entry["output"] = $out = $this->getItemStackWithoutStackId();
if($out->getDamage() === 0x7fff){
$out->setDamage(0); //TODO HACK: some 1.12 furnace recipe outputs have wildcard damage values
}
@ -198,7 +198,7 @@ class CraftingDataPacket extends DataPacket{
$results = $recipe->getResults();
$stream->putUnsignedVarInt(count($results));
foreach($results as $item){
$stream->putSlot($item);
$stream->putItemStackWithoutStackId($item);
}
$stream->put(str_repeat("\x00", 16)); //Null UUID
@ -223,7 +223,7 @@ class CraftingDataPacket extends DataPacket{
$results = $recipe->getResults();
$stream->putUnsignedVarInt(count($results));
foreach($results as $item){
$stream->putSlot($item);
$stream->putItemStackWithoutStackId($item);
}
$stream->put(str_repeat("\x00", 16)); //Null UUID
@ -244,7 +244,7 @@ class CraftingDataPacket extends DataPacket{
}
$stream->putVarInt($netId);
$stream->putVarInt($netData);
$stream->putSlot($recipe->getResult());
$stream->putItemStackWithoutStackId($recipe->getResult());
$stream->putString("furnace"); //TODO: blocktype (no prefix) (this might require internal API breaks)
return CraftingDataPacket::ENTRY_FURNACE_DATA;
}
@ -276,7 +276,7 @@ class CraftingDataPacket extends DataPacket{
$writer = new NetworkBinaryStream();
$counter = 0;
foreach($this->entries as $d){
$entryType = self::writeEntry($d, $writer, $counter++);
$entryType = self::writeEntry($d, $writer, ++$counter);
if($entryType >= 0){
$this->putVarInt($entryType);
$this->put($writer->getBuffer());

View File

@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\utils\UUID;
use function count;
@ -39,9 +39,9 @@ class CraftingEventPacket extends DataPacket{
public $type;
/** @var UUID */
public $id;
/** @var Item[] */
/** @var ItemStackWrapper[] */
public $input = [];
/** @var Item[] */
/** @var ItemStackWrapper[] */
public $output = [];
public function clean(){
@ -57,12 +57,12 @@ class CraftingEventPacket extends DataPacket{
$size = $this->getUnsignedVarInt();
for($i = 0; $i < $size and $i < 128; ++$i){
$this->input[] = $this->getSlot();
$this->input[] = ItemStackWrapper::read($this);
}
$size = $this->getUnsignedVarInt();
for($i = 0; $i < $size and $i < 128; ++$i){
$this->output[] = $this->getSlot();
$this->output[] = ItemStackWrapper::read($this);
}
}
@ -73,12 +73,12 @@ class CraftingEventPacket extends DataPacket{
$this->putUnsignedVarInt(count($this->input));
foreach($this->input as $item){
$this->putSlot($item);
$item->write($this);
}
$this->putUnsignedVarInt(count($this->output));
foreach($this->output as $item){
$this->putSlot($item);
$item->write($this);
}
}

View File

@ -32,7 +32,7 @@ class GameRulesChangedPacket extends DataPacket{
/**
* @var mixed[][]
* @phpstan-var array<string, array{0: int, 1: bool|int|float}>
* @phpstan-var array<string, array{0: int, 1: bool|int|float, 2: bool}>
*/
public $gameRules = [];

View File

@ -25,9 +25,15 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\NetworkSession as PacketHandlerInterface;
use pocketmine\network\mcpe\protocol\types\inventory\InventoryTransactionChangedSlotsHack;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData;
use pocketmine\network\mcpe\protocol\types\inventory\NormalTransactionData;
use pocketmine\network\mcpe\protocol\types\inventory\ReleaseItemTransactionData;
use pocketmine\network\mcpe\protocol\types\inventory\TransactionData;
use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData;
use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData;
use UnexpectedValueException as PacketDecodeException;
use function count;
class InventoryTransactionPacket extends DataPacket{
@ -39,137 +45,64 @@ class InventoryTransactionPacket extends DataPacket{
public const TYPE_USE_ITEM_ON_ENTITY = 3;
public const TYPE_RELEASE_ITEM = 4;
public const USE_ITEM_ACTION_CLICK_BLOCK = 0;
public const USE_ITEM_ACTION_CLICK_AIR = 1;
public const USE_ITEM_ACTION_BREAK_BLOCK = 2;
public const RELEASE_ITEM_ACTION_RELEASE = 0; //bow shoot
public const RELEASE_ITEM_ACTION_CONSUME = 1; //eat food, drink potion
public const USE_ITEM_ON_ENTITY_ACTION_INTERACT = 0;
public const USE_ITEM_ON_ENTITY_ACTION_ATTACK = 1;
/** @var int */
public $requestId;
/** @var InventoryTransactionChangedSlotsHack[] */
public $requestChangedSlots;
/** @var int */
public $transactionType;
/** @var bool */
public $hasItemStackIds;
/** @var NetworkInventoryAction[] */
public $actions = [];
/** @var \stdClass */
/** @var TransactionData */
public $trData;
protected function decodePayload(){
$this->requestId = $this->readGenericTypeNetworkId();
protected function decodePayload() : void{
$in = $this;
$this->requestId = $in->readGenericTypeNetworkId();
$this->requestChangedSlots = [];
if($this->requestId !== 0){
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
$this->requestChangedSlots[] = InventoryTransactionChangedSlotsHack::read($this);
for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){
$this->requestChangedSlots[] = InventoryTransactionChangedSlotsHack::read($in);
}
}
$this->transactionType = $this->getUnsignedVarInt();
$transactionType = $in->getUnsignedVarInt();
$this->hasItemStackIds = $this->getBool();
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->actions[] = $action = (new NetworkInventoryAction())->read($this, $this->hasItemStackIds);
}
$this->trData = new \stdClass();
switch($this->transactionType){
switch($transactionType){
case self::TYPE_NORMAL:
$this->trData = new NormalTransactionData();
break;
case self::TYPE_MISMATCH:
//Regular ComplexInventoryTransaction doesn't read any extra data
$this->trData = new MismatchTransactionData();
break;
case self::TYPE_USE_ITEM:
$this->trData->actionType = $this->getUnsignedVarInt();
$this->getBlockPosition($this->trData->x, $this->trData->y, $this->trData->z);
$this->trData->face = $this->getVarInt();
$this->trData->hotbarSlot = $this->getVarInt();
$this->trData->itemInHand = $this->getSlot();
$this->trData->playerPos = $this->getVector3();
$this->trData->clickPos = $this->getVector3();
$this->trData->blockRuntimeId = $this->getUnsignedVarInt();
$this->trData = new UseItemTransactionData();
break;
case self::TYPE_USE_ITEM_ON_ENTITY:
$this->trData->entityRuntimeId = $this->getEntityRuntimeId();
$this->trData->actionType = $this->getUnsignedVarInt();
$this->trData->hotbarSlot = $this->getVarInt();
$this->trData->itemInHand = $this->getSlot();
$this->trData->playerPos = $this->getVector3();
$this->trData->clickPos = $this->getVector3();
$this->trData = new UseItemOnEntityTransactionData();
break;
case self::TYPE_RELEASE_ITEM:
$this->trData->actionType = $this->getUnsignedVarInt();
$this->trData->hotbarSlot = $this->getVarInt();
$this->trData->itemInHand = $this->getSlot();
$this->trData->headPos = $this->getVector3();
$this->trData = new ReleaseItemTransactionData();
break;
default:
throw new \UnexpectedValueException("Unknown transaction type $this->transactionType");
throw new PacketDecodeException("Unknown transaction type $transactionType");
}
$this->trData->decode($in);
}
protected function encodePayload(){
$this->writeGenericTypeNetworkId($this->requestId);
protected function encodePayload() : void{
$out = $this;
$out->writeGenericTypeNetworkId($this->requestId);
if($this->requestId !== 0){
$this->putUnsignedVarInt(count($this->requestChangedSlots));
$out->putUnsignedVarInt(count($this->requestChangedSlots));
foreach($this->requestChangedSlots as $changedSlots){
$changedSlots->write($this);
$changedSlots->write($out);
}
}
$this->putUnsignedVarInt($this->transactionType);
$out->putUnsignedVarInt($this->trData->getTypeId());
$this->putBool($this->hasItemStackIds);
$this->putUnsignedVarInt(count($this->actions));
foreach($this->actions as $action){
$action->write($this, $this->hasItemStackIds);
}
switch($this->transactionType){
case self::TYPE_NORMAL:
case self::TYPE_MISMATCH:
break;
case self::TYPE_USE_ITEM:
$this->putUnsignedVarInt($this->trData->actionType);
$this->putBlockPosition($this->trData->x, $this->trData->y, $this->trData->z);
$this->putVarInt($this->trData->face);
$this->putVarInt($this->trData->hotbarSlot);
$this->putSlot($this->trData->itemInHand);
$this->putVector3($this->trData->playerPos);
$this->putVector3($this->trData->clickPos);
$this->putUnsignedVarInt($this->trData->blockRuntimeId);
break;
case self::TYPE_USE_ITEM_ON_ENTITY:
$this->putEntityRuntimeId($this->trData->entityRuntimeId);
$this->putUnsignedVarInt($this->trData->actionType);
$this->putVarInt($this->trData->hotbarSlot);
$this->putSlot($this->trData->itemInHand);
$this->putVector3($this->trData->playerPos);
$this->putVector3($this->trData->clickPos);
break;
case self::TYPE_RELEASE_ITEM:
$this->putUnsignedVarInt($this->trData->actionType);
$this->putVarInt($this->trData->hotbarSlot);
$this->putSlot($this->trData->itemInHand);
$this->putVector3($this->trData->headPos);
break;
default:
throw new \InvalidArgumentException("Unknown transaction type $this->transactionType");
}
$this->trData->encode($out);
}
public function handle(NetworkSession $session) : bool{
return $session->handleInventoryTransaction($this);
public function handle(PacketHandlerInterface $handler) : bool{
return $handler->handleInventoryTransaction($this);
}
}

View File

@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
class MobArmorEquipmentPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::MOB_ARMOR_EQUIPMENT_PACKET;
@ -36,29 +36,29 @@ class MobArmorEquipmentPacket extends DataPacket{
//this intentionally doesn't use an array because we don't want any implicit dependencies on internal order
/** @var Item */
/** @var ItemStackWrapper */
public $head;
/** @var Item */
/** @var ItemStackWrapper */
public $chest;
/** @var Item */
/** @var ItemStackWrapper */
public $legs;
/** @var Item */
/** @var ItemStackWrapper */
public $feet;
protected function decodePayload(){
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->head = $this->getSlot();
$this->chest = $this->getSlot();
$this->legs = $this->getSlot();
$this->feet = $this->getSlot();
$this->head = ItemStackWrapper::read($this);
$this->chest = ItemStackWrapper::read($this);
$this->legs = ItemStackWrapper::read($this);
$this->feet = ItemStackWrapper::read($this);
}
protected function encodePayload(){
$this->putEntityRuntimeId($this->entityRuntimeId);
$this->putSlot($this->head);
$this->putSlot($this->chest);
$this->putSlot($this->legs);
$this->putSlot($this->feet);
$this->head->write($this);
$this->chest->write($this);
$this->legs->write($this);
$this->feet->write($this);
}
public function handle(NetworkSession $session) : bool{

View File

@ -25,15 +25,15 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
class MobEquipmentPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::MOB_EQUIPMENT_PACKET;
/** @var int */
public $entityRuntimeId;
/** @var Item */
/** @var ItemStackWrapper */
public $item;
/** @var int */
public $inventorySlot;
@ -44,7 +44,7 @@ class MobEquipmentPacket extends DataPacket{
protected function decodePayload(){
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->item = $this->getSlot();
$this->item = ItemStackWrapper::read($this);
$this->inventorySlot = $this->getByte();
$this->hotbarSlot = $this->getByte();
$this->windowId = $this->getByte();
@ -52,7 +52,7 @@ class MobEquipmentPacket extends DataPacket{
protected function encodePayload(){
$this->putEntityRuntimeId($this->entityRuntimeId);
$this->putSlot($this->item);
$this->item->write($this);
$this->putByte($this->inventorySlot);
$this->putByte($this->hotbarSlot);
$this->putByte($this->windowId);

View File

@ -0,0 +1,87 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class NpcDialoguePacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::NPC_DIALOGUE_PACKET;
public const ACTION_OPEN = 0;
public const ACTION_CLOSE = 1;
private int $npcActorUniqueId;
private int $actionType;
private string $dialogue;
private string $sceneName;
private string $npcName;
private string $actionJson;
public static function create(int $npcActorUniqueId, int $actionType, string $dialogue, string $sceneName, string $npcName, string $actionJson) : self{
$result = new self;
$result->npcActorUniqueId = $npcActorUniqueId;
$result->actionType = $actionType;
$result->dialogue = $dialogue;
$result->sceneName = $sceneName;
$result->npcName = $npcName;
$result->actionJson = $actionJson;
return $result;
}
public function getNpcActorUniqueId() : int{ return $this->npcActorUniqueId; }
public function getActionType() : int{ return $this->actionType; }
public function getDialogue() : string{ return $this->dialogue; }
public function getSceneName() : string{ return $this->sceneName; }
public function getNpcName() : string{ return $this->npcName; }
public function getActionJson() : string{ return $this->actionJson; }
protected function decodePayload() : void{
$this->npcActorUniqueId = $this->getEntityUniqueId();
$this->actionType = $this->getVarInt();
$this->dialogue = $this->getString();
$this->sceneName = $this->getString();
$this->npcName = $this->getString();
$this->actionJson = $this->getString();
}
protected function encodePayload() : void{
$this->putEntityUniqueId($this->npcActorUniqueId);
$this->putVarInt($this->actionType);
$this->putString($this->dialogue);
$this->putString($this->sceneName);
$this->putString($this->npcName);
$this->putString($this->actionJson);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleNpcDialogue($this);
}
}

View File

@ -36,6 +36,7 @@ class NpcRequestPacket extends DataPacket{
public const REQUEST_SET_NAME = 3;
public const REQUEST_SET_SKIN = 4;
public const REQUEST_SET_INTERACTION_TEXT = 5;
public const REQUEST_EXECUTE_OPENING_COMMANDS = 6;
/** @var int */
public $entityRuntimeId;
@ -45,12 +46,14 @@ class NpcRequestPacket extends DataPacket{
public $commandString;
/** @var int */
public $actionType;
public string $sceneName;
protected function decodePayload(){
$this->entityRuntimeId = $this->getEntityRuntimeId();
$this->requestType = $this->getByte();
$this->commandString = $this->getString();
$this->actionType = $this->getByte();
$this->sceneName = $this->getString();
}
protected function encodePayload(){
@ -58,6 +61,7 @@ class NpcRequestPacket extends DataPacket{
$this->putByte($this->requestType);
$this->putString($this->commandString);
$this->putByte($this->actionType);
$this->putString($this->sceneName);
}
public function handle(NetworkSession $session) : bool{

View File

@ -195,6 +195,11 @@ class PacketPool{
static::registerPacket(new ItemComponentPacket());
static::registerPacket(new FilterTextPacket());
static::registerPacket(new ClientboundDebugRendererPacket());
static::registerPacket(new SyncActorPropertyPacket());
static::registerPacket(new AddVolumeEntityPacket());
static::registerPacket(new RemoveVolumeEntityPacket());
static::registerPacket(new SimulationTypePacket());
static::registerPacket(new NpcDialoguePacket());
}
/**

View File

@ -37,11 +37,11 @@ interface ProtocolInfo{
*/
/** Actual Minecraft: PE protocol version */
public const CURRENT_PROTOCOL = 428;
public const CURRENT_PROTOCOL = 448;
/** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */
public const MINECRAFT_VERSION = 'v1.16.210';
public const MINECRAFT_VERSION = 'v1.17.10';
/** Version number sent to clients in ping responses. */
public const MINECRAFT_VERSION_NETWORK = '1.16.210';
public const MINECRAFT_VERSION_NETWORK = '1.17.10';
public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02;
@ -207,5 +207,10 @@ interface ProtocolInfo{
public const ITEM_COMPONENT_PACKET = 0xa2;
public const FILTER_TEXT_PACKET = 0xa3;
public const CLIENTBOUND_DEBUG_RENDERER_PACKET = 0xa4;
public const SYNC_ACTOR_PROPERTY_PACKET = 0xa5;
public const ADD_VOLUME_ENTITY_PACKET = 0xa6;
public const REMOVE_VOLUME_ENTITY_PACKET = 0xa7;
public const SIMULATION_TYPE_PACKET = 0xa8;
public const NPC_DIALOGUE_PACKET = 0xa9;
}

View File

@ -31,24 +31,24 @@ class RemoveEntityPacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::REMOVE_ENTITY_PACKET;
/** @var int */
private $uvarint1;
private $entityNetId;
public static function create(int $uvarint1) : self{
public static function create(int $entityNetId) : self{
$result = new self;
$result->uvarint1 = $uvarint1;
$result->entityNetId = $entityNetId;
return $result;
}
public function getUvarint1() : int{
return $this->uvarint1;
public function getEntityNetId() : int{
return $this->entityNetId;
}
protected function decodePayload() : void{
$this->uvarint1 = $this->getUnsignedVarInt();
$this->entityNetId = $this->getUnsignedVarInt();
}
protected function encodePayload() : void{
$this->putUnsignedVarInt($this->uvarint1);
$this->putUnsignedVarInt($this->entityNetId);
}
public function handle(NetworkSession $handler) : bool{

View File

@ -0,0 +1,55 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class RemoveVolumeEntityPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::REMOVE_VOLUME_ENTITY_PACKET;
/** @var int */
private $entityNetId;
public static function create(int $entityNetId) : self{
$result = new self;
$result->entityNetId = $entityNetId;
return $result;
}
public function getEntityNetId() : int{ return $this->entityNetId; }
protected function decodePayload() : void{
$this->entityNetId = $this->getUnsignedVarInt();
}
protected function encodePayload() : void{
$this->putUnsignedVarInt($this->entityNetId);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleRemoveVolumeEntity($this);
}
}

View File

@ -33,9 +33,11 @@ class ResourcePacksInfoPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::RESOURCE_PACKS_INFO_PACKET;
/** @var bool */
public $mustAccept = false; //if true, forces client to use selected resource packs
public $mustAccept = false; //if true, forces client to choose between accepting packs or being disconnected
/** @var bool */
public $hasScripts = false; //if true, causes disconnect for any platform that doesn't support scripts yet
public bool $forceServerPacks = false;
/** @var ResourcePack[] */
public $behaviorPackEntries = [];
/** @var ResourcePack[] */
@ -44,6 +46,7 @@ class ResourcePacksInfoPacket extends DataPacket{
protected function decodePayload(){
$this->mustAccept = $this->getBool();
$this->hasScripts = $this->getBool();
$this->forceServerPacks = $this->getBool();
$behaviorPackCount = $this->getLShort();
while($behaviorPackCount-- > 0){
$this->getString();
@ -71,6 +74,7 @@ class ResourcePacksInfoPacket extends DataPacket{
protected function encodePayload(){
$this->putBool($this->mustAccept);
$this->putBool($this->hasScripts);
$this->putBool($this->forceServerPacks);
$this->putLShort(count($this->behaviorPackEntries));
foreach($this->behaviorPackEntries as $entry){
$this->putString($entry->getPackId());

View File

@ -30,6 +30,13 @@ use pocketmine\network\mcpe\NetworkSession;
class SetDisplayObjectivePacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SET_DISPLAY_OBJECTIVE_PACKET;
public const DISPLAY_SLOT_LIST = "list";
public const DISPLAY_SLOT_SIDEBAR = "sidebar";
public const DISPLAY_SLOT_BELOW_NAME = "belowname";
public const SORT_ORDER_ASCENDING = 0;
public const SORT_ORDER_DESCENDING = 1;
/** @var string */
public $displaySlot;
/** @var string */

View File

@ -50,6 +50,8 @@ class SetTitlePacket extends DataPacket{
public $stayTime = 0;
/** @var int */
public $fadeOutTime = 0;
public string $xuid = "";
public string $platformOnlineId = "";
protected function decodePayload(){
$this->type = $this->getVarInt();
@ -57,6 +59,8 @@ class SetTitlePacket extends DataPacket{
$this->fadeInTime = $this->getVarInt();
$this->stayTime = $this->getVarInt();
$this->fadeOutTime = $this->getVarInt();
$this->xuid = $this->getString();
$this->platformOnlineId = $this->getString();
}
protected function encodePayload(){
@ -65,6 +69,8 @@ class SetTitlePacket extends DataPacket{
$this->putVarInt($this->fadeInTime);
$this->putVarInt($this->stayTime);
$this->putVarInt($this->fadeOutTime);
$this->putString($this->xuid);
$this->putString($this->platformOnlineId);
}
public function handle(NetworkSession $session) : bool{

View File

@ -0,0 +1,58 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
class SimulationTypePacket extends DataPacket/* implements ClientboundPacket*/{
public const NETWORK_ID = ProtocolInfo::SIMULATION_TYPE_PACKET;
public const GAME = 0;
public const EDITOR = 1;
public const TEST = 2;
private int $type;
public static function create(int $type) : self{
$result = new self;
$result->type = $type;
return $result;
}
public function getType() : int{ return $this->type; }
protected function decodePayload() : void{
$this->type = $this->getByte();
}
protected function encodePayload() : void{
$this->putByte($this->type);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleSimulationType($this);
}
}

View File

@ -104,10 +104,10 @@ class StartGamePacket extends DataPacket{
public $isTexturePacksRequired = true;
/**
* @var mixed[][]
* @phpstan-var array<string, array{0: int, 1: bool|int|float}>
* @phpstan-var array<string, array{0: int, 1: bool|int|float, 2: bool}>
*/
public $gameRules = [ //TODO: implement this
"naturalregeneration" => [GameRuleType::BOOL, false] //Hack for client side regeneration
"naturalregeneration" => [GameRuleType::BOOL, false, false] //Hack for client side regeneration
];
/** @var Experiments */
public $experiments;
@ -176,6 +176,8 @@ class StartGamePacket extends DataPacket{
public $itemTable;
/** @var bool */
public $enableNewInventorySystem = false; //TODO
/** @var string */
public $serverSoftwareVersion;
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
@ -258,6 +260,7 @@ class StartGamePacket extends DataPacket{
$this->multiplayerCorrelationId = $this->getString();
$this->enableNewInventorySystem = $this->getBool();
$this->serverSoftwareVersion = $this->getString();
}
protected function encodePayload(){
@ -337,6 +340,7 @@ class StartGamePacket extends DataPacket{
$this->putString($this->multiplayerCorrelationId);
$this->putBool($this->enableNewInventorySystem);
$this->putString($this->serverSoftwareVersion);
}
public function handle(NetworkSession $session) : bool{

View File

@ -0,0 +1,57 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\NetworkSession;
class SyncActorPropertyPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::SYNC_ACTOR_PROPERTY_PACKET;
/** @var CompoundTag */
private $data;
public static function create(CompoundTag $data) : self{
$result = new self;
$result->data = $data;
return $result;
}
public function getData() : CompoundTag{ return $this->data; }
protected function decodePayload() : void{
$this->data = $this->getNbtCompoundRoot();
}
protected function encodePayload() : void{
$this->put((new NetworkLittleEndianNBTStream())->write($this->data));
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleSyncActorProperty($this);
}
}

View File

@ -30,6 +30,7 @@ use pocketmine\inventory\transaction\action\InventoryAction;
use pocketmine\inventory\transaction\action\SlotChangeAction;
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
use pocketmine\Player;
use function array_key_exists;
@ -79,17 +80,15 @@ class NetworkInventoryAction{
public $sourceFlags = 0;
/** @var int */
public $inventorySlot;
/** @var Item */
/** @var ItemStackWrapper */
public $oldItem;
/** @var Item */
/** @var ItemStackWrapper */
public $newItem;
/** @var int|null */
public $newItemStackId = null;
/**
* @return $this
*/
public function read(NetworkBinaryStream $packet, bool $hasItemStackIds){
public function read(NetworkBinaryStream $packet){
$this->sourceType = $packet->getUnsignedVarInt();
switch($this->sourceType){
@ -109,11 +108,8 @@ class NetworkInventoryAction{
}
$this->inventorySlot = $packet->getUnsignedVarInt();
$this->oldItem = $packet->getSlot();
$this->newItem = $packet->getSlot();
if($hasItemStackIds){
$this->newItemStackId = $packet->readGenericTypeNetworkId();
}
$this->oldItem = ItemStackWrapper::read($packet);
$this->newItem = ItemStackWrapper::read($packet);
return $this;
}
@ -121,7 +117,7 @@ class NetworkInventoryAction{
/**
* @return void
*/
public function write(NetworkBinaryStream $packet, bool $hasItemStackIds){
public function write(NetworkBinaryStream $packet){
$packet->putUnsignedVarInt($this->sourceType);
switch($this->sourceType){
@ -141,14 +137,8 @@ class NetworkInventoryAction{
}
$packet->putUnsignedVarInt($this->inventorySlot);
$packet->putSlot($this->oldItem);
$packet->putSlot($this->newItem);
if($hasItemStackIds){
if($this->newItemStackId === null){
throw new \InvalidStateException("Item stack ID for newItem must be provided");
}
$packet->writeGenericTypeNetworkId($this->newItemStackId);
}
$this->oldItem->write($packet);
$this->newItem->write($packet);
}
/**
@ -157,7 +147,9 @@ class NetworkInventoryAction{
* @throws \UnexpectedValueException
*/
public function createInventoryAction(Player $player){
if($this->oldItem->equalsExact($this->newItem)){
$oldItem = $this->oldItem->getItemStack();
$newItem = $this->newItem->getItemStack();
if($oldItem->equalsExact($newItem)){
//filter out useless noise in 1.13
return null;
}
@ -187,7 +179,7 @@ class NetworkInventoryAction{
$slot = $this->inventorySlot;
}
if($window !== null){
return new SlotChangeAction($window, $slot, $this->oldItem, $this->newItem);
return new SlotChangeAction($window, $slot, $oldItem, $newItem);
}
throw new \UnexpectedValueException("Player " . $player->getName() . " has no open container with window ID $this->windowId");
@ -196,7 +188,7 @@ class NetworkInventoryAction{
throw new \UnexpectedValueException("Only expecting drop-item world actions from the client!");
}
return new DropItemAction($this->newItem);
return new DropItemAction($newItem);
case self::SOURCE_CREATIVE:
switch($this->inventorySlot){
case self::ACTION_MAGIC_SLOT_CREATIVE_DELETE_ITEM:
@ -210,7 +202,7 @@ class NetworkInventoryAction{
}
return new CreativeInventoryAction($this->oldItem, $this->newItem, $type);
return new CreativeInventoryAction($oldItem, $newItem, $type);
case self::SOURCE_TODO:
//These types need special handling.
switch($this->windowId){

View File

@ -56,8 +56,8 @@ final class PlayerAuthInputFlags{
public const WANT_DOWN_SLOW = 18;
public const WANT_UP_SLOW = 19;
public const SPRINTING = 20;
public const ASCEND_SCAFFOLDING = 21;
public const DESCEND_SCAFFOLDING = 22;
public const ASCEND_BLOCK = 21;
public const DESCEND_BLOCK = 22;
public const SNEAK_TOGGLE_DOWN = 23;
public const PERSIST_SNEAK = 24;
public const START_SPRINTING = 25;

View File

@ -44,12 +44,12 @@ final class CreativeContentEntry{
public static function read(NetworkBinaryStream $in) : self{
$entryId = $in->readGenericTypeNetworkId();
$item = $in->getSlot();
$item = $in->getItemStackWithoutStackId();
return new self($entryId, $item);
}
public function write(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->entryId);
$out->putSlot($this->item);
$out->putItemStackWithoutStackId($this->item);
}
}

View File

@ -47,13 +47,22 @@ final class ItemStackWrapper{
public function getItemStack() : Item{ return $this->itemStack; }
public static function read(NetworkBinaryStream $in) : self{
$stackId = $in->readGenericTypeNetworkId();
$stack = $in->getSlot();
$stackId = 0;
$stack = $in->getItemStack(function(NetworkBinaryStream $in) use (&$stackId) : void{
$hasNetId = $in->getBool();
if($hasNetId){
$stackId = $in->readGenericTypeNetworkId();
}
});
return new self($stackId, $stack);
}
public function write(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->stackId);
$out->putSlot($this->itemStack);
$out->putItemStack($this->itemStack, function(NetworkBinaryStream $out) : void{
$out->putBool($this->stackId !== 0);
if($this->stackId !== 0){
$out->writeGenericTypeNetworkId($this->stackId);
}
});
}
}

View File

@ -0,0 +1,50 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use UnexpectedValueException as PacketDecodeException;
use function count;
class MismatchTransactionData extends TransactionData{
public function getTypeId() : int{
return InventoryTransactionPacket::TYPE_MISMATCH;
}
protected function decodeData(PacketSerializer $stream) : void{
if(count($this->actions) > 0){
throw new PacketDecodeException("Mismatch transaction type should not have any actions associated with it, but got " . count($this->actions));
}
}
protected function encodeData(PacketSerializer $stream) : void{
}
public static function new() : self{
return new self; //no arguments
}
}

View File

@ -0,0 +1,54 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
class NormalTransactionData extends TransactionData{
public function getTypeId() : int{
return InventoryTransactionPacket::TYPE_NORMAL;
}
protected function decodeData(PacketSerializer $stream) : void{
}
protected function encodeData(PacketSerializer $stream) : void{
}
/**
* @param NetworkInventoryAction[] $actions
*
* @return NormalTransactionData
*/
public static function new(array $actions) : self{
$result = new self();
$result->actions = $actions;
return $result;
}
}

View File

@ -0,0 +1,91 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
class ReleaseItemTransactionData extends TransactionData{
public const ACTION_RELEASE = 0; //bow shoot
public const ACTION_CONSUME = 1; //eat food, drink potion
/** @var int */
private $actionType;
/** @var int */
private $hotbarSlot;
/** @var ItemStackWrapper */
private $itemInHand;
/** @var Vector3 */
private $headPos;
public function getActionType() : int{
return $this->actionType;
}
public function getHotbarSlot() : int{
return $this->hotbarSlot;
}
public function getItemInHand() : ItemStackWrapper{
return $this->itemInHand;
}
public function getHeadPos() : Vector3{
return $this->headPos;
}
public function getTypeId() : int{
return InventoryTransactionPacket::TYPE_RELEASE_ITEM;
}
protected function decodeData(PacketSerializer $stream) : void{
$this->actionType = $stream->getUnsignedVarInt();
$this->hotbarSlot = $stream->getVarInt();
$this->itemInHand = ItemStackWrapper::read($stream);
$this->headPos = $stream->getVector3();
}
protected function encodeData(PacketSerializer $stream) : void{
$stream->putUnsignedVarInt($this->actionType);
$stream->putVarInt($this->hotbarSlot);
$this->itemInHand->write($stream);
$stream->putVector3($this->headPos);
}
/**
* @param NetworkInventoryAction[] $actions
*/
public static function new(array $actions, int $actionType, int $hotbarSlot, ItemStackWrapper $itemInHand, Vector3 $headPos) : self{
$result = new self;
$result->actions = $actions;
$result->actionType = $actionType;
$result->hotbarSlot = $hotbarSlot;
$result->itemInHand = $itemInHand;
$result->headPos = $headPos;
return $result;
}
}

View File

@ -0,0 +1,72 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
use pocketmine\utils\BinaryDataException;
use UnexpectedValueException as PacketDecodeException;
use function count;
abstract class TransactionData{
/** @var NetworkInventoryAction[] */
protected $actions = [];
/**
* @return NetworkInventoryAction[]
*/
final public function getActions() : array{
return $this->actions;
}
abstract public function getTypeId() : int;
/**
* @throws BinaryDataException
* @throws PacketDecodeException
*/
final public function decode(PacketSerializer $stream) : void{
$actionCount = $stream->getUnsignedVarInt();
for($i = 0; $i < $actionCount; ++$i){
$this->actions[] = (new NetworkInventoryAction())->read($stream);
}
$this->decodeData($stream);
}
/**
* @throws BinaryDataException
* @throws PacketDecodeException
*/
abstract protected function decodeData(PacketSerializer $stream) : void;
final public function encode(PacketSerializer $stream) : void{
$stream->putUnsignedVarInt(count($this->actions));
foreach($this->actions as $action){
$action->write($stream);
}
$this->encodeData($stream);
}
abstract protected function encodeData(PacketSerializer $stream) : void;
}

View File

@ -0,0 +1,109 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
class UseItemOnEntityTransactionData extends TransactionData{
public const ACTION_INTERACT = 0;
public const ACTION_ATTACK = 1;
public const ACTION_ITEM_INTERACT = 2;
/** @var int */
private $entityRuntimeId;
/** @var int */
private $actionType;
/** @var int */
private $hotbarSlot;
/** @var ItemStackWrapper */
private $itemInHand;
/** @var Vector3 */
private $playerPos;
/** @var Vector3 */
private $clickPos;
public function getEntityRuntimeId() : int{
return $this->entityRuntimeId;
}
public function getActionType() : int{
return $this->actionType;
}
public function getHotbarSlot() : int{
return $this->hotbarSlot;
}
public function getItemInHand() : ItemStackWrapper{
return $this->itemInHand;
}
public function getPlayerPos() : Vector3{
return $this->playerPos;
}
public function getClickPos() : Vector3{
return $this->clickPos;
}
public function getTypeId() : int{
return InventoryTransactionPacket::TYPE_USE_ITEM_ON_ENTITY;
}
protected function decodeData(PacketSerializer $stream) : void{
$this->entityRuntimeId = $stream->getEntityRuntimeId();
$this->actionType = $stream->getUnsignedVarInt();
$this->hotbarSlot = $stream->getVarInt();
$this->itemInHand = ItemStackWrapper::read($stream);
$this->playerPos = $stream->getVector3();
$this->clickPos = $stream->getVector3();
}
protected function encodeData(PacketSerializer $stream) : void{
$stream->putEntityRuntimeId($this->entityRuntimeId);
$stream->putUnsignedVarInt($this->actionType);
$stream->putVarInt($this->hotbarSlot);
$this->itemInHand->write($stream);
$stream->putVector3($this->playerPos);
$stream->putVector3($this->clickPos);
}
/**
* @param NetworkInventoryAction[] $actions
*/
public static function new(array $actions, int $entityRuntimeId, int $actionType, int $hotbarSlot, ItemStackWrapper $itemInHand, Vector3 $playerPos, Vector3 $clickPos) : self{
$result = new self;
$result->actions = $actions;
$result->entityRuntimeId = $entityRuntimeId;
$result->actionType = $actionType;
$result->hotbarSlot = $hotbarSlot;
$result->itemInHand = $itemInHand;
$result->playerPos = $playerPos;
$result->clickPos = $clickPos;
return $result;
}
}

View File

@ -0,0 +1,129 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\NetworkBinaryStream as PacketSerializer;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
class UseItemTransactionData extends TransactionData{
public const ACTION_CLICK_BLOCK = 0;
public const ACTION_CLICK_AIR = 1;
public const ACTION_BREAK_BLOCK = 2;
/** @var int */
private $actionType;
/** @var Vector3 */
private $blockPos;
/** @var int */
private $face;
/** @var int */
private $hotbarSlot;
/** @var ItemStackWrapper */
private $itemInHand;
/** @var Vector3 */
private $playerPos;
/** @var Vector3 */
private $clickPos;
/** @var int */
private $blockRuntimeId;
public function getActionType() : int{
return $this->actionType;
}
public function getBlockPos() : Vector3{
return $this->blockPos;
}
public function getFace() : int{
return $this->face;
}
public function getHotbarSlot() : int{
return $this->hotbarSlot;
}
public function getItemInHand() : ItemStackWrapper{
return $this->itemInHand;
}
public function getPlayerPos() : Vector3{
return $this->playerPos;
}
public function getClickPos() : Vector3{
return $this->clickPos;
}
public function getBlockRuntimeId() : int{
return $this->blockRuntimeId;
}
public function getTypeId() : int{
return InventoryTransactionPacket::TYPE_USE_ITEM;
}
protected function decodeData(PacketSerializer $stream) : void{
$this->actionType = $stream->getUnsignedVarInt();
$x = $y = $z = 0;
$stream->getBlockPosition($x, $y, $z);
$this->blockPos = new Vector3($x, $y, $z);
$this->face = $stream->getVarInt();
$this->hotbarSlot = $stream->getVarInt();
$this->itemInHand = ItemStackWrapper::read($stream);
$this->playerPos = $stream->getVector3();
$this->clickPos = $stream->getVector3();
$this->blockRuntimeId = $stream->getUnsignedVarInt();
}
protected function encodeData(PacketSerializer $stream) : void{
$stream->putUnsignedVarInt($this->actionType);
$stream->putBlockPosition($this->blockPos->x, $this->blockPos->y, $this->blockPos->z);
$stream->putVarInt($this->face);
$stream->putVarInt($this->hotbarSlot);
$this->itemInHand->write($stream);
$stream->putVector3($this->playerPos);
$stream->putVector3($this->clickPos);
$stream->putUnsignedVarInt($this->blockRuntimeId);
}
/**
* @param NetworkInventoryAction[] $actions
*/
public static function new(array $actions, int $actionType, Vector3 $blockPos, int $face, int $hotbarSlot, ItemStackWrapper $itemInHand, Vector3 $playerPos, Vector3 $clickPos, int $blockRuntimeId) : self{
$result = new self;
$result->actions = $actions;
$result->actionType = $actionType;
$result->blockPos = $blockPos;
$result->face = $face;
$result->hotbarSlot = $hotbarSlot;
$result->itemInHand = $itemInHand;
$result->playerPos = $playerPos;
$result->clickPos = $clickPos;
$result->blockRuntimeId = $blockRuntimeId;
return $result;
}
}

View File

@ -58,7 +58,7 @@ final class DeprecatedCraftingResultsStackRequestAction extends ItemStackRequest
public static function read(NetworkBinaryStream $in) : self{
$results = [];
for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){
$results[] = $in->getSlot();
$results[] = $in->getItemStackWithoutStackId();
}
$iterations = $in->getByte();
return new self($results, $iterations);
@ -67,7 +67,7 @@ final class DeprecatedCraftingResultsStackRequestAction extends ItemStackRequest
public function write(NetworkBinaryStream $out) : void{
$out->putUnsignedVarInt(count($this->results));
foreach($this->results as $result){
$out->putSlot($result);
$out->putItemStackWithoutStackId($result);
}
$out->putByte($this->iterations);
}

View File

@ -177,7 +177,7 @@ class TaskScheduler{
continue;
}
$task->run($this->currentTick);
if($task->isRepeating()){
if(!$task->isCancelled() && $task->isRepeating()){
$task->setNextRun($this->currentTick + $task->getPeriod());
$this->queue->insert($task, $this->currentTick + $task->getPeriod());
}else{

View File

@ -52,6 +52,9 @@ class Sign extends Spawnable{
/** @var string[] */
protected $text = ["", "", "", ""];
/** @var int|null */
protected $editorEntityRuntimeId = null;
protected function readSaveData(CompoundTag $nbt) : void{
if($nbt->hasTag(self::TAG_TEXT_BLOB, StringTag::class)){ //MCPE 1.2 save format
$this->text = self::fixTextBlob($nbt->getString(self::TAG_TEXT_BLOB));
@ -132,6 +135,22 @@ class Sign extends Spawnable{
return $this->text;
}
/**
* Returns the entity runtime ID of the player who placed this sign. Only the player whose entity ID matches this
* one may edit the sign text.
* This is needed because as of 1.16.220, there is still no reliable way to detect when the MCPE client closed the
* sign edit GUI, so we have no way to know when the text is finalized. This limits editing of the text to only the
* player who placed it, and only while that player is online.
* We can say for sure that the sign is finalized if either of the following occurs:
* - The player quits (after rejoin, the player's entity runtimeID will be different).
* - The chunk is unloaded (on next load, the entity runtimeID will be null, because it's not saved).
*/
public function getEditorEntityRuntimeId() : ?int{ return $this->editorEntityRuntimeId; }
public function setEditorEntityRuntimeId(?int $editorEntityRuntimeId) : void{
$this->editorEntityRuntimeId = $editorEntityRuntimeId;
}
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text));
}
@ -158,6 +177,9 @@ class Sign extends Spawnable{
$removeFormat = $player->getRemoveFormat();
$ev = new SignChangeEvent($this->getBlock(), $player, array_map(function(string $line) use ($removeFormat) : string{ return TextFormat::clean($line, $removeFormat); }, $lines));
if($this->editorEntityRuntimeId === null || $this->editorEntityRuntimeId !== $player->getId()){
$ev->setCancelled();
}
$ev->call();
if(!$ev->isCancelled()){

View File

@ -23,4 +23,3 @@ cd php-build
echo '"pthreads",,"https://github.com/pmmp/pthreads.git",,,"extension",' >> share/php-build/extension/definition
PHP_BUILD_INSTALL_EXTENSION='pthreads=@acc6e52b2144c61c434b62a3cb680d537e06828e 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
cp install-dependencies.sh "$INSTALL_DIR"

View File

@ -0,0 +1,3 @@
#!/bin/bash
sudo apt update && sudo apt install -y \
libzip5

View File

@ -1,7 +1,7 @@
parameters:
ignoreErrors:
-
message: "#^Cannot access offset float\\|int on mixed\\.$#"
message: "#^Cannot access offset \\(float\\|int\\) on mixed\\.$#"
count: 1
path: ../../../src/pocketmine/CrashDump.php

View File

@ -581,7 +581,7 @@ parameters:
path: ../../../src/pocketmine/level/generator/object/TallGrass.php
-
message: "#^Method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:getGameRules\\(\\) should return array\\<string, array\\(int, bool\\|float\\|int\\)\\> but returns array\\<string, array\\(int, bool\\|float\\|int\\|null\\)\\>\\.$#"
message: "#^Method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:getGameRules\\(\\) should return array\\<string, array\\(int, bool\\|float\\|int, bool\\)\\> but returns array\\<string, array\\(int, bool\\|float\\|int\\|null, bool\\)\\>\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php
@ -635,6 +635,11 @@ parameters:
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
@ -680,11 +685,31 @@ parameters:
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

View File

@ -1605,6 +1605,11 @@ parameters:
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

View File

@ -25,12 +25,15 @@ namespace pocketmine\item;
use PHPUnit\Framework\TestCase;
use pocketmine\block\BlockFactory;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\enchantment\EnchantmentInstance;
class ItemTest extends TestCase{
public function setUp() : void{
BlockFactory::init();
ItemFactory::init();
Enchantment::init();
}
/**
@ -61,6 +64,16 @@ class ItemTest extends TestCase{
}
}
/**
* Tests that when all enchantments are removed from an item, the "ench" tag is removed as well
*/
public function testEnchantmentRemoval() : void{
$item = ItemFactory::get(Item::DIAMOND_SWORD);
$item->addEnchantment(new EnchantmentInstance(Enchantment::getEnchantment(Enchantment::SHARPNESS)));
$item->removeEnchantment(Enchantment::SHARPNESS);
self::assertNull($item->getNamedTag()->getTag(Item::TAG_ENCH));
}
/**
* @return mixed[][]
* @phpstan-return list<array{string,int,int}>