Compare commits

...

129 Commits
4.6.0 ... 4.9.0

Author SHA1 Message Date
785dc71256 Release 4.9.0 2022-09-20 20:09:38 +01:00
d459afaa54 fix CS 2022-09-20 20:00:40 +01:00
db586233da Changes for 1.19.30 support 2022-09-20 19:50:27 +01:00
23e98a30f5 ItemEntity: don't ignore parent's savable state 2022-09-20 14:50:35 +01:00
5bc7ca6569 ItemEntity: disable saving if the contained item is air or has a zero count 2022-09-20 14:45:10 +01:00
f39d2a9be3 bootstrap: update JIT warning 2022-09-20 14:43:05 +01:00
47d98af6ac Bump ramsey/uuid from 4.5.0 to 4.5.1 (#5292)
Bumps [ramsey/uuid](https://github.com/ramsey/uuid) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/ramsey/uuid/releases)
- [Changelog](https://github.com/ramsey/uuid/blob/4.x/CHANGELOG.md)
- [Commits](https://github.com/ramsey/uuid/compare/4.5.0...4.5.1)

---
updated-dependencies:
- dependency-name: ramsey/uuid
  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-09-16 12:53:46 +01:00
82ba7903c8 Fixed wrong key being used for entity type ID in save data (#5288)
closes #5260
2022-09-15 13:40:48 +01:00
112974758e Updated PHPStan to 1.8.5 2022-09-15 12:13:50 +01:00
313850eec4 Updated composer dependencies 2022-09-15 12:08:36 +01:00
a82923acb4 Updated Actions PHP versions 2022-09-15 12:03:36 +01:00
67887afd6b Updated php-cs-fixer version for Actions 2022-09-15 12:03:04 +01:00
3d03bb1301 Fix CS 2022-09-15 12:01:26 +01:00
c063198b89 Fixed incorrect array key type in BrewingStandTest 2022-09-02 20:01:52 +01:00
f3ca6de1eb shut 2022-09-02 20:00:52 +01:00
88eafdd614 Improve type info for RegistryTrait::getAll() and its users 2022-09-02 19:57:22 +01:00
6dd5fec4ea ExperienceManager: remove superfluous doc comment 2022-09-02 19:38:23 +01:00
6866c86d39 BaseInventory: fix CS 2022-09-02 19:36:45 +01:00
a735a69870 BaseInventory: improve type info available to setContents() and internalSetContents() 2022-09-02 19:36:08 +01:00
a0ea74c08f Inventory: Improve quality of type info of arrays 2022-09-02 19:34:12 +01:00
ca4b8a5827 World: remove local static recursion guard variable, closes #3125 2022-09-02 19:24:09 +01:00
f88c4d9a8c Remove more unnecessary local static variable usages
these are never mutated. Local constants would be better, if we had those.
2022-09-02 19:19:04 +01:00
66cd156d80 Utils: use static property for core count cache, instead of local static variable 2022-09-02 19:18:01 +01:00
222049927a Language: fixed bogus callable reference in array_map
for some reason phpstan only reports this under checkImplicitMixed.
2022-09-02 19:15:05 +01:00
d72e947d15 BlockFactory: avoid unnecessary local static variable usage
phpstan treats these as always mixed, because it can't be sure what their types will be.
2022-09-02 19:14:35 +01:00
770cca2efa Server: harden response handling for crash report submission
this eliminates some checkImplicitMixed errors in phpstan.
2022-09-02 19:13:54 +01:00
033dac3d16 Server: be explicit about the player promise resolver type
since there's no way for phpstan to infer the type of this, it becomes implicit mixed, which can conceal bugs.
2022-09-02 19:13:16 +01:00
1ee02d7e02 Do not install pocketmine/locale-data 2.8.9 (it's incorrectly versioned)
the changes made in 2.8.9 should have been released as a new minor version, not a patch.
2022-09-02 18:43:39 +01:00
85678aa356 phpstan 1.8.3 2022-09-02 18:28:33 +01:00
1d253bc8c2 Utils: remove 32-bit specific code from javaStringHash()
this was necessary in the days of 32-bit, but for 64-bit, the 0xffffffff mask is sufficient and produces the exact same result.
2022-09-02 18:23:49 +01:00
973a56ab28 Update composer dependencies 2022-09-02 18:02:16 +01:00
9e0b4621be Fixed languages-not-found bug (#5272)
* Fixed languages-not-found bug

* Update Language.php

Co-authored-by: Dylan T <odigiman@gmail.com>
2022-09-02 03:51:31 +01:00
b7a15b6e01 Bump phpunit/phpunit from 9.5.23 to 9.5.24 (#5266)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.23 to 9.5.24.
- [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.23...9.5.24)

---
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-08-31 02:11:18 +01:00
456439566b Language: treat empty translation files the same as missing ones 2022-08-31 01:53:15 +01:00
fb25e05416 InventoryManager: fixed current window getting removed in race conditions with close window ACK
this could be observed by pressing E and immediately clicking a chest, which, if timed correctly, would lead to the chest lid closing, but the inventory being opened anyway.
2022-08-27 17:26:43 +01:00
78b5be8dd0 4.8.2 is next 2022-08-26 19:16:39 +01:00
0a92e91a30 Release 4.8.1 2022-08-26 19:16:39 +01:00
b3a13a2f21 in future, do not allow Copilot to write changelogs ... 2022-08-26 19:13:13 +01:00
08b9495bce DyeColorIdMap: fixed uninitialized offset error on invalid dye colours 2022-08-26 18:58:00 +01:00
5779622235 Bump phpunit/phpunit from 9.5.22 to 9.5.23 (#5252)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.22 to 9.5.23.
- [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.22...9.5.23)

---
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-08-25 19:29:25 +01:00
7f175b47e6 Fix CS 2022-08-25 18:19:22 +01:00
0e73ffe555 CrashDump: Added JIT mode to data
this is necessary for identifying JIT-specific bugs, which, unfortunately, are very common.
2022-08-25 17:39:40 +01:00
1ffd38b37b Utils: fixed currentTrace() when xdebug is loaded, but not in develop mode
this is really dumb... why does it register the functions at all if they aren't usable ???
2022-08-25 16:56:26 +01:00
bd13f39156 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2022-08-24 20:04:15 +01:00
0c446c276c 4.8.1 is next 2022-08-24 20:03:57 +01:00
0284e65f60 Release 4.8.0 2022-08-24 20:03:56 +01:00
b0d787b3d3 Update BedrockProtocol for 1.19.21 2022-08-24 19:54:41 +01:00
65e3ed43d5 Bump build/php from e90ff50 to cf79c01 (#5248)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `e90ff50` to `cf79c01`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](e90ff50310...cf79c01722)

---
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-08-24 18:47:04 +01:00
75eba9c9ed 4.7.4 is next 2022-08-22 19:28:47 +01:00
b5a049d1fe Release 4.7.3 2022-08-22 19:28:43 +01:00
bd9fcffe62 Bump build/php from f292501 to e90ff50 (#5242)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `f292501` to `e90ff50`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](f292501a70...e90ff50310)

---
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-08-22 14:42:17 +01:00
feffbc2c5b Bump phpunit/phpunit from 9.5.21 to 9.5.22 (#5243)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.21 to 9.5.22.
- [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.21...9.5.22)

---
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-08-22 14:33:16 +01:00
53b51c99b4 Bump pocketmine/locale-data from 2.8.6 to 2.8.7 (#5244)
Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.8.6 to 2.8.7.
- [Release notes](https://github.com/pmmp/Language/releases)
- [Commits](https://github.com/pmmp/Language/compare/2.8.6...2.8.7)

---
updated-dependencies:
- dependency-name: pocketmine/locale-data
  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-08-22 14:32:50 +01:00
5cb77c8365 GiveCommand: fix CS 2022-08-22 00:55:17 +01:00
bf8befc40b Remove dead comment on GiveCommand (#5241) 2022-08-22 00:49:22 +01:00
f75ca312cc Worker: Unstack tasks in a synchronized block
this prevents any tasks still left in the queue on shutdown getting pulled out by the worker when we're attempting to shut it down.
This led to various race conditions, most notably weird cases where PopulationTask would inexplicably find its expected generator state had not been correctly set up.
2022-08-21 21:57:11 +01:00
d144832928 GiveCommand: limit max amount in line with vanilla 2022-08-21 21:19:16 +01:00
709a869045 Vines can now only be placed on full cube blocks (#5053)
fixes #2673
2022-08-21 21:04:24 +01:00
ac056044ce Updated PHPStan baseline 2022-08-21 20:46:38 +01:00
fc8434308b SignText: changed misleading documentation
this looks like a leftover from the days when sign text was handled by the tile directly
2022-08-21 20:45:23 +01:00
5426b41447 InventoryTransaction: prevent client-authoritative item overstacking
this cheat is often used to carry more items in the inventory, wear multiple pieces of armour in one slot, and more.
2022-08-21 20:35:23 +01:00
af2babec23 GiveCommand: do not accept negative amounts 2022-08-21 20:28:39 +01:00
717ab1989a Update setup-php-action to pmmp/setup-php-action@82a44d659b 2022-08-21 18:14:07 +01:00
83db186b6a Updated setup-php-action to pmmp/setup-php-action@e128aee02f 2022-08-20 18:53:08 +01:00
6a4e5aba8b Update setup-php-action to pmmp/setup-php-action@330b4c2940 2022-08-20 18:03:30 +01:00
c13170a00b Avoid implicit integer cast in Normal::pickBiome()
this throws deprecation warnings on PHP 8.1.
2022-08-20 17:16:38 +01:00
98778052bb actions: start building on 8.1 2022-08-20 16:32:36 +01:00
e86e8254a8 Workaround PHPStan "feature" phpstan/phpstan#7701 2022-08-20 16:29:26 +01:00
1b852ac290 bootstrap: do not complain about xdebug if mode is 'off'
if xdebug.mode=off, the performance impact is the same as if xdebug wasn't loaded.
2022-08-19 16:45:40 +01:00
10b799fadb Bump shivammathur/setup-php from 2.21.1 to 2.21.2 (#5238)
Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.21.1 to 2.21.2.
- [Release notes](https://github.com/shivammathur/setup-php/releases)
- [Commits](https://github.com/shivammathur/setup-php/compare/2.21.1...2.21.2)

---
updated-dependencies:
- dependency-name: shivammathur/setup-php
  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-08-19 15:51:44 +01:00
bc5008334a Bump pocketmine/locale-data from 2.8.3 to 2.8.6 (#5239)
Bumps [pocketmine/locale-data](https://github.com/pmmp/Language) from 2.8.3 to 2.8.6.
- [Release notes](https://github.com/pmmp/Language/releases)
- [Commits](https://github.com/pmmp/Language/compare/2.8.3...2.8.6)

---
updated-dependencies:
- dependency-name: pocketmine/locale-data
  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-08-19 15:51:04 +01:00
575dd47db7 4.7.3 is next 2022-08-16 17:51:26 +01:00
e4a5defabb Release 4.7.2 2022-08-16 17:51:26 +01:00
c9626c610b Skin: Correctly handle errors produced by commented JSON decoder 2022-08-16 17:35:23 +01:00
8fb7fff6b9 Update SECURITY.md 2022-08-16 17:22:22 +01:00
5c8d8ff61f Update SECURITY.md 2022-08-16 17:04:25 +01:00
99b55f7427 actions: use newer php-cs-fixer 2022-08-15 17:26:42 +01:00
dce8bd6d21 CS: Standardize new with braces 2022-08-15 17:16:23 +01:00
8fa81242d6 Sugarcane: fixed support conditions (#5052) 2022-08-15 17:08:26 +01:00
2f4a9469b6 Player: spectator shouldn't able to pick blocks they don't have (#5111)
Jury is out on whether they should be able to pick blocks at all, or be considered to have infinite resources, but this solution has been used in a few other places already anyway, so it can be cleaned up another time.
2022-08-15 16:48:37 +01:00
c5b2488fc1 oh come on... 2022-08-14 20:02:07 +01:00
d62df585f2 4.7.2 is next 2022-08-14 19:56:00 +01:00
19d7c2b552 Release 4.7.1 2022-08-14 19:55:56 +01:00
036e06e889 Revert "Workaround items in blockentity NBT not being processed correctly in 1.19.10"
This reverts commit 2b61c025c2.
2022-08-14 17:25:55 +01:00
9343a0b800 Added build log link to Discord release embed 2022-08-14 17:20:01 +01:00
14b4644b03 Added build_log_url to build_info.json 2022-08-14 17:20:01 +01:00
464b65b25c Bump docker/build-push-action from 3.1.0 to 3.1.1 (#5213)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: docker/build-push-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-08-12 21:11:11 +01:00
15586ed80e Fix CS 2022-08-12 21:09:15 +01:00
0f8ad8ecf7 Update permission doc output format 2022-08-12 20:47:38 +01:00
82b9afef77 Allow generating RST permission summaries, to be used on doc.pmmp.io 2022-08-12 18:00:52 +01:00
2fc84f6c67 ItemFactory: treat durables with negative meta as unknown items
fixes #5117
2022-08-12 17:24:43 +01:00
566f5935a3 CraftingManagerFromDataHelper: do not register recipes with unknown outputs
fixes #5093

we don't need to check the inputs, since unknown input items shouldn't be obtainable anyway.
2022-08-12 17:19:47 +01:00
44e4dabf6e Fixed Turtle Master potions giving no effects 2022-08-12 17:05:08 +01:00
8acc535218 ffs 2022-08-09 19:27:54 +01:00
e9a1cb7ce5 4.7.1 is next 2022-08-09 19:24:02 +01:00
a21419d120 Release 4.7.0 2022-08-09 19:24:01 +01:00
c2b599166c Added new shiny webhook for Discord release notifications 2022-08-09 19:21:36 +01:00
df7a1fcba6 Changes for 1.19.20 2022-08-09 19:06:05 +01:00
d77a95e4af actions/draft-release: bake the full changelog blob URL into the release notes, to ensure it works properly in emails and embeds 2022-08-06 15:49:04 +01:00
5c72807b16 Bump shivammathur/setup-php from 2.21.0 to 2.21.1 (#5199)
Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.21.0 to 2.21.1.
- [Release notes](https://github.com/shivammathur/setup-php/releases)
- [Commits](https://github.com/shivammathur/setup-php/compare/2.21.0...2.21.1)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-06 15:39:36 +01:00
5c6927e16c 4.6.3 is next 2022-08-06 15:35:47 +01:00
9abbb85a93 Release 4.6.2 2022-08-06 15:35:47 +01:00
554182b2cb Update composer dependencies 2022-08-06 15:27:11 +01:00
d669a6f0c7 ReversePriorityQueue: add ReturnTypeWillChange attribute
it's doubtful any plugin dev is extending this, but nonetheless, we can't change it in a patch.
2022-07-27 03:51:06 +01:00
5d9f783037 InGamePacketHandler: do not update player rotation if it didn't change
setRotation() does an alarmingly large amount of work...
2022-07-24 21:07:35 +01:00
01ca14c314 InGamePacketHandler: avoid processing movement if position is unchanged since last tick 2022-07-24 21:00:12 +01:00
608c6ed6db Improved suboptimal code in Player::handleMovement() 2022-07-24 20:51:28 +01:00
c26631d06d InGamePacketHandler: avoid useless object allocations when forceMoveSync=false (99.9% of the time) 2022-07-24 20:44:27 +01:00
b75bc61a64 InGamePacketHandler: don't bother checking for flag changes if the flag fields are identical
we don't need to check this on a bit by bit level if the integers are the same.

this saves 2-3 microseconds per packet on my machine, which doesn't sound like much, but it adds up when there are lots of players.
2022-07-24 20:35:49 +01:00
3724479be3 InGamePacketHandler: improve performance of input flag resolving 2022-07-24 20:33:35 +01:00
eb916fe43d Use a falling block entity to improve client side performance of FloatingTextParticle (#4714)
Performance tests show that this has a considerable client-side performance advantage over using players. In my local tests, using 1000 floating texts in a 10x10x10 area, I observed an FPS increase from 1.5 to 8.0.
2022-07-24 18:22:21 +01:00
5e3b3a0700 Fix assert spam on debug clients 2022-07-24 17:51:02 +01:00
e10a624444 4.6.2 is next 2022-07-22 19:35:10 +01:00
b20e04539d Release 4.6.1 2022-07-22 19:34:57 +01:00
4852f8029a AsyncTask: update documentation 2022-07-21 23:26:46 +01:00
c4f85e526b Bump shivammathur/setup-php from 2.20.0 to 2.21.0 (#5181)
Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.20.0 to 2.21.0.
- [Release notes](https://github.com/shivammathur/setup-php/releases)
- [Commits](https://github.com/shivammathur/setup-php/compare/2.20.0...2.21.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>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-20 15:19:21 +01:00
6cee428287 Bump docker/build-push-action from 3.0.0 to 3.1.0 (#5182)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3.0.0...v3.1.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-20 15:18:38 +01:00
bcba064d69 Bump build/php from 1110349 to f292501 (#5180)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `1110349` to `f292501`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](11103498ca...f292501a70)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-20 15:16:34 +01:00
86647683bc fix CS again 2022-07-19 20:35:34 +01:00
64f0e58e60 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2022-07-19 20:17:15 +01:00
62f21516d1 build/generate-registry-annotations.php: allow processing a single file
this is useful for automatically invoking the script via a PhpStorm file watcher.
2022-07-19 20:17:07 +01:00
c553f7cf06 build/generate-registry-annotations.php: write to stderr on error 2022-07-19 20:15:44 +01:00
fec89b7803 Lava burns entities for only 8 seconds in Bedrock (#5173) 2022-07-17 20:50:15 +01:00
2b61c025c2 Workaround items in blockentity NBT not being processed correctly in 1.19.10
closes #5154

this hack sends only the bare essential data to create the tiles in LevelChunkPacket,
and then separately sending the full tile data using BlockActorDataPacket afterwards.

This is necessary because the client doesn't handle items correctly in NBT when chunks are sent without using the SubChunkRequest system.
In 4.6 this is observed with incorrect items shown in item frames; in 5.0 it's seen with items simply not showing up at all (difference due to modernization of the serialization format in 5.0).
2022-07-14 21:54:01 +01:00
c7133bc2e6 InGamePacketHandler: don't kick the player out of inventory windows on actor events
this is sent when the player crafts something using an anvil.
2022-07-14 20:36:11 +01:00
baf75089f5 Entity: cancel fire damage for fireproof entities 2022-07-14 19:53:25 +01:00
Ali
705df7d508 EffectManager: remove redundant check (#5153) 2022-07-14 17:56:18 +01:00
75d7adfb2d WitherEffect: fixed incorrect damage interval 2022-07-14 16:05:35 +01:00
9d535e2917 4.6.1 is next 2022-07-13 01:28:42 +01:00
89 changed files with 1045 additions and 679 deletions

View File

@ -46,7 +46,7 @@ jobs:
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
- name: Build image for tag
uses: docker/build-push-action@v3.0.0
uses: docker/build-push-action@v3.1.1
with:
push: true
context: ./pocketmine-mp
@ -59,7 +59,7 @@ jobs:
- name: Build image for major tag
if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v3.0.0
uses: docker/build-push-action@v3.1.1
with:
push: true
context: ./pocketmine-mp
@ -72,7 +72,7 @@ jobs:
- name: Build image for minor tag
if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v3.0.0
uses: docker/build-push-action@v3.1.1
with:
push: true
context: ./pocketmine-mp
@ -85,7 +85,7 @@ jobs:
- name: Build image for latest tag
if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v3.0.0
uses: docker/build-push-action@v3.1.1
with:
push: true
context: ./pocketmine-mp

View File

@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace pocketmine;
use pocketmine\utils\Internet;
use function dirname;
use function fwrite;
use function is_array;
use function json_decode;
use function json_encode;
use const JSON_THROW_ON_ERROR;
use const STDERR;
require dirname(__DIR__, 2) . '/vendor/autoload.php';
/**
* @phpstan-return array<string, mixed>
*/
function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl) : array{
return [
"embeds" => [
[
"title" => "New PocketMine-MP release: $version ($channel)",
"description" => <<<DESCRIPTION
$description
[Details]($detailsUrl) | [Source Code]($sourceUrl) | [Build Log]($buildLogUrl) | [Download]($pharDownloadUrl)
DESCRIPTION,
"url" => $detailsUrl,
"color" => $channel === "stable" ? 0x57ab5a : 0xc69026
]
]
];
}
if(count($argv) !== 5){
fwrite(STDERR, "Required arguments: github repo, version, API token\n");
exit(1);
}
[, $repo, $tagName, $token, $hookURL] = $argv;
$result = Internet::getURL('https://api.github.com/repos/' . $repo . '/releases/tags/' . $tagName, extraHeaders: [
'Authorization: token ' . $token
]);
if($result === null){
fwrite(STDERR, "failed to access GitHub API\n");
return;
}
if($result->getCode() !== 200){
fwrite(STDERR, "Error accessing GitHub API: " . $result->getCode() . "\n");
fwrite(STDERR, $result->getBody() . "\n");
exit(1);
}
$releaseInfoJson = json_decode($result->getBody(), true, JSON_THROW_ON_ERROR);
if(!is_array($releaseInfoJson)){
fwrite(STDERR, "Invalid release JSON returned from GitHub API\n");
exit(1);
}
$buildInfoPath = 'https://github.com/' . $repo . '/releases/download/' . $tagName . '/build_info.json';
$buildInfoResult = Internet::getURL($buildInfoPath, extraHeaders: [
'Authorization: token ' . $token
]);
if($buildInfoResult === null){
fwrite(STDERR, "missing build_info.json\n");
exit(1);
}
if($buildInfoResult->getCode() !== 200){
fwrite(STDERR, "error accessing build_info.json: " . $buildInfoResult->getCode() . "\n");
fwrite(STDERR, $buildInfoResult->getBody() . "\n");
exit(1);
}
$buildInfoJson = json_decode($buildInfoResult->getBody(), true, JSON_THROW_ON_ERROR);
if(!is_array($buildInfoJson)){
fwrite(STDERR, "invalid build_info.json\n");
exit(1);
}
$detailsUrl = $buildInfoJson["details_url"];
$sourceUrl = $buildInfoJson["source_url"];
$pharDownloadUrl = $buildInfoJson["download_url"];
$buildLogUrl = $buildInfoJson["build_log_url"];
$description = $releaseInfoJson["body"];
$discordPayload = generateDiscordEmbed($buildInfoJson["base_version"], $buildInfoJson["channel"], $description, $detailsUrl, $sourceUrl, $pharDownloadUrl, $buildLogUrl);
$response = Internet::postURL(
$hookURL,
json_encode($discordPayload, JSON_THROW_ON_ERROR),
extraHeaders: ['Content-Type: application/json']
);
if($response?->getCode() !== 204){
fwrite(STDERR, "failed to send Discord webhook\n");
fwrite(STDERR, $response?->getBody() ?? "no response body\n");
exit(1);
}

View File

@ -0,0 +1,38 @@
name: Notify Discord webhook of release
on:
release:
types:
- published
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.21.2
with:
php-version: 8.0
- name: Restore Composer package cache
uses: actions/cache@v3
with:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
key: "composer-v2-cache-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
- name: Install Composer dependencies
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
- name: Get actual tag name
id: tag-name
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
- name: Run webhook post script
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }}

View File

@ -18,7 +18,7 @@ jobs:
submodules: true
- name: Setup PHP
uses: shivammathur/setup-php@2.20.0
uses: shivammathur/setup-php@2.21.2
with:
php-version: 8.0
@ -57,7 +57,7 @@ jobs:
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);')
- name: Generate build info
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} > build_info.json
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} ${{ github.run_id }} > build_info.json
- name: Upload release artifacts
uses: actions/upload-artifact@v3
@ -80,4 +80,4 @@ jobs:
body: |
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
Please see the [changelogs](/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.

View File

@ -13,11 +13,11 @@ jobs:
strategy:
matrix:
image: [ubuntu-20.04]
php: [8.0.18]
php: [8.0.23, 8.1.10]
steps:
- name: Build and prepare PHP cache
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -31,13 +31,13 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.18]
php: [8.0.23, 8.1.10]
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -69,13 +69,13 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.18]
php: [8.0.23, 8.1.10]
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -107,7 +107,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.18]
php: [8.0.23, 8.1.10]
steps:
- uses: actions/checkout@v3
@ -115,7 +115,7 @@ jobs:
submodules: true
- name: Setup PHP
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -147,13 +147,13 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.18]
php: [8.0.23, 8.1.10]
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -195,10 +195,10 @@ jobs:
- uses: actions/checkout@v3
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.20.0
uses: shivammathur/setup-php@2.21.2
with:
php-version: 8.0
tools: php-cs-fixer:3.2
tools: php-cs-fixer:3.11
- name: Run PHP-CS-Fixer
run: php-cs-fixer fix --dry-run --diff --ansi

View File

@ -22,7 +22,8 @@
declare(strict_types=1);
const VERSIONS = [
"8.0"
"8.0",
"8.1"
];
$workflowFile = file_get_contents(__DIR__ . '/main.yml');

View File

@ -70,6 +70,10 @@ BODY,
'scope' => 'namespaced',
'include' => ['@all'],
],
'new_with_braces' => [
'named_class' => true,
'anonymous_class' => false,
],
'no_closing_tag' => true,
'no_empty_phpdoc' => true,
'no_extra_blank_lines' => true,

View File

@ -7,10 +7,11 @@ GitHub is public and anyone can see the issues you post on the issue tracker, in
**WARNING: You may put live servers at risk by reporting a vulnerability on the GitHub issue tracker.**
**Contact us** by sending an email to [**team@pmmp.io**](mailto:team@pmmp.io?subject=Security%20Vulnerability%20in%20PocketMine-MP). Include the following information:
**Contact us** by sending an email to [**security@pmmp.io**](mailto:security@pmmp.io). Include the following information:
- Version of PocketMine-MP
- Detailed description of the vulnerability (e.g. how to exploit it, what the effects are)
- Your GitHub username, if you wish to be credited for reporting the problem in the security advisory
Please note that we can't guarantee a reply to every email.

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
require dirname(__DIR__) . '/vendor/autoload.php';
if(count($argv) !== 5){
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number>");
if(count($argv) !== 6){
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number> <github actions run ID>\n");
exit(1);
}
@ -40,4 +40,5 @@ echo json_encode([
"details_url" => "https://github.com/$argv[3]/releases/tag/$argv[2]",
"download_url" => "https://github.com/$argv[3]/releases/download/$argv[2]/PocketMine-MP.phar",
"source_url" => "https://github.com/$argv[3]/tree/$argv[2]",
"build_log_url" => "https://github.com/$argv[3]/actions/runs/$argv[5]",
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n";

View File

@ -29,7 +29,9 @@ use function count;
use function dirname;
use function file_get_contents;
use function file_put_contents;
use function fwrite;
use function implode;
use function is_dir;
use function ksort;
use function mb_strtoupper;
use function preg_match;
@ -39,7 +41,8 @@ use function substr;
use const SORT_STRING;
if(count($argv) !== 2){
die("Provide a path to process");
fwrite(STDERR, "Provide a path to process\n");
exit(1);
}
/**
@ -80,30 +83,24 @@ function generateMethodAnnotations(string $namespaceName, array $members) : stri
return implode("\n", $lines);
}
require dirname(__DIR__) . '/vendor/autoload.php';
/** @var string $file */
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $file){
if(substr($file, -4) !== ".php"){
continue;
}
function processFile(string $file) : void{
$contents = file_get_contents($file);
if($contents === false){
throw new \RuntimeException("Failed to get contents of $file");
}
if(preg_match("/(*ANYCRLF)^namespace (.+);$/m", $contents, $matches) !== 1 || preg_match('/(*ANYCRLF)^((final|abstract)\s+)?class /m', $contents) !== 1){
continue;
return;
}
$shortClassName = basename($file, ".php");
$className = $matches[1] . "\\" . $shortClassName;
if(!class_exists($className)){
continue;
return;
}
$reflect = new \ReflectionClass($className);
$docComment = $reflect->getDocComment();
if($docComment === false || preg_match("/(*ANYCRLF)^\s*\*\s*@generate-registry-docblock$/m", $docComment) !== 1){
continue;
return;
}
echo "Found registry in $file\n";
@ -117,3 +114,18 @@ foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1],
echo "No changes made to file $file\n";
}
}
require dirname(__DIR__) . '/vendor/autoload.php';
if(is_dir($argv[1])){
/** @var string $file */
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $file){
if(substr($file, -4) !== ".php"){
continue;
}
processFile($file);
}
}else{
processFile($argv[1]);
}

View File

@ -12,3 +12,31 @@ Released 13th July 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.10.
- Removed support for older versions.
# 4.6.1
Released 22nd July 2022.
## Tools
- `build/generate-registry-annotations.php` now supports processing single files (useful for PhpStorm file watchers).
## API
- Updated documentation for `AsyncTask`.
## Fixes
- Fixed incorrect items being displayed in item frames.
- Fixed books not showing in lecterns.
- Fixed incorrect damage interval of Wither status effect.
- Fixed incorrect fire ticks when being set on fire by lava (8 seconds in Bedrock instead of 15).
- `Entity->attack()` now cancels damage from `FIRE` and `FIRE_TICK` damage causes if the entity is fireproof.
- Fixed inventory windows getting force-closed when the client attempts to use an enchanting table or anvil.
# 4.6.2
Released 6th August 2022.
## Core
- Improved server-side performance of `PlayerAuthInputPacket` handler.
- Improved client-side performance of `FloatingTextParticle` by using an invisible falling block entity. This offered a roughly 5x performance improvement over using tiny invisible players in local testing.
## Fixes
- Fixed assert failures and debug spam on debug Minecraft clients related to abilities in `AddPlayerPacket`.
- Fixed crash in `ReversePriorityQueue` on PHP 8.1 by adding `#[ReturnTypeWillChange]` attribute.

46
changelogs/4.7.md Normal file
View File

@ -0,0 +1,46 @@
**For Minecraft: Bedrock Edition 1.19.20**
### 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.7.0
Released 9th August 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.20.
- Removed support for older versions.
# 4.7.1
Released 14th August 2022.
## Fixes
- Fixed server crash when loading items from disk which have negative meta values.
- Fixed Turtle Master potions not giving any effects.
- Unimplemented items are no longer craftable.
- Fixed incorrect items appearing in item frames (due to an obsolete workaround for 1.19.10).
# 4.7.2
Released 16th August 2022.
## Fixes
- Fixed crash when processing player skins with invalid geometry data.
- Fixed spectator players being able to pick blocks using mousewheel click.
- Improved supporting requirements for sugarcane.
# 4.7.3
Released 22nd August 2022.
## General
- Added complete translations for Spanish and Vietnamese.
- All continuous integration (static analysis, unit tests, integration tests) are now performed on PHP 8.1 as well as 8.0.
- InventoryTransaction now verifies that stack sizes of items after the transaction don't exceed the maximum stack size of the item type or the containing inventory.
## Fixes
- Fixed Normal generator crash on PHP 8.1.
- Fixed a race condition during async worker shutdown that could lead to tasks executing in the wrong order. This (very rarely) led to a crash in `PopulationTask` due to its preceding `GeneratorRegisterTask` not being executed.
- Fixed `/give` accepting negative amounts or amounts larger than 32767 (vanilla max).
- Fixed placement conditions for vines (no longer able to be placed on the side of cacti).
- Fixed incorrect documentation of `SignText::__construct()`.

23
changelogs/4.8.md Normal file
View File

@ -0,0 +1,23 @@
**For Minecraft: Bedrock Edition 1.19.21**
### 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.8.0
Released 24th August 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.21.
- Removed support for older versions.
# 4.8.1
Released 26th August 2022.
## General
- Crashdumps now include JIT mode information for use by the Crash Archive.
## Fixes
- Fixed uninitialized offset error in `DyeColorIdMap` when given invalid dye color IDs.

14
changelogs/4.9.md Normal file
View File

@ -0,0 +1,14 @@
**For Minecraft: Bedrock Edition 1.19.30**
### 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.9.0
Released 20th September 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.30.
- Removed support for older versions.

View File

@ -34,14 +34,14 @@
"adhocore/json-comment": "^1.1",
"fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0",
"pocketmine/bedrock-data": "~1.9.0+bedrock-1.19.10",
"pocketmine/bedrock-protocol": "~11.0.0+bedrock-1.19.10",
"pocketmine/bedrock-data": "~1.11.0+bedrock-1.19.30",
"pocketmine/bedrock-protocol": "~13.0.0+bedrock-1.19.30",
"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.8.0",
"pocketmine/locale-data": "~2.8.0 <2.8.9",
"pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.4.0",
"pocketmine/math": "^0.4.0",
@ -53,7 +53,7 @@
"webmozart/path-util": "^2.3"
},
"require-dev": {
"phpstan/phpstan": "1.8.0",
"phpstan/phpstan": "1.8.5",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "^9.2"

457
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": "e03c7f446cee1fdb97ee79817c78470a",
"content-hash": "0f6c845836d4ec6f221415d2f9dd1fc5",
"packages": [
{
"name": "adhocore/json-comment",
@ -63,26 +63,26 @@
},
{
"name": "brick/math",
"version": "0.9.3",
"version": "0.10.2",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae"
"reference": "459f2781e1a08d52ee56b0b1444086e038561e3f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae",
"reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae",
"url": "https://api.github.com/repos/brick/math/zipball/459f2781e1a08d52ee56b0b1444086e038561e3f",
"reference": "459f2781e1a08d52ee56b0b1444086e038561e3f",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^7.1 || ^8.0"
"php": "^7.4 || ^8.0"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
"vimeo/psalm": "4.9.2"
"phpunit/phpunit": "^9.0",
"vimeo/psalm": "4.25.0"
},
"type": "library",
"autoload": {
@ -107,19 +107,15 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.9.3"
"source": "https://github.com/brick/math/tree/0.10.2"
},
"funding": [
{
"url": "https://github.com/BenMorel",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/brick/math",
"type": "tidelift"
}
],
"time": "2021-08-15T20:50:18+00:00"
"time": "2022-08-10T22:54:19+00:00"
},
{
"name": "fgrosse/phpasn1",
@ -249,16 +245,16 @@
},
{
"name": "pocketmine/bedrock-data",
"version": "1.9.0+bedrock-1.19.10",
"version": "1.11.0+bedrock-1.19.30",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
"reference": "ecd798a3e7ead50b7da73141bbb0c4ba14dd76a1"
"reference": "2cca1d48421db20740ffd1ce67b40b91acc61187"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/ecd798a3e7ead50b7da73141bbb0c4ba14dd76a1",
"reference": "ecd798a3e7ead50b7da73141bbb0c4ba14dd76a1",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/2cca1d48421db20740ffd1ce67b40b91acc61187",
"reference": "2cca1d48421db20740ffd1ce67b40b91acc61187",
"shasum": ""
},
"type": "library",
@ -269,22 +265,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.10"
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.19.30"
},
"time": "2022-07-12T19:33:21+00:00"
"time": "2022-09-20T18:19:22+00:00"
},
{
"name": "pocketmine/bedrock-protocol",
"version": "11.0.0+bedrock-1.19.10",
"version": "13.0.0+bedrock-1.19.30",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "705f928bd010ba093d8781d20006e4cd5f79f335"
"reference": "94de2221676ca717587e1ff4e45445c24ada1749"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/705f928bd010ba093d8781d20006e4cd5f79f335",
"reference": "705f928bd010ba093d8781d20006e4cd5f79f335",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/94de2221676ca717587e1ff4e45445c24ada1749",
"reference": "94de2221676ca717587e1ff4e45445c24ada1749",
"shasum": ""
},
"require": {
@ -316,9 +312,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/11.0.0+bedrock-1.19.10"
"source": "https://github.com/pmmp/BedrockProtocol/tree/bedrock-1.19.30"
},
"time": "2022-07-12T23:47:47+00:00"
"time": "2022-09-20T18:35:00+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -536,16 +532,16 @@
},
{
"name": "pocketmine/locale-data",
"version": "2.8.3",
"version": "2.8.7",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Language.git",
"reference": "113c115a3b8976917eb22b74dccab464831b6483"
"reference": "e115d3d64a508065f1cedad1be55528906308456"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Language/zipball/113c115a3b8976917eb22b74dccab464831b6483",
"reference": "113c115a3b8976917eb22b74dccab464831b6483",
"url": "https://api.github.com/repos/pmmp/Language/zipball/e115d3d64a508065f1cedad1be55528906308456",
"reference": "e115d3d64a508065f1cedad1be55528906308456",
"shasum": ""
},
"type": "library",
@ -553,9 +549,9 @@
"description": "Language resources used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Language/issues",
"source": "https://github.com/pmmp/Language/tree/2.8.3"
"source": "https://github.com/pmmp/Language/tree/2.8.7"
},
"time": "2022-05-11T13:51:37+00:00"
"time": "2022-08-21T20:37:16+00:00"
},
{
"name": "pocketmine/log",
@ -644,16 +640,16 @@
},
{
"name": "pocketmine/math",
"version": "0.4.2",
"version": "0.4.3",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Math.git",
"reference": "aacc3759a508a69dfa5bc4dfa770ab733c5c94bf"
"reference": "47a243d320b01c8099d65309967934c188111549"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Math/zipball/aacc3759a508a69dfa5bc4dfa770ab733c5c94bf",
"reference": "aacc3759a508a69dfa5bc4dfa770ab733c5c94bf",
"url": "https://api.github.com/repos/pmmp/Math/zipball/47a243d320b01c8099d65309967934c188111549",
"reference": "47a243d320b01c8099d65309967934c188111549",
"shasum": ""
},
"require": {
@ -662,7 +658,7 @@
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "1.2.0",
"phpstan/phpstan": "1.8.2",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^8.5 || ^9.5"
},
@ -679,9 +675,9 @@
"description": "PHP library containing math related code used in PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Math/issues",
"source": "https://github.com/pmmp/Math/tree/0.4.2"
"source": "https://github.com/pmmp/Math/tree/0.4.3"
},
"time": "2021-12-05T01:15:17+00:00"
"time": "2022-08-25T18:43:37+00:00"
},
{
"name": "pocketmine/nbt",
@ -727,16 +723,16 @@
},
{
"name": "pocketmine/raklib",
"version": "0.14.4",
"version": "0.14.5",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
"reference": "1ea8e3b95a1b6bf785dc27d76578657be4185f42"
"reference": "85b4e5cb7117d37e010eeadb3ff53b21276c6f48"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/1ea8e3b95a1b6bf785dc27d76578657be4185f42",
"reference": "1ea8e3b95a1b6bf785dc27d76578657be4185f42",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/85b4e5cb7117d37e010eeadb3ff53b21276c6f48",
"reference": "85b4e5cb7117d37e010eeadb3ff53b21276c6f48",
"shasum": ""
},
"require": {
@ -748,7 +744,7 @@
"pocketmine/log": "^0.3.0 || ^0.4.0"
},
"require-dev": {
"phpstan/phpstan": "1.5.4",
"phpstan/phpstan": "1.7.7",
"phpstan/phpstan-strict-rules": "^1.0"
},
"type": "library",
@ -764,9 +760,9 @@
"description": "A RakNet server implementation written in PHP",
"support": {
"issues": "https://github.com/pmmp/RakLib/issues",
"source": "https://github.com/pmmp/RakLib/tree/0.14.4"
"source": "https://github.com/pmmp/RakLib/tree/0.14.5"
},
"time": "2022-04-17T18:42:17+00:00"
"time": "2022-08-25T16:16:44+00:00"
},
{
"name": "pocketmine/raklib-ipc",
@ -930,20 +926,20 @@
},
{
"name": "ramsey/uuid",
"version": "4.3.1",
"version": "4.5.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
"reference": "8505afd4fea63b81a85d3b7b53ac3cb8dc347c28"
"reference": "a161a26d917604dc6d3aa25100fddf2556e9f35d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/8505afd4fea63b81a85d3b7b53ac3cb8dc347c28",
"reference": "8505afd4fea63b81a85d3b7b53ac3cb8dc347c28",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/a161a26d917604dc6d3aa25100fddf2556e9f35d",
"reference": "a161a26d917604dc6d3aa25100fddf2556e9f35d",
"shasum": ""
},
"require": {
"brick/math": "^0.8 || ^0.9",
"brick/math": "^0.8.8 || ^0.9 || ^0.10",
"ext-ctype": "*",
"ext-json": "*",
"php": "^8.0",
@ -959,18 +955,18 @@
"doctrine/annotations": "^1.8",
"ergebnis/composer-normalize": "^2.15",
"mockery/mockery": "^1.3",
"moontoast/math": "^1.1",
"paragonie/random-lib": "^2",
"php-mock/php-mock": "^2.2",
"php-mock/php-mock-mockery": "^1.3",
"php-parallel-lint/php-parallel-lint": "^1.1",
"phpbench/phpbench": "^1.0",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-mockery": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-phpunit": "^1.1",
"phpunit/phpunit": "^8.5 || ^9",
"slevomat/coding-standard": "^7.0",
"ramsey/composer-repl": "^1.4",
"slevomat/coding-standard": "^8.4",
"squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.9"
},
@ -1008,7 +1004,7 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.3.1"
"source": "https://github.com/ramsey/uuid/tree/4.5.1"
},
"funding": [
{
@ -1020,7 +1016,7 @@
"type": "tidelift"
}
],
"time": "2022-03-27T21:42:02+00:00"
"time": "2022-09-16T03:22:46+00:00"
},
{
"name": "symfony/polyfill-php81",
@ -1343,16 +1339,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.14.0",
"version": "v4.15.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1"
"reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/34bea19b6e03d8153165d8f30bba4c3be86184c1",
"reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
"reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
"shasum": ""
},
"require": {
@ -1393,9 +1389,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.14.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1"
},
"time": "2022-05-31T20:59:12+00:00"
"time": "2022-09-04T07:30:47+00:00"
},
{
"name": "phar-io/manifest",
@ -1508,245 +1504,18 @@
},
"time": "2022-02-21T01:04:05+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-2.x": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jaap van Otterdijk",
"email": "opensource@ijaap.nl"
}
],
"description": "Common reflection classes used by phpdocumentor to reflect the code structure",
"homepage": "http://www.phpdoc.org",
"keywords": [
"FQSEN",
"phpDocumentor",
"phpdoc",
"reflection",
"static analysis"
],
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
},
"time": "2020-06-27T09:03:43+00:00"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.3.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170",
"reference": "622548b623e81ca6d78b721c5e029f4ce664f170",
"shasum": ""
},
"require": {
"ext-filter": "*",
"php": "^7.2 || ^8.0",
"phpdocumentor/reflection-common": "^2.2",
"phpdocumentor/type-resolver": "^1.3",
"webmozart/assert": "^1.9.1"
},
"require-dev": {
"mockery/mockery": "~1.3.2",
"psalm/phar": "^4.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
},
{
"name": "Jaap van Otterdijk",
"email": "account@ijaap.nl"
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0"
},
"time": "2021-10-19T17:43:47+00:00"
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.6.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "77a32518733312af16a44300404e945338981de3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3",
"reference": "77a32518733312af16a44300404e945338981de3",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpdocumentor/reflection-common": "^2.0"
},
"require-dev": {
"ext-tokenizer": "*",
"psalm/phar": "^4.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-1.x": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
}
],
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1"
},
"time": "2022-03-15T21:29:03+00:00"
},
{
"name": "phpspec/prophecy",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
"reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.2",
"php": "^7.2 || ~8.0, <8.2",
"phpdocumentor/reflection-docblock": "^5.2",
"sebastian/comparator": "^3.0 || ^4.0",
"sebastian/recursion-context": "^3.0 || ^4.0"
},
"require-dev": {
"phpspec/phpspec": "^6.0 || ^7.0",
"phpunit/phpunit": "^8.0 || ^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Prophecy\\": "src/Prophecy"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Konstantin Kudryashov",
"email": "ever.zet@gmail.com",
"homepage": "http://everzet.com"
},
{
"name": "Marcello Duarte",
"email": "marcello.duarte@gmail.com"
}
],
"description": "Highly opinionated mocking framework for PHP 5.3+",
"homepage": "https://github.com/phpspec/prophecy",
"keywords": [
"Double",
"Dummy",
"fake",
"mock",
"spy",
"stub"
],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
"source": "https://github.com/phpspec/prophecy/tree/v1.15.0"
},
"time": "2021-12-08T12:19:24+00:00"
},
{
"name": "phpstan/phpstan",
"version": "1.8.0",
"version": "1.8.5",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "b7648d4ee9321665acaf112e49da9fd93df8fbd5"
"reference": "f6598a5ff12ca4499a836815e08b4d77a2ddeb20"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/b7648d4ee9321665acaf112e49da9fd93df8fbd5",
"reference": "b7648d4ee9321665acaf112e49da9fd93df8fbd5",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/f6598a5ff12ca4499a836815e08b4d77a2ddeb20",
"reference": "f6598a5ff12ca4499a836815e08b4d77a2ddeb20",
"shasum": ""
},
"require": {
@ -1770,9 +1539,13 @@
"MIT"
],
"description": "PHPStan - PHP Static Analysis Tool",
"keywords": [
"dev",
"static analysis"
],
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.8.0"
"source": "https://github.com/phpstan/phpstan/tree/1.8.5"
},
"funding": [
{
@ -1783,16 +1556,12 @@
"url": "https://github.com/phpstan",
"type": "github"
},
{
"url": "https://www.patreon.com/phpstan",
"type": "patreon"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
"type": "tidelift"
}
],
"time": "2022-06-29T08:53:31+00:00"
"time": "2022-09-07T16:05:32+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
@ -1848,21 +1617,21 @@
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "1.3.0",
"version": "1.4.3",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "543675a9be82d4befb9ca0bd8cdc9d211665037f"
"reference": "431b3d6e8040075de196680cd5bc95735987b4ae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/543675a9be82d4befb9ca0bd8cdc9d211665037f",
"reference": "543675a9be82d4befb9ca0bd8cdc9d211665037f",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/431b3d6e8040075de196680cd5bc95735987b4ae",
"reference": "431b3d6e8040075de196680cd5bc95735987b4ae",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.7.15"
"phpstan/phpstan": "^1.8.3"
},
"require-dev": {
"nikic/php-parser": "^4.13.0",
@ -1890,29 +1659,29 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.3.0"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.3"
},
"time": "2022-06-24T06:47:20+00:00"
"time": "2022-08-26T15:05:46+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.15",
"version": "9.2.17",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f"
"reference": "aa94dc41e8661fe90c7316849907cba3007b10d8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f",
"reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa94dc41e8661fe90c7316849907cba3007b10d8",
"reference": "aa94dc41e8661fe90c7316849907cba3007b10d8",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
"nikic/php-parser": "^4.13.0",
"nikic/php-parser": "^4.14",
"php": ">=7.3",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2",
@ -1961,7 +1730,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.17"
},
"funding": [
{
@ -1969,7 +1738,7 @@
"type": "github"
}
],
"time": "2022-03-07T09:28:20+00:00"
"time": "2022-08-30T12:24:04+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -2214,16 +1983,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.21",
"version": "9.5.24",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1"
"reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0e32b76be457de00e83213528f6bb37e2a38fcb1",
"reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d0aa6097bef9fd42458a9b3c49da32c6ce6129c5",
"reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5",
"shasum": ""
},
"require": {
@ -2238,7 +2007,6 @@
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"php": ">=7.3",
"phpspec/prophecy": "^1.12.1",
"phpunit/php-code-coverage": "^9.2.13",
"phpunit/php-file-iterator": "^3.0.5",
"phpunit/php-invoker": "^3.1.1",
@ -2253,12 +2021,9 @@
"sebastian/global-state": "^5.0.1",
"sebastian/object-enumerator": "^4.0.3",
"sebastian/resource-operations": "^3.0.3",
"sebastian/type": "^3.0",
"sebastian/type": "^3.1",
"sebastian/version": "^3.0.2"
},
"require-dev": {
"phpspec/prophecy-phpunit": "^2.0.1"
},
"suggest": {
"ext-soap": "*",
"ext-xdebug": "*"
@ -2300,7 +2065,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.21"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.24"
},
"funding": [
{
@ -2312,7 +2077,7 @@
"type": "github"
}
],
"time": "2022-06-19T12:14:25+00:00"
"time": "2022-08-30T07:42:16+00:00"
},
{
"name": "sebastian/cli-parser",
@ -2483,16 +2248,16 @@
},
{
"name": "sebastian/comparator",
"version": "4.0.6",
"version": "4.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "55f4261989e546dc112258c7a75935a81a7ce382"
"reference": "fa0f136dd2334583309d32b62544682ee972b51a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382",
"reference": "55f4261989e546dc112258c7a75935a81a7ce382",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
"reference": "fa0f136dd2334583309d32b62544682ee972b51a",
"shasum": ""
},
"require": {
@ -2545,7 +2310,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6"
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
},
"funding": [
{
@ -2553,7 +2318,7 @@
"type": "github"
}
],
"time": "2020-10-26T15:49:45+00:00"
"time": "2022-09-14T12:41:17+00:00"
},
{
"name": "sebastian/complexity",
@ -2743,16 +2508,16 @@
},
{
"name": "sebastian/exporter",
"version": "4.0.4",
"version": "4.0.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9"
"reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9",
"reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
"reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
"shasum": ""
},
"require": {
@ -2808,7 +2573,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4"
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
},
"funding": [
{
@ -2816,7 +2581,7 @@
"type": "github"
}
],
"time": "2021-11-11T14:18:36+00:00"
"time": "2022-09-14T06:03:37+00:00"
},
{
"name": "sebastian/global-state",
@ -3171,16 +2936,16 @@
},
{
"name": "sebastian/type",
"version": "3.0.0",
"version": "3.2.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
"reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad"
"reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
"reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad",
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e",
"reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e",
"shasum": ""
},
"require": {
@ -3192,7 +2957,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
"dev-master": "3.2-dev"
}
},
"autoload": {
@ -3215,7 +2980,7 @@
"homepage": "https://github.com/sebastianbergmann/type",
"support": {
"issues": "https://github.com/sebastianbergmann/type/issues",
"source": "https://github.com/sebastianbergmann/type/tree/3.0.0"
"source": "https://github.com/sebastianbergmann/type/tree/3.2.0"
},
"funding": [
{
@ -3223,7 +2988,7 @@
"type": "github"
}
],
"time": "2022-03-15T09:54:48+00:00"
"time": "2022-09-12T14:47:03+00:00"
},
{
"name": "sebastian/version",

View File

@ -1,4 +1,5 @@
includes:
- tests/phpstan/analyse-for-current-php-version.neon.php
- tests/phpstan/configs/actual-problems.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/impossible-generics.neon

View File

@ -37,6 +37,7 @@ namespace pocketmine {
use Webmozart\PathUtil\Path;
use function defined;
use function extension_loaded;
use function function_exists;
use function getcwd;
use function phpversion;
use function preg_match;
@ -160,7 +161,7 @@ namespace pocketmine {
if(PHP_DEBUG !== 0){
$logger->warning("This PHP binary was compiled in debug mode. This has a major impact on performance.");
}
if(extension_loaded("xdebug")){
if(extension_loaded("xdebug") && (!function_exists('xdebug_info') || count(xdebug_info('mode')) !== 0)){
$logger->warning("Xdebug extension is enabled. This has a major impact on performance.");
}
if(((int) ini_get('zend.assertions')) !== -1){
@ -176,10 +177,10 @@ namespace pocketmine {
--------------------------------------- ! WARNING ! ---------------------------------------
You're using PHP 8.0 with JIT enabled. This provides significant performance improvements.
You're using PHP with JIT enabled. This provides significant performance improvements.
HOWEVER, it is EXPERIMENTAL, and has already been seen to cause weird and unexpected bugs.
Proceed with caution.
If you want to report any bugs, make sure to mention that you are using PHP 8.0 with JIT.
If you want to report any bugs, make sure to mention that you have enabled PHP JIT.
To turn off JIT, change `opcache.jit` to `0` in your php.ini file.
-------------------------------------------------------------------------------------------

View File

@ -132,6 +132,7 @@ use function get_class;
use function ini_set;
use function is_array;
use function is_dir;
use function is_int;
use function is_object;
use function is_resource;
use function is_string;
@ -570,6 +571,7 @@ class Server{
$playerPos = null;
$spawn = $world->getSpawnLocation();
}
/** @phpstan-var PromiseResolver<Player> $playerPromiseResolver */
$playerPromiseResolver = new PromiseResolver();
$world->requestChunkPopulation($spawn->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawn->getFloorZ() >> Chunk::COORD_BIT_SIZE, null)->onCompletion(
function() use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $world, $playerPos, $spawn, $offlinePlayerData) : void{
@ -1650,12 +1652,14 @@ class Server{
], 10, [], $postUrlError);
if($reply !== null && is_object($data = json_decode($reply->getBody()))){
if(isset($data->crashId) && isset($data->crashUrl)){
if(isset($data->crashId) && is_int($data->crashId) && isset($data->crashUrl) && is_string($data->crashUrl)){
$reportId = $data->crashId;
$reportUrl = $data->crashUrl;
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
}elseif(isset($data->error)){
}elseif(isset($data->error) && is_string($data->error)){
$this->logger->emergency("Automatic crash report submission failed: $data->error");
}else{
$this->logger->emergency("Invalid JSON response received from crash archive: " . $reply->getBody());
}
}else{
$this->logger->emergency("Failed to communicate with crash archive: $postUrlError");

View File

@ -31,7 +31,7 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "4.6.0";
public const BASE_VERSION = "4.9.0";
public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";

View File

@ -523,12 +523,6 @@ class BlockFactory{
$this->registerAllMeta(...$leaves);
$this->registerAllMeta(...$allSidedLogs);
static $sandstoneTypes = [
Meta::SANDSTONE_NORMAL => "",
Meta::SANDSTONE_CHISELED => "Chiseled ",
Meta::SANDSTONE_CUT => "Cut ",
Meta::SANDSTONE_SMOOTH => "Smooth "
];
$sandstoneBreakInfo = new BreakInfo(0.8, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
$this->registerAllMeta(new Stair(new BID(Ids::RED_SANDSTONE_STAIRS, 0), "Red Sandstone Stairs", $sandstoneBreakInfo));
$this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_RED_SANDSTONE_STAIRS, 0), "Smooth Red Sandstone Stairs", $sandstoneBreakInfo));
@ -536,7 +530,12 @@ class BlockFactory{
$this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_SANDSTONE_STAIRS, 0), "Smooth Sandstone Stairs", $sandstoneBreakInfo));
$sandstones = [];
$redSandstones = [];
foreach($sandstoneTypes as $variant => $prefix){
foreach([
Meta::SANDSTONE_NORMAL => "",
Meta::SANDSTONE_CHISELED => "Chiseled ",
Meta::SANDSTONE_CUT => "Cut ",
Meta::SANDSTONE_SMOOTH => "Smooth "
] as $variant => $prefix){
$sandstones[] = new Opaque(new BID(Ids::SANDSTONE, $variant), $prefix . "Sandstone", $sandstoneBreakInfo);
$redSandstones[] = new Opaque(new BID(Ids::RED_SANDSTONE, $variant), $prefix . "Red Sandstone", $sandstoneBreakInfo);
}

View File

@ -72,7 +72,7 @@ class Cactus extends Transparent{
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
static $shrinkSize = 1 / 16;
$shrinkSize = 1 / 16;
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];
}

View File

@ -94,7 +94,8 @@ class Lava extends Liquid{
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
$entity->attack($ev);
$ev = new EntityCombustByBlockEvent($this, $entity, 15);
//in java burns entities for 15 seconds - seems to be a parity issue in bedrock
$ev = new EntityCombustByBlockEvent($this, $entity, 8);
$ev->call();
if(!$ev->isCancelled()){
$entity->setOnFire($ev->getDuration());

View File

@ -69,7 +69,6 @@ class Lever extends Flowable{
5 => LeverFacing::UP_AXIS_Z(),
6 => LeverFacing::UP_AXIS_X(),
7 => LeverFacing::DOWN_AXIS_Z(),
default => throw new AssumptionFailedError("0x07 mask should make this impossible"), //phpstan doesn't understand :(
};
$this->activated = ($stateMeta & BlockLegacyMetadata::LEVER_FLAG_POWERED) !== 0;

View File

@ -98,7 +98,7 @@ class Sugarcane extends Flowable{
public function onNearbyBlockChange() : void{
$down = $this->getSide(Facing::DOWN);
if($down->isTransparent() && !$down->isSameType($this)){
if(!$this->isValidSupport($down)){
$this->position->getWorld()->useBreakOn($this->position);
}
}
@ -122,9 +122,10 @@ class Sugarcane extends Flowable{
$down = $this->getSide(Facing::DOWN);
if($down->isSameType($this)){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}elseif($down->getId() === BlockLegacyIds::GRASS || $down->getId() === BlockLegacyIds::DIRT || $down->getId() === BlockLegacyIds::SAND || $down->getId() === BlockLegacyIds::PODZOL){
}elseif($this->isValidSupport($down)){
foreach(Facing::HORIZONTAL as $side){
if($down->getSide($side) instanceof Water){
$sideBlock = $down->getSide($side);
if($sideBlock instanceof Water || $sideBlock instanceof FrostedIce){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}
@ -132,4 +133,15 @@ class Sugarcane extends Flowable{
return false;
}
private function isValidSupport(Block $block) : bool{
$id = $block->getId();
//TODO: rooted dirt, moss block
return $block->isSameType($this)
|| $id === BlockLegacyIds::GRASS
|| $id === BlockLegacyIds::DIRT
|| $id === BlockLegacyIds::PODZOL
|| $id === BlockLegacyIds::MYCELIUM
|| $id === BlockLegacyIds::SAND;
}
}

View File

@ -585,6 +585,7 @@ final class VanillaBlocks{
/**
* @return Block[]
* @phpstan-return array<string, Block>
*/
public static function getAll() : array{
//phpstan doesn't support generic traits yet :(

View File

@ -116,7 +116,7 @@ class Vine extends Flowable{
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$blockClicked->isSolid() || Facing::axis($face) === Axis::Y){
if(!$blockClicked->isFullCube() || Facing::axis($face) === Axis::Y){
return false;
}

View File

@ -39,7 +39,7 @@ class SignText{
private array $lines;
/**
* @param string[]|null $lines index-sensitive; omitting an index will leave it unchanged
* @param string[]|null $lines index-sensitive; keys 0-3 will be used, regardless of array order
*
* @throws \InvalidArgumentException if the array size is greater than 4
* @throws \InvalidArgumentException if invalid keys (out of bounds or string) are found in the array

View File

@ -75,7 +75,11 @@ class GiveCommand extends VanillaCommand{
if(!isset($args[2])){
$item->setCount($item->getMaxStackSize());
}else{
$item->setCount((int) $args[2]);
$count = $this->getBoundedInt($sender, $args[2], 1, 32767);
if($count === null){
return true;
}
$item->setCount($count);
}
if(isset($args[3])){

View File

@ -32,9 +32,7 @@ use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils;
use pocketmine\VersionInfo;
use function count;
use function function_exists;
use function implode;
use function opcache_get_status;
use function sprintf;
use function stripos;
use function strtolower;
@ -71,16 +69,10 @@ class VersionCommand extends VanillaCommand{
));
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_version_phpVersion(PHP_VERSION));
if(
function_exists('opcache_get_status') &&
($opcacheStatus = opcache_get_status(false)) !== false &&
isset($opcacheStatus["jit"]["on"])
){
$jit = $opcacheStatus["jit"];
if($jit["on"] === true){
$jitStatus = KnownTranslationFactory::pocketmine_command_version_phpJitEnabled(
sprintf("CRTO: %s%s%s%s", $jit["opt_flags"] >> 2, $jit["opt_flags"] & 0x03, $jit["kind"], $jit["opt_level"])
);
$jitMode = Utils::getOpcacheJitMode();
if($jitMode !== null){
if($jitMode !== 0){
$jitStatus = KnownTranslationFactory::pocketmine_command_version_phpJitEnabled(sprintf("CRTO: %d", $jitMode));
}else{
$jitStatus = KnownTranslationFactory::pocketmine_command_version_phpJitDisabled();
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\crafting;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Utils;
use function array_map;
@ -33,6 +34,23 @@ use function json_decode;
final class CraftingManagerFromDataHelper{
/**
* @param Item[] $items
*/
private static function containsUnknownOutputs(array $items) : bool{
$factory = ItemFactory::getInstance();
foreach($items as $item){
if($item->hasAnyDamageValue()){
throw new \InvalidArgumentException("Recipe outputs must not have wildcard meta values");
}
if(!$factory->isRegistered($item->getId(), $item->getMeta())){
return true;
}
}
return false;
}
public static function make(string $filePath) : CraftingManager{
$recipes = json_decode(Utils::assumeNotFalse(file_get_contents($filePath), "Missing required resource file"), true);
if(!is_array($recipes)){
@ -52,9 +70,13 @@ final class CraftingManagerFromDataHelper{
if($recipeType === null){
continue;
}
$output = array_map($itemDeserializerFunc, $recipe["output"]);
if(self::containsUnknownOutputs($output)){
continue;
}
$result->registerShapelessRecipe(new ShapelessRecipe(
array_map($itemDeserializerFunc, $recipe["input"]),
array_map($itemDeserializerFunc, $recipe["output"]),
$output,
$recipeType
));
}
@ -62,10 +84,14 @@ final class CraftingManagerFromDataHelper{
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
continue;
}
$output = array_map($itemDeserializerFunc, $recipe["output"]);
if(self::containsUnknownOutputs($output)){
continue;
}
$result->registerShapedRecipe(new ShapedRecipe(
$recipe["shape"],
array_map($itemDeserializerFunc, $recipe["input"]),
array_map($itemDeserializerFunc, $recipe["output"])
$output
));
}
foreach($recipes["smelting"] as $recipe){
@ -79,19 +105,30 @@ final class CraftingManagerFromDataHelper{
if($furnaceType === null){
continue;
}
$output = Item::jsonDeserialize($recipe["output"]);
if(self::containsUnknownOutputs([$output])){
continue;
}
$result->getFurnaceRecipeManager($furnaceType)->register(new FurnaceRecipe(
Item::jsonDeserialize($recipe["output"]),
$output,
Item::jsonDeserialize($recipe["input"]))
);
}
foreach($recipes["potion_type"] as $recipe){
$output = Item::jsonDeserialize($recipe["output"]);
if(self::containsUnknownOutputs([$output])){
continue;
}
$result->registerPotionTypeRecipe(new PotionTypeRecipe(
Item::jsonDeserialize($recipe["input"]),
Item::jsonDeserialize($recipe["ingredient"]),
Item::jsonDeserialize($recipe["output"])
$output
));
}
foreach($recipes["potion_container_change"] as $recipe){
if(!ItemFactory::getInstance()->isRegistered($recipe["output_item_id"])){
continue;
}
$result->registerPotionContainerChangeRecipe(new PotionContainerChangeRecipe(
$recipe["input_item_id"],
Item::jsonDeserialize($recipe["ingredient"]),

View File

@ -164,6 +164,8 @@ class CrashDump{
}
$this->data->extensions = $extensions;
$this->data->jit_mode = Utils::getOpcacheJitMode();
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-phpinfo", true)){
ob_start();
phpinfo();

View File

@ -66,6 +66,8 @@ final class CrashDumpData implements \JsonSerializable{
*/
public array $extensions = [];
public ?int $jit_mode = null;
public string $phpinfo = "";
public CrashDumpDataGeneral $general;

View File

@ -74,7 +74,7 @@ final class DyeColorIdMap{
}
public function fromId(int $id) : ?DyeColor{
return $this->idToEnum[$id];
return $this->idToEnum[$id] ?? null;
}
public function fromInvertedId(int $id) : ?DyeColor{

View File

@ -522,6 +522,9 @@ abstract class Entity{
}
public function attack(EntityDamageEvent $source) : void{
if($this->isFireProof() && ($source->getCause() === EntityDamageEvent::CAUSE_FIRE || $source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK)){
$source->cancel();
}
$source->call();
if($source->isCancelled()){
return;
@ -1463,7 +1466,7 @@ abstract class Entity{
$this->location->yaw, //TODO: head yaw
$this->location->yaw, //TODO: body yaw (wtf mojang?)
array_map(function(Attribute $attr) : NetworkAttribute{
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue());
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []);
}, $this->attributeMap->getAll()),
$this->getAllNetworkData(),
[] //TODO: entity links

View File

@ -227,7 +227,7 @@ final class EntityFactory{
*/
public function createFromData(World $world, CompoundTag $nbt) : ?Entity{
try{
$saveId = $nbt->getTag("id") ?? $nbt->getTag("identifier");
$saveId = $nbt->getTag("identifier") ?? $nbt->getTag("id");
$func = null;
if($saveId instanceof StringTag){
$func = $this->creationFuncs[$saveId->getValue()] ?? null;
@ -248,7 +248,7 @@ final class EntityFactory{
public function injectSaveId(string $class, CompoundTag $saveData) : void{
if(isset($this->saveNames[$class])){
$saveData->setTag("id", new StringTag($this->saveNames[$class]));
$saveData->setTag("identifier", new StringTag($this->saveNames[$class]));
}else{
throw new \InvalidArgumentException("Entity $class is not registered");
}

View File

@ -237,11 +237,10 @@ class ExperienceManager{
}
public function onPickupXp(int $xpValue) : void{
static $mainHandIndex = -1;
static $offHandIndex = -2;
$mainHandIndex = -1;
$offHandIndex = -2;
//TODO: replace this with a more generic equipment getting/setting interface
/** @var Durable[] $equipment */
$equipment = [];
if(($item = $this->entity->getInventory()->getItemInHand()) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){

View File

@ -50,6 +50,7 @@ use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
use pocketmine\network\mcpe\protocol\types\DeviceOS;
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
@ -57,12 +58,15 @@ use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
use pocketmine\network\mcpe\protocol\types\GameMode;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
use pocketmine\network\mcpe\protocol\types\UpdateAbilitiesPacketLayer;
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
use pocketmine\player\Player;
use pocketmine\utils\Limits;
use pocketmine\world\sound\TotemUseSound;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use function array_fill;
use function array_filter;
use function array_key_exists;
use function array_merge;
@ -481,7 +485,14 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())),
GameMode::SURVIVAL,
$this->getAllNetworkData(),
UpdateAbilitiesPacket::create(0, 0, $this->getId() /* TODO: this should be unique ID */, []),
UpdateAbilitiesPacket::create(CommandPermissions::NORMAL, PlayerPermissions::VISITOR, $this->getId() /* TODO: this should be unique ID */, [
new UpdateAbilitiesPacketLayer(
UpdateAbilitiesPacketLayer::LAYER_BASE,
array_fill(0, UpdateAbilitiesPacketLayer::NUMBER_OF_ABILITIES, false),
0.0,
0.0
)
]),
[], //TODO: entity links
"", //device ID (we intentionally don't send this - secvuln)
DeviceOS::UNKNOWN //we intentionally don't send this (secvuln)

View File

@ -28,7 +28,6 @@ use pocketmine\utils\Limits;
use function implode;
use function in_array;
use function json_encode;
use function json_last_error_msg;
use function strlen;
use const JSON_THROW_ON_ERROR;
@ -68,9 +67,10 @@ final class Skin{
}
if($geometryData !== ""){
$decodedGeometry = (new CommentedJsonDecoder())->decode($geometryData);
if($decodedGeometry === false){
throw new InvalidSkinException("Invalid geometry data (" . json_last_error_msg() . ")");
try{
$decodedGeometry = (new CommentedJsonDecoder())->decode($geometryData);
}catch(\RuntimeException $e){
throw new InvalidSkinException("Invalid geometry data: " . $e->getMessage(), 0, $e);
}
/*

View File

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

View File

@ -85,14 +85,11 @@ class EffectManager{
$index = spl_object_id($effectType);
if(isset($this->effects[$index])){
$effect = $this->effects[$index];
$hasExpired = $effect->hasExpired();
$ev = new EntityEffectRemoveEvent($this->entity, $effect);
$ev->call();
if($ev->isCancelled()){
if($hasExpired && !$ev->getEffect()->hasExpired()){ //altered duration of an expired effect to make it not get removed
foreach($this->effectAddHooks as $hook){
$hook($ev->getEffect(), true);
}
foreach($this->effectAddHooks as $hook){
$hook($ev->getEffect(), true);
}
return;
}

View File

@ -35,7 +35,7 @@ final class StringToEffectParser extends StringToTParser{
use SingletonTrait;
private static function make() : self{
$result = new self;
$result = new self();
$result->register("absorption", fn() => VanillaEffects::ABSORPTION());
$result->register("blindness", fn() => VanillaEffects::BLINDNESS());

View File

@ -101,6 +101,7 @@ final class VanillaEffects{
/**
* @return Effect[]
* @phpstan-return array<string, Effect>
*/
public static function getAll() : array{
//phpstan doesn't support generic traits yet :(

View File

@ -30,7 +30,7 @@ use pocketmine\event\entity\EntityDamageEvent;
class WitherEffect extends Effect{
public function canTick(EffectInstance $instance) : bool{
if(($interval = (50 >> $instance->getAmplifier())) > 0){
if(($interval = (40 >> $instance->getAmplifier())) > 0){
return ($instance->getDuration() % $interval) === 0;
}
return true;

View File

@ -186,6 +186,10 @@ class ItemEntity extends Entity{
return true;
}
public function canSaveWithChunk() : bool{
return !$this->item->isNull() && parent::canSaveWithChunk();
}
public function saveNBT() : CompoundTag{
$nbt = parent::saveNBT();
$nbt->setTag("Item", $this->item->nbtSerialize());

View File

@ -31,7 +31,7 @@ class HandlerListManager{
private static ?self $globalInstance = null;
public static function global() : self{
return self::$globalInstance ?? (self::$globalInstance = new self);
return self::$globalInstance ?? (self::$globalInstance = new self());
}
/** @var HandlerList[] classname => HandlerList */

View File

@ -76,11 +76,13 @@ abstract class BaseInventory implements Inventory{
/**
* @param Item[] $items
* @phpstan-param array<int, Item> $items
*/
abstract protected function internalSetContents(array $items) : void;
/**
* @param Item[] $items
* @phpstan-param array<int, Item> $items
*/
public function setContents(array $items) : void{
if(count($items) > $this->getSize()){
@ -132,6 +134,7 @@ abstract class BaseInventory implements Inventory{
return $slots;
}
public function first(Item $item, bool $exact = false) : int{
$count = $exact ? $item->getCount() : max(1, $item->getCount());
$checkDamage = $exact || !$item->hasAnyDamageValue();

View File

@ -47,12 +47,20 @@ interface Inventory{
public function setItem(int $index, Item $item) : void;
/**
* Returns an array of all the itemstacks in the inventory, indexed by their slot number.
* Empty slots are not included unless includeEmpty is true.
*
* @return Item[]
* @phpstan-return array<int, Item>
*/
public function getContents(bool $includeEmpty = false) : array;
/**
* Sets the contents of the inventory. Non-numeric offsets or offsets larger than the size of the inventory are
* ignored.
*
* @param Item[] $items
* @phpstan-param array<int, Item> $items
*/
public function setContents(array $items) : void;
@ -85,8 +93,10 @@ interface Inventory{
/**
* 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.
*
* @return Item[]
* @phpstan-return array<int, Item>
*/
public function all(Item $item) : array;

View File

@ -58,6 +58,7 @@ class SimpleInventory extends BaseInventory{
/**
* @return Item[]
* @phpstan-return array<int, Item>
*/
public function getContents(bool $includeEmpty = false) : array{
$contents = [];

View File

@ -42,6 +42,9 @@ class DropItemAction extends InventoryAction{
if($this->targetItem->isNull()){
throw new TransactionValidationException("Cannot drop an empty itemstack");
}
if($this->targetItem->getCount() > $this->targetItem->getMaxStackSize()){
throw new TransactionValidationException("Target item exceeds item type max stack size");
}
}
public function onPreExecute(Player $source) : bool{

View File

@ -70,6 +70,12 @@ class SlotChangeAction extends InventoryAction{
if(!$this->inventory->getItem($this->inventorySlot)->equalsExact($this->sourceItem)){
throw new TransactionValidationException("Slot does not contain expected original item");
}
if($this->targetItem->getCount() > $this->targetItem->getMaxStackSize()){
throw new TransactionValidationException("Target item exceeds item type max stack size");
}
if($this->targetItem->getCount() > $this->inventory->getMaxStackSize()){
throw new TransactionValidationException("Target item exceeds inventory max stack size");
}
}
/**

View File

@ -472,7 +472,7 @@ class ItemFactory{
if(isset($this->list[$offset = self::getListOffset($id, $meta)])){
$item = clone $this->list[$offset];
}elseif(isset($this->list[$zero = self::getListOffset($id, 0)]) && $this->list[$zero] instanceof Durable){
if($meta <= $this->list[$zero]->getMaxDurability()){
if($meta >= 0 && $meta <= $this->list[$zero]->getMaxDurability()){
$item = clone $this->list[$zero];
$item->setDamage($meta);
}else{

View File

@ -185,13 +185,16 @@ final class PotionType{
new EffectInstance(VanillaEffects::WITHER(), 800, 1)
]),
new self("turtle_master", "Turtle Master", fn() => [
//TODO
new EffectInstance(VanillaEffects::SLOWNESS(), 20 * 20, 3),
new EffectInstance(VanillaEffects::RESISTANCE(), 20 * 20, 2),
]),
new self("long_turtle_master", "Long Turtle Master", fn() => [
//TODO
new EffectInstance(VanillaEffects::SLOWNESS(), 40 * 20, 3),
new EffectInstance(VanillaEffects::RESISTANCE(), 40 * 20, 2),
]),
new self("strong_turtle_master", "Strong Turtle Master", fn() => [
//TODO
new EffectInstance(VanillaEffects::SLOWNESS(), 20 * 20, 5),
new EffectInstance(VanillaEffects::RESISTANCE(), 20 * 20, 3),
]),
new self("slow_falling", "Slow Falling", fn() => [
//TODO

View File

@ -41,7 +41,7 @@ final class StringToItemParser extends StringToTParser{
use SingletonTrait;
private static function make() : self{
$result = new self;
$result = new self();
foreach(DyeColor::getAll() as $color){
$prefix = fn(string $name) => $color->name() . "_" . $name;

View File

@ -384,6 +384,7 @@ final class VanillaItems{
/**
* @return Item[]
* @phpstan-return array<string, Item>
*/
public static function getAll() : array{
//phpstan doesn't support generic traits yet :(

View File

@ -35,7 +35,7 @@ final class StringToEnchantmentParser extends StringToTParser{
use SingletonTrait;
private static function make() : self{
$result = new self;
$result = new self();
$result->register("blast_protection", fn() => VanillaEnchantments::BLAST_PROTECTION());
$result->register("efficiency", fn() => VanillaEnchantments::EFFICIENCY());

View File

@ -27,6 +27,7 @@ use pocketmine\utils\Utils;
use Webmozart\PathUtil\Path;
use function array_filter;
use function array_map;
use function count;
use function explode;
use function file_exists;
use function is_dir;
@ -67,10 +68,14 @@ class Language{
$result = [];
foreach($files as $file){
$code = explode(".", $file)[0];
$strings = self::loadLang($path, $code);
if(isset($strings["language.name"])){
$result[$code] = $strings["language.name"];
try{
$code = explode(".", $file)[0];
$strings = self::loadLang($path, $code);
if(isset($strings["language.name"])){
$result[$code] = $strings["language.name"];
}
}catch(LanguageNotFoundException $e){
// no-op
}
}
@ -124,7 +129,10 @@ class Language{
protected static function loadLang(string $path, string $languageCode) : array{
$file = Path::join($path, $languageCode . ".ini");
if(file_exists($file)){
return array_map('\stripcslashes', Utils::assumeNotFalse(parse_ini_file($file, false, INI_SCANNER_RAW), "Missing or inaccessible required resource files"));
$strings = array_map('stripcslashes', Utils::assumeNotFalse(parse_ini_file($file, false, INI_SCANNER_RAW), "Missing or inaccessible required resource files"));
if(count($strings) > 0){
return $strings;
}
}
throw new LanguageNotFoundException("Language \"$languageCode\" not found");

View File

@ -30,6 +30,7 @@ use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\network\mcpe\protocol\types\ChunkPosition;
use pocketmine\network\mcpe\serializer\ChunkSerializer;
use pocketmine\scheduler\AsyncTask;
use pocketmine\world\format\Chunk;
@ -71,7 +72,7 @@ class ChunkRequestTask extends AsyncTask{
$subCount = ChunkSerializer::getSubChunkCount($chunk) + ChunkSerializer::LOWER_PADDING_SIZE;
$encoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$payload = ChunkSerializer::serializeFullChunk($chunk, RuntimeBlockMapping::getInstance(), $encoderContext, $this->tiles);
$this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::create($this->chunkX, $this->chunkZ, $subCount, false, null, $payload))->getBuffer()));
$this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $subCount, false, null, $payload))->getBuffer()));
}
public function onError() : void{

View File

@ -259,8 +259,10 @@ class InventoryManager{
public function onClientRemoveWindow(int $id) : void{
if($id === $this->lastInventoryNetworkId){
$this->remove($id);
$this->player->removeCurrentWindow();
if($id !== $this->pendingCloseWindowId){
$this->remove($id);
$this->player->removeCurrentWindow();
}
}else{
$this->session->getLogger()->debug("Attempted to close inventory with network ID $id, but current is $this->lastInventoryNetworkId");
}

View File

@ -56,6 +56,7 @@ use pocketmine\network\mcpe\handler\LoginPacketHandler;
use pocketmine\network\mcpe\handler\PacketHandler;
use pocketmine\network\mcpe\handler\PreSpawnPacketHandler;
use pocketmine\network\mcpe\handler\ResourcePacksPacketHandler;
use pocketmine\network\mcpe\handler\SessionStartPacketHandler;
use pocketmine\network\mcpe\handler\SpawnResponsePacketHandler;
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
@ -164,6 +165,7 @@ class NetworkSession{
*/
private \SplQueue $compressedQueue;
private bool $forceAsyncCompression = true;
private bool $enableCompression = false; //disabled until handshake completed
private PacketSerializerContext $packetSerializerContext;
@ -196,17 +198,10 @@ class NetworkSession{
$this->connectTime = time();
$this->setHandler(new LoginPacketHandler(
$this->setHandler(new SessionStartPacketHandler(
$this->server,
$this,
function(PlayerInfo $info) : void{
$this->info = $info;
$this->logger->info("Player: " . TextFormat::AQUA . $info->getUsername() . TextFormat::RESET);
$this->logger->setPrefix($this->getLogPrefix());
},
function(bool $isAuthenticated, bool $authRequired, ?string $error, ?string $clientPubKey) : void{
$this->setAuthenticationStatus($isAuthenticated, $authRequired, $error, $clientPubKey);
}
fn() => $this->onSessionStartSuccess()
));
$this->manager->add($this);
@ -221,6 +216,24 @@ class NetworkSession{
return $this->logger;
}
private function onSessionStartSuccess() : void{
$this->logger->debug("Session start handshake completed, awaiting login packet");
$this->flushSendBuffer(true);
$this->enableCompression = true;
$this->setHandler(new LoginPacketHandler(
$this->server,
$this,
function(PlayerInfo $info) : void{
$this->info = $info;
$this->logger->info("Player: " . TextFormat::AQUA . $info->getUsername() . TextFormat::RESET);
$this->logger->setPrefix($this->getLogPrefix());
},
function(bool $isAuthenticated, bool $authRequired, ?string $error, ?string $clientPubKey) : void{
$this->setAuthenticationStatus($isAuthenticated, $authRequired, $error, $clientPubKey);
}
));
}
protected function createPlayer() : void{
$this->server->createPlayer($this, $this->info, $this->authenticated, $this->cachedOfflinePlayerData)->onCompletion(
\Closure::fromCallable([$this, 'onPlayerCreated']),
@ -335,18 +348,22 @@ class NetworkSession{
}
}
Timings::$playerNetworkReceiveDecompress->startTiming();
try{
$stream = new PacketBatch($this->compressor->decompress($payload));
}catch(DecompressionException $e){
$this->logger->debug("Failed to decompress packet: " . base64_encode($payload));
throw PacketHandlingException::wrap($e, "Compressed packet batch decode error");
}finally{
Timings::$playerNetworkReceiveDecompress->stopTiming();
if($this->enableCompression){
Timings::$playerNetworkReceiveDecompress->startTiming();
try{
$decompressed = $this->compressor->decompress($payload);
}catch(DecompressionException $e){
$this->logger->debug("Failed to decompress packet: " . base64_encode($payload));
throw PacketHandlingException::wrap($e, "Compressed packet batch decode error");
}finally{
Timings::$playerNetworkReceiveDecompress->stopTiming();
}
}else{
$decompressed = $payload;
}
try{
foreach($stream->getPackets($this->packetPool, $this->packetSerializerContext, 500) as [$packet, $buffer]){
foreach((new PacketBatch($decompressed))->getPackets($this->packetPool, $this->packetSerializerContext, 500) as [$packet, $buffer]){
if($packet === null){
$this->logger->debug("Unknown packet: " . base64_encode($buffer));
throw new PacketHandlingException("Unknown packet received");
@ -444,7 +461,14 @@ class NetworkSession{
}elseif($this->forceAsyncCompression){
$syncMode = false;
}
$promise = $this->server->prepareBatch(PacketBatch::fromPackets($this->packetSerializerContext, ...$this->sendBuffer), $this->compressor, $syncMode);
$batch = PacketBatch::fromPackets($this->packetSerializerContext, ...$this->sendBuffer);
if($this->enableCompression){
$promise = $this->server->prepareBatch($batch, $this->compressor, $syncMode);
}else{
$promise = new CompressBatchPromise();
$promise->resolve($batch->getBuffer());
}
$this->sendBuffer = [];
$this->queueCompressedNoBufferFlush($promise, $immediate);
}
@ -754,7 +778,7 @@ class NetworkSession{
}
public function syncViewAreaCenterPoint(Vector3 $newPos, int $viewDistance) : void{
$this->sendDataPacket(NetworkChunkPublisherUpdatePacket::create(BlockPosition::fromVector3($newPos), $viewDistance * 16)); //blocks, not chunks >.>
$this->sendDataPacket(NetworkChunkPublisherUpdatePacket::create(BlockPosition::fromVector3($newPos), $viewDistance * 16, [])); //blocks, not chunks >.>
}
public function syncPlayerSpawnPoint(Position $newSpawn) : void{
@ -832,7 +856,7 @@ class NetworkSession{
public function syncAttributes(Living $entity, array $attributes) : void{
if(count($attributes) > 0){
$this->sendDataPacket(UpdateAttributesPacket::create($entity->getId(), array_map(function(Attribute $attr) : NetworkAttribute{
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue());
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []);
}, $attributes), 0));
}
}

View File

@ -43,8 +43,6 @@ class ChunkCache implements ChunkListener{
/**
* Fetches the ChunkCache instance for the given world. This lazily creates cache systems as needed.
*
* @return ChunkCache
*/
public static function getInstance(World $world, Compressor $compressor) : self{
$worldId = spl_object_id($world);

View File

@ -48,7 +48,9 @@ use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
use pocketmine\network\mcpe\protocol\types\inventory\NetworkInventoryAction;
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
use pocketmine\network\mcpe\protocol\types\recipe\IntIdMetaItemDescriptor;
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient;
use pocketmine\network\mcpe\protocol\types\recipe\StringIdMetaItemDescriptor;
use pocketmine\player\GameMode;
use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
@ -115,7 +117,7 @@ class TypeConverter{
public function coreItemStackToRecipeIngredient(Item $itemStack) : RecipeIngredient{
if($itemStack->isNull()){
return new RecipeIngredient(0, 0, 0);
return new RecipeIngredient(null, 0);
}
if($itemStack->hasAnyDamageValue()){
[$id, ] = ItemTranslator::getInstance()->toNetworkId($itemStack->getId(), 0);
@ -123,15 +125,25 @@ class TypeConverter{
}else{
[$id, $meta] = ItemTranslator::getInstance()->toNetworkId($itemStack->getId(), $itemStack->getMeta());
}
return new RecipeIngredient($id, $meta, $itemStack->getCount());
return new RecipeIngredient(new IntIdMetaItemDescriptor($id, $meta), $itemStack->getCount());
}
public function recipeIngredientToCoreItemStack(RecipeIngredient $ingredient) : Item{
if($ingredient->getId() === 0){
$descriptor = $ingredient->getDescriptor();
if($descriptor === null){
return VanillaItems::AIR();
}
[$id, $meta] = ItemTranslator::getInstance()->fromNetworkIdWithWildcardHandling($ingredient->getId(), $ingredient->getMeta());
return ItemFactory::getInstance()->get($id, $meta, $ingredient->getCount());
if($descriptor instanceof IntIdMetaItemDescriptor){
[$id, $meta] = ItemTranslator::getInstance()->fromNetworkIdWithWildcardHandling($descriptor->getId(), $descriptor->getMeta());
return ItemFactory::getInstance()->get($id, $meta, $ingredient->getCount());
}
if($descriptor instanceof StringIdMetaItemDescriptor){
$intId = GlobalItemTypeDictionary::getInstance()->getDictionary()->fromStringId($descriptor->getId());
[$id, $meta] = ItemTranslator::getInstance()->fromNetworkIdWithWildcardHandling($intId, $descriptor->getMeta());
return ItemFactory::getInstance()->get($id, $meta, $ingredient->getCount());
}
throw new \LogicException("Unsupported conversion of recipe ingredient to core item stack");
}
public function coreItemStackToNet(Item $itemStack) : ItemStack{

View File

@ -51,7 +51,6 @@ use pocketmine\network\mcpe\InventoryManager;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\ActorEventPacket;
use pocketmine\network\mcpe\protocol\ActorPickRequestPacket;
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
@ -145,6 +144,11 @@ class InGamePacketHandler extends PacketHandler{
/** @var UseItemTransactionData|null */
protected $lastRightClickData = null;
protected ?Vector3 $lastPlayerAuthInputPosition = null;
protected ?float $lastPlayerAuthInputYaw = null;
protected ?float $lastPlayerAuthInputPitch = null;
protected ?int $lastPlayerAuthInputFlags = null;
/** @var bool */
public $forceMoveSync = false;
@ -168,9 +172,10 @@ class InGamePacketHandler extends PacketHandler{
return true;
}
private function resolveOnOffInputFlags(PlayerAuthInputPacket $packet, int $startFlag, int $stopFlag) : ?bool{
$enabled = $packet->hasFlag($startFlag);
if($enabled !== $packet->hasFlag($stopFlag)){
private function resolveOnOffInputFlags(int $inputFlags, int $startFlag, int $stopFlag) : ?bool{
$enabled = ($inputFlags & (1 << $startFlag)) !== 0;
$disabled = ($inputFlags & (1 << $stopFlag)) !== 0;
if($enabled !== $disabled){
return $enabled;
}
//neither flag was set, or both were set
@ -179,51 +184,68 @@ class InGamePacketHandler extends PacketHandler{
public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
$rawPos = $packet->getPosition();
foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->getYaw(), $packet->getHeadYaw(), $packet->getPitch()] as $float){
$rawYaw = $packet->getYaw();
$rawPitch = $packet->getPitch();
foreach([$rawPos->x, $rawPos->y, $rawPos->z, $rawYaw, $packet->getHeadYaw(), $rawPitch] as $float){
if(is_infinite($float) || is_nan($float)){
$this->session->getLogger()->debug("Invalid movement received, contains NAN/INF components");
return false;
}
}
$yaw = fmod($packet->getYaw(), 360);
$pitch = fmod($packet->getPitch(), 360);
if($yaw < 0){
$yaw += 360;
if($rawYaw !== $this->lastPlayerAuthInputYaw || $rawPitch !== $this->lastPlayerAuthInputPitch){
$this->lastPlayerAuthInputYaw = $rawYaw;
$this->lastPlayerAuthInputPitch = $rawPitch;
$yaw = fmod($rawYaw, 360);
$pitch = fmod($rawPitch, 360);
if($yaw < 0){
$yaw += 360;
}
$this->player->setRotation($yaw, $pitch);
}
$this->player->setRotation($yaw, $pitch);
$curPos = $this->player->getLocation();
$hasMoved = $this->lastPlayerAuthInputPosition === null || !$this->lastPlayerAuthInputPosition->equals($rawPos);
$newPos = $rawPos->round(4)->subtract(0, 1.62, 0);
if($this->forceMoveSync && $newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
$this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos);
//Still getting movements from before teleport, ignore them
return false;
if($this->forceMoveSync && $hasMoved){
$curPos = $this->player->getLocation();
if($newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
$this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos);
//Still getting movements from before teleport, ignore them
return false;
}
// Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock
$this->forceMoveSync = false;
}
// Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock
$this->forceMoveSync = false;
$inputFlags = $packet->getInputFlags();
if($inputFlags !== $this->lastPlayerAuthInputFlags){
$this->lastPlayerAuthInputFlags = $inputFlags;
$sneaking = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING);
$sprinting = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING);
$swimming = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING);
$gliding = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING);
$mismatch =
($sneaking !== null && !$this->player->toggleSneak($sneaking)) |
($sprinting !== null && !$this->player->toggleSprint($sprinting)) |
($swimming !== null && !$this->player->toggleSwim($swimming)) |
($gliding !== null && !$this->player->toggleGlide($gliding));
if((bool) $mismatch){
$this->player->sendData([$this->player]);
$sneaking = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING);
$sprinting = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING);
$swimming = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING);
$gliding = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING);
$mismatch =
($sneaking !== null && !$this->player->toggleSneak($sneaking)) |
($sprinting !== null && !$this->player->toggleSprint($sprinting)) |
($swimming !== null && !$this->player->toggleSwim($swimming)) |
($gliding !== null && !$this->player->toggleGlide($gliding));
if((bool) $mismatch){
$this->player->sendData([$this->player]);
}
if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){
$this->player->jump();
}
}
if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){
$this->player->jump();
}
if(!$this->forceMoveSync){
if(!$this->forceMoveSync && $hasMoved){
$this->lastPlayerAuthInputPosition = $rawPos;
//TODO: this packet has WAYYYYY more useful information that we're not using
$this->player->handleMovement($newPos);
}
@ -269,7 +291,6 @@ class InGamePacketHandler extends PacketHandler{
//TODO HACK: EATING_ITEM is sent back to the server when the server sends it for other players (1.14 bug, maybe earlier)
return $packet->actorRuntimeId === ActorEvent::EATING_ITEM;
}
$this->player->removeCurrentWindow();
switch($packet->eventId){
case ActorEvent::EATING_ITEM: //TODO: ignore this and handle it server-side
@ -647,10 +668,6 @@ class InGamePacketHandler extends PacketHandler{
return true; //this is a broken useless packet, so we don't use it
}
public function handleAdventureSettings(AdventureSettingsPacket $packet) : bool{
return true; //no longer used, but the client still sends it for flight changes
}
public function handleBlockActorData(BlockActorDataPacket $packet) : bool{
$pos = new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ());
if($pos->distanceSquared($this->player->getLocation()) > 10000){
@ -868,7 +885,14 @@ class InGamePacketHandler extends PacketHandler{
}
public function handleModalFormResponse(ModalFormResponsePacket $packet) : bool{
return $this->player->onFormSubmit($packet->formId, self::stupid_json_decode($packet->formData, true));
if($packet->cancelReason !== null){
//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));
}else{
throw new PacketHandlingException("Expected either formData or cancelReason to be set in ModalFormResponsePacket");
}
}
/**

View File

@ -165,13 +165,13 @@ class LoginPacketHandler extends PacketHandler{
if(!is_array($claims["extraData"])){
throw new PacketHandlingException("'extraData' key should be an array");
}
$mapper = new \JsonMapper;
$mapper = new \JsonMapper();
$mapper->bEnforceMapType = false; //TODO: we don't really need this as an array, but right now we don't have enough models
$mapper->bExceptionOnMissingData = true;
$mapper->bExceptionOnUndefinedProperty = true;
try{
/** @var AuthenticationData $extraData */
$extraData = $mapper->map($claims["extraData"], new AuthenticationData);
$extraData = $mapper->map($claims["extraData"], new AuthenticationData());
}catch(\JsonMapper_Exception $e){
throw PacketHandlingException::wrap($e);
}
@ -193,12 +193,12 @@ class LoginPacketHandler extends PacketHandler{
throw PacketHandlingException::wrap($e);
}
$mapper = new \JsonMapper;
$mapper = new \JsonMapper();
$mapper->bEnforceMapType = false; //TODO: we don't really need this as an array, but right now we don't have enough models
$mapper->bExceptionOnMissingData = true;
$mapper->bExceptionOnUndefinedProperty = true;
try{
$clientData = $mapper->map($clientDataClaims, new ClientData);
$clientData = $mapper->map($clientDataClaims, new ClientData());
}catch(\JsonMapper_Exception $e){
throw PacketHandlingException::wrap($e);
}

View File

@ -98,9 +98,10 @@ class PreSpawnPacketHandler extends PacketHandler{
false,
sprintf("%s %s", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(true)),
Uuid::fromString(Uuid::NIL),
false,
[],
0,
GlobalItemTypeDictionary::getInstance()->getDictionary()->getEntries()
GlobalItemTypeDictionary::getInstance()->getDictionary()->getEntries(),
));
$this->session->sendDataPacket(StaticPacketCache::getInstance()->getAvailableActorIdentifiers());

View File

@ -0,0 +1,76 @@
<?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 pocketmine\lang\KnownTranslationFactory;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\NetworkSettingsPacket;
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\RequestNetworkSettingsPacket;
use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm;
use pocketmine\Server;
final class SessionStartPacketHandler extends PacketHandler{
/**
* @phpstan-param \Closure() : void $onSuccess
*/
public function __construct(
private Server $server,
private NetworkSession $session,
private \Closure $onSuccess
){}
public function handleRequestNetworkSettings(RequestNetworkSettingsPacket $packet) : bool{
$protocolVersion = $packet->getProtocolVersion();
if(!$this->isCompatibleProtocol($protocolVersion)){
$this->session->sendDataPacket(PlayStatusPacket::create($protocolVersion < ProtocolInfo::CURRENT_PROTOCOL ? PlayStatusPacket::LOGIN_FAILED_CLIENT : PlayStatusPacket::LOGIN_FAILED_SERVER), true);
//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
$this->session->disconnect(
$this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_disconnect_incompatibleProtocol((string) $protocolVersion)),
false
);
return true;
}
//TODO: we're filling in the defaults to get pre-1.19.30 behaviour back for now, but we should explore the new options in the future
$this->session->sendDataPacket(NetworkSettingsPacket::create(
NetworkSettingsPacket::COMPRESS_EVERYTHING,
CompressionAlgorithm::ZLIB,
false,
0,
0
));
($this->onSuccess)();
return true;
}
protected function isCompatibleProtocol(int $protocolVersion) : bool{
return $protocolVersion === ProtocolInfo::CURRENT_PROTOCOL;
}
}

View File

@ -58,7 +58,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
* Sometimes this gets changed when the MCPE-layer protocol gets broken to the point where old and new can't
* communicate. It's important that we check this to avoid catastrophes.
*/
private const MCPE_RAKNET_PROTOCOL_VERSION = 10;
private const MCPE_RAKNET_PROTOCOL_VERSION = 11;
private const MCPE_RAKNET_PACKET_ID = "\xfe";
@ -84,8 +84,8 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
$this->sleeper = new SleeperNotifier();
$mainToThreadBuffer = new \Threaded;
$threadToMainBuffer = new \Threaded;
$mainToThreadBuffer = new \Threaded();
$threadToMainBuffer = new \Threaded();
$this->rakLib = new RakLibServer(
$this->server->getLogger(),

View File

@ -31,7 +31,7 @@ class PermissionManager{
public static function getInstance() : PermissionManager{
if(self::$instance === null){
self::$instance = new self;
self::$instance = new self();
}
return self::$instance;

View File

@ -1180,7 +1180,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
return;
}
$oldPos = $this->getLocation();
$oldPos = $this->location;
$distanceSquared = $newPos->distanceSquared($oldPos);
$revert = false;
@ -1198,7 +1198,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
* asking for help if you suffer the consequences of messing with this.
*/
$this->logger->debug("Moved too fast, reverting movement");
$this->logger->debug("Old position: " . $this->location->asVector3() . ", new position: " . $newPos);
$this->logger->debug("Old position: " . $oldPos->asVector3() . ", new position: " . $newPos);
$revert = true;
}elseif(!$this->getWorld()->isInLoadedTerrain($newPos)){
$revert = true;
@ -1206,9 +1206,9 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
}
if(!$revert && $distanceSquared != 0){
$dx = $newPos->x - $this->location->x;
$dy = $newPos->y - $this->location->y;
$dz = $newPos->z - $this->location->z;
$dx = $newPos->x - $oldPos->x;
$dy = $newPos->y - $oldPos->y;
$dz = $newPos->z - $oldPos->z;
$this->move($dx, $dy, $dz);
}
@ -1558,7 +1558,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$ev = new PlayerBlockPickEvent($this, $block, $item);
$existingSlot = $this->inventory->first($item);
if($existingSlot === -1 && $this->hasFiniteResources()){
if($existingSlot === -1 && ($this->hasFiniteResources() || $this->isSpectator())){
$ev->cancel();
}
$ev->call();

View File

@ -163,7 +163,7 @@ class AsyncPool{
throw new \InvalidArgumentException("Cannot submit the same AsyncTask instance more than once");
}
$task->progressUpdates = new \Threaded;
$task->progressUpdates = new \Threaded();
$task->setSubmitted();
$this->getWorker($worker)->stack($task);

View File

@ -33,19 +33,31 @@ use function spl_object_id;
/**
* Class used to run async tasks in other threads.
*
* An AsyncTask does not have its own thread. It is queued into an AsyncPool and executed if there is an async worker
* with no AsyncTask running. Therefore, an AsyncTask SHOULD NOT execute for more than a few seconds. For tasks that
* run for a long time or infinitely, start another thread instead.
* An AsyncTask is run by a thread pool of reusable threads, and doesn't have its own dedicated thread. A thread is
* usually chosen from the pool at random to run the task (though a specific thread in the pool may be selected
* manually, if needed).
* Reusing threads this way has a much lower performance cost than starting an entirely new thread for every operation.
* AsyncTasks are therefore suitable for brief CPU-bound tasks, such as world generation, compression/decompression of
* data, etc.
*
* AsyncTask SHOULD NOT be used for I/O-bound tasks, such as network I/O, file I/O, database I/O, etc. The server's
* central AsyncPool is used for things like compressing network packets for sending, so using AsyncTask for I/O will
* slow the whole server down, stall chunk loading, etc.
*
* An AsyncTask SHOULD NOT run for more than a few seconds. For tasks that run for a long time or indefinitely, create
* a dedicated thread instead.
*
* The Server instance is not accessible inside {@link AsyncTask::onRun()}. It can only be accessed in the main server
* thread, e.g. during {@link AsyncTask::onCompletion()} or {@link AsyncTask::onProgressUpdate()}. This means that
* whatever you do in onRun() must be able to work without the Server instance.
*
* WARNING: Any non-Threaded objects WILL BE SERIALIZED when assigned to members of AsyncTasks or other Threaded object.
* If later accessed from said Threaded object, you will be operating on a COPY OF THE OBJECT, NOT THE ORIGINAL OBJECT.
* If you want to store non-serializable objects to access when the task completes, store them using
* {@link AsyncTask::storeLocal}.
*
* WARNING: As of pthreads v3.1.6, arrays are converted to Volatile objects when assigned as members of Threaded objects.
* WARNING: Arrays are converted to Volatile objects when assigned as members of Threaded objects.
* Keep this in mind when using arrays stored as members of your AsyncTask.
*
* WARNING: Do not call PocketMine-MP API methods from other Threads!!
*/
abstract class AsyncTask extends \Threaded{
/**

View File

@ -56,7 +56,9 @@ abstract class Worker extends \Worker{
$this->isKilled = true;
if(!$this->isShutdown()){
while($this->unstack() !== null);
$this->synchronized(function() : void{
while($this->unstack() !== null);
});
$this->notify();
$this->shutdown();
}

View File

@ -48,6 +48,7 @@ trait EnumTrait{
* This is overridden to change the return typehint.
*
* @return self[]
* @phpstan-return array<string, self>
*/
public static function getAll() : array{
//phpstan doesn't support generic traits yet :(

View File

@ -29,7 +29,10 @@ use function mb_strtoupper;
use function preg_match;
trait RegistryTrait{
/** @var object[] */
/**
* @var object[]
* @phpstan-var array<string, object>
*/
private static $members = null;
private static function verifyName(string $name) : void{
@ -107,6 +110,7 @@ trait RegistryTrait{
/**
* @return object[]
* @phpstan-return array<string, object>
*/
private static function _registryGetAll() : array{
self::checkInit();

View File

@ -38,6 +38,7 @@ class ReversePriorityQueue extends \SplPriorityQueue{
*
* @return int
*/
#[\ReturnTypeWillChange]
public function compare($priority1, $priority2){
//TODO: this will crash if non-numeric priorities are used
return (int) -($priority1 - $priority2);

View File

@ -28,7 +28,7 @@ trait SingletonTrait{
private static $instance = null;
private static function make() : self{
return new self;
return new self();
}
public static function getInstance() : self{

View File

@ -69,6 +69,7 @@ use function mb_check_encoding;
use function ob_end_clean;
use function ob_get_contents;
use function ob_start;
use function opcache_get_status;
use function ord;
use function php_uname;
use function phpversion;
@ -108,6 +109,7 @@ final class Utils{
private static ?string $os = null;
private static ?UuidInterface $serverUniqueId = null;
private static ?int $cpuCores = null;
/**
* Returns a readable identifier for the given Closure, including file and line.
@ -295,14 +297,11 @@ final class Utils{
}
public static function getCoreCount(bool $recalculate = false) : int{
static $processors = 0;
if($processors > 0 && !$recalculate){
return $processors;
}else{
$processors = 0;
if(self::$cpuCores !== null && !$recalculate){
return self::$cpuCores;
}
$processors = 0;
switch(Utils::getOS()){
case Utils::OS_LINUX:
case Utils::OS_ANDROID:
@ -326,7 +325,7 @@ final class Utils{
$processors = (int) getenv("NUMBER_OF_PROCESSORS");
break;
}
return $processors;
return self::$cpuCores = $processors;
}
/**
@ -365,12 +364,6 @@ final class Utils{
$ord -= 0x100;
}
$hash = 31 * $hash + $ord;
while($hash > 0x7FFFFFFF){
$hash -= 0x100000000;
}
while($hash < -0x80000000){
$hash += 0x100000000;
}
$hash &= 0xFFFFFFFF;
}
return $hash;
@ -486,8 +479,8 @@ final class Utils{
*/
public static function currentTrace(int $skipFrames = 0) : array{
++$skipFrames; //omit this frame from trace, in addition to other skipped frames
if(function_exists("xdebug_get_function_stack")){
$trace = array_reverse(xdebug_get_function_stack());
if(function_exists("xdebug_get_function_stack") && count($trace = @xdebug_get_function_stack()) !== 0){
$trace = array_reverse($trace);
}else{
$e = new \Exception();
$trace = $e->getTrace();
@ -634,4 +627,30 @@ final class Utils{
public static function checkLocationNotInfOrNaN(Location $location) : void{
self::checkVector3NotInfOrNaN($location);
}
/**
* Returns an integer describing the current OPcache JIT setting.
* @see https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit
*/
public static function getOpcacheJitMode() : ?int{
if(
function_exists('opcache_get_status') &&
($opcacheStatus = opcache_get_status(false)) !== false &&
isset($opcacheStatus["jit"]["on"])
){
$jit = $opcacheStatus["jit"];
if($jit["on"] === true){
return (($jit["opt_flags"] >> 2) * 1000) +
(($jit["opt_flags"] & 0x03) * 100) +
($jit["kind"] * 10) +
$jit["opt_level"];
}
//jit available, but disabled
return 0;
}
//jit not available
return null;
}
}

View File

@ -171,6 +171,8 @@ class World implements ChunkManager{
/** @var Entity[] */
public $updateEntities = [];
private bool $inDynamicStateRecalculation = false;
/** @var Block[][] */
private array $blockCache = [];
@ -1536,17 +1538,15 @@ class World implements ChunkManager{
$block->position($this, $x, $y, $z);
static $dynamicStateRead = false;
if($dynamicStateRead){
if($this->inDynamicStateRecalculation){
//this call was generated by a parent getBlock() call calculating dynamic stateinfo
//don't calculate dynamic state and don't add to block cache (since it won't have dynamic state calculated).
//this ensures that it's impossible for dynamic state properties to recursively depend on each other.
$addToCache = false;
}else{
$dynamicStateRead = true;
$this->inDynamicStateRecalculation = true;
$block->readStateFromWorld();
$dynamicStateRead = false;
$this->inDynamicStateRecalculation = false;
}
if($addToCache && $relativeBlockHash !== null){
@ -2492,7 +2492,7 @@ class World implements ChunkManager{
continue;
}
if($entity === null){
$saveIdTag = $nbt->getTag("id") ?? $nbt->getTag("identifier");
$saveIdTag = $nbt->getTag("identifier") ?? $nbt->getTag("id");
$saveId = "<unknown>";
if($saveIdTag instanceof StringTag){
$saveId = $saveIdTag->getValue();

View File

@ -48,7 +48,7 @@ final class WorldCreationOptions{
}
public static function create() : self{
return new self;
return new self();
}
/** @phpstan-return class-string<Generator> */

View File

@ -123,6 +123,7 @@ class Normal extends Generator{
private function pickBiome(int $x, int $z) : Biome{
$hash = $x * 2345803 ^ $z * 9236449 ^ $this->seed;
$hash *= $hash + 223;
$hash = (int) $hash;
$xNoise = $hash >> 20 & 3;
$zNoise = $hash >> 22 & 3;
if($xNoise == 3){

View File

@ -23,25 +23,20 @@ declare(strict_types=1);
namespace pocketmine\world\particle;
use pocketmine\block\VanillaBlocks;
use pocketmine\entity\Entity;
use pocketmine\entity\Skin;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
use pocketmine\network\mcpe\protocol\types\DeviceOS;
use pocketmine\network\mcpe\protocol\types\entity\ByteMetadataProperty;
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
use pocketmine\network\mcpe\protocol\types\entity\FloatMetadataProperty;
use pocketmine\network\mcpe\protocol\types\entity\IntMetadataProperty;
use pocketmine\network\mcpe\protocol\types\entity\LongMetadataProperty;
use pocketmine\network\mcpe\protocol\types\GameMode;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
use Ramsey\Uuid\Uuid;
use function str_repeat;
use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
class FloatingTextParticle implements Particle{
//TODO: HACK!
@ -94,38 +89,34 @@ class FloatingTextParticle implements Particle{
}
if(!$this->invisible){
$uuid = Uuid::uuid4();
$name = $this->title . ($this->text !== "" ? "\n" . $this->text : "");
$p[] = PlayerListPacket::add([PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, SkinAdapterSingleton::get()->toSkinData(new Skin("Standard_Custom", str_repeat("\x00", 8192))))]);
$actorFlags = (
1 << EntityMetadataFlags::IMMOBILE
);
$actorMetadata = [
EntityMetadataProperties::FLAGS => new LongMetadataProperty($actorFlags),
EntityMetadataProperties::SCALE => new FloatMetadataProperty(0.01) //zero causes problems on debug builds
EntityMetadataProperties::SCALE => new FloatMetadataProperty(0.01), //zero causes problems on debug builds
EntityMetadataProperties::BOUNDING_BOX_WIDTH => new FloatMetadataProperty(0.0),
EntityMetadataProperties::BOUNDING_BOX_HEIGHT => new FloatMetadataProperty(0.0),
EntityMetadataProperties::NAMETAG => new StringMetadataProperty($name),
EntityMetadataProperties::VARIANT => new IntMetadataProperty(RuntimeBlockMapping::getInstance()->toRuntimeId(VanillaBlocks::AIR()->getFullId())),
EntityMetadataProperties::ALWAYS_SHOW_NAMETAG => new ByteMetadataProperty(1),
];
$p[] = AddPlayerPacket::create(
$uuid,
$name,
$p[] = AddActorPacket::create(
$this->entityId, //TODO: actor unique ID
"",
$pos, //TODO: check offset
$this->entityId,
EntityIds::FALLING_BLOCK,
$pos, //TODO: check offset (0.49?)
null,
0,
0,
0,
ItemStackWrapper::legacy(ItemStack::null()),
GameMode::SURVIVAL,
$actorMetadata,
UpdateAbilitiesPacket::create(0, 0, $this->entityId, []),
0,
[],
"",
DeviceOS::UNKNOWN
$actorMetadata,
[]
);
$p[] = PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($uuid)]);
}
return $p;

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);
/*
* This hack works around a "feature" in PHPStan which locks in analysis version based on platform.php in composer.json
* See https://github.com/phpstan/phpstan/issues/7701 for details
*/
return [
'parameters' => [
'phpVersion' => PHP_VERSION_ID
]
];

View File

@ -775,18 +775,8 @@ parameters:
count: 1
path: ../../../src/plugin/PluginBase.php
-
message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Cannot cast mixed to string\\.$#"
count: 5
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Parameter \\#1 \\$data of static method pocketmine\\\\permission\\\\PermissionParser\\:\\:loadPermissions\\(\\) expects array\\<string, array\\<string, mixed\\>\\>, mixed given\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
@ -795,11 +785,6 @@ parameters:
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Parameter \\#1 \\$name of static method pocketmine\\\\plugin\\\\PluginEnableOrder\\:\\:fromString\\(\\) expects string, mixed given\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Parameter \\#2 \\$subject of function preg_match expects string, mixed given\\.$#"
count: 1
@ -810,26 +795,6 @@ parameters:
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$authors \\(array\\<string\\>\\) does not accept array\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$authors \\(array\\<string\\>\\) does not accept array\\<mixed\\>\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$depend \\(array\\<string\\>\\) does not accept array\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$loadBefore \\(array\\<string\\>\\) does not accept array\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$main \\(string\\) does not accept mixed\\.$#"
count: 1
@ -840,16 +805,6 @@ parameters:
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$softDepend \\(array\\<string\\>\\) does not accept array\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Property pocketmine\\\\plugin\\\\PluginDescription\\:\\:\\$srcNamespacePrefix \\(string\\) does not accept mixed\\.$#"
count: 1
path: ../../../src/plugin/PluginDescription.php
-
message: "#^Cannot call method addChild\\(\\) on pocketmine\\\\permission\\\\Permission\\|null\\.$#"
count: 4

View File

@ -10,8 +10,3 @@ parameters:
count: 1
path: ../../../src/event/RegisteredListener.php
-
message: "#^Property pocketmine\\\\event\\\\RegisteredListener\\:\\:\\$handler type has no signature specified for Closure\\.$#"
count: 1
path: ../../../src/event/RegisteredListener.php

View File

@ -1,7 +1,6 @@
parameters:
ignoreErrors:
-
message: "#^Property pocketmine\\\\network\\\\mcpe\\\\handler\\\\StupidJsonDecodeTest\\:\\:\\$stupidJsonDecodeFunc \\(Closure\\(string, bool\\)\\: mixed\\) does not accept Closure\\|null\\.$#"
message: "#^Property pocketmine\\\\network\\\\mcpe\\\\handler\\\\StupidJsonDecodeTest\\:\\:\\$stupidJsonDecodeFunc \\(Closure\\(string, bool=\\)\\: mixed\\) does not accept Closure\\|null\\.$#"
count: 1
path: ../../phpunit/network/mcpe/handler/StupidJsonDecodeTest.php

View File

@ -35,11 +35,6 @@ parameters:
count: 1
path: ../../../src/network/mcpe/handler/InGamePacketHandler.php
-
message: "#^Negated boolean expression is always true\\.$#"
count: 1
path: ../../../src/network/mcpe/handler/InGamePacketHandler.php
-
message: "#^Property pocketmine\\\\network\\\\mcpe\\\\raklib\\\\PthreadsChannelWriter\\:\\:\\$buffer is never read, only written\\.$#"
count: 1
@ -60,6 +55,11 @@ parameters:
count: 1
path: ../../../src/plugin/PluginManager.php
-
message: "#^Offset \\(int\\|string\\) on non\\-empty\\-array\\<pocketmine\\\\plugin\\\\Plugin\\> in isset\\(\\) always exists and is not nullable\\.$#"
count: 1
path: ../../../src/plugin/PluginManager.php
-
message: "#^Static property pocketmine\\\\scheduler\\\\AsyncTask\\:\\:\\$threadLocalStorage \\(ArrayObject\\<int, array\\<string, mixed\\>\\>\\|null\\) does not accept non\\-empty\\-array\\<int, non\\-empty\\-array\\<string, mixed\\>\\>\\|ArrayObject\\<int, array\\<string, mixed\\>\\>\\.$#"
count: 1
@ -75,8 +75,18 @@ 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
path: ../../../src/world/format/io/region/RegionLoader.php
-
message: "#^Casting to int something that's already int\\.$#"
count: 1
path: ../../../src/world/generator/normal/Normal.php

View File

@ -25,6 +25,7 @@ namespace pocketmine\block;
use PHPUnit\Framework\TestCase;
use pocketmine\block\utils\BrewingStandSlot;
use function array_values;
use function count;
class BrewingStandTest extends TestCase{
@ -33,7 +34,7 @@ class BrewingStandTest extends TestCase{
* @phpstan-return \Generator<int, array{list<BrewingStandSlot>}, void, void>
*/
public function slotsProvider() : \Generator{
yield [BrewingStandSlot::getAll()];
yield [array_values(BrewingStandSlot::getAll())];
yield [[BrewingStandSlot::EAST()]];
yield [[BrewingStandSlot::EAST(), BrewingStandSlot::NORTHWEST()]];
}

View File

@ -35,20 +35,32 @@ use function fopen;
use function fwrite;
use function getcwd;
use function ksort;
use function str_repeat;
use function str_replace;
use function strlen;
use function strtolower;
use const SORT_STRING;
use const STDERR;
require dirname(__DIR__) . '/vendor/autoload.php';
if(count($argv) > 2){
fwrite(STDERR, "Required arguments: md|rst\n");
exit(1);
}
$format = $argv[1] ?? "md";
if($format !== "md" && $format !== "rst"){
fwrite(STDERR, "Invalid format, expected either \"md\" or \"rst\"\n");
exit(1);
}
function markdownify(string $name) : string{
return str_replace(['.', '`', ' '], ['', '', '-'], strtolower($name));
}
DefaultPermissions::registerCorePermissions();
$cwd = Utils::assumeNotFalse(getcwd());
$output = Path::join($cwd, "core-permissions.md");
$output = Path::join($cwd, "core-permissions.$format");
echo "Writing output to $output\n";
$doc = fopen($output, "wb");
if($doc === false){
@ -59,36 +71,92 @@ if($doc === false){
$permissions = PermissionManager::getInstance()->getPermissions();
ksort($permissions, SORT_STRING);
fwrite($doc, "# PocketMine-MP Core Permissions\n");
fwrite($doc, "Generated from PocketMine-MP " . VersionInfo::VERSION()->getFullVersion() . "\n");
$title = "List of " . VersionInfo::NAME . " core permissions";
if($format === "md"){
fwrite($doc, "# $title\n");
}else{
fwrite($doc, ".. _corepermissions:\n\n");
fwrite($doc, "$title\n");
fwrite($doc, str_repeat("=", strlen($title)) . "\n\n");
}
fwrite($doc, "Generated from " . VersionInfo::NAME . " " . VersionInfo::VERSION()->getFullVersion() . "\n");
fwrite($doc, "\n");
fwrite($doc, "| Name | Description | Implied permissions |\n");
fwrite($doc, "|:-----|:------------|:-------------------:|\n");
if($format === "md"){
fwrite($doc, "| Name | Description | Implied permissions |\n");
fwrite($doc, "|:-----|:------------|:-------------------:|\n");
}else{
fwrite($doc, ".. list-table::\n");
fwrite($doc, " :header-rows: 1\n\n");
fwrite($doc, " * - Name\n");
fwrite($doc, " - Description\n");
fwrite($doc, " - Implied permissions\n");
fwrite($doc, "\n");
}
foreach($permissions as $permission){
$link = count($permission->getChildren()) === 0 ? "N/A" : "[Jump](#" . markdownify("Permissions implied by `" . $permission->getName() . "`") . ")";
fwrite($doc, "| `" . $permission->getName() . "` | " . $permission->getDescription() . " | $link |\n");
if($format === "md"){
$link = count($permission->getChildren()) === 0 ? "N/A" : "[Jump](#" . markdownify("Permissions implied by `" . $permission->getName() . "`") . ")";
fwrite($doc, "| `" . $permission->getName() . "` | " . $permission->getDescription() . " | $link |\n");
}else{
fwrite($doc, " * - ``" . $permission->getName() . "``\n");
fwrite($doc, " - " . $permission->getDescription() . "\n");
if(count($permission->getChildren()) === 0){
fwrite($doc, " - N/A\n");
}else{
fwrite($doc, " - :ref:`Jump<permissions_implied_by_" . $permission->getName() . ">`\n");
}
}
}
fwrite($doc, "\n\n");
fwrite($doc, "## Implied permissions\n");
fwrite($doc, "Some permissions automatically grant (or deny) other permissions by default when granted. These are referred to as **implied permissions**.<br>\n");
fwrite($doc, "Permissions may imply permissions which in turn imply other permissions (e.g. `pocketmine.group.operator` implies `pocketmine.group.user`, which in turn implies `pocketmine.command.help`).<br>\n");
fwrite($doc, "Implied permissions can be overridden by explicit permissions from elsewhere.<br>\n");
fwrite($doc, "**Note:** When explicitly denied, implied permissions are inverted. This means that \"granted\" becomes \"denied\" and vice versa.\n");
$title = "Implied permissions";
if($format === "md"){
fwrite($doc, "## $title\n");
}else{
fwrite($doc, "$title\n");
fwrite($doc, str_repeat("-", strlen($title)) . "\n\n");
}
$newline = $format === "md" ? "<br>\n" : "\n\n";
$code = $format === "md" ? "`" : "``";
fwrite($doc, "Some permissions automatically grant (or deny) other permissions by default when granted. These are referred to as **implied permissions**.$newline");
fwrite($doc, "Permissions may imply permissions which in turn imply other permissions (e.g. {$code}pocketmine.group.operator{$code} implies {$code}pocketmine.group.user{$code}, which in turn implies {$code}pocketmine.command.help{$code}).$newline");
fwrite($doc, "Implied permissions can be overridden by explicit permissions from elsewhere.$newline");
fwrite($doc, "**Note:** When explicitly denied, implied permissions are inverted. This means that \"granted\" becomes \"denied\" and vice versa.$newline");
fwrite($doc, "\n\n");
foreach($permissions as $permission){
if(count($permission->getChildren()) === 0){
continue;
}
fwrite($doc, "### Permissions implied by `" . $permission->getName() . "`\n");
$title = "Permissions implied by " . $code . $permission->getName() . $code;
if($format === "md"){
fwrite($doc, "### $title\n");
}else{
fwrite($doc, ".. _permissions_implied_by_" . $permission->getName() . ":\n\n");
fwrite($doc, "$title\n");
fwrite($doc, str_repeat("~", strlen($title)) . "\n\n");
}
fwrite($doc, "Users granted this permission will also be granted/denied the following permissions implicitly:\n\n");
fwrite($doc, "| Name | Type |\n");
fwrite($doc, "|:-----|:----:|\n");
$children = $permission->getChildren();
ksort($children, SORT_STRING);
foreach(Utils::stringifyKeys($children) as $childName => $isGranted){
fwrite($doc, "| `$childName` | " . ($isGranted ? "Granted" : "Denied") . " |\n");
if($format === "md"){
fwrite($doc, "| Name | Type |\n");
fwrite($doc, "|:-----|:----:|\n");
$children = $permission->getChildren();
ksort($children, SORT_STRING);
foreach(Utils::stringifyKeys($children) as $childName => $isGranted){
fwrite($doc, "| `$childName` | " . ($isGranted ? "Granted" : "Denied") . " |\n");
}
}else{
fwrite($doc, ".. list-table::\n");
fwrite($doc, " :header-rows: 1\n\n");
fwrite($doc, " * - Name\n");
fwrite($doc, " - Type\n");
$children = $permission->getChildren();
ksort($children, SORT_STRING);
foreach(Utils::stringifyKeys($children) as $childName => $isGranted){
fwrite($doc, " * - ``$childName``\n");
fwrite($doc, " - " . ($isGranted ? "Granted" : "Denied") . "\n");
}
}
fwrite($doc, "\n");
}