Compare commits

...

94 Commits

Author SHA1 Message Date
52b6f1a492 Release 4.12.7 2023-01-08 20:23:15 +00:00
0233e74f4f NetworkSession: micro optimisation - do not check if a debugger is active unless the packet limit is exceeded 2023-01-08 19:45:14 +00:00
dd355c58d8 NetworkSession: fix CS 2023-01-08 19:35:43 +00:00
267032cff9 NetworkSession: do not rate limit packets if a debugging session is active 2023-01-08 19:31:39 +00:00
6cecd690b2 CS 2023-01-07 21:33:53 +00:00
91e38d1f97 NetworkSession: compensate for server lag in batch budgeting 2023-01-07 21:33:34 +00:00
653178c1fd 4.12.7 is next 2023-01-07 16:22:01 +00:00
eb06535ed1 Release 4.12.6 2023-01-07 16:22:01 +00:00
f9bcc8e862 NetworkSession: added a rate-limit for incoming batches 2023-01-07 16:19:02 +00:00
f43ca405d4 4.12.6 is next 2023-01-06 00:44:58 +00:00
d146175d27 Release 4.12.5 2023-01-06 00:44:58 +00:00
3baa5ab712 InGamePacketHandler: removed obsolete workaround 2023-01-06 00:41:57 +00:00
c02bead12b Bump phpstan/phpstan from 1.9.6 to 1.9.7 (#5495)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.9.6 to 1.9.7.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.9.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.9.6...1.9.7)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-05 16:46:45 +00:00
e9ca25c1cb typo 2023-01-05 16:45:56 +00:00
a513cca582 Stop Dependabot from creating PRs for locale-data minor and major versions 2023-01-05 16:45:22 +00:00
9a47c1d401 Bump shivammathur/setup-php from 2.22.0 to 2.23.0 (#5474)
Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.22.0 to 2.23.0.
- [Release notes](https://github.com/shivammathur/setup-php/releases)
- [Commits](https://github.com/shivammathur/setup-php/compare/2.22.0...2.23.0)

---
updated-dependencies:
- dependency-name: shivammathur/setup-php
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-04 20:15:11 +00:00
433f5451d7 Improve World::notifyNeighbourBlockUpdate() doc (#5491) 2023-01-04 20:11:55 +00:00
64e505defb Bump phpstan/phpstan from 1.9.4 to 1.9.6 (#5492)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.9.4 to 1.9.6.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.9.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.9.4...1.9.6)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-04 20:05:34 +00:00
33d1755eae Player: fixed not receiving slot updates for small crafting grid
I'm not really sure why this tracking logic is here and not in InventoryManager, but for now it is what it is.
2023-01-04 01:28:25 +00:00
fc63c54116 CraftingManager: more detailed type information for shapelessRecipes and shapedRecipes 2023-01-04 00:32:26 +00:00
db07976aab TypeConverter: do not send useless meta to the client 2023-01-03 23:50:31 +00:00
0e4b79ea77 InGamePacketHandler: fixed client-side predictions not getting rolled back for block placement 2023-01-03 19:43:21 +00:00
588c9b114b 4.12.5 is next 2023-01-03 19:30:02 +00:00
b095f606c1 Release 4.12.4 2023-01-03 19:29:47 +00:00
b312e93176 Limit list max size in transactions
this duct tape is to limit the impact of a security vulnerability being actively exploited.
2023-01-02 22:59:48 +00:00
61933624d2 NetworkSession: Lift batch limit to 1300 to allow shift-click crafting to work correctly
the theoretical limit for transactions in this case is 64x9 (inputs) + 64x9 (output on crafting grid) + 64 (outputs to main slot) + 64 CraftingEventPackets = 1280.
This is an extreme case which assumes that a recipe could generate up to 64x10 (640) output items per iteration, filling every slot of the output grid, which should never occur in any reasonable circumstances.
2022-12-30 22:11:35 +00:00
90beaeaeb4 4.12.4 is next 2022-12-28 21:01:50 +00:00
466f7e98ed Release 4.12.3 2022-12-28 21:01:47 +00:00
59be901efe Fixed unauthenticated sessions taking up player slots 2022-12-28 20:42:33 +00:00
5d2b0acfc8 GamemodeCommand: report failure if the target's game mode is already the desired game mode
this has irritated me for years.
2022-12-22 18:38:10 +00:00
7d1d62042c attempted fix for GitHub rate limiting php-cs-fixer installation
from https://github.com/shivammathur/setup-php/issues/678#issuecomment-1363128626
2022-12-22 18:13:03 +00:00
17dde140a5 Bump phpstan/phpstan-phpunit from 1.3.2 to 1.3.3 (#5465)
Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 1.3.2 to 1.3.3.
- [Release notes](https://github.com/phpstan/phpstan-phpunit/releases)
- [Commits](https://github.com/phpstan/phpstan-phpunit/compare/1.3.2...1.3.3)

---
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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-22 15:23:10 +00:00
1e5597f0d5 World: account for null chunk edge case in tickChunk()
the target chunk may no longer be loaded if it was unloaded during a previous chunk's tick (e.g. during BlockGrowEvent).
Since the parent function iterates over a pre-selected array of chunks, the chunk will still be present in the list even if it's no longer loaded by the time it's reached.
2022-12-19 20:20:52 +00:00
97ef209c5f HandlerList: added missing class-string type for constructor 2022-12-19 16:26:36 +00:00
1305fd5fb2 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2022-12-19 15:52:56 +00:00
7a137f932f Updated build/php submodule to pmmp/php-build-scripts@6b605ed7c4 2022-12-19 15:52:44 +00:00
63e8b1cf3a Bump phpstan/phpstan from 1.9.3 to 1.9.4 (#5458)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.9.3 to 1.9.4.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.9.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.9.3...1.9.4)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-19 15:39:59 +00:00
65bce762ff Updated transient Composer dependencies 2022-12-19 15:34:17 +00:00
529700bb8b PotionTypeIdMap: fixed uninitialized fields
I have no idea why this didn't ever cause a problem before... probably an edge-case in the typed properties implementation
2022-12-19 15:33:15 +00:00
437fa615b8 4.12.3 is next 2022-12-15 21:08:28 +00:00
0ee6cdb058 Release 4.12.2 2022-12-15 21:08:23 +00:00
97d6a79b25 Updated BedrockProtocol 2022-12-15 20:37:36 +00:00
8b5e4c1c16 Updated PHPStan 2022-12-15 20:16:56 +00:00
214a5ddc15 Bump netresearch/jsonmapper from 4.0.0 to 4.1.0 (#5446)
Bumps [netresearch/jsonmapper](https://github.com/cweiske/jsonmapper) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/cweiske/jsonmapper/releases)
- [Changelog](https://github.com/cweiske/jsonmapper/blob/master/ChangeLog)
- [Commits](https://github.com/cweiske/jsonmapper/compare/v4.0.0...v4.1.0)

---
updated-dependencies:
- dependency-name: netresearch/jsonmapper
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-15 19:28:11 +00:00
9f7dfe3355 Bump phpunit/phpunit from 9.5.26 to 9.5.27 (#5447)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.26 to 9.5.27.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/main/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.26...9.5.27)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-15 19:21:39 +00:00
9b55d18393 Bump ncipollo/release-action from 1.11.2 to 1.12.0 (#5451)
Bumps [ncipollo/release-action](https://github.com/ncipollo/release-action) from 1.11.2 to 1.12.0.
- [Release notes](https://github.com/ncipollo/release-action/releases)
- [Commits](https://github.com/ncipollo/release-action/compare/v1.11.2...v1.12.0)

---
updated-dependencies:
- dependency-name: ncipollo/release-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-15 19:20:28 +00:00
31465525e3 Fixed PHP-CS-Fixer not import global constants. (#5449) 2022-12-12 17:12:33 +00:00
74613b9b09 Bump phpstan/phpstan-phpunit from 1.2.2 to 1.3.0 (#5445)
Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 1.2.2 to 1.3.0.
- [Release notes](https://github.com/phpstan/phpstan-phpunit/releases)
- [Commits](https://github.com/phpstan/phpstan-phpunit/compare/1.2.2...1.3.0)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-10 21:17:03 +00:00
1cefe24414 InGamePacketHandler: fixed transaction predictions not getting rolled back for failed use/release/interact transactions
this was caused by b5cfab497d.
2022-12-10 21:16:08 +00:00
8bf85d4a18 bootstrap: avoid using is_writable() to check for data directory access permissions
closes #5440
2022-12-06 14:13:37 +00:00
b5e6dec0c6 Filesystem: capture error information from attempted lock file creation 2022-12-06 14:06:08 +00:00
a3306914cc bootstrap: do not require the plugins dir to be writable
on a modern installation, the plugins folder does not need to be writable by the server. Perhaps DevTools should be checking this for /genplugin, but it's not required otherwise.
2022-12-06 13:58:50 +00:00
3b32ea1b0b Update PhpStorm code style settings 2022-12-06 13:22:54 +00:00
7ec32f981e Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2022-12-06 13:22:15 +00:00
b0c87e9d06 Added phpdoc_align rule for php-cs-fixer 2022-12-06 13:21:57 +00:00
99996b62d6 Align PhpDoc @param tags according to PHP-CS-Fixer 2022-12-06 13:21:20 +00:00
1cb6d9f5af Bump dessant/support-requests from 2 to 3 (#5442)
Bumps [dessant/support-requests](https://github.com/dessant/support-requests) from 2 to 3.
- [Release notes](https://github.com/dessant/support-requests/releases)
- [Changelog](https://github.com/dessant/support-requests/blob/master/CHANGELOG.md)
- [Commits](https://github.com/dessant/support-requests/compare/v2...v3)

---
updated-dependencies:
- dependency-name: dessant/support-requests
  dependency-type: direct:production
  update-type: version-update:semver-major
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-05 21:10:09 +00:00
0a9b52618d 4.12.2 is next 2022-12-04 23:11:48 +00:00
7ae6425d05 Release 4.12.1 2022-12-04 23:11:48 +00:00
b5cfab497d Clean up inventory content syncing, fixes #5441
these remnants should have been cleaned up in 4.11, but I somehow managed to skip over them.
2022-12-04 23:05:30 +00:00
774e23137e changelog: added detail about InventoryManager internals changes
this isn't considered part of the API, but certain specialized popular plugins (e.g. InvMenu) require it.
2022-12-01 20:48:38 +00:00
43bc3c7b25 Added tool to dump JSON contents of encoded crashdump data 2022-12-01 19:36:31 +00:00
eb62dc3294 Added documentation for RegistryTrait, EnumTrait and CloningRegistryTrait 2022-11-30 21:04:17 +00:00
279056fe2f 4.12.1 is next 2022-11-30 16:35:58 +00:00
cd233b123b Release 4.12.0 2022-11-30 16:35:58 +00:00
64dd5e3bf6 Update dependencies for 1.19.50 2022-11-30 16:32:04 +00:00
4e5cc57560 Bump build/php from 9353116 to 27cc1fc (#5438)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `9353116` to `27cc1fc`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](9353116fa8...27cc1fcdfa)

---
updated-dependencies:
- dependency-name: build/php
  dependency-type: direct:production
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-28 11:15:09 +00:00
95263795a8 Durable: fix misbehaviour of isBroken() since fe982c697b (#5436)
this broke tool and armour break sounds.
2022-11-27 00:13:41 +00:00
2db86d151f Bump ncipollo/release-action from 1.11.1 to 1.11.2 (#5414)
Bumps [ncipollo/release-action](https://github.com/ncipollo/release-action) from 1.11.1 to 1.11.2.
- [Release notes](https://github.com/ncipollo/release-action/releases)
- [Commits](https://github.com/ncipollo/release-action/compare/v1.11.1...v1.11.2)

---
updated-dependencies:
- dependency-name: ncipollo/release-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-26 20:26:02 +00:00
f0358b09b7 changelog: added commit links to internals changes 2022-11-25 21:47:27 +00:00
80a432d9ff Merge branch 'next-minor' into stable 2022-11-25 20:30:57 +00:00
ec9f9a469f 4.11.1 is next 2022-11-25 20:29:49 +00:00
d450264e1c Release 4.11.0 2022-11-25 20:29:46 +00:00
5e92f55d35 4.10.3 is next 2022-11-25 15:20:18 +00:00
58c1bfe5d2 Release 4.10.2 2022-11-25 15:20:15 +00:00
641d35a30f Updated pocketmine/locale-data to get new translations 2022-11-25 14:59:58 +00:00
642630a4d2 ... 2022-11-25 14:57:47 +00:00
d79e6354a0 Merge branch 'stable' into next-minor 2022-11-25 14:41:05 +00:00
ff63983de4 Update transient composer dependencies 2022-11-25 14:39:34 +00:00
588215044e Update BedrockProtocol 2022-11-25 14:37:37 +00:00
5c1e9a35a9 Fix missing sounds when interacting with item frames (#5383)
closes #5168
2022-11-25 14:28:41 +00:00
aad9f5fb45 Terminal: use fallback escape codes if TERM env var is not set
tput requires a value for TERM, so it will generate errors if the var is
not set, as it appears not to be in PhpStorm on macOS.
2022-11-24 22:52:33 +00:00
a8dca190c6 Updated build/php submodule to pmmp/php-build-scripts@9353116fa8 2022-11-24 21:07:59 +00:00
e5f5fe80f9 BlockGrowEvent: Remove unnecessary Cancellable implementation (#5359)
this is already implemented by BaseBlockChangeEvent
2022-11-23 13:29:23 +00:00
36ab34df29 Implement BlockDeathEvent (#5420)
closes #4711
2022-11-23 12:57:26 +00:00
dda8ff18b1 Missing space (#5419) 2022-11-21 10:25:17 +00:00
6562335120 CrashDump: fixed failure to generate crash report when error messages contain invalid characters
closes #2986
2022-11-15 22:00:20 +00:00
0c463a8721 PlayerCreationEvent: update woefully inadequate documentation
closes #4581
2022-11-15 21:45:08 +00:00
a66f966b08 Update API documentation for Inventory methods 2022-11-15 21:00:13 +00:00
cca22046ab Updated pocketmine/locale-data 2022-11-15 20:21:39 +00:00
d19f0bf7be Language: added getAll() 2022-11-15 15:27:14 +00:00
ff2391e74a FormattedCommandAlias: use new string for description 2022-11-15 15:26:55 +00:00
39e10da88d PlayerChatEvent: replace hardcoded translation key with KnownTranslationKeys constant 2022-11-15 15:15:34 +00:00
9650b7f03a Update PHPStan to 1.9.2 2022-11-12 17:31:39 +00:00
101 changed files with 992 additions and 397 deletions

View File

@ -6,6 +6,12 @@ updates:
interval: daily
time: "10:00"
open-pull-requests-limit: 10
ignore:
#only allow patch updates for locale-data - this has to be updated manually due to codegen
- dependency-name: pocketmine/locale-data
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
- package-ecosystem: gitsubmodule
directory: "/"

View File

@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v3
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.22.0
uses: shivammathur/setup-php@2.23.0
with:
php-version: 8.0

View File

@ -18,7 +18,7 @@ jobs:
submodules: true
- name: Setup PHP
uses: shivammathur/setup-php@2.22.0
uses: shivammathur/setup-php@2.23.0
with:
php-version: 8.0
@ -69,7 +69,7 @@ jobs:
${{ github.workspace }}/build_info.json
- name: Create draft release
uses: ncipollo/release-action@v1.11.1
uses: ncipollo/release-action@v1.12.0
with:
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
commit: ${{ github.sha }}

View File

@ -195,10 +195,12 @@ jobs:
- uses: actions/checkout@v3
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.22.0
uses: shivammathur/setup-php@2.23.0
with:
php-version: 8.0
tools: php-cs-fixer:3.11
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run PHP-CS-Fixer
run: php-cs-fixer fix --dry-run --diff --ansi

View File

@ -8,7 +8,7 @@ jobs:
support:
runs-on: ubuntu-latest
steps:
- uses: dessant/support-requests@v2
- uses: dessant/support-requests@v3
with:
github-token: ${{ github.token }}
support-label: "Support request"

View File

@ -62,6 +62,11 @@
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Shell Script">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="neon">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />

View File

@ -66,6 +66,9 @@ BODY,
],
'indentation_type' => true,
'logical_operators' => true,
'native_constant_invocation' => [
'scope' => 'namespaced'
],
'native_function_invocation' => [
'scope' => 'namespaced',
'include' => ['@all'],
@ -92,6 +95,12 @@ BODY,
],
'sort_algorithm' => 'alpha'
],
'phpdoc_align' => [
'align' => 'vertical',
'tags' => [
'param',
]
],
'phpdoc_line_span' => [
'property' => 'single',
'method' => null,

View File

@ -39,6 +39,7 @@ use function sprintf;
use function str_replace;
use function substr;
use const SORT_STRING;
use const STDERR;
if(count($argv) !== 2){
fwrite(STDERR, "Provide a path to process\n");

View File

@ -40,12 +40,13 @@ use function rtrim;
use function sprintf;
use function str_replace;
use function unlink;
use const DIRECTORY_SEPARATOR;
use const PHP_EOL;
require dirname(__DIR__) . '/vendor/autoload.php';
/**
* @param string[] $strings
* @param string[] $strings
*
* @return string[]
*/

View File

@ -36,3 +36,18 @@ Released 7th November 2022.
- Added validation for the array given to `BaseInventory->setContents()` to ensure that it contains only `Item` instances.
- Silenced `PlayerAuthInputPacket` spam when the session is in the "spawn response" state.
- Updated to PHPStan 1.9.
# 4.10.2
Released 25th November 2022.
## Fixes
- Fixed crashes on macOS and Linux when using console colours without the `TERM` environment variable set.
- Fixed crashdumps not being generated when error messages contained invalid UTF-8 characters.
## Documentation
- Clarified documentation of caching behaviour for `Internet::getIP()`.
- Added and improved documentation for many `Inventory` methods.
- Rewritten documentation for `PlayerCreationEvent` with warnings and more detail.
## Internals
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.

106
changelogs/4.11.md Normal file
View File

@ -0,0 +1,106 @@
**For Minecraft: Bedrock Edition 1.19.40**
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.11.0
Released 25th November 2022.
## General
- Packet receive timings have now been split into two subcategories - Decode and Handle.
- Console command entry can now be disabled via the `console.enable-input` setting in `pocketmine.yml`.
- Best suited for headless servers (e.g. in a Docker container) where the console will never be used anyway.
- Disabling the console reader slightly reduces memory usage, because console reading currently requires an additional subprocess.
- Console command output now appears on the terminal only, and is not written to the log file.
- The output from console commands now appears with a `Command output |` prefix, instead of as a log message.
- User-defined `pocketmine.yml` custom commands now use a generic description which makes clear the command is config-defined.
- Introduced validation for the `--data` and `--plugins` command line options.
- Encrypted resource packs are now supported, by means of adding a `.key` file alongside the pack in the `resource_packs` folder.
- e.g. `MyEncryptedPack.zip` -> `MyEncryptedPack.zip.key`
- The file must contain the raw key bytes, and must not end with a newline.
## Configuration
- The `chunk-ticking.per-tick` setting is now deprecated, and will be removed in a future release.
- The functionality of this setting has been removed, since it caused more problems than it solved.
- Setting it to zero will still disable chunk ticking (for now), but this should now be done by setting `chunk-ticking.tick-radius` to `0` instead.
## Gameplay
- Fixed supporting blocks of dead bush to be in line with vanilla.
- Sugarcane can now be grown using bonemeal on any part of the sugarcane. Previously, it only worked when used on the bottom block.
- Fixed missing sounds when adding, rotating, or removing items in item frames.
- Fixed modifier values for Instant Damage and Regeneration effects.
- Implemented Darkness effect.
- Improved chunk random ticking:
- Removed the limit on chunks ticked per tick, and its associated config option is no longer respected.
- This change significantly improves crop and plant growth with large numbers of players.
- This limit was causing a linear decrease in chunk ticking speed with larger numbers of players, leading to worsened gameplay experience.
- **Warning: This change will result in increased CPU usage if players are spread over a very large area.**
- Every chunk within the configured tick radius of a player will be ticked. Previously, chunks were randomly selected from the radius.
## API
### General
- Plugins are now always disabled before their dependencies, to ensure that they are able to shutdown properly (e.g. a core plugin depending on a database plugin may want to save data to a DB during `onDisable()`).
- [`webmozart/path-util`](https://packagist.org/packages/webmozart/path-util) has been deprecated, and will be dropped in favour of [`symfony/filesystem`](https://packagist.org/packages/symfony/filesystem) in PM5.
- To prepare for this change, simply replace any usage of `Webmozart\PathUtil\Path` with `Symfony\Component\Filesystem\Path`, which is available as a dependency in this release.
### `pocketmine`
- The following API methods are now deprecated:
- `Server->getPlayerByPrefix()`
### `pocketmine\entity`
- `EntitySpawnEvent` and `ItemSpawnEvent` are now fired on the first tick after the entity is added to the world. Previously, these events were called directly from the entity constructor, making it impossible to get properties like velocity which are often set after the entity is created.
- The following API methods are now deprecated:
- `Living->hasLineOfSight()`
### `pocketmine\event\block`
- The following new classes have been added:
- `BlockDeathEvent` - event called when coral or coral blocks die due to lack of water
### `pocketmine\item`
- The following new API methods have been added:
- `public Armor->clearCustomColor() : $this`
### `pocketmine\inventory\transaction`
- Introduced a `TransactionBuilder` class. This makes it less of a hassle to build an `InventoryTransaction` server-side, since the regular `Inventory` API methods can be used, rather than having to manually create `SlotChangeAction`s.
### `pocketmine\lang`
- The following new API methods have been added:
- `public Language->getAll() : array<string, string>`
### `pocketmine\player`
- The following new API methods have been added:
- `public Player->sendToastNotification(string $title, string $body) : void` - makes a grey box appear at the top of the player's screen containing the specified message
### `pocketmine\utils`
- The following new API methods have been added:
- `public static TextFormat::addBase(string $baseFormat, string $string) : string` - used for coloured log messages, changes the base formatting of a string by inserting the given formatting codes after every RESET code
### `pocketmine\world`
- The following new API methods have been added:
- `public World->getChunkTickRadius() : int` - returns the world's simulation radius
- `public World->setChunkTickRadius(int $radius) : void` - sets the world's simulation radius
### `pocketmine\world\sound`
- The following new classes have been added:
- `ItemFrameAddItemSound`
- `ItemFrameRemoveItemSound`
- `ItemFrameRotateItemSound`
## Internals
- Improved performance of `ContainerTrait` dropping items on block destroy. ([link](https://github.com/pmmp/PocketMine-MP/commits/24e72ec109c1442b09558df89b6833cf2f2e0ec7))
- Avoid repeated calls to `Position->getWorld()` (use local variables). ([link](https://github.com/pmmp/PocketMine-MP/commit/2940547026db40ce76deb46e992870de3ead79ad))
- Revamped the way `InventoryManager` handles fake inventory slot mappings for stuff like crafting tables. ([link](https://github.com/pmmp/PocketMine-MP/commit/e90abecf38d9c57635fa0497514bba7e546a2469))
- Inventories are now mapped on a per-slot basis. This means that more than one inventory can be mapped to the same window ID, which is necessary for correctly handling "UI" inventories like crafting tables.
- `InventoryManager->getWindow(int $windowId) : ?Inventory` is replaced by `locateWindowAndSlot` (see below).
- Added `InventoryManager->locateWindowAndSlot(int $windowId, int $netSlotId) : array{Inventory, int}` - accepts a window ID and absolute slot ID, and returns the associated inventory and the slot relative to the inventory's own start (for use with `getItem()` etc.).
- Slot offset mapping for "UI" inventories is now handled in `InventoryManager->createComplexSlotMapping()` instead of in `TypeConverter`.
- Console polling is now done on the main thread (no longer a performance concern). ([link](https://github.com/pmmp/PocketMine-MP/commit/b3f03d7ae645de67a54b7300c09b94eeca16298e))
- Console reader subprocess should now automatically die if the server main process is killed, instead of persisting as a zombie. ([link](https://github.com/pmmp/PocketMine-MP/commit/2585160ca2c4df5758b8b980331307402ff9f0fb))
- `ConsoleCommandSender` is no longer responsible for relaying broadcast messages to `MainLogger`. A new `BroadcastLoggerForwarder` has been added, which is subscribed to the appropriate server broadcast channels in order to relay messages. This ensures that chat messages and command audit messages are logged. ([link](https://github.com/pmmp/PocketMine-MP/commit/83e5b0adb6fa0dddec377182bb1c7945ac8f7820))
- `DelegateInventory` now uses `WeakReference` to track its inventory listener. This allows the delegate to be reused. ([link](https://github.com/pmmp/PocketMine-MP/commit/3feaa18f6c10c3a99c0deca75f57ec2d74b92ab4))
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.

65
changelogs/4.12.md Normal file
View File

@ -0,0 +1,65 @@
**For Minecraft: Bedrock Edition 1.19.50**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.12.0
Released 30th November 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.50.
- Removed support for older versions.
# 4.12.1
Released 4th December 2022.
## Fixes
- Fixed items glitching when dragging a stack of items across the crafting grid (desync issues).
# 4.12.2
Released 15th December 2022.
## Fixes
- Folder used for plugins (optionally specified by `--plugins`) is no longer required to be writable.
- Fixed broken writable check for server data folder (`is_writable()` broken on NFS and similar filesystems).
- `Filesystem::createLockFile()` exceptions now include more information about why the lock file could not be created.
- Fixed client-side item predictions not being rolled back when cancelling events such as `PlayerItemUseEvent`.
## Dependencies
- Updated BedrockProtocol to [17.1.0](https://github.com/pmmp/BedrockProtocol/releases/tag/17.1.0+bedrock-1.19.50). This adds some missing `LevelSoundEvent` constants and fixes the values for `ContainerUIIds`.
# 4.12.3
Released 28th December 2022.
## Fixes
- Fixed unauthenticated connections taking up player count slots, preventing players from joining.
- Fixed a possible crash in `World->tickChunk()` when plugins unload chunks during some events.
- `/gamemode` will now report a failure to change game mode if the player is already in the requested game mode.
# 4.12.4
Released 3rd January 2023.
## Fixes
- Added workarounds for an active exploit being used to deny service to servers.
# 4.12.5
Released 6th January 2023.
## Fixes
- Removed a workaround for an old client bug in custom form responses. The code contained a denial-of-service vulnerability.
# 4.12.6
Released 7th January 2023.
## Changes
- Added a new security measure to `NetworkSession` to detect and ban players who flood the server with packets.
# 4.12.7
Released 8th January 2023.
## Fixes
- Fixed players getting kicked when the server lags for too long.
- Fixed players getting kicked when a debugging session is active and a breakpoint is hit.

View File

@ -34,14 +34,14 @@
"adhocore/json-comment": "^1.1",
"fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0",
"pocketmine/bedrock-data": "~1.12.0+bedrock-1.19.40",
"pocketmine/bedrock-protocol": "~14.0.0+bedrock-1.19.40",
"pocketmine/bedrock-data": "~1.13.0+bedrock-1.19.50",
"pocketmine/bedrock-protocol": "~17.1.0+bedrock-1.19.50",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.2.0",
"pocketmine/color": "^0.2.0",
"pocketmine/errorhandler": "^0.6.0",
"pocketmine/locale-data": "~2.9.0",
"pocketmine/locale-data": "~2.11.0",
"pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.4.0",
"pocketmine/math": "^0.4.0",
@ -54,7 +54,7 @@
"webmozart/path-util": "^2.3"
},
"require-dev": {
"phpstan/phpstan": "1.9.1",
"phpstan/phpstan": "1.9.7",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "^9.2"

187
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b535dc262141936698680b92902f8e28",
"content-hash": "76c6b5521d8f88d9070e8dec1c0ae144",
"packages": [
{
"name": "adhocore/json-comment",
@ -123,24 +123,24 @@
},
{
"name": "fgrosse/phpasn1",
"version": "v2.4.0",
"version": "v2.5.0",
"source": {
"type": "git",
"url": "https://github.com/fgrosse/PHPASN1.git",
"reference": "eef488991d53e58e60c9554b09b1201ca5ba9296"
"reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/eef488991d53e58e60c9554b09b1201ca5ba9296",
"reference": "eef488991d53e58e60c9554b09b1201ca5ba9296",
"url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/42060ed45344789fb9f21f9f1864fc47b9e3507b",
"reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b",
"shasum": ""
},
"require": {
"php": "~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0"
"php": "^7.1 || ^8.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "~2.0",
"phpunit/phpunit": "^6.3 || ^7.0 || ^8.0"
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
},
"suggest": {
"ext-bcmath": "BCmath is the fallback extension for big integer calculations",
@ -192,22 +192,23 @@
],
"support": {
"issues": "https://github.com/fgrosse/PHPASN1/issues",
"source": "https://github.com/fgrosse/PHPASN1/tree/v2.4.0"
"source": "https://github.com/fgrosse/PHPASN1/tree/v2.5.0"
},
"time": "2021-12-11T12:41:06+00:00"
"abandoned": true,
"time": "2022-12-19T11:08:26+00:00"
},
{
"name": "netresearch/jsonmapper",
"version": "v4.0.0",
"version": "v4.1.0",
"source": {
"type": "git",
"url": "https://github.com/cweiske/jsonmapper.git",
"reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d"
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
"reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d",
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
"reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f",
"shasum": ""
},
"require": {
@ -243,22 +244,22 @@
"support": {
"email": "cweiske@cweiske.de",
"issues": "https://github.com/cweiske/jsonmapper/issues",
"source": "https://github.com/cweiske/jsonmapper/tree/v4.0.0"
"source": "https://github.com/cweiske/jsonmapper/tree/v4.1.0"
},
"time": "2020-12-01T19:48:11+00:00"
"time": "2022-12-08T20:46:14+00:00"
},
{
"name": "pocketmine/bedrock-data",
"version": "1.12.0+bedrock-1.19.40",
"version": "1.13.0+bedrock-1.19.50",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
"reference": "32690f1dac05608b558fe7c40b6d634772c8e416"
"reference": "57337ddc9433a0e245a1ce48c51af05f0573d58d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/32690f1dac05608b558fe7c40b6d634772c8e416",
"reference": "32690f1dac05608b558fe7c40b6d634772c8e416",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/57337ddc9433a0e245a1ce48c51af05f0573d58d",
"reference": "57337ddc9433a0e245a1ce48c51af05f0573d58d",
"shasum": ""
},
"type": "library",
@ -269,22 +270,22 @@
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/BedrockData/issues",
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.19.40"
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.19.50"
},
"time": "2022-10-25T21:45:24+00:00"
"time": "2022-11-30T16:19:59+00:00"
},
{
"name": "pocketmine/bedrock-protocol",
"version": "14.0.0+bedrock-1.19.40",
"version": "17.1.0+bedrock-1.19.50",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "b455a742779fee94d25f931cc2cbf6b2c5d61c1f"
"reference": "c572706cf5e3202718dd35a35dd30fe08cd671de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/b455a742779fee94d25f931cc2cbf6b2c5d61c1f",
"reference": "b455a742779fee94d25f931cc2cbf6b2c5d61c1f",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/c572706cf5e3202718dd35a35dd30fe08cd671de",
"reference": "c572706cf5e3202718dd35a35dd30fe08cd671de",
"shasum": ""
},
"require": {
@ -298,7 +299,7 @@
"ramsey/uuid": "^4.1"
},
"require-dev": {
"phpstan/phpstan": "1.8.8",
"phpstan/phpstan": "1.9.3",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5"
@ -316,9 +317,9 @@
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
"support": {
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
"source": "https://github.com/pmmp/BedrockProtocol/tree/bedrock-1.19.40"
"source": "https://github.com/pmmp/BedrockProtocol/tree/17.1.0+bedrock-1.19.50"
},
"time": "2022-10-25T21:51:46+00:00"
"time": "2022-12-15T20:34:49+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -536,16 +537,16 @@
},
{
"name": "pocketmine/locale-data",
"version": "2.9.2",
"version": "2.11.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Language.git",
"reference": "8813ffd2a4501521ca9433c534f3009f941de136"
"reference": "4b33d8fa53eda53d9662a7478806ebae2e4a5c53"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Language/zipball/8813ffd2a4501521ca9433c534f3009f941de136",
"reference": "8813ffd2a4501521ca9433c534f3009f941de136",
"url": "https://api.github.com/repos/pmmp/Language/zipball/4b33d8fa53eda53d9662a7478806ebae2e4a5c53",
"reference": "4b33d8fa53eda53d9662a7478806ebae2e4a5c53",
"shasum": ""
},
"type": "library",
@ -553,9 +554,9 @@
"description": "Language resources used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Language/issues",
"source": "https://github.com/pmmp/Language/tree/2.9.2"
"source": "https://github.com/pmmp/Language/tree/2.11.0"
},
"time": "2022-10-21T20:30:38+00:00"
"time": "2022-11-25T14:24:34+00:00"
},
{
"name": "pocketmine/log",
@ -1086,16 +1087,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"shasum": ""
},
"require": {
@ -1110,7 +1111,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1148,7 +1149,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
},
"funding": [
{
@ -1164,20 +1165,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"shasum": ""
},
"require": {
@ -1192,7 +1193,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1231,7 +1232,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
},
"funding": [
{
@ -1247,20 +1248,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"shasum": ""
},
"require": {
@ -1269,7 +1270,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1314,7 +1315,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
},
"funding": [
{
@ -1330,20 +1331,20 @@
"type": "tidelift"
}
],
"time": "2022-05-10T07:21:04+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1"
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1",
"reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
"shasum": ""
},
"require": {
@ -1352,7 +1353,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1393,7 +1394,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
},
"funding": [
{
@ -1409,7 +1410,7 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "webmozart/assert",
@ -1653,16 +1654,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.15.1",
"version": "v4.15.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900"
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
"reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
"shasum": ""
},
"require": {
@ -1703,9 +1704,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2"
},
"time": "2022-09-04T07:30:47+00:00"
"time": "2022-11-12T15:38:23+00:00"
},
{
"name": "phar-io/manifest",
@ -1820,16 +1821,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.9.1",
"version": "1.9.7",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "a59c8b5bfd4a236f27efc8b5ce72c313c2b54b5f"
"reference": "0501435cd342eac7664bd62155b1ef907fc60b6f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/a59c8b5bfd4a236f27efc8b5ce72c313c2b54b5f",
"reference": "a59c8b5bfd4a236f27efc8b5ce72c313c2b54b5f",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/0501435cd342eac7664bd62155b1ef907fc60b6f",
"reference": "0501435cd342eac7664bd62155b1ef907fc60b6f",
"shasum": ""
},
"require": {
@ -1859,7 +1860,7 @@
],
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.9.1"
"source": "https://github.com/phpstan/phpstan/tree/1.9.7"
},
"funding": [
{
@ -1875,25 +1876,25 @@
"type": "tidelift"
}
],
"time": "2022-11-04T13:35:59+00:00"
"time": "2023-01-04T21:59:57+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "1.2.2",
"version": "1.3.3",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "dea1f87344c6964c607d9076dee42d891f3923f0"
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/dea1f87344c6964c607d9076dee42d891f3923f0",
"reference": "dea1f87344c6964c607d9076dee42d891f3923f0",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/54a24bd23e9e80ee918cdc24f909d376c2e273f7",
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.8.11"
"phpstan/phpstan": "^1.9.3"
},
"conflict": {
"phpunit/phpunit": "<7.0"
@ -1925,9 +1926,9 @@
"description": "PHPUnit extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.2.2"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.3"
},
"time": "2022-10-28T10:23:07+00:00"
"time": "2022-12-21T15:25:00+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
@ -1979,16 +1980,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.18",
"version": "9.2.22",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a"
"reference": "e4bf60d2220b4baaa0572986b5d69870226b06df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/12fddc491826940cf9b7e88ad9664cf51f0f6d0a",
"reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e4bf60d2220b4baaa0572986b5d69870226b06df",
"reference": "e4bf60d2220b4baaa0572986b5d69870226b06df",
"shasum": ""
},
"require": {
@ -2044,7 +2045,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.18"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.22"
},
"funding": [
{
@ -2052,7 +2053,7 @@
"type": "github"
}
],
"time": "2022-10-27T13:35:33+00:00"
"time": "2022-12-18T16:40:55+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -2297,16 +2298,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.26",
"version": "9.5.27",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2"
"reference": "a2bc7ffdca99f92d959b3f2270529334030bba38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/851867efcbb6a1b992ec515c71cdcf20d895e9d2",
"reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a2bc7ffdca99f92d959b3f2270529334030bba38",
"reference": "a2bc7ffdca99f92d959b3f2270529334030bba38",
"shasum": ""
},
"require": {
@ -2379,7 +2380,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.26"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.27"
},
"funding": [
{
@ -2395,7 +2396,7 @@
"type": "tidelift"
}
],
"time": "2022-10-28T06:00:21+00:00"
"time": "2022-12-09T07:31:23+00:00"
},
{
"name": "sebastian/cli-parser",

View File

@ -286,7 +286,7 @@ class MemoryManager{
/**
* Static memory dumper accessible from any thread.
*
* @param mixed $startingObject
* @param mixed $startingObject
*/
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
$hardLimit = Utils::assumeNotFalse(ini_get('memory_limit'), "memory_limit INI directive should always exist");
@ -480,7 +480,7 @@ class MemoryManager{
/**
* @param mixed $from
* @param object[] $objects reference parameter
* @param object[] $objects reference parameter
* @param int[] $refCounts reference parameter
*
* @phpstan-param array<string, object> $objects

View File

@ -39,11 +39,14 @@ namespace pocketmine {
use function extension_loaded;
use function function_exists;
use function getcwd;
use function is_dir;
use function mkdir;
use function phpversion;
use function preg_match;
use function preg_quote;
use function realpath;
use function version_compare;
use const DIRECTORY_SEPARATOR;
require_once __DIR__ . '/VersionInfo.php';
@ -273,25 +276,33 @@ JIT_WARNING
$pluginPath = getopt_string("plugins") ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX);
if(!@mkdir($dataPath, 0777, true) && (!is_dir($dataPath) || !is_writable($dataPath))){
if(!@mkdir($dataPath, 0777, true) && !is_dir($dataPath)){
critical_error("Unable to create/access data directory at $dataPath. Check that the target location is accessible by the current user.");
exit(1);
}
//this has to be done after we're sure the data path exists
$dataPath = realpath($dataPath) . DIRECTORY_SEPARATOR;
if(!@mkdir($pluginPath, 0777, true) && (!is_dir($pluginPath) || !is_writable($pluginPath))){
critical_error("Unable to create plugin directory at $pluginPath. Check that the target location is accessible by the current user.");
exit(1);
}
$pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
$lockFilePath = Path::join($dataPath, 'server.lock');
if(($pid = Filesystem::createLockFile($lockFilePath)) !== null){
try{
$pid = Filesystem::createLockFile($lockFilePath);
}catch(\InvalidArgumentException $e){
critical_error($e->getMessage());
critical_error("Please ensure that there is enough space on the disk and that the current user has read/write permissions to the selected data directory $dataPath.");
exit(1);
}
if($pid !== null){
critical_error("Another " . VersionInfo::NAME . " instance (PID $pid) is already using this folder (" . realpath($dataPath) . ").");
critical_error("Please stop the other server first before running a new one.");
exit(1);
}
if(!@mkdir($pluginPath, 0777, true) && !is_dir($pluginPath)){
critical_error("Unable to create plugin directory at $pluginPath. Check that the target location is accessible by the current user.");
exit(1);
}
$pluginPath = realpath($pluginPath) . DIRECTORY_SEPARATOR;
//Logger has a dependency on timezone
Timezone::init();

View File

@ -1268,7 +1268,7 @@ class Server{
}
/**
* @param CommandSender[]|null $recipients
* @param CommandSender[]|null $recipients
*/
public function broadcastMessage(Translatable|string $message, ?array $recipients = null) : int{
$recipients = $recipients ?? $this->getBroadcastChannelSubscribers(self::BROADCAST_CHANNEL_USERS);
@ -1321,9 +1321,9 @@ class Server{
}
/**
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
* @param int $stay Duration in ticks to stay on screen for
* @param int $fadeOut Duration in ticks for fade-out.
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
* @param int $stay Duration in ticks to stay on screen for
* @param int $fadeOut Duration in ticks for fade-out.
* @param Player[]|null $recipients
*/
public function broadcastTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1, ?array $recipients = null) : int{

View File

@ -44,7 +44,7 @@ final class ServerConfigGroup{
){}
/**
* @param mixed $defaultValue
* @param mixed $defaultValue
*
* @return mixed
*/

View File

@ -31,9 +31,9 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "4.11.0-BETA3";
public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "beta";
public const BASE_VERSION = "4.12.7";
public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
private function __construct(){
//NOOP

View File

@ -87,7 +87,7 @@ abstract class BaseBanner extends Transparent{
}
/**
* @param BannerPatternLayer[] $patterns
* @param BannerPatternLayer[] $patterns
*
* @phpstan-param list<BannerPatternLayer> $patterns
* @return $this

View File

@ -26,6 +26,7 @@ namespace pocketmine\block;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\BlockDeathEvent;
use pocketmine\item\Item;
abstract class BaseCoral extends Transparent{
@ -50,7 +51,11 @@ abstract class BaseCoral extends Transparent{
//TODO: check water inside the block itself (not supported on the API yet)
if(!$hasWater){
$world->setBlock($this->position, $this->setDead(true));
$ev = new BlockDeathEvent($this, $this->setDead(true));
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
}
}
}
}

View File

@ -62,7 +62,7 @@ class Block{
protected ?array $collisionBoxes = null;
/**
* @param string $name English name of the block type (TODO: implement translations)
* @param string $name English name of the block type (TODO: implement translations)
*/
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
if(($idInfo->getVariant() & $this->getStateBitmask()) !== 0){

View File

@ -968,7 +968,7 @@ class BlockFactory{
* NOTE: If you are registering a new block type, you will need to add it to the creative inventory yourself - it
* will not automatically appear there.
*
* @param bool $override Whether to override existing registrations
* @param bool $override Whether to override existing registrations
*
* @throws \RuntimeException if something attempted to override an already-registered block without specifying the
* $override parameter.

View File

@ -27,6 +27,7 @@ use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\data\bedrock\CoralTypeIdMap;
use pocketmine\event\block\BlockDeathEvent;
use pocketmine\item\Item;
use function mt_rand;
@ -77,7 +78,11 @@ final class CoralBlock extends Opaque{
}
}
if(!$hasWater){
$world->setBlock($this->position, $this->setDead(true));
$ev = new BlockDeathEvent($this, $this->setDead(true));
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
}
}
}
}

View File

@ -31,6 +31,9 @@ use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\ItemFrameAddItemSound;
use pocketmine\world\sound\ItemFrameRemoveItemSound;
use pocketmine\world\sound\ItemFrameRotateItemSound;
use function is_infinite;
use function is_nan;
use function lcg_value;
@ -136,8 +139,12 @@ class ItemFrame extends Flowable{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->framedItem !== null){
$this->itemRotation = ($this->itemRotation + 1) % self::ROTATIONS;
$this->position->getWorld()->addSound($this->position, new ItemFrameRotateItemSound());
}elseif(!$item->isNull()){
$this->framedItem = $item->pop();
$this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
}else{
return true;
}
@ -154,6 +161,7 @@ class ItemFrame extends Flowable{
$world = $this->position->getWorld();
if(lcg_value() <= $this->itemDropChance){
$world->dropItem($this->position->add(0.5, 0.5, 0.5), clone $this->framedItem);
$world->addSound($this->position, new ItemFrameRemoveItemSound());
}
$this->setFramedItem(null);
$world->setBlock($this->position, $this);

View File

@ -135,7 +135,7 @@ class Banner extends Spawnable{
}
/**
* @param BannerPatternLayer[] $patterns
* @param BannerPatternLayer[] $patterns
*
* @phpstan-param list<BannerPatternLayer> $patterns
*/

View File

@ -26,7 +26,7 @@ namespace pocketmine\command;
interface CommandExecutor{
/**
* @param string[] $args
* @param string[] $args
*/
public function onCommand(CommandSender $sender, Command $command, string $label, array $args) : bool;

View File

@ -52,7 +52,7 @@ class FormattedCommandAlias extends Command{
string $alias,
private array $formatStrings
){
parent::__construct($alias);
parent::__construct($alias, KnownTranslationFactory::pocketmine_command_userDefined_description());
}
public function execute(CommandSender $sender, string $commandLabel, array $args){

View File

@ -72,6 +72,11 @@ class GamemodeCommand extends VanillaCommand{
throw new InvalidCommandSyntaxException();
}
if($target->getGamemode()->equals($gameMode)){
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_failure($target->getName()));
return true;
}
$target->setGamemode($gameMode);
if(!$gameMode->equals($target->getGamemode())){
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_failure($target->getName()));

View File

@ -34,9 +34,15 @@ use function usort;
class CraftingManager{
use DestructorCallbackTrait;
/** @var ShapedRecipe[][] */
/**
* @var ShapedRecipe[][]
* @phpstan-var array<string, list<ShapedRecipe>>
*/
protected $shapedRecipes = [];
/** @var ShapelessRecipe[][] */
/**
* @var ShapelessRecipe[][]
* @phpstan-var array<string, list<ShapelessRecipe>>
*/
protected $shapelessRecipes = [];
/**
@ -133,6 +139,7 @@ class CraftingManager{
/**
* @return ShapelessRecipe[][]
* @phpstan-return array<string, list<ShapelessRecipe>>
*/
public function getShapelessRecipes() : array{
return $this->shapelessRecipes;
@ -140,6 +147,7 @@ class CraftingManager{
/**
* @return ShapedRecipe[][]
* @phpstan-return array<string, list<ShapedRecipe>>
*/
public function getShapedRecipes() : array{
return $this->shapedRecipes;
@ -201,7 +209,7 @@ class CraftingManager{
}
/**
* @param Item[] $outputs
* @param Item[] $outputs
*/
public function matchRecipe(CraftingGrid $grid, array $outputs) : ?CraftingRecipe{
//TODO: try to match special recipes before anything else (first they need to be implemented!)

View File

@ -46,15 +46,15 @@ class ShapedRecipe implements CraftingRecipe{
/**
* Constructs a ShapedRecipe instance.
*
* @param string[] $shape <br>
* Array of 1, 2, or 3 strings representing the rows of the recipe.
* This accepts an array of 1, 2 or 3 strings. Each string should be of the same length and must be at most 3
* characters long. Each character represents a unique type of ingredient. Spaces are interpreted as air.
* @param string[] $shape <br>
* Array of 1, 2, or 3 strings representing the rows of the recipe.
* This accepts an array of 1, 2 or 3 strings. Each string should be of the same length and must be at most 3
* characters long. Each character represents a unique type of ingredient. Spaces are interpreted as air.
* @param Item[] $ingredients <br>
* Char => Item map of items to be set into the shape.
* This accepts an array of Items, indexed by character. Every unique character (except space) in the shape
* array MUST have a corresponding item in this list. Space character is automatically treated as air.
* @param Item[] $results List of items that this recipe produces when crafted.
* Char => Item map of items to be set into the shape.
* This accepts an array of Items, indexed by character. Every unique character (except space) in the shape
* array MUST have a corresponding item in this list. Space character is automatically treated as air.
* @param Item[] $results List of items that this recipe produces when crafted.
*
* Note: Recipes **do not** need to be square. Do NOT add padding for empty rows/columns.
*/

View File

@ -36,7 +36,8 @@ class ShapelessRecipe implements CraftingRecipe{
/**
* @param Item[] $ingredients No more than 9 total. This applies to sum of item stack counts, not count of array.
* @param Item[] $results List of result items created by this recipe.
* @param Item[] $results List of result items created by this recipe.
*
* TODO: we'll want to make the type parameter mandatory in PM5
*/
public function __construct(array $ingredients, array $results, ?ShapelessRecipeType $type = null){

View File

@ -43,6 +43,7 @@ use function get_loaded_extensions;
use function json_encode;
use function ksort;
use function max;
use function mb_scrub;
use function mb_strtoupper;
use function microtime;
use function ob_end_clean;
@ -196,12 +197,14 @@ class CrashDump{
$error["message"] = substr($error["message"], 0, $pos);
}
}
$error["message"] = mb_scrub($error["message"], 'UTF-8');
if(isset($lastError)){
if(isset($lastError["trace"])){
$lastError["trace"] = Utils::printableTrace($lastError["trace"]);
}
$this->data->lastError = $lastError;
$this->data->lastError["message"] = mb_scrub($this->data->lastError["message"], 'UTF-8');
}
$this->data->error = $error;

View File

@ -33,13 +33,13 @@ final class PotionTypeIdMap{
* @var PotionType[]
* @phpstan-var array<int, PotionType>
*/
private array $idToEnum;
private array $idToEnum = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enumToId;
private array $enumToId = [];
private function __construct(){
$this->register(PotionTypeIds::WATER, PotionType::WATER());

View File

@ -1598,7 +1598,7 @@ abstract class Entity{
/**
* @param Player[]|null $targets
* @param MetadataProperty[] $data Properly formatted entity data, defaults to everything
* @param MetadataProperty[] $data Properly formatted entity data, defaults to everything
*
* @phpstan-param array<int, MetadataProperty> $data
*/

View File

@ -35,9 +35,9 @@ class Effect{
use NotSerializable;
/**
* @param Translatable|string $name Translation key used for effect name
* @param Color $color Color of bubbles given by this effect
* @param bool $bad Whether the effect is harmful
* @param Translatable|string $name Translation key used for effect name
* @param Color $color Color of bubbles given by this effect
* @param bool $bad Whether the effect is harmful
* @param bool $hasBubbles Whether the effect has potion bubbles. Some do not (e.g. Instant Damage has its own particles instead of bubbles)
*/
public function __construct(

View File

@ -36,7 +36,7 @@ class EffectInstance{
private Color $color;
/**
* @param int|null $duration Passing null will use the effect type's default duration
* @param int|null $duration Passing null will use the effect type's default duration
*/
public function __construct(Effect $effectType, ?int $duration = null, int $amplifier = 0, bool $visible = true, bool $ambient = false, ?Color $overrideColor = null){
$this->effectType = $effectType;

View File

@ -31,6 +31,10 @@ class HandlerList{
/** @var RegisteredListener[][] */
private array $handlerSlots = [];
/**
* @phpstan-template TEvent of Event
* @phpstan-param class-string<TEvent> $class
*/
public function __construct(
private string $class,
private ?HandlerList $parentList

View File

@ -0,0 +1,32 @@
<?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\event\block;
/**
* Called when a block dies.
* This could be things like corals dying due to no water being nearby.
*/
class BlockDeathEvent extends BaseBlockChangeEvent{
}

View File

@ -23,11 +23,9 @@ declare(strict_types=1);
namespace pocketmine\event\block;
use pocketmine\event\Cancellable;
/**
* Called when plants or crops grow.
*/
class BlockGrowEvent extends BaseBlockChangeEvent implements Cancellable{
class BlockGrowEvent extends BaseBlockChangeEvent{
}

View File

@ -52,7 +52,7 @@ class EntityExplodeEvent extends EntityEvent implements Cancellable{
/**
* @param Block[] $blocks
* @param float $yield 0-100
* @param float $yield 0-100
*/
public function __construct(Entity $entity, Position $position, array $blocks, float $yield){
$this->entity = $entity;

View File

@ -35,8 +35,8 @@ class CraftItemEvent extends Event implements Cancellable{
use CancellableTrait;
/**
* @param Item[] $inputs
* @param Item[] $outputs
* @param Item[] $inputs
* @param Item[] $outputs
*/
public function __construct(
private CraftingTransaction $transaction,

View File

@ -26,6 +26,7 @@ namespace pocketmine\event\player;
use pocketmine\command\CommandSender;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
use pocketmine\lang\KnownTranslationKeys;
use pocketmine\player\Player;
use pocketmine\utils\Utils;
@ -47,7 +48,7 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{
/**
* @param CommandSender[] $recipients
*/
public function __construct(Player $player, string $message, array $recipients, string $format = "chat.type.text"){
public function __construct(Player $player, string $message, array $recipients, string $format = KnownTranslationKeys::CHAT_TYPE_TEXT){
$this->player = $player;
$this->message = $message;

View File

@ -30,7 +30,20 @@ use pocketmine\utils\Utils;
use function is_a;
/**
* Allows the creation of players overriding the base Player class
* Allows the use of custom Player classes. This enables overriding built-in Player methods to change behaviour that is
* not possible to alter any other way.
*
* You probably don't need this event, and found your way here because you looked at some code in an old plugin that
* abused it (very common). Instead of using custom player classes, you should consider making session classes instead.
*
* @see https://github.com/pmmp/SessionsDemo
*
* This event is a power-user feature, and multiple plugins using it at the same time will conflict and break unless
* they've been designed to work together. This means that it's only usually useful in private plugins.
*
* WARNING: This should NOT be used for adding extra functions or properties. This is intended for **overriding existing
* core behaviour**, and should only be used if you know EXACTLY what you're doing.
* Custom player classes may break in any update without warning. This event isn't much more than glorified reflection.
*/
class PlayerCreationEvent extends Event{
@ -54,6 +67,8 @@ class PlayerCreationEvent extends Event{
}
/**
* Returns the base class that the final player class must extend.
*
* @return string
* @phpstan-return class-string<Player>
*/
@ -62,6 +77,10 @@ class PlayerCreationEvent extends Event{
}
/**
* Sets the class that the final player class must extend.
* The new base class must be a subclass of the current base class.
* This can (perhaps) be used to limit the options for custom player classes provided by other plugins.
*
* @param string $class
* @phpstan-param class-string<Player> $class
*/
@ -74,6 +93,8 @@ class PlayerCreationEvent extends Event{
}
/**
* Returns the class that will be instantiated to create the player after the event.
*
* @return string
* @phpstan-return class-string<Player>
*/
@ -82,6 +103,9 @@ class PlayerCreationEvent extends Event{
}
/**
* Sets the class that will be instantiated to create the player after the event. The class must not be abstract,
* and must be an instance of the base class.
*
* @param string $class
* @phpstan-param class-string<Player> $class
*/

View File

@ -34,7 +34,7 @@ interface Form extends \JsonSerializable{
/**
* Handles a form response from a player.
*
* @param mixed $data
* @param mixed $data
*
* @throws FormValidationException if the data could not be processed
*/

View File

@ -33,12 +33,25 @@ use pocketmine\utils\ObjectSet;
interface Inventory{
public const MAX_STACK = 64;
/**
* Returns the number of slots in the inventory.
*/
public function getSize() : int;
/**
* Returns the maximum stack size for items in this inventory. Individual item types (such as armor or tools) may
* have a smaller maximum stack size.
*/
public function getMaxStackSize() : int;
/**
* Sets the maximum stack size for items in this inventory.
*/
public function setMaxStackSize(int $size) : void;
/**
* Returns the item in the specified slot.
*/
public function getItem(int $index) : Item;
/**
@ -65,10 +78,11 @@ interface Inventory{
public function setContents(array $items) : void;
/**
* Stores the given Items in the inventory. This will try to fill
* existing stacks and empty slots as well as it can.
* Stores the given Items in the inventory.
* This will add to any non-full existing stacks first, and then put the remaining items in empty slots if there are
* any available.
*
* Returns the Items that did not fit.
* Returns an array of items which could not fit in the inventory.
*
* @return Item[]
*/
@ -85,15 +99,20 @@ interface Inventory{
public function getAddableItemQuantity(Item $item) : int;
/**
* Checks if the inventory contains any Item with the same material data.
* It will check id, amount, and metadata (if not null)
* Returns whether the total amount of matching items is at least the stack size of the given item. Multiple stacks
* of the same item are added together.
*
* If the input item has specific NBT, only items with the same type and NBT will match. Otherwise, only the item
* type is checked.
*/
public function contains(Item $item) : bool;
/**
* Will return all the Items that has the same id and metadata (if not null).
* Won't check amount
* The returned array is indexed by slot number.
* Returns all matching items in the inventory, irrespective of stack size. The returned array is indexed by slot
* number.
*
* If the input item has specific NBT, only items with the same type and NBT will match. Otherwise, only the item
* type is checked.
*
* @return Item[]
* @phpstan-return array<int, Item>
@ -101,10 +120,10 @@ interface Inventory{
public function all(Item $item) : array;
/**
* Returns the first slot number containing an item with the same ID, damage (if not any-damage), NBT (if not empty)
* and count >= to the count of the specified item stack.
* Returns the first slot number containing a matching item with a stack size greater than or equal to the input item.
*
* If $exact is true, only items with equal ID, damage, NBT and count will match.
* If the input item has specific NBT, or if $exact is true, only items with the same type and NBT will match.
* Otherwise, only the item type is checked.
*/
public function first(Item $item, bool $exact = false) : int;
@ -119,13 +138,19 @@ interface Inventory{
public function isSlotEmpty(int $index) : bool;
/**
* Will remove all the Items that has the same id and metadata (if not null)
* Clears all slots containing items equivalent to the given item.
*
* If the input item has specific NBT, only items with the same type and NBT will match. Otherwise, only the item
* type is checked.
*/
public function remove(Item $item) : void;
/**
* Removes the given Item from the inventory.
* It will return the Items that couldn't be removed.
* Removes items from the inventory in the amounts specified by the given itemstacks.
* Returns an array of items that couldn't be removed.
*
* If the input item has specific NBT, only items with the same type and NBT will match. Otherwise, only the item
* type is checked.
*
* @return Item[]
*/

View File

@ -75,7 +75,7 @@ class Banner extends ItemBlockWallOrFloor{
}
/**
* @param BannerPatternLayer[] $patterns
* @param BannerPatternLayer[] $patterns
*
* @phpstan-param list<BannerPatternLayer> $patterns
*

View File

@ -121,7 +121,7 @@ abstract class Durable extends Item{
* Returns whether the item is broken.
*/
public function isBroken() : bool{
return $this->damage >= $this->getMaxDurability();
return $this->damage >= $this->getMaxDurability() || $this->isNull();
}
protected function deserializeCompoundTag(CompoundTag $tag) : void{

View File

@ -564,7 +564,7 @@ class Item implements \JsonSerializable{
/**
* Compares an Item to this Item and check if they match.
*
* @param bool $checkDamage Whether to verify that the damage values match.
* @param bool $checkDamage Whether to verify that the damage values match.
* @param bool $checkCompound Whether to verify that the items' NBT match.
*/
final public function equals(Item $item, bool $checkDamage = true, bool $checkCompound = true) : bool{

View File

@ -43,6 +43,34 @@ final class KnownTranslationFactory{
return new Translatable(KnownTranslationKeys::ACCEPT_LICENSE, []);
}
public static function action_interact_armorstand_equip() : Translatable{
return new Translatable(KnownTranslationKeys::ACTION_INTERACT_ARMORSTAND_EQUIP, []);
}
public static function action_interact_armorstand_pose() : Translatable{
return new Translatable(KnownTranslationKeys::ACTION_INTERACT_ARMORSTAND_POSE, []);
}
public static function action_interact_exit_boat() : Translatable{
return new Translatable(KnownTranslationKeys::ACTION_INTERACT_EXIT_BOAT, []);
}
public static function action_interact_fishing() : Translatable{
return new Translatable(KnownTranslationKeys::ACTION_INTERACT_FISHING, []);
}
public static function action_interact_name() : Translatable{
return new Translatable(KnownTranslationKeys::ACTION_INTERACT_NAME, []);
}
public static function action_interact_ride_boat() : Translatable{
return new Translatable(KnownTranslationKeys::ACTION_INTERACT_RIDE_BOAT, []);
}
public static function action_interact_ride_minecart() : Translatable{
return new Translatable(KnownTranslationKeys::ACTION_INTERACT_RIDE_MINECART, []);
}
public static function chat_type_achievement(Translatable|string $param0, Translatable|string $param1) : Translatable{
return new Translatable(KnownTranslationKeys::CHAT_TYPE_ACHIEVEMENT, [
0 => $param0,
@ -627,6 +655,12 @@ final class KnownTranslationFactory{
]);
}
public static function death_attack_fallingBlock(Translatable|string $param0) : Translatable{
return new Translatable(KnownTranslationKeys::DEATH_ATTACK_FALLINGBLOCK, [
0 => $param0,
]);
}
public static function death_attack_generic(Translatable|string $param0) : Translatable{
return new Translatable(KnownTranslationKeys::DEATH_ATTACK_GENERIC, [
0 => $param0,
@ -691,6 +725,13 @@ final class KnownTranslationFactory{
]);
}
public static function death_attack_trident(Translatable|string $param0, Translatable|string $param1) : Translatable{
return new Translatable(KnownTranslationKeys::DEATH_ATTACK_TRIDENT, [
0 => $param0,
1 => $param1,
]);
}
public static function death_attack_wither(Translatable|string $param0) : Translatable{
return new Translatable(KnownTranslationKeys::DEATH_ATTACK_WITHER, [
0 => $param0,
@ -863,6 +904,10 @@ final class KnownTranslationFactory{
return new Translatable(KnownTranslationKeys::ENCHANTMENT_SOUL_SPEED, []);
}
public static function enchantment_swift_sneak() : Translatable{
return new Translatable(KnownTranslationKeys::ENCHANTMENT_SWIFT_SNEAK, []);
}
public static function enchantment_thorns() : Translatable{
return new Translatable(KnownTranslationKeys::ENCHANTMENT_THORNS, []);
}
@ -954,6 +999,10 @@ final class KnownTranslationFactory{
return new Translatable(KnownTranslationKeys::ITEM_RECORD_13_DESC, []);
}
public static function item_record_5_desc() : Translatable{
return new Translatable(KnownTranslationKeys::ITEM_RECORD_5_DESC, []);
}
public static function item_record_blocks_desc() : Translatable{
return new Translatable(KnownTranslationKeys::ITEM_RECORD_BLOCKS_DESC, []);
}
@ -978,6 +1027,10 @@ final class KnownTranslationFactory{
return new Translatable(KnownTranslationKeys::ITEM_RECORD_MELLOHI_DESC, []);
}
public static function item_record_otherside_desc() : Translatable{
return new Translatable(KnownTranslationKeys::ITEM_RECORD_OTHERSIDE_DESC, []);
}
public static function item_record_pigstep_desc() : Translatable{
return new Translatable(KnownTranslationKeys::ITEM_RECORD_PIGSTEP_DESC, []);
}

View File

@ -33,6 +33,13 @@ final class KnownTranslationKeys{
public const ABILITY_FLIGHT = "ability.flight";
public const ABILITY_NOCLIP = "ability.noclip";
public const ACCEPT_LICENSE = "accept_license";
public const ACTION_INTERACT_ARMORSTAND_EQUIP = "action.interact.armorstand.equip";
public const ACTION_INTERACT_ARMORSTAND_POSE = "action.interact.armorstand.pose";
public const ACTION_INTERACT_EXIT_BOAT = "action.interact.exit.boat";
public const ACTION_INTERACT_FISHING = "action.interact.fishing";
public const ACTION_INTERACT_NAME = "action.interact.name";
public const ACTION_INTERACT_RIDE_BOAT = "action.interact.ride.boat";
public const ACTION_INTERACT_RIDE_MINECART = "action.interact.ride.minecart";
public const CHAT_TYPE_ACHIEVEMENT = "chat.type.achievement";
public const CHAT_TYPE_ADMIN = "chat.type.admin";
public const CHAT_TYPE_ANNOUNCEMENT = "chat.type.announcement";
@ -138,6 +145,7 @@ final class KnownTranslationKeys{
public const DEATH_ATTACK_EXPLOSION = "death.attack.explosion";
public const DEATH_ATTACK_EXPLOSION_PLAYER = "death.attack.explosion.player";
public const DEATH_ATTACK_FALL = "death.attack.fall";
public const DEATH_ATTACK_FALLINGBLOCK = "death.attack.fallingBlock";
public const DEATH_ATTACK_GENERIC = "death.attack.generic";
public const DEATH_ATTACK_INFIRE = "death.attack.inFire";
public const DEATH_ATTACK_INWALL = "death.attack.inWall";
@ -148,6 +156,7 @@ final class KnownTranslationKeys{
public const DEATH_ATTACK_OUTOFWORLD = "death.attack.outOfWorld";
public const DEATH_ATTACK_PLAYER = "death.attack.player";
public const DEATH_ATTACK_PLAYER_ITEM = "death.attack.player.item";
public const DEATH_ATTACK_TRIDENT = "death.attack.trident";
public const DEATH_ATTACK_WITHER = "death.attack.wither";
public const DEATH_FELL_ACCIDENT_GENERIC = "death.fell.accident.generic";
public const DEFAULT_GAMEMODE = "default_gamemode";
@ -190,6 +199,7 @@ final class KnownTranslationKeys{
public const ENCHANTMENT_PROTECT_FIRE = "enchantment.protect.fire";
public const ENCHANTMENT_PROTECT_PROJECTILE = "enchantment.protect.projectile";
public const ENCHANTMENT_SOUL_SPEED = "enchantment.soul_speed";
public const ENCHANTMENT_SWIFT_SNEAK = "enchantment.swift_sneak";
public const ENCHANTMENT_THORNS = "enchantment.thorns";
public const ENCHANTMENT_TRIDENTCHANNELING = "enchantment.tridentChanneling";
public const ENCHANTMENT_TRIDENTIMPALING = "enchantment.tridentImpaling";
@ -211,12 +221,14 @@ final class KnownTranslationKeys{
public const IP_WARNING = "ip_warning";
public const ITEM_RECORD_11_DESC = "item.record_11.desc";
public const ITEM_RECORD_13_DESC = "item.record_13.desc";
public const ITEM_RECORD_5_DESC = "item.record_5.desc";
public const ITEM_RECORD_BLOCKS_DESC = "item.record_blocks.desc";
public const ITEM_RECORD_CAT_DESC = "item.record_cat.desc";
public const ITEM_RECORD_CHIRP_DESC = "item.record_chirp.desc";
public const ITEM_RECORD_FAR_DESC = "item.record_far.desc";
public const ITEM_RECORD_MALL_DESC = "item.record_mall.desc";
public const ITEM_RECORD_MELLOHI_DESC = "item.record_mellohi.desc";
public const ITEM_RECORD_OTHERSIDE_DESC = "item.record_otherside.desc";
public const ITEM_RECORD_PIGSTEP_DESC = "item.record_pigstep.desc";
public const ITEM_RECORD_STAL_DESC = "item.record_stal.desc";
public const ITEM_RECORD_STRAD_DESC = "item.record_strad.desc";

View File

@ -173,6 +173,14 @@ class Language{
return $this->internalGet($id) ?? $id;
}
/**
* @return string[]
* @phpstan-return array<string, string>
*/
public function getAll() : array{
return $this->lang;
}
protected function parseTranslation(string $text, ?string $onlyPrefix = null) : string{
$newString = "";

View File

@ -35,7 +35,7 @@ interface AdvancedNetworkInterface extends NetworkInterface{
/**
* Prevents packets received from the IP address getting processed for the given timeout.
*
* @param int $timeout Seconds
* @param int $timeout Seconds
*/
public function blockAddress(string $address, int $timeout = 300) : void;

View File

@ -54,7 +54,7 @@ class Network{
private BidirectionalBandwidthStatsTracker $bandwidthTracker;
private string $name;
private NetworkSessionManager$sessionManager;
private NetworkSessionManager $sessionManager;
public function __construct(
private \Logger $logger
@ -80,6 +80,10 @@ class Network{
return $this->sessionManager->getSessionCount();
}
public function getValidConnectionCount() : int{
return $this->sessionManager->getValidSessionCount();
}
public function tick() : void{
foreach($this->interfaces as $interface){
$interface->tick();

View File

@ -32,12 +32,25 @@ class NetworkSessionManager{
/** @var NetworkSession[] */
private array $sessions = [];
/** @var NetworkSession[] */
private array $pendingLoginSessions = [];
/**
* Adds a network session to the manager. This should only be called on session creation.
*/
public function add(NetworkSession $session) : void{
$idx = spl_object_id($session);
$this->sessions[$idx] = $session;
$this->pendingLoginSessions[$idx] = $session;
}
/**
* Marks the session as having sent a login request. After this point, they are counted towards the total player
* count.
*/
public function markLoginReceived(NetworkSession $session) : void{
$idx = spl_object_id($session);
unset($this->pendingLoginSessions[$idx]);
}
/**
@ -47,15 +60,24 @@ class NetworkSessionManager{
public function remove(NetworkSession $session) : void{
$idx = spl_object_id($session);
unset($this->sessions[$idx]);
unset($this->pendingLoginSessions[$idx]);
}
/**
* Returns the number of known connected sessions.
* Returns the number of known connected sessions, including sessions which have not yet sent a login request.
*/
public function getSessionCount() : int{
return count($this->sessions);
}
/**
* Returns the number of connected sessions which have either sent a login request, or have already completed the
* login sequence.
*/
public function getValidSessionCount() : int{
return count($this->sessions) - count($this->pendingLoginSessions);
}
/** @return NetworkSession[] */
public function getSessions() : array{ return $this->sessions; }

View File

@ -191,8 +191,10 @@ class InventoryManager{
*/
public function addPredictedSlotChanges(array $networkInventoryActions) : void{
foreach($networkInventoryActions as $action){
if($action->sourceType === NetworkInventoryAction::SOURCE_CONTAINER && isset($this->windowMap[$action->windowId])){
//this won't cover stuff like crafting grid due to too much magic
if($action->sourceType === NetworkInventoryAction::SOURCE_CONTAINER && (
isset($this->windowMap[$action->windowId]) ||
($action->windowId === ContainerIds::UI && isset($this->complexSlotToWindowMap[$action->inventorySlot]))
)){
try{
$item = TypeConverter::getInstance()->netItemStackToCore($action->newItem->getItemStack());
}catch(TypeConversionException $e){

View File

@ -128,20 +128,38 @@ use function array_values;
use function base64_encode;
use function bin2hex;
use function count;
use function function_exists;
use function get_class;
use function hrtime;
use function in_array;
use function intdiv;
use function json_encode;
use function ksort;
use function min;
use function strcasecmp;
use function strlen;
use function strtolower;
use function substr;
use function time;
use function ucfirst;
use function xdebug_is_debugger_active;
use const JSON_THROW_ON_ERROR;
use const SORT_NUMERIC;
class NetworkSession{
private const INCOMING_PACKET_BATCH_PER_TICK = 2; //we should normally see only 1 per tick - 2 allows recovery of the budget after a lag spike
private const INCOMING_PACKET_BATCH_MAX_BUDGET = 100; //enough to account for a 5-second lag spike
/**
* At most this many more packets can be received. If this reaches zero, any additional packets received will cause
* the player to be kicked from the server.
* This number is increased every tick up to a maximum limit.
*
* @see self::INCOMING_PACKET_BATCH_PER_TICK
* @see self::INCOMING_PACKET_BATCH_MAX_BUDGET
*/
private int $incomingPacketBatchBudget = self::INCOMING_PACKET_BATCH_MAX_BUDGET;
private \PrefixedLogger $logger;
private ?Player $player = null;
private ?PlayerInfo $info = null;
@ -179,6 +197,8 @@ class NetworkSession{
*/
private ObjectSet $disposeHooks;
private int $lastUpdateTimeNs;
public function __construct(
private Server $server,
private NetworkSessionManager $manager,
@ -199,6 +219,7 @@ class NetworkSession{
$this->disposeHooks = new ObjectSet();
$this->connectTime = time();
$this->lastUpdateTimeNs = hrtime(true);
$this->setHandler(new SessionStartPacketHandler(
$this->server,
@ -229,6 +250,7 @@ class NetworkSession{
$this->info = $info;
$this->logger->info("Player: " . TextFormat::AQUA . $info->getUsername() . TextFormat::RESET);
$this->logger->setPrefix($this->getLogPrefix());
$this->manager->markLoginReceived($this);
},
function(bool $isAuthenticated, bool $authRequired, ?string $error, ?string $clientPubKey) : void{
$this->setAuthenticationStatus($isAuthenticated, $authRequired, $error, $clientPubKey);
@ -338,6 +360,17 @@ class NetworkSession{
return;
}
if($this->incomingPacketBatchBudget <= 0){
if(!function_exists('xdebug_is_debugger_active') || !xdebug_is_debugger_active()){
throw new PacketHandlingException("Receiving packets too fast");
}else{
//when a debugging session is active, the server may halt at any point for an indefinite length of time,
//in which time the client will continue to send packets
$this->incomingPacketBatchBudget = self::INCOMING_PACKET_BATCH_MAX_BUDGET;
}
}
$this->incomingPacketBatchBudget--;
if($this->cipher !== null){
Timings::$playerNetworkReceiveDecrypt->startTiming();
try{
@ -365,7 +398,7 @@ class NetworkSession{
}
try{
foreach((new PacketBatch($decompressed))->getPackets($this->packetPool, $this->packetSerializerContext, 500) as [$packet, $buffer]){
foreach((new PacketBatch($decompressed))->getPackets($this->packetPool, $this->packetSerializerContext, 1300) as [$packet, $buffer]){
if($packet === null){
$this->logger->debug("Unknown packet: " . base64_encode($buffer));
throw new PacketHandlingException("Unknown packet received");
@ -1107,6 +1140,10 @@ class NetworkSession{
}
public function tick() : void{
$nowNs = hrtime(true);
$timeSinceLastUpdateNs = $nowNs - $this->lastUpdateTimeNs;
$this->lastUpdateTimeNs = $nowNs;
if($this->info === null){
if(time() >= $this->connectTime + 10){
$this->disconnect("Login timeout");
@ -1128,5 +1165,15 @@ class NetworkSession{
}
$this->flushSendBuffer();
$ticksSinceLastUpdate = intdiv($timeSinceLastUpdateNs, 50_000_000);
if($ticksSinceLastUpdate > 0){
if($ticksSinceLastUpdate > 1){
$this->logger->debug("Adding packet budget for $ticksSinceLastUpdate ticks (current budget is $this->incomingPacketBatchBudget)");
}
$this->incomingPacketBatchBudget = min(
$this->incomingPacketBatchBudget + (self::INCOMING_PACKET_BATCH_PER_TICK * $ticksSinceLastUpdate),
self::INCOMING_PACKET_BATCH_MAX_BUDGET
);
}
}
}

View File

@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\ClientboundPacket;
interface PacketBroadcaster{
/**
* @param NetworkSession[] $recipients
* @param NetworkSession[] $recipients
* @param ClientboundPacket[] $packets
*/
public function broadcastPackets(array $recipients, array $packets) : void;

View File

@ -118,7 +118,7 @@ final class ItemTranslator{
}
/**
* @param int[] $simpleMappings
* @param int[] $simpleMappings
* @param int[][] $complexMappings
* @phpstan-param array<string, int> $simpleMappings
* @phpstan-param array<string, array<int, int>> $complexMappings

View File

@ -175,6 +175,7 @@ class TypeConverter{
$nbt = new CompoundTag();
}
$nbt->setInt(self::DAMAGE_TAG, $itemStack->getDamage());
$meta = 0;
}elseif($isBlockItem && $itemStack->getMeta() !== 0){
//TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the
//client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata
@ -183,6 +184,7 @@ class TypeConverter{
$nbt = new CompoundTag();
}
$nbt->setInt(self::PM_META_TAG, $itemStack->getMeta());
$meta = 0;
}
}

View File

@ -34,6 +34,7 @@ use function openssl_digest;
use function openssl_error_string;
use function openssl_pkey_derive;
use function str_pad;
use const STR_PAD_LEFT;
final class EncryptionUtils{

View File

@ -112,7 +112,6 @@ use function array_push;
use function base64_encode;
use function count;
use function fmod;
use function implode;
use function in_array;
use function is_bool;
use function is_infinite;
@ -122,12 +121,9 @@ use function json_encode;
use function max;
use function mb_strlen;
use function microtime;
use function preg_match;
use function sprintf;
use function strlen;
use function strpos;
use function substr;
use function trim;
use const JSON_THROW_ON_ERROR;
/**
@ -254,6 +250,10 @@ class InGamePacketHandler extends PacketHandler{
$useItemTransaction = $packet->getItemInteractionData();
if($useItemTransaction !== null){
if(count($useItemTransaction->getTransactionData()->getActions()) > 100){
throw new PacketHandlingException("Too many actions in item use transaction");
}
$this->inventoryManager->addPredictedSlotChanges($useItemTransaction->getTransactionData()->getActions());
if(!$this->handleUseItemTransaction($useItemTransaction->getTransactionData())){
$packetHandled = false;
$this->session->getLogger()->debug("Unhandled transaction in PlayerAuthInputPacket (type " . $useItemTransaction->getTransactionData()->getActionType() . ")");
@ -264,6 +264,9 @@ class InGamePacketHandler extends PacketHandler{
$blockActions = $packet->getBlockActions();
if($blockActions !== null){
if(count($blockActions) > 100){
throw new PacketHandlingException("Too many block actions in PlayerAuthInputPacket");
}
foreach($blockActions as $k => $blockAction){
$actionHandled = false;
if($blockAction instanceof PlayerBlockActionStopBreak){
@ -310,6 +313,12 @@ class InGamePacketHandler extends PacketHandler{
public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
$result = true;
if(count($packet->trData->getActions()) > 100){
throw new PacketHandlingException("Too many actions in inventory transaction");
}
$this->inventoryManager->addPredictedSlotChanges($packet->trData->getActions());
if($packet->trData instanceof NormalTransactionData){
$result = $this->handleNormalTransaction($packet->trData);
}elseif($packet->trData instanceof MismatchTransactionData){
@ -324,9 +333,7 @@ class InGamePacketHandler extends PacketHandler{
$result = $this->handleReleaseItemTransaction($packet->trData);
}
if(!$result){
$this->inventoryManager->syncAll();
}else{
if($this->craftingTransaction === null){ //don't sync if we're waiting to complete a crafting transaction
$this->inventoryManager->syncMismatchedPredictedSlotChanges();
}
return $result;
@ -381,15 +388,9 @@ class InGamePacketHandler extends PacketHandler{
}
$this->player->setUsingItem(false);
try{
$this->inventoryManager->onTransactionStart($this->craftingTransaction);
$this->craftingTransaction->execute();
}catch(TransactionException $e){
$this->session->getLogger()->debug("Failed to execute crafting transaction: " . $e->getMessage());
//TODO: only sync slots that the client tried to change
foreach($this->craftingTransaction->getInventories() as $inventory){
$this->inventoryManager->syncContents($inventory);
}
return false;
}finally{
$this->craftingTransaction = null;
@ -409,18 +410,12 @@ class InGamePacketHandler extends PacketHandler{
$this->player->setUsingItem(false);
$transaction = new InventoryTransaction($this->player, $actions);
$this->inventoryManager->onTransactionStart($transaction);
try{
$transaction->execute();
}catch(TransactionException $e){
$logger = $this->session->getLogger();
$logger->debug("Failed to execute inventory transaction: " . $e->getMessage());
$logger->debug("Actions: " . json_encode($data->getActions()));
foreach($transaction->getInventories() as $inventory){
$this->inventoryManager->syncContents($inventory);
}
return false;
}
}
@ -430,7 +425,6 @@ class InGamePacketHandler extends PacketHandler{
private function handleUseItemTransaction(UseItemTransactionData $data) : bool{
$this->player->selectHotbarSlot($data->getHotbarSlot());
$this->inventoryManager->addPredictedSlotChanges($data->getActions());
switch($data->getActionType()){
case UseItemTransactionData::ACTION_CLICK_BLOCK:
@ -516,9 +510,7 @@ class InGamePacketHandler extends PacketHandler{
}
$this->player->selectHotbarSlot($data->getHotbarSlot());
$this->inventoryManager->addPredictedSlotChanges($data->getActions());
//TODO: use transactiondata for rollbacks here
switch($data->getActionType()){
case UseItemOnEntityTransactionData::ACTION_INTERACT:
$this->player->interactEntity($target, $data->getClickPosition());
@ -533,15 +525,10 @@ class InGamePacketHandler extends PacketHandler{
private function handleReleaseItemTransaction(ReleaseItemTransactionData $data) : bool{
$this->player->selectHotbarSlot($data->getHotbarSlot());
$this->inventoryManager->addPredictedSlotChanges($data->getActions());
//TODO: use transactiondata for rollbacks here (resending entire inventory is very wasteful)
switch($data->getActionType()){
case ReleaseItemTransactionData::ACTION_RELEASE:
if(!$this->player->releaseHeldItem()){
$this->inventoryManager->syncContents($this->player->getInventory());
}
return true;
if($data->getActionType() == ReleaseItemTransactionData::ACTION_RELEASE){
$this->player->releaseHeldItem();
return true;
}
return false;
@ -884,60 +871,17 @@ class InGamePacketHandler extends PacketHandler{
//TODO: make APIs for this to allow plugins to use this information
return $this->player->onFormSubmit($packet->formId, null);
}elseif($packet->formData !== null){
return $this->player->onFormSubmit($packet->formId, self::stupid_json_decode($packet->formData, true));
try{
$responseData = json_decode($packet->formData, true, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR);
}catch(\JsonException $e){
throw PacketHandlingException::wrap($e, "Failed to decode form response data");
}
return $this->player->onFormSubmit($packet->formId, $responseData);
}else{
throw new PacketHandlingException("Expected either formData or cancelReason to be set in ModalFormResponsePacket");
}
}
/**
* Hack to work around a stupid bug in Minecraft W10 which causes empty strings to be sent unquoted in form responses.
*
* @return mixed
* @throws PacketHandlingException
*/
private static function stupid_json_decode(string $json, bool $assoc = false){
if(preg_match('/^\[(.+)\]$/s', $json, $matches) > 0){
$raw = $matches[1];
$lastComma = -1;
$newParts = [];
$inQuotes = false;
for($i = 0, $len = strlen($raw); $i <= $len; ++$i){
if($i === $len || ($raw[$i] === "," && !$inQuotes)){
$part = substr($raw, $lastComma + 1, $i - ($lastComma + 1));
if(trim($part) === ""){ //regular parts will have quotes or something else that makes them non-empty
$part = '""';
}
$newParts[] = $part;
$lastComma = $i;
}elseif($raw[$i] === '"'){
if(!$inQuotes){
$inQuotes = true;
}else{
$backslashes = 0;
for(; $backslashes < $i && $raw[$i - $backslashes - 1] === "\\"; ++$backslashes){}
if(($backslashes % 2) === 0){ //unescaped quote
$inQuotes = false;
}
}
}
}
$fixed = "[" . implode(",", $newParts) . "]";
try{
return json_decode($fixed, $assoc, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR);
}catch(\JsonException $e){
throw PacketHandlingException::wrap($e, "Failed to fix JSON (original: $json, modified: $fixed)");
}
}
try{
return json_decode($json, $assoc, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR);
}catch(\JsonException $e){
throw PacketHandlingException::wrap($e);
}
}
public function handleServerSettingsRequest(ServerSettingsRequestPacket $packet) : bool{
return false; //TODO: GUI stuff
}

View File

@ -123,7 +123,7 @@ class LoginPacketHandler extends PacketHandler{
$this->session->getPort(),
$this->server->requiresAuthentication()
);
if($this->server->getNetwork()->getConnectionCount() > $this->server->getMaxPlayers()){
if($this->server->getNetwork()->getValidConnectionCount() > $this->server->getMaxPlayers()){
$ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_SERVER_FULL, KnownTranslationKeys::DISCONNECTIONSCREEN_SERVERFULL);
}
if(!$this->server->isWhitelisted($playerInfo->getUsername())){

View File

@ -52,6 +52,7 @@ use function mt_rand;
use function random_bytes;
use function rtrim;
use function substr;
use const PHP_INT_MAX;
class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
/**

View File

@ -40,6 +40,7 @@ use function strlen;
use function time;
use function trim;
use const AF_INET;
use const AF_INET6;
use const IPPROTO_IPV6;
use const IPV6_V6ONLY;
use const PHP_INT_MAX;

View File

@ -73,6 +73,12 @@ use function sprintf;
use function strlen;
use function trim;
use const AF_INET;
use const PREG_BACKTRACK_LIMIT_ERROR;
use const PREG_BAD_UTF8_ERROR;
use const PREG_BAD_UTF8_OFFSET_ERROR;
use const PREG_INTERNAL_ERROR;
use const PREG_JIT_STACKLIMIT_ERROR;
use const PREG_RECURSION_LIMIT_ERROR;
use const SO_RCVTIMEO;
use const SOCK_DGRAM;
use const SOCKET_ETIMEDOUT;

View File

@ -1390,7 +1390,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
/**
* Returns whether the player can interact with the specified position. This checks distance and direction.
*
* @param float $maxDiff defaults to half of the 3D diagonal width of a block
* @param float $maxDiff defaults to half of the 3D diagonal width of a block
*/
public function canInteract(Vector3 $pos, float $maxDistance, float $maxDiff = M_SQRT3 / 2) : bool{
$eyePos = $this->getEyePos();
@ -1916,9 +1916,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
/**
* Adds a title text to the user's screen, with an optional subtitle.
*
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
* @param int $stay Duration in ticks to stay on screen for
* @param int $fadeOut Duration in ticks for fade-out.
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
* @param int $stay Duration in ticks to stay on screen for
* @param int $fadeOut Duration in ticks for fade-out.
*/
public function sendTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1) : void{
$this->setTitleDuration($fadeIn, $stay, $fadeOut);
@ -1959,8 +1959,8 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
/**
* Sets the title duration.
*
* @param int $fadeIn Title fade-in time in ticks.
* @param int $stay Title stay time in ticks.
* @param int $fadeIn Title fade-in time in ticks.
* @param int $stay Title stay time in ticks.
* @param int $fadeOut Title fade-out time in ticks.
*/
public function setTitleDuration(int $fadeIn, int $stay, int $fadeOut) : void{
@ -2061,7 +2061,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
* Transfers a player to another server.
*
* @param string $address The IP address or hostname of the destination server
* @param int $port The destination port, defaults to 19132
* @param int $port The destination port, defaults to 19132
* @param string $message Message to show in the console when closing the player
*
* @return bool if transfer was successful.
@ -2105,7 +2105,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
*
* Note for internals developers: Do not call this from network sessions. It will cause a feedback loop.
*
* @param string $reason Shown to the player, usually this will appear on their disconnect screen.
* @param string $reason Shown to the player, usually this will appear on their disconnect screen.
* @param Translatable|string|null $quitMessage Message to broadcast to online players (null will use default)
*/
public function disconnect(string $reason, Translatable|string|null $quitMessage = null) : void{
@ -2121,7 +2121,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
* @internal
* This method executes post-disconnect actions and cleanups.
*
* @param string $reason Shown to the player, usually this will appear on their disconnect screen.
* @param string $reason Shown to the player, usually this will appear on their disconnect screen.
* @param Translatable|string|null $quitMessage Message to broadcast to online players (null will use default)
*/
public function onPostDisconnect(string $reason, Translatable|string|null $quitMessage) : void{
@ -2448,7 +2448,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->cursorInventory = new PlayerCursorInventory($this);
$this->craftingGrid = new PlayerCraftingInventory($this);
$this->addPermanentInventories($this->inventory, $this->armorInventory, $this->cursorInventory, $this->offHandInventory);
$this->addPermanentInventories($this->inventory, $this->armorInventory, $this->cursorInventory, $this->offHandInventory, $this->craftingGrid);
//TODO: more windows
}

View File

@ -45,6 +45,7 @@ use function stream_copy_to_stream;
use function strpos;
use function strtolower;
use function trim;
use const DIRECTORY_SEPARATOR;
abstract class PluginBase implements Plugin, CommandExecutor{
private bool $isEnabled = false;
@ -201,7 +202,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
}
/**
* @param string[] $args
* @param string[] $args
*/
public function onCommand(CommandSender $sender, Command $command, string $label, array $args) : bool{
return false;

View File

@ -57,7 +57,7 @@ interface ResourcePack{
* Note that resource packs must **always** be in zip archive format for sending.
* A folder resource loader may need to perform on-the-fly compression for this purpose.
*
* @param int $start Offset to start reading the chunk from
* @param int $start Offset to start reading the chunk from
* @param int $length Maximum length of data to return.
*
* @return string byte-array

View File

@ -58,7 +58,7 @@ class ResourcePackManager{
private array $encryptionKeys = [];
/**
* @param string $path Path to resource-packs directory.
* @param string $path Path to resource-packs directory.
*/
public function __construct(string $path, \Logger $logger){
$this->path = $path;

View File

@ -187,7 +187,7 @@ abstract class AsyncTask extends \Threaded{
* {@link AsyncTask::onCompletion} is called.
*
* @param mixed $progress The parameter passed to {@link AsyncTask#publishProgress}. It is serialize()'ed
* and then unserialize()'ed, as if it has been cloned.
* and then unserialize()'ed, as if it has been cloned.
*/
public function onProgressUpdate($progress) : void{
@ -215,7 +215,7 @@ abstract class AsyncTask extends \Threaded{
* Objects stored in this storage can be retrieved using fetchLocal() on the same thread that this method was called
* from.
*
* @param mixed $complexData the data to store
* @param mixed $complexData the data to store
*/
protected function storeLocal(string $key, $complexData) : void{
if(self::$threadLocalStorage === null){

View File

@ -77,7 +77,7 @@ class AsyncWorker extends Worker{
* Saves mixed data into the worker's thread-local object store. This can be used to store objects which you
* want to use on this worker thread from multiple AsyncTasks.
*
* @param mixed $value
* @param mixed $value
*/
public function saveToThreadStore(string $identifier, $value) : void{
if(\Thread::getCurrentThread() !== $this){

View File

@ -26,7 +26,7 @@ namespace pocketmine\scheduler;
final class BulkCurlTaskOperation{
/**
* @param string[] $extraHeaders
* @param mixed[] $extraOpts
* @param mixed[] $extraOpts
* @phpstan-param list<string> $extraHeaders
* @phpstan-param array<int, mixed> $extraOpts
*/

View File

@ -29,6 +29,7 @@ use pocketmine\lang\Translatable;
use pocketmine\permission\PermissibleBase;
use pocketmine\permission\PermissibleDelegateTrait;
use pocketmine\Server;
use const PHP_INT_MAX;
/**
* Forwards any messages it receives via sendMessage() to the given logger. Used for forwarding chat messages and

View File

@ -23,6 +23,10 @@ declare(strict_types=1);
namespace pocketmine\utils;
/**
* This trait offers the same functionality as RegistryTrait, but also clones any returned objects to prevent outside
* modification.
*/
trait CloningRegistryTrait{
use RegistryTrait;

View File

@ -55,6 +55,7 @@ use const CASE_LOWER;
use const JSON_BIGINT_AS_STRING;
use const JSON_PRETTY_PRINT;
use const JSON_THROW_ON_ERROR;
use const YAML_UTF8_ENCODING;
/**
* Config Class for simple config manipulation of multiple formats.
@ -108,8 +109,8 @@ class Config{
];
/**
* @param string $file Path of the file to be loaded
* @param int $type Config type to load, -1 by default (detect)
* @param string $file Path of the file to be loaded
* @param int $type Config type to load, -1 by default (detect)
* @param mixed[] $default Array with the default values that will be written to the file if it did not exist
* @phpstan-param array<string, mixed> $default
*/
@ -493,7 +494,7 @@ class Config{
/**
* @param mixed[] $default
* @param mixed[] $data reference parameter
* @param mixed[] $data reference parameter
* @phpstan-param array<string, mixed> $default
* @phpstan-param array<string, mixed> $data
* @phpstan-param-out array<string, mixed> $data

View File

@ -23,6 +23,13 @@ declare(strict_types=1);
namespace pocketmine\utils;
/**
* This trait allows a class to simulate a Java-style enum. Members are exposed as static methods and handled via
* __callStatic().
*
* Classes using this trait need to include \@method tags in their class docblock for every enum member.
* Alternatively, just put \@generate-registry-docblock in the docblock and run tools/generate-registry-annotations.php
*/
trait EnumTrait{
use RegistryTrait;
use NotCloneable;

View File

@ -187,9 +187,10 @@ final class Filesystem{
* @throws \InvalidArgumentException if the lock file path is invalid (e.g. parent directory doesn't exist, permission denied)
*/
public static function createLockFile(string $lockFilePath) : ?int{
$resource = fopen($lockFilePath, "a+b");
if($resource === false){
throw new \InvalidArgumentException("Invalid lock file path or read/write permissions denied");
try{
$resource = ErrorToExceptionHandler::trapAndRemoveFalse(fn() => fopen($lockFilePath, "a+b"));
}catch(\ErrorException $e){
throw new \InvalidArgumentException("Failed to open lock file: " . $e->getMessage(), 0, $e);
}
if(!flock($resource, LOCK_EX | LOCK_NB)){
//wait for a shared lock to avoid race conditions if two servers started at the same time - this makes sure the

View File

@ -36,7 +36,7 @@ final class Git{
/**
* Returns the git hash of the currently checked out head of the given repository, or null on failure.
*
* @param bool $dirty reference parameter, set to whether the repo has local changes
* @param bool $dirty reference parameter, set to whether the repo has local changes
*/
public static function getRepositoryState(string $dir, bool &$dirty) : ?string{
if(Process::execute("git -C \"$dir\" rev-parse HEAD", $out) === 0 && $out !== false && strlen($out = trim($out)) === 40){

View File

@ -141,9 +141,9 @@ class Internet{
*
* @phpstan-template TErrorVar of mixed
*
* @param int $timeout default 10
* @param int $timeout default 10
* @param string[] $extraHeaders
* @param string|null $err reference parameter, will be set to the output of curl_error(). Use this to retrieve errors that occured during the operation.
* @param string|null $err reference parameter, will be set to the output of curl_error(). Use this to retrieve errors that occured during the operation.
* @phpstan-param list<string> $extraHeaders
* @phpstan-param TErrorVar $err
* @phpstan-param-out TErrorVar|string $err
@ -165,7 +165,7 @@ class Internet{
*
* @param string[]|string $args
* @param string[] $extraHeaders
* @param string|null $err reference parameter, will be set to the output of curl_error(). Use this to retrieve errors that occurred during the operation.
* @param string|null $err reference parameter, will be set to the output of curl_error(). Use this to retrieve errors that occurred during the operation.
* @phpstan-param string|array<string, string> $args
* @phpstan-param list<string> $extraHeaders
* @phpstan-param TErrorVar $err
@ -187,7 +187,7 @@ class Internet{
* General cURL shorthand function.
* NOTE: This is a blocking operation and can take a significant amount of time. It is inadvisable to use this method on the main thread.
*
* @param float|int $timeout The maximum connect timeout and timeout in seconds, correct to ms.
* @param float|int $timeout The maximum connect timeout and timeout in seconds, correct to ms.
* @param string[] $extraHeaders extra headers to send as a plain string array
* @param array $extraOpts extra CURLOPT_* to set as an [opt => value] map
* @param \Closure|null $onSuccess function to be called if there is no error. Accepts a resource argument as the cURL handle.

View File

@ -150,8 +150,8 @@ final class Process{
/**
* @param string $command Command to execute
* @param string|null $stdout Reference parameter to write stdout to
* @param string|null $stderr Reference parameter to write stderr to
* @param string|null $stdout Reference parameter to write stdout to
* @param string|null $stderr Reference parameter to write stderr to
* @phpstan-param-out string $stdout
* @phpstan-param-out string $stderr
*

View File

@ -115,7 +115,7 @@ class Random{
* Returns a random integer between $start and $end
*
* @param int $start default 0
* @param int $end default 0x7fffffff
* @param int $end default 0x7fffffff
*/
public function nextRange(int $start = 0, int $end = 0x7fffffff) : int{
return $start + ($this->nextInt() % ($end + 1 - $start));

View File

@ -28,6 +28,13 @@ use function count;
use function mb_strtoupper;
use function preg_match;
/**
* This trait allows a class to simulate object class constants, since PHP doesn't currently support this.
* These faux constants are exposed in static class methods, which are handled using __callStatic().
*
* Classes using this trait need to include \@method tags in their class docblock for every faux constant.
* Alternatively, just put \@generate-registry-docblock in the docblock and run tools/generate-registry-annotations.php
*/
trait RegistryTrait{
/**
* @var object[]

View File

@ -166,8 +166,10 @@ abstract class Terminal{
case Utils::OS_LINUX:
case Utils::OS_MACOS:
case Utils::OS_BSD:
self::getEscapeCodes();
return;
if(getenv('TERM') !== false){
self::getEscapeCodes();
return;
}
case Utils::OS_WINDOWS:
case Utils::OS_ANDROID:

View File

@ -539,7 +539,7 @@ final class Utils{
* incompatible.
*
* @param callable|CallbackType $signature Dummy callable with the required parameters and return type
* @param callable $subject Callable to check the signature of
* @param callable $subject Callable to check the signature of
* @phpstan-param anyCallable|CallbackType $signature
* @phpstan-param anyCallable $subject
*

View File

@ -643,7 +643,7 @@ class World implements ChunkManager{
* Returns a list of players who are in the given filter and also using the chunk containing the target position.
* Used for broadcasting sounds and particles with specific targets.
*
* @param Player[] $allowed
* @param Player[] $allowed
* @phpstan-param list<Player> $allowed
*
* @return array<int, Player>
@ -1222,7 +1222,8 @@ class World implements ChunkManager{
private function tickChunk(int $chunkX, int $chunkZ) : void{
$chunk = $this->getChunk($chunkX, $chunkZ);
if($chunk === null){
throw new \InvalidArgumentException("Chunk is not loaded");
//the chunk may have been unloaded during a previous chunk's update (e.g. during BlockGrowEvent)
return;
}
foreach($this->getChunkEntities($chunkX, $chunkZ) as $entity){
$entity->onRandomUpdate();
@ -1320,7 +1321,9 @@ class World implements ChunkManager{
/**
* Notify the blocks at and around the position that the block at the position may have changed.
* This will cause onNeighbourBlockUpdate() to be called for these blocks.
* This will cause onNearbyBlockChange() to be called for these blocks.
*
* @see Block::onNearbyBlockChange()
*/
public function notifyNeighbourBlockUpdate(Vector3 $pos) : void{
$this->tryAddToNeighbourUpdateQueue($pos);
@ -1634,8 +1637,8 @@ class World implements ChunkManager{
* Note: If you're using this for performance-sensitive code, and you're guaranteed to be supplying ints in the
* specified vector, consider using {@link getBlockAt} instead for better performance.
*
* @param bool $cached Whether to use the block cache for getting the block (faster, but may be inaccurate)
* @param bool $addToCache Whether to cache the block object created by this method call.
* @param bool $cached Whether to use the block cache for getting the block (faster, but may be inaccurate)
* @param bool $addToCache Whether to cache the block object created by this method call.
*/
public function getBlock(Vector3 $pos, bool $cached = true, bool $addToCache = true) : Block{
return $this->getBlockAt((int) floor($pos->x), (int) floor($pos->y), (int) floor($pos->z), $cached, $addToCache);
@ -1647,7 +1650,7 @@ class World implements ChunkManager{
* Note for plugin developers: If you are using this method a lot (thousands of times for many positions for
* example), you may want to set addToCache to false to avoid using excessive amounts of memory.
*
* @param bool $cached Whether to use the block cache for getting the block (faster, but may be inaccurate)
* @param bool $cached Whether to use the block cache for getting the block (faster, but may be inaccurate)
* @param bool $addToCache Whether to cache the block object created by this method call.
*/
public function getBlockAt(int $x, int $y, int $z, bool $cached = true, bool $addToCache = true) : Block{
@ -1794,7 +1797,7 @@ class World implements ChunkManager{
* Tries to break a block using a item, including Player time checks if available
* It'll try to lower the durability if Item is a tool, and set it to Air if broken.
*
* @param Item $item reference parameter (if null, can break anything)
* @param Item $item reference parameter (if null, can break anything)
* @phpstan-param-out Item $item
*/
public function useBreakOn(Vector3 $vector, Item &$item = null, ?Player $player = null, bool $createParticles = false) : bool{
@ -1896,8 +1899,8 @@ class World implements ChunkManager{
/**
* Uses a item on a position and face, placing it or activating the block
*
* @param Player|null $player default null
* @param bool $playSound Whether to play a block-place sound if the block was placed successfully.
* @param Player|null $player default null
* @param bool $playSound Whether to play a block-place sound if the block was placed successfully.
*/
public function useItemOn(Vector3 $vector, Item &$item, int $face, ?Vector3 $clickVector = null, ?Player $player = null, bool $playSound = false) : bool{
$blockClicked = $this->getBlock($vector);
@ -2092,8 +2095,8 @@ class World implements ChunkManager{
/**
* Returns the closest Entity to the specified position, within the given radius.
*
* @param string $entityType Class of entity to use for instanceof
* @param bool $includeDead Whether to include entitites which are dead
* @param string $entityType Class of entity to use for instanceof
* @param bool $includeDead Whether to include entitites which are dead
* @phpstan-template TEntity of Entity
* @phpstan-param class-string<TEntity> $entityType
*

View File

@ -166,7 +166,7 @@ class WorldManager{
/**
* Loads a world from the data directory
*
* @param bool $autoUpgrade Converts worlds to the default format if the world's format is not writable / deprecated
* @param bool $autoUpgrade Converts worlds to the default format if the world's format is not writable / deprecated
*
* @throws WorldException
*/

View File

@ -164,8 +164,8 @@ class Chunk{
/**
* Sets the biome ID at the specified X/Z chunk block coordinates
*
* @param int $x 0-15
* @param int $z 0-15
* @param int $x 0-15
* @param int $z 0-15
* @param int $biomeId 0-255
*/
public function setBiomeId(int $x, int $z, int $biomeId) : void{

View File

@ -504,7 +504,7 @@ class LevelDB extends BaseWorldProvider implements WritableWorldProvider{
}
/**
* @param CompoundTag[] $targets
* @param CompoundTag[] $targets
*/
private function writeTags(array $targets, string $index, \LevelDBWriteBatch $write) : void{
if(count($targets) > 0){

View File

@ -38,7 +38,7 @@ use function preg_match_all;
final class FlatGeneratorOptions{
/**
* @param int[] $structure
* @param int[] $structure
* @param mixed[] $extraOptions
* @phpstan-param array<int, int> $structure
* @phpstan-param array<string, array<string, string>|true> $extraOptions

View File

@ -58,10 +58,10 @@ final class GeneratorManager{
}
/**
* @param string $class Fully qualified name of class that extends \pocketmine\world\generator\Generator
* @param string $name Alias for this generator type that can be written in configs
* @param \Closure $presetValidator Callback to validate generator options for new worlds
* @param bool $overwrite Whether to force overwriting any existing registered generator with the same name
* @param string $class Fully qualified name of class that extends \pocketmine\world\generator\Generator
* @param string $name Alias for this generator type that can be written in configs
* @param \Closure $presetValidator Callback to validate generator options for new worlds
* @param bool $overwrite Whether to force overwriting any existing registered generator with the same name
*
* @phpstan-param \Closure(string) : ?InvalidGeneratorOptionsException $presetValidator
*

View File

@ -208,8 +208,8 @@ class SkyLightUpdate extends LightUpdate{
/**
* Recalculates the heightmap for the block column at the specified X/Z chunk coordinates
*
* @param int $x 0-15
* @param int $z 0-15
* @param int $x 0-15
* @param int $z 0-15
* @param \SplFixedArray|bool[] $directSkyLightBlockers
* @phpstan-param \SplFixedArray<bool> $directSkyLightBlockers
*

View File

@ -0,0 +1,35 @@
<?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\world\sound;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\types\LevelEvent;
class ItemFrameAddItemSound implements Sound{
public function encode(Vector3 $pos) : array{
return [LevelEventPacket::create(LevelEvent::SOUND_ITEMFRAME_ADD_ITEM, 0, $pos)];
}
}

View File

@ -0,0 +1,35 @@
<?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\world\sound;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\types\LevelEvent;
class ItemFrameRemoveItemSound implements Sound{
public function encode(Vector3 $pos) : array{
return [LevelEventPacket::create(LevelEvent::SOUND_ITEMFRAME_REMOVE_ITEM, 0, $pos)];
}
}

View File

@ -0,0 +1,35 @@
<?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\world\sound;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\types\LevelEvent;
class ItemFrameRotateItemSound implements Sound{
public function encode(Vector3 $pos) : array{
return [LevelEventPacket::create(LevelEvent::SOUND_ITEMFRAME_ROTATE_ITEM, 0, $pos)];
}
}

View File

@ -15,11 +15,6 @@ parameters:
count: 1
path: ../../../src/entity/projectile/Projectile.php
-
message: "#^Empty array passed to foreach\\.$#"
count: 1
path: ../../../src/network/mcpe/cache/ChunkCache.php
-
message: "#^Match arm comparison between 4 and 4 is always true\\.$#"
count: 1
@ -51,7 +46,7 @@ parameters:
path: ../../../src/plugin/PluginManager.php
-
message: "#^Offset \\(int\\|string\\) on non\\-empty\\-array\\<pocketmine\\\\plugin\\\\Plugin\\> in isset\\(\\) always exists and is not nullable\\.$#"
message: "#^Offset \\(int\\|string\\) on array\\<pocketmine\\\\plugin\\\\Plugin\\> in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: ../../../src/plugin/PluginManager.php
@ -70,11 +65,6 @@ parameters:
count: 1
path: ../../../src/thread/Worker.php
-
message: "#^Offset \\(int\\|string\\) on non\\-empty\\-array\\<pocketmine\\\\world\\\\World\\> in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: ../../../src/world/WorldManager.php
-
message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#"
count: 2

View File

@ -1,68 +0,0 @@
<?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\handler;
use PHPUnit\Framework\TestCase;
class StupidJsonDecodeTest extends TestCase{
/**
* @var \Closure
* @phpstan-var \Closure(string $json, bool $assoc=) : mixed
*/
private $stupidJsonDecodeFunc;
public function setUp() : void{
$this->stupidJsonDecodeFunc = (new \ReflectionMethod(InGamePacketHandler::class, 'stupid_json_decode'))->getClosure();
}
/**
* @return mixed[][]
* @phpstan-return list<array{string,mixed}>
*/
public function stupidJsonDecodeProvider() : array{
return [
["[\n \"a\",\"b,c,d,e\\\" \",,0,1,2, false, 0.001]", ['a', 'b,c,d,e" ', '', 0, 1, 2, false, 0.001]],
["0", 0],
["false", false],
["null", null],
['["\",,\"word","a\",,\"word2",]', ['",,"word', 'a",,"word2', '']],
['["\",,\"word","a\",,\"word2",""]', ['",,"word', 'a",,"word2', '']],
['["Hello,, PocketMine"]', ['Hello,, PocketMine']],
['[,]', ['', '']],
['[]', []]
];
}
/**
* @dataProvider stupidJsonDecodeProvider
*
* @param mixed $expect
*
* @throws \ReflectionException
*/
public function testStupidJsonDecode(string $brokenJson, $expect) : void{
$decoded = ($this->stupidJsonDecodeFunc)($brokenJson, true);
self::assertEquals($expect, $decoded);
}
}

View File

@ -43,6 +43,10 @@ use function rename;
use function round;
use function scandir;
use function unlink;
use const PATHINFO_EXTENSION;
use const PHP_BINARY;
use const SCANDIR_SORT_NONE;
use const SORT_NUMERIC;
require dirname(__DIR__) . '/vendor/autoload.php';

View File

@ -0,0 +1,89 @@
<?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\tools\decode_crashdump;
use function array_pop;
use function array_slice;
use function base64_decode;
use function count;
use function file;
use function file_put_contents;
use function fwrite;
use function implode;
use function json_decode;
use function json_encode;
use function realpath;
use function trim;
use function zlib_decode;
use const FILE_IGNORE_NEW_LINES;
use const JSON_PRETTY_PRINT;
use const JSON_UNESCAPED_SLASHES;
use const PHP_EOL;
use const STDERR;
if(count($argv) === 2){
$input = $argv[1];
$output = "decoded.json";
}elseif(count($argv) === 3){
[, $input, $output] = $argv;
}else{
fwrite(STDERR, "Required arguments: input file, output file" . PHP_EOL);
exit(1);
}
$lines = file($input, FILE_IGNORE_NEW_LINES);
if($lines === false){
fwrite(STDERR, "Unable to read file $input" . PHP_EOL);
exit(1);
}
$start = -1;
foreach($lines as $num => $line){
if(trim($line) === "===BEGIN CRASH DUMP==="){
$start = $num + 1;
break;
}
}
if($start === -1){
fwrite(STDERR, "Crashdump encoded data not found in target file" . PHP_EOL);
exit(1);
}
$data = array_slice($lines, $start);
array_pop($data);
$zlibData = base64_decode(implode("", $data), true);
if($zlibData === false){
fwrite(STDERR, "Invalid encoded data in crashdump" . PHP_EOL);
exit(1);
}
$decoded = zlib_decode($zlibData);
if($decoded === false){
fwrite(STDERR, "Invalid compressed data in crashdump" . PHP_EOL);
exit(1);
}
file_put_contents($output, json_encode(json_decode($decoded), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
echo "Wrote decoded crashdump to " . realpath($output) . PHP_EOL;

Some files were not shown because too many files have changed in this diff Show More