Compare commits

...

52 Commits

Author SHA1 Message Date
3339225fe8 Release 4.2.10 2022-04-20 13:03:25 +01:00
df33e179e5 Player: fixed chat newlines denial-of-service vulnerability
irresponsibly reported in #4974

closes #4974
2022-04-20 13:01:05 +01:00
624a7dff16 4.2.10 is next 2022-04-19 16:53:12 +01:00
1d314ad4ce Release 4.2.9 2022-04-19 16:53:11 +01:00
5a98b08ee8 Fixed several crashes on bad data due to inadequate TAG_List type checks 2022-04-19 16:48:18 +01:00
d9d02d526a Updated PHP versions for GitHub Actions 2022-04-19 15:06:00 +01:00
f272986903 4.2.9 is next 2022-04-17 20:45:32 +01:00
988da8eaab Release 4.2.8 2022-04-17 20:45:32 +01:00
ea7f706aed RakLib 0.14.4 2022-04-17 20:41:18 +01:00
52e3f1e269 ZippedResourcePack: ensure non-empty file
ZipArchive raises deprecation errors on empty files for some reason
2022-04-17 20:32:23 +01:00
4c9d2a989e cs again 2022-04-17 19:32:30 +01:00
022db5cbe3 NetworkSession: compare usernames case-insensitively
the current data management system uses case-insensitive names, so we can't allow different players with the same name in different cases to join, or we will have duplication exploits.

This typically only applies to offline servers, since Xbox Live doesn't permit reuse of a username, same case or otherwise.

closes #4965
2022-04-17 19:28:10 +01:00
3bbf558883 4.2.8 is next 2022-04-15 16:36:47 +01:00
1d68d9f71a Release 4.2.7 2022-04-15 16:36:42 +01:00
f2e8824242 fix CS 2022-04-15 16:24:15 +01:00
a0e47b5a64 phpstan 1.5.6 2022-04-15 16:21:05 +01:00
f7465f55e7 Update transient composer dependencies 2022-04-15 16:17:33 +01:00
741182c55f InGamePacketHandler: skip processing movement if the player's position
was changed during processing other properties (#4913)

fixes #4952
2022-04-10 21:02:45 +01:00
2efce35331 PluginManager: fixed updating disabled scheduler when plugins cause other plugins to be disabled from within scheduled tasks 2022-04-10 21:00:16 +01:00
d1dfbd95e2 Entity: workaround teleport client bug #4394 by despawning and respawning the entity (#4870)
this is a sucky solution but it works well enough for this scenario.

From my research it appears that while the client-side MovementInterpolator is active on the client and hasn't yet reached its target, any teleport sent during the lerp will get overridden by the lerp.
This appears to last 3-4 ticks (about 150-200 ms) which explains why this can be reproduced by stopping movement just before the ender pearl lands (human reaction times would make the reproduction unreliable otherwise).

Things to note:
- All entities are affected by this bug.
- MovePlayerPacket appears not to have the problem, but we can't use it because it doesn't work for non-players.
- MoveActorAbsolute and MoveActorDelta are both handled by the same code and will have the same lerping bug.

This is the cleanest solution I could come up with.
2022-04-08 23:12:01 +01:00
1aee5b1ed8 Bump ramsey/uuid from 4.2.3 to 4.3.1 (#4929)
Bumps [ramsey/uuid](https://github.com/ramsey/uuid) from 4.2.3 to 4.3.1.
- [Release notes](https://github.com/ramsey/uuid/releases)
- [Changelog](https://github.com/ramsey/uuid/blob/5.x/CHANGELOG.md)
- [Commits](https://github.com/ramsey/uuid/compare/4.2.3...4.3.1)

---
updated-dependencies:
- dependency-name: ramsey/uuid
  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>
Co-authored-by: Dylan T <dktapps@pmmp.io>
2022-04-08 22:22:51 +01:00
fefd3e6b29 Document how to passthru arguments to aliased commands 2022-04-07 23:36:04 +01:00
9b43be9d9c Improved documentation of pocketmine.yml aliases 2022-04-07 23:10:18 +01:00
ea677154cb InGamePacketHandler: rely exclusively on prediction mismatch checking to re-sync slots during bad transactions
fixes #4894
closes #4926
relying on the core code to guess which slots should be synced is unreliable at best.
2022-04-04 21:58:19 +01:00
7f2802e75f Bump phpstan/phpstan from 1.5.3 to 1.5.4 (#4942)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.5.3 to 1.5.4.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.6.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.5.3...1.5.4)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-04 14:03:07 +01:00
f924208881 Update PlayerPreLoginEvent documentation (#4940)
Removed outdated documentation that was very misleading. Replaced with better documentation that accurately describes how to cancel the event.
2022-04-03 17:59:07 +01:00
6bea2961d9 Bump phpunit/phpunit from 9.5.19 to 9.5.20 (#4939)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.5.19 to 9.5.20.
- [Release notes](https://github.com/sebastianbergmann/phpunit/releases)
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/master/ChangeLog-9.5.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.5.19...9.5.20)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-01 23:52:55 +01:00
ac3a6033b9 PluginManager: account for possible abstract main classes
idk why anyone does this, but it shouldn't cause a core crash ...
2022-04-01 23:42:37 +01:00
d7e6b01216 4.2.7 is next 2022-04-01 23:01:15 +01:00
26aee7ff73 Release 4.2.6 2022-04-01 23:01:15 +01:00
319c8fe32c Updated BedrockProtocol 2022-04-01 22:59:43 +01:00
ce121ccea9 Bump phpstan/phpstan from 1.5.2 to 1.5.3 (#4935)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.5.2 to 1.5.3.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.6.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.5.2...1.5.3)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-31 13:37:32 +01:00
7f1a4185b5 Bump phpstan/phpstan from 1.5.1 to 1.5.2 (#4933)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.5.1 to 1.5.2.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.6.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.5.1...1.5.2)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-29 12:41:54 +01:00
8cc7fb9dd9 fix CS 2022-03-28 17:16:35 +01:00
194cb1fb84 phpstan 1.5.1 2022-03-28 17:12:00 +01:00
8ea106c091 4.2.6 is next 2022-03-28 16:35:10 +01:00
a6cb3313b0 Release 4.2.5 2022-03-28 16:34:57 +01:00
c6374b79b0 Improve crashdump ergonomics
hopefully this will result in less people making useless pastes that don't contain backtraces ...
2022-03-24 19:46:11 +00:00
901449b0b1 Player: simplify PlayerItemHeldEvent calling on content change
the second parameter to this callback is the OLD slots, not the changed slots. This means that ALL slots are included, including empty and unchanged slots.
2022-03-23 13:47:01 +00:00
4e777572c9 fix CS 2022-03-23 13:28:21 +00:00
90a8595a40 Check for mismatched inventory slot predictions in transactions
this should limit the problems caused by mismatched gameplay features that result in ghost items, such as #4896.
2022-03-22 17:42:19 +00:00
bf71eb448a Reduce chaos in inventory classes 2022-03-22 17:19:55 +00:00
2c29d272ad BaseInventory: move setMaxStackSize() to a more sensible place 2022-03-22 17:11:48 +00:00
98aa2b9ff9 Inventory: move removeItem() next to remove()
this should hopefully be more attention grabbing and a bit less misleading, since people will wonder why there are 'remove' and 'removeItem' both.

we really need to rename one of these...
2022-03-22 17:08:30 +00:00
ea33a04d00 Player: ensure that PlayerItemHeldEvent is called when the contents of the held slot changes
in PM3, this was done by implicitly relying on the client to send a MobEquipmentPacket selecting the same hotbar slot when the slot contents changes.
In PM4, we avoid relying on this, and fire the event directly when the listener detects a held slot change.
This ensures that the behaviour remains consistent regardless of what the client starts doing in the future.

closes #4905
2022-03-22 16:53:02 +00:00
4a94cb85a2 fix CS 2022-03-22 15:44:11 +00:00
b7e6854189 RegistryTrait: enforce name validation rules on everything, not just enums
fixes #4916
2022-03-22 15:41:17 +00:00
2b8a54f8ff Entity: added a guard to prevent __construct() from running multiple times
this typically happens due to flawed logic in child classes in plugins which causes parent::__construct() to get called multiple times.
2022-03-22 15:33:31 +00:00
a5dab0f61e Bump build/php from b6bb711 to 1fae6b8 (#4918)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `b6bb711` to `1fae6b8`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](b6bb7114b3...1fae6b8d4a)

---
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-03-21 21:05:13 +00:00
824f1f24ff Build release Docker images on GitHub Actions (#4891)
this has been tested on a fork using GitHub Container Registry, but we'll have to do an actual release to test if it will work with Docker Hub. However, I don't expect there to be any problems.

This is one of two remaining jobs to be migrated off Jenkins.
2022-03-20 01:03:27 +00:00
f4f5c3128f EnumTrait: fixed regex not accepting member names with 1 character
this also fixes EnumTrait accepting invalid non-numeric characters for the first character, such as @.
2022-03-19 16:47:36 +00:00
fdd42fd15f 4.2.5 is next 2022-03-18 20:20:47 +00:00
32 changed files with 468 additions and 301 deletions

View File

@ -0,0 +1,97 @@
name: Update Docker Hub images
on:
release:
types:
- published
jobs:
build:
name: Update Docker Hub images
runs-on: ubuntu-20.04
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Clone pmmp/PocketMine-Docker repository
uses: actions/checkout@v2
with:
repository: pmmp/PocketMine-Docker
fetch-depth: 1
- name: Get tag names
id: tag-name
run: |
VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
echo ::set-output name=TAG_NAME::$VERSION
echo ::set-output name=MAJOR::$(echo $VERSION | cut -d. -f1)
echo ::set-output name=MINOR::$(echo $VERSION | cut -d. -f1-2)
- name: Download new release information
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
- name: Detect channel
id: channel
run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json)
- name: Get name of Docker repository name
id: docker-repo-name
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
- name: Build image for tag
uses: docker/build-push-action@v2.10.0
with:
push: true
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }}
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
- name: Build image for major tag
if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v2.10.0
with:
push: true
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
- name: Build image for minor tag
if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v2.10.0
with:
push: true
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
- name: Build image for latest tag
if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v2.10.0
with:
push: true
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:latest
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:latest
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}

View File

@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
image: [ubuntu-20.04]
php: [8.0.16]
php: [8.0.18]
steps:
- name: Build and prepare PHP cache
@ -31,7 +31,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.16]
php: [8.0.18]
steps:
- uses: actions/checkout@v2
@ -69,7 +69,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.16]
php: [8.0.18]
steps:
- uses: actions/checkout@v2
@ -107,7 +107,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.16]
php: [8.0.18]
steps:
- uses: actions/checkout@v2
@ -147,7 +147,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.16]
php: [8.0.18]
steps:
- uses: actions/checkout@v2

View File

@ -57,3 +57,65 @@ Released 18th March 2022.
## Fixes
- Fixed a crash when handling out-of-bounds meta values on the network.
# 4.2.5
Released 28th March 2022.
## General
- The layout of the human-readable part of crashdumps has been changed in an effort to improve the useful information density. It is hoped that this change will cause more useful information to be provided when people paste crash traces on Discord, since all the most important information is now at the top of the file.
- Version, git hash, PHP version and OS have been moved to the top of the crashdump.
- Backtrace has been moved above code sample.
- Docker images are now built by GitHub Actions (first live test).
## Technical
- The methods of `Inventory` and `BaseInventory` have been rearranged to improve coherency.
## Fixes
### API
- Enum members of enums created using `EnumTrait` are now able to have single-character names.
- Registry members of registries created using `RegistryTrait` or `CloningRegistryTrait` now have their names checked for invalid characters.
- `Entity::__construct()` now uses a guard variable to prevent it from being called multiple times unintentionally. This is necessary because `Entity::__construct()` has side effects.
- Fixed `PlayerItemHeldEvent` not being called when the content of the held slot was changed (e.g. replacing the held item via inventory menu).
### Gameplay
- Reduced the appearance of ghost items in unsupported gameplay scenarios using client prediction information. This fixes, for example, the appearance of ghost items when right-clicking on a filled flower pot.
# 4.2.6
Released 1st April 2022.
## Fixes
- Fixed buffer length underflow crash in `LoginPacket` handling.
# 4.2.7
Released 15th April 2022.
## General
- Added lots more documentation (in comments) about the `aliases` section in `pocketmine.yml`. You can read about this feature in the `aliases` section of the [updated `pocketmine.yml` template](/resources/pocketmine.yml).
- Improved wording of documentation of `PlayerPreLoginEvent`.
## Fixes
- Fixed core server crash when a plugin causes another plugin to be disabled during a scheduled task.
- Fixed core server crash when loading a plugin with an abstract main class.
- Fixed ghost items in many interaction situations (most notably, using projectiles while looking at an entity or block).
- Implemented a workaround for a client teleport bug which led to player positions not updating properly when using ender pearls.
- Fixed buggy movement when teleporting the player during `PlayerToggleSneakEvent`, `PlayerToggleSprintEvent`, `PlayerToggleSwimEvent` and `PlayerToggleGlideEvent`.
# 4.2.8
Released 17th April 2022.
## Fixes
- Fixed a memory leak in RakLib which could result in a server crash when players stay online for a long time.
- Fixed server crash when attempting to load a corrupted empty resource pack.
- Fixed users with the same name with differerently cased letters being able to duplicate items (userdata is matched by case-insensitive name).
# 4.2.9
Released 19th April 2022.
## Fixes
- Fixed several potential crashes when deserializing item NBT (due to insufficient validation of input data).
# 4.2.10
Released 20th April 2022.
## Fixes
- Fixed performance issue when chat messages received from the client contain many newlines. This security vulnerability was disclosed publicly necessitating a priority fix.

View File

@ -35,13 +35,13 @@
"fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0",
"pocketmine/bedrock-data": "~1.6.0+bedrock-1.18.10",
"pocketmine/bedrock-protocol": "~8.0.0+bedrock-1.18.10",
"pocketmine/bedrock-protocol": "~8.0.2+bedrock-1.18.10",
"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.4.2",
"pocketmine/locale-data": "~2.5.0",
"pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.4.0",
"pocketmine/math": "^0.4.0",
@ -53,8 +53,8 @@
"webmozart/path-util": "^2.3"
},
"require-dev": {
"phpstan/phpstan": "1.4.10",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan": "1.5.6",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.2"
},

216
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": "f3800582ad388d0ec2a95dffc3742d8e",
"content-hash": "b20ae069f5f467084bcbaae90c893bc9",
"packages": [
{
"name": "adhocore/json-comment",
@ -275,16 +275,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
"version": "8.0.1+bedrock-1.18.10",
"version": "8.0.2+bedrock-1.18.10",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "a740f6095b35278c0e0dac6db84a5e4d2456b113"
"reference": "d1f1afdbb4ea61ea52eb511a79ee1ca561da349c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/a740f6095b35278c0e0dac6db84a5e4d2456b113",
"reference": "a740f6095b35278c0e0dac6db84a5e4d2456b113",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/d1f1afdbb4ea61ea52eb511a79ee1ca561da349c",
"reference": "d1f1afdbb4ea61ea52eb511a79ee1ca561da349c",
"shasum": ""
},
"require": {
@ -298,7 +298,7 @@
"ramsey/uuid": "^4.1"
},
"require-dev": {
"phpstan/phpstan": "1.4.5",
"phpstan/phpstan": "1.5.3",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5"
@ -316,9 +316,9 @@
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
"support": {
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
"source": "https://github.com/pmmp/BedrockProtocol/tree/8.0.1+bedrock-1.18.10"
"source": "https://github.com/pmmp/BedrockProtocol/tree/8.0.2+bedrock-1.18.10"
},
"time": "2022-02-21T03:31:48+00:00"
"time": "2022-04-01T21:55:10+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -536,16 +536,16 @@
},
{
"name": "pocketmine/locale-data",
"version": "2.4.3",
"version": "2.5.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Language.git",
"reference": "4d0b081f1a79407e087968ea76aaf330db6ea2b5"
"reference": "df6fc7f2b48850b306c60466a11f7a27bb8fe1de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Language/zipball/4d0b081f1a79407e087968ea76aaf330db6ea2b5",
"reference": "4d0b081f1a79407e087968ea76aaf330db6ea2b5",
"url": "https://api.github.com/repos/pmmp/Language/zipball/df6fc7f2b48850b306c60466a11f7a27bb8fe1de",
"reference": "df6fc7f2b48850b306c60466a11f7a27bb8fe1de",
"shasum": ""
},
"type": "library",
@ -553,9 +553,9 @@
"description": "Language resources used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Language/issues",
"source": "https://github.com/pmmp/Language/tree/2.4.3"
"source": "https://github.com/pmmp/Language/tree/2.5.0"
},
"time": "2022-01-25T23:18:24+00:00"
"time": "2022-04-01T22:36:58+00:00"
},
{
"name": "pocketmine/log",
@ -727,16 +727,16 @@
},
{
"name": "pocketmine/raklib",
"version": "0.14.3",
"version": "0.14.4",
"source": {
"type": "git",
"url": "https://github.com/pmmp/RakLib.git",
"reference": "4798576fec0364266dce23b368a7fec5e5de7927"
"reference": "1ea8e3b95a1b6bf785dc27d76578657be4185f42"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/4798576fec0364266dce23b368a7fec5e5de7927",
"reference": "4798576fec0364266dce23b368a7fec5e5de7927",
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/1ea8e3b95a1b6bf785dc27d76578657be4185f42",
"reference": "1ea8e3b95a1b6bf785dc27d76578657be4185f42",
"shasum": ""
},
"require": {
@ -748,7 +748,7 @@
"pocketmine/log": "^0.3.0 || ^0.4.0"
},
"require-dev": {
"phpstan/phpstan": "1.3.3",
"phpstan/phpstan": "1.5.4",
"phpstan/phpstan-strict-rules": "^1.0"
},
"type": "library",
@ -764,9 +764,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.3"
"source": "https://github.com/pmmp/RakLib/tree/0.14.4"
},
"time": "2022-01-10T21:29:48+00:00"
"time": "2022-04-17T18:42:17+00:00"
},
{
"name": "pocketmine/raklib-ipc",
@ -930,25 +930,24 @@
},
{
"name": "ramsey/uuid",
"version": "4.2.3",
"version": "4.3.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
"reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df"
"reference": "8505afd4fea63b81a85d3b7b53ac3cb8dc347c28"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df",
"reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/8505afd4fea63b81a85d3b7b53ac3cb8dc347c28",
"reference": "8505afd4fea63b81a85d3b7b53ac3cb8dc347c28",
"shasum": ""
},
"require": {
"brick/math": "^0.8 || ^0.9",
"ext-ctype": "*",
"ext-json": "*",
"php": "^7.2 || ^8.0",
"ramsey/collection": "^1.0",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-php80": "^1.14"
"php": "^8.0",
"ramsey/collection": "^1.0"
},
"replace": {
"rhumsaa/uuid": "self.version"
@ -985,9 +984,6 @@
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "4.x-dev"
},
"captainhook": {
"force-install": true
}
@ -1012,7 +1008,7 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.2.3"
"source": "https://github.com/ramsey/uuid/tree/4.3.1"
},
"funding": [
{
@ -1024,7 +1020,7 @@
"type": "tidelift"
}
],
"time": "2021-09-25T23:10:38+00:00"
"time": "2022-03-27T21:42:02+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -1108,89 +1104,6 @@
],
"time": "2021-10-20T20:35:02+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.25.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c",
"reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ion Bazan",
"email": "ion.bazan@gmail.com"
},
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-03-04T08:16:47+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.25.0",
@ -1789,16 +1702,16 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.6.0",
"version": "1.6.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706"
"reference": "77a32518733312af16a44300404e945338981de3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706",
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3",
"reference": "77a32518733312af16a44300404e945338981de3",
"shasum": ""
},
"require": {
@ -1833,9 +1746,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1"
},
"time": "2022-01-04T19:58:01+00:00"
"time": "2022-03-15T21:29:03+00:00"
},
{
"name": "phpspec/prophecy",
@ -1906,20 +1819,20 @@
},
{
"name": "phpstan/phpstan",
"version": "1.4.10",
"version": "1.5.6",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "898c479c39caa727bedf4311dd294a8f4e250e72"
"reference": "799dd8c2d2c9c704bb55d2078078cb970cf0f6d1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/898c479c39caa727bedf4311dd294a8f4e250e72",
"reference": "898c479c39caa727bedf4311dd294a8f4e250e72",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/799dd8c2d2c9c704bb55d2078078cb970cf0f6d1",
"reference": "799dd8c2d2c9c704bb55d2078078cb970cf0f6d1",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
"php": "^7.2|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
@ -1941,7 +1854,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.4.10"
"source": "https://github.com/phpstan/phpstan/tree/1.5.6"
},
"funding": [
{
@ -1961,25 +1874,25 @@
"type": "tidelift"
}
],
"time": "2022-03-14T10:25:45+00:00"
"time": "2022-04-15T11:13:37+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "1.0.0",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "9eb88c9f689003a8a2a5ae9e010338ee94dc39b3"
"reference": "09133ce914f1388a8bb8c7f8573aaa3723cff52a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/9eb88c9f689003a8a2a5ae9e010338ee94dc39b3",
"reference": "9eb88c9f689003a8a2a5ae9e010338ee94dc39b3",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/09133ce914f1388a8bb8c7f8573aaa3723cff52a",
"reference": "09133ce914f1388a8bb8c7f8573aaa3723cff52a",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"phpstan/phpstan": "^1.0"
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.5.0"
},
"conflict": {
"phpunit/phpunit": "<7.0"
@ -1992,9 +1905,6 @@
},
"type": "phpstan-extension",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
},
"phpstan": {
"includes": [
"extension.neon",
@ -2014,9 +1924,9 @@
"description": "PHPUnit extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.0.0"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.1.0"
},
"time": "2021-10-14T08:03:54+00:00"
"time": "2022-03-28T09:20:49+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
@ -2389,16 +2299,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.19",
"version": "9.5.20",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807"
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/35ea4b7f3acabb26f4bb640f8c30866c401da807",
"reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba",
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba",
"shasum": ""
},
"require": {
@ -2476,7 +2386,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.19"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20"
},
"funding": [
{
@ -2488,7 +2398,7 @@
"type": "github"
}
],
"time": "2022-03-15T09:57:31+00:00"
"time": "2022-04-01T12:37:26+00:00"
},
{
"name": "sebastian/cli-parser",
@ -2856,16 +2766,16 @@
},
{
"name": "sebastian/environment",
"version": "5.1.3",
"version": "5.1.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "388b6ced16caa751030f6a69e588299fa09200ac"
"reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac",
"reference": "388b6ced16caa751030f6a69e588299fa09200ac",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7",
"reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7",
"shasum": ""
},
"require": {
@ -2907,7 +2817,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.3"
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.4"
},
"funding": [
{
@ -2915,7 +2825,7 @@
"type": "github"
}
],
"time": "2020-09-28T05:52:38+00:00"
"time": "2022-04-03T09:37:03+00:00"
},
{
"name": "sebastian/exporter",

View File

@ -173,10 +173,31 @@ console:
title-tick: true
aliases:
#Examples:
#showtheversion: version
##This section allows you to add, remove or remap command aliases.
##A single alias can call one or more other commands (or aliases).
##Aliases defined here will override any command aliases declared by plugins or PocketMine-MP itself.
##To remove an alias, set it to [], like so (note that prefixed aliases like "pocketmine:stop" will remain and can't
##be removed):
#stop: []
##Commands are not removed, only their aliases. You can still refer to a command using its full (prefixed)
##name, even if all its aliases are overwritten. The full name is usually something like "pocketmine:commandname" or
##"pluginname:commandname".
#abort: [pocketmine:stop]
##To add an alias, list the command(s) that it calls:
#showtheversion: [version]
#savestop: [save-all, stop]
##To invoke another command with arguments, use $1 to pass the first argument, $2 for the second etc:
#giveadmin: [op $1] ## `giveadmin alex` -> `op alex`
#kill: [suicide, say "I tried to kill $1"] ## `kill alex` -> `suicide` + `say "I tried to kill alex"`
#giverandom: [give $1 $2, say "Someone has just received a $2!"] ## `giverandom alex diamond` -> `give alex diamond` + `say "Someone has just received a diamond!"`
##To change an existing command alias and make it do something else:
#tp: [suicide]
worlds:
#These settings will override the generator set in server.properties and allows loading multiple worlds
#Example:

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_object;
use function is_resource;
use function is_string;
use function json_decode;
@ -1606,7 +1607,7 @@ class Server{
"reportPaste" => base64_encode($dump->getEncodedData())
], 10, [], $postUrlError);
if($reply !== null && ($data = json_decode($reply->getBody())) !== null){
if($reply !== null && is_object($data = json_decode($reply->getBody()))){
if(isset($data->crashId) && isset($data->crashUrl)){
$reportId = $data->crashId;
$reportUrl = $data->crashUrl;

View File

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

View File

@ -44,7 +44,7 @@ trait ContainerTrait{
abstract public function getRealInventory();
protected function loadItems(CompoundTag $tag) : void{
if(($inventoryTag = $tag->getTag(Container::TAG_ITEMS)) instanceof ListTag){
if(($inventoryTag = $tag->getTag(Container::TAG_ITEMS)) instanceof ListTag && $inventoryTag->getTagType() === NBT::TAG_Compound){
$inventory = $this->getRealInventory();
$listeners = $inventory->getListeners()->toArray();
$inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization

View File

@ -44,10 +44,11 @@ final class CrashDumpRenderer{
$this->addLine($this->data->general->name . " Crash Dump " . date("D M j H:i:s T Y", (int) $this->data->time));
$this->addLine();
$this->addLine("Error: " . $this->data->error["message"]);
$this->addLine("File: " . $this->data->error["file"]);
$this->addLine("Line: " . $this->data->error["line"]);
$this->addLine("Type: " . $this->data->error["type"]);
$version = new VersionString($this->data->general->base_version, $this->data->general->is_dev, $this->data->general->build);
$this->addLine($this->data->general->name . " version: " . $version->getFullVersion(true) . " [Protocol " . $this->data->general->protocol . "]");
$this->addLine("Git commit: " . $this->data->general->git);
$this->addLine("PHP version: " . $this->data->general->php);
$this->addLine("OS: " . $this->data->general->php_os . ", " . $this->data->general->os);
if($this->data->plugin_involvement !== CrashDump::PLUGIN_INVOLVEMENT_NONE){
$this->addLine();
@ -62,30 +63,21 @@ final class CrashDumpRenderer{
}
$this->addLine();
$this->addLine("Code:");
foreach($this->data->code as $lineNumber => $line){
$this->addLine("[$lineNumber] $line");
}
$this->addLine();
$this->addLine("Error: " . $this->data->error["message"]);
$this->addLine("File: " . $this->data->error["file"]);
$this->addLine("Line: " . $this->data->error["line"]);
$this->addLine("Type: " . $this->data->error["type"]);
$this->addLine("Backtrace:");
foreach($this->data->trace as $line){
$this->addLine($line);
}
$this->addLine();
$this->addLine("Code:");
$version = new VersionString($this->data->general->base_version, $this->data->general->is_dev, $this->data->general->build);
$this->addLine($this->data->general->name . " version: " . $version->getFullVersion(true) . " [Protocol " . $this->data->general->protocol . "]");
$this->addLine("Git commit: " . $this->data->general->git);
$this->addLine("uname -a: " . $this->data->general->uname);
$this->addLine("PHP Version: " . $this->data->general->php);
$this->addLine("Zend version: " . $this->data->general->zend);
$this->addLine("OS: " . $this->data->general->php_os . ", " . $this->data->general->os);
$this->addLine("Composer libraries: ");
foreach(Utils::stringifyKeys($this->data->general->composer_libraries) as $library => $libraryVersion){
$this->addLine("- $library $libraryVersion");
foreach($this->data->code as $lineNumber => $line){
$this->addLine("[$lineNumber] $line");
}
if(count($this->data->plugins) > 0){
@ -95,6 +87,14 @@ final class CrashDumpRenderer{
$this->addLine($p->name . " " . $p->version . " by " . implode(", ", $p->authors) . " for API(s) " . implode(", ", $p->api));
}
}
$this->addLine();
$this->addLine("uname -a: " . $this->data->general->uname);
$this->addLine("Zend version: " . $this->data->general->zend);
$this->addLine("Composer libraries: ");
foreach(Utils::stringifyKeys($this->data->general->composer_libraries) as $library => $libraryVersion){
$this->addLine("- $library $libraryVersion");
}
}
public function addLine(string $line = "") : void{

View File

@ -216,7 +216,13 @@ abstract class Entity{
/** @var int|null */
protected $targetId = null;
private bool $constructorCalled = false;
public function __construct(Location $location, ?CompoundTag $nbt = null){
if($this->constructorCalled){
throw new \LogicException("Attempted to call constructor for an Entity multiple times");
}
$this->constructorCalled = true;
Utils::checkLocationNotInfOrNaN($location);
$this->timings = Timings::getEntityTimings($this);
@ -762,17 +768,29 @@ abstract class Entity{
}
protected function broadcastMovement(bool $teleport = false) : void{
$this->server->broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
$this->id,
$this->getOffsetPosition($this->location),
$this->location->pitch,
$this->location->yaw,
$this->location->yaw,
(
($teleport ? MoveActorAbsolutePacket::FLAG_TELEPORT : 0) |
($this->onGround ? MoveActorAbsolutePacket::FLAG_GROUND : 0)
)
)]);
if($teleport){
//TODO: HACK! workaround for https://github.com/pmmp/PocketMine-MP/issues/4394
//this happens because MoveActor*Packet doesn't clear interpolation targets on the client, so the entity
//snaps to the teleport position, but then lerps back to the original position if a normal movement for the
//entity was recently broadcasted. This can be seen with players throwing ender pearls.
//TODO: remove this if the bug ever gets fixed (lol)
foreach($this->hasSpawned as $player){
$this->despawnFrom($player);
$this->spawnTo($player);
}
}else{
$this->server->broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
$this->id,
$this->getOffsetPosition($this->location),
$this->location->pitch,
$this->location->yaw,
$this->location->yaw,
(
//TODO: if the above hack for #4394 gets removed, we should be setting FLAG_TELEPORT here
($this->onGround ? MoveActorAbsolutePacket::FLAG_GROUND : 0)
)
)]);
}
}
protected function broadcastMotion() : void{

View File

@ -31,7 +31,7 @@ use function count;
/**
* Called when a player connects to the server, prior to authentication taking place.
* Cancelling this event will cause the player to be disconnected with the kick message set.
* Set a kick reason to cancel the event and disconnect the player with the kick message set.
*
* This event should be used to decide if the player may continue to login to the server. Do things like checking
* bans, whitelisting, server-full etc here.

View File

@ -55,6 +55,25 @@ abstract class BaseInventory implements Inventory{
return $this->maxStackSize;
}
public function setMaxStackSize(int $size) : void{
$this->maxStackSize = $size;
}
abstract protected function internalSetItem(int $index, Item $item) : void;
public function setItem(int $index, Item $item) : void{
if($item->isNull()){
$item = VanillaItems::AIR();
}else{
$item = clone $item;
}
$oldItem = $this->getItem($index);
$this->internalSetItem($index, $item);
$this->onSlotChange($index, $oldItem);
}
/**
* @param Item[] $items
*/
@ -85,21 +104,6 @@ abstract class BaseInventory implements Inventory{
$this->onContentChange($oldContents);
}
abstract protected function internalSetItem(int $index, Item $item) : void;
public function setItem(int $index, Item $item) : void{
if($item->isNull()){
$item = VanillaItems::AIR();
}else{
$item = clone $item;
}
$oldItem = $this->getItem($index);
$this->internalSetItem($index, $item);
$this->onSlotChange($index, $oldItem);
}
public function contains(Item $item) : bool{
$count = max(1, $item->getCount());
$checkDamage = !$item->hasAnyDamageValue();
@ -128,18 +132,6 @@ abstract class BaseInventory implements Inventory{
return $slots;
}
public function remove(Item $item) : void{
$checkDamage = !$item->hasAnyDamageValue();
$checkTags = $item->hasNamedTag();
foreach($this->getContents() as $index => $i){
if($item->equals($i, $checkDamage, $checkTags)){
$this->clear($index);
}
}
}
public function first(Item $item, bool $exact = false) : int{
$count = $exact ? $item->getCount() : max(1, $item->getCount());
$checkDamage = $exact || !$item->hasAnyDamageValue();
@ -253,6 +245,17 @@ abstract class BaseInventory implements Inventory{
return $slot;
}
public function remove(Item $item) : void{
$checkDamage = !$item->hasAnyDamageValue();
$checkTags = $item->hasNamedTag();
foreach($this->getContents() as $index => $i){
if($item->equals($i, $checkDamage, $checkTags)){
$this->clear($index);
}
}
}
public function removeItem(Item ...$slots) : array{
/** @var Item[] $itemSlots */
/** @var Item[] $slots */
@ -323,10 +326,6 @@ abstract class BaseInventory implements Inventory{
}
}
public function setMaxStackSize(int $size) : void{
$this->maxStackSize = $size;
}
public function onOpen(Player $who) : void{
$this->viewers[spl_object_id($who)] = $who;
}

View File

@ -46,6 +46,16 @@ interface Inventory{
*/
public function setItem(int $index, Item $item) : void;
/**
* @return Item[]
*/
public function getContents(bool $includeEmpty = false) : array;
/**
* @param Item[] $items
*/
public function setContents(array $items) : void;
/**
* Stores the given Items in the inventory. This will try to fill
* existing stacks and empty slots as well as it can.
@ -66,24 +76,6 @@ interface Inventory{
*/
public function getAddableItemQuantity(Item $item) : int;
/**
* Removes the given Item from the inventory.
* It will return the Items that couldn't be removed.
*
* @return Item[]
*/
public function removeItem(Item ...$slots) : array;
/**
* @return Item[]
*/
public function getContents(bool $includeEmpty = false) : array;
/**
* @param Item[] $items
*/
public function setContents(array $items) : void;
/**
* Checks if the inventory contains any Item with the same material data.
* It will check id, amount, and metadata (if not null)
@ -121,6 +113,14 @@ interface Inventory{
*/
public function remove(Item $item) : void;
/**
* Removes the given Item from the inventory.
* It will return the Items that couldn't be removed.
*
* @return Item[]
*/
public function removeItem(Item ...$slots) : array;
/**
* Will clear a specific slot
*/

View File

@ -52,6 +52,10 @@ class SimpleInventory extends BaseInventory{
return $this->slots[$index] !== null ? clone $this->slots[$index] : VanillaItems::AIR();
}
protected function internalSetItem(int $index, Item $item) : void{
$this->slots[$index] = $item->isNull() ? null : $item;
}
/**
* @return Item[]
*/
@ -78,8 +82,4 @@ class SimpleInventory extends BaseInventory{
}
}
}
protected function internalSetItem(int $index, Item $item) : void{
$this->slots[$index] = $item->isNull() ? null : $item;
}
}

View File

@ -29,6 +29,7 @@ use pocketmine\block\utils\BannerPatternLayer;
use pocketmine\block\utils\DyeColor;
use pocketmine\data\bedrock\BannerPatternTypeIdMap;
use pocketmine\data\bedrock\DyeColorIdMap;
use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use function count;
@ -98,7 +99,7 @@ class Banner extends ItemBlockWallOrFloor{
$colorIdMap = DyeColorIdMap::getInstance();
$patternIdMap = BannerPatternTypeIdMap::getInstance();
$patterns = $tag->getListTag(self::TAG_PATTERNS);
if($patterns !== null){
if($patterns !== null && $patterns->getTagType() === NBT::TAG_Compound){
/** @var CompoundTag $t */
foreach($patterns as $t){
$patternColor = $colorIdMap->fromInvertedId($t->getInt(self::TAG_PATTERN_COLOR)) ?? DyeColor::BLACK(); //TODO: missing pattern colour should be an error

View File

@ -306,7 +306,7 @@ class Item implements \JsonSerializable{
$this->canPlaceOn = [];
$canPlaceOn = $tag->getListTag("CanPlaceOn");
if($canPlaceOn !== null){
if($canPlaceOn !== null && $canPlaceOn->getTagType() === NBT::TAG_String){
/** @var StringTag $entry */
foreach($canPlaceOn as $entry){
$this->canPlaceOn[$entry->getValue()] = $entry->getValue();
@ -314,7 +314,7 @@ class Item implements \JsonSerializable{
}
$this->canDestroy = [];
$canDestroy = $tag->getListTag("CanDestroy");
if($canDestroy !== null){
if($canDestroy !== null && $canDestroy->getTagType() === NBT::TAG_String){
/** @var StringTag $entry */
foreach($canDestroy as $entry){
$this->canDestroy[$entry->getValue()] = $entry->getValue();

View File

@ -1829,6 +1829,10 @@ final class KnownTranslationFactory{
]);
}
public static function pocketmine_plugin_mainClassAbstract() : Translatable{
return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_MAINCLASSABSTRACT, []);
}
public static function pocketmine_plugin_mainClassNotFound() : Translatable{
return new Translatable(KnownTranslationKeys::POCKETMINE_PLUGIN_MAINCLASSNOTFOUND, []);
}

View File

@ -379,6 +379,7 @@ final class KnownTranslationKeys{
public const POCKETMINE_PLUGIN_INVALIDMANIFEST = "pocketmine.plugin.invalidManifest";
public const POCKETMINE_PLUGIN_LOAD = "pocketmine.plugin.load";
public const POCKETMINE_PLUGIN_LOADERROR = "pocketmine.plugin.loadError";
public const POCKETMINE_PLUGIN_MAINCLASSABSTRACT = "pocketmine.plugin.mainClassAbstract";
public const POCKETMINE_PLUGIN_MAINCLASSNOTFOUND = "pocketmine.plugin.mainClassNotFound";
public const POCKETMINE_PLUGIN_MAINCLASSWRONGTYPE = "pocketmine.plugin.mainClassWrongType";
public const POCKETMINE_PLUGIN_RESTRICTEDNAME = "pocketmine.plugin.restrictedName";

View File

@ -59,7 +59,9 @@ use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\ObjectSet;
use function array_map;
use function array_search;
use function get_class;
use function max;
use function spl_object_id;
/**
* @phpstan-type ContainerOpenClosure \Closure(int $id, Inventory $inventory) : (list<ClientboundPacket>|null)
@ -304,6 +306,28 @@ class InventoryManager{
}
}
public function syncMismatchedPredictedSlotChanges() : void{
foreach($this->initiatedSlotChanges as $windowId => $slots){
if(!isset($this->windowMap[$windowId])){
continue;
}
$inventory = $this->windowMap[$windowId];
foreach($slots as $slot => $expectedItem){
if(!$inventory->slotExists($slot)){
continue; //TODO: size desync ???
}
$actualItem = $inventory->getItem($slot);
if(!$actualItem->equalsExact($expectedItem)){
$this->session->getLogger()->debug("Detected prediction mismatch in inventory " . get_class($inventory) . "#" . spl_object_id($inventory) . " slot $slot");
$this->syncSlot($inventory, $slot);
}
}
}
$this->initiatedSlotChanges = [];
}
public function syncData(Inventory $inventory, int $propertyId, int $value) : void{
$windowId = $this->getWindowId($inventory);
if($windowId !== null){

View File

@ -125,6 +125,7 @@ use function get_class;
use function in_array;
use function json_encode;
use function ksort;
use function strcasecmp;
use function strlen;
use function strtolower;
use function substr;
@ -635,7 +636,7 @@ class NetworkSession{
continue;
}
$info = $existingSession->getPlayerInfo();
if($info !== null && ($info->getUsername() === $this->info->getUsername() || $info->getUuid()->equals($this->info->getUuid()))){
if($info !== null && (strcasecmp($info->getUsername(), $this->info->getUsername()) === 0 || $info->getUuid()->equals($this->info->getUuid()))){
if($kickForXUIDMismatch($info instanceof XboxLivePlayerInfo ? $info->getXuid() : "")){
return;
}

View File

@ -228,15 +228,21 @@ class InGamePacketHandler extends PacketHandler{
$this->player->jump();
}
//TODO: this packet has WAYYYYY more useful information that we're not using
$this->player->handleMovement($newPos);
if(!$this->forceMoveSync){
//TODO: this packet has WAYYYYY more useful information that we're not using
$this->player->handleMovement($newPos);
}
$packetHandled = true;
$useItemTransaction = $packet->getItemInteractionData();
if($useItemTransaction !== null && !$this->handleUseItemTransaction($useItemTransaction->getTransactionData())){
$packetHandled = false;
$this->session->getLogger()->debug("Unhandled transaction in PlayerAuthInputPacket (type " . $useItemTransaction->getTransactionData()->getActionType() . ")");
if($useItemTransaction !== null){
if(!$this->handleUseItemTransaction($useItemTransaction->getTransactionData())){
$packetHandled = false;
$this->session->getLogger()->debug("Unhandled transaction in PlayerAuthInputPacket (type " . $useItemTransaction->getTransactionData()->getActionType() . ")");
}else{
$this->inventoryManager->syncMismatchedPredictedSlotChanges();
}
}
$blockActions = $packet->getBlockActions();
@ -304,6 +310,8 @@ class InGamePacketHandler extends PacketHandler{
if(!$result){
$this->inventoryManager->syncAll();
}else{
$this->inventoryManager->syncMismatchedPredictedSlotChanges();
}
return $result;
}
@ -451,13 +459,10 @@ class InGamePacketHandler extends PacketHandler{
if(!$this->player->consumeHeldItem()){
$hungerAttr = $this->player->getAttributeMap()->get(Attribute::HUNGER) ?? throw new AssumptionFailedError();
$hungerAttr->markSynchronized(false);
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
}
return true;
}
if(!$this->player->useHeldItem()){
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
}
$this->player->useHeldItem();
return true;
}
@ -477,7 +482,6 @@ class InGamePacketHandler extends PacketHandler{
* Internal function used to execute rollbacks when an action fails on a block.
*/
private function onFailedBlockAction(Vector3 $blockPos, ?int $face) : void{
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
if($blockPos->distanceSquared($this->player->getLocation()) < 10000){
$blocks = $blockPos->sidesArray();
if($face !== null){
@ -506,14 +510,10 @@ class InGamePacketHandler extends PacketHandler{
//TODO: use transactiondata for rollbacks here
switch($data->getActionType()){
case UseItemOnEntityTransactionData::ACTION_INTERACT:
if(!$this->player->interactEntity($target, $data->getClickPosition())){
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
}
$this->player->interactEntity($target, $data->getClickPosition());
return true;
case UseItemOnEntityTransactionData::ACTION_ATTACK:
if(!$this->player->attackEntity($target)){
$this->inventoryManager->syncSlot($this->player->getInventory(), $this->player->getInventory()->getHeldItemIndex());
}
$this->player->attackEntity($target);
return true;
}

View File

@ -313,6 +313,16 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->setNameTag($this->username);
}
private function callDummyItemHeldEvent() : void{
$slot = $this->inventory->getHeldItemIndex();
$event = new PlayerItemHeldEvent($this, $this->inventory->getItem($slot), $slot);
$event->call();
//TODO: this event is actually cancellable, but cancelling it here has no meaningful result, so we
//just ignore it. We fire this only because the content of the held slot changed, not because the
//held slot index changed. We can't prevent that from here, and nor would it be sensible to.
}
protected function initEntity(CompoundTag $nbt) : void{
parent::initEntity($nbt);
$this->addDefaultWindows();
@ -321,10 +331,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
function(Inventory $unused, int $slot) : void{
if($slot === $this->inventory->getHeldItemIndex()){
$this->setUsingItem(false);
$this->callDummyItemHeldEvent();
}
},
function() : void{
$this->setUsingItem(false);
$this->callDummyItemHeldEvent();
}
));
@ -1364,8 +1377,14 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
public function chat(string $message) : bool{
$this->removeCurrentWindow();
//Fast length check, to make sure we don't get hung trying to explode MBs of string ...
$maxTotalLength = $this->messageCounter * (self::MAX_CHAT_BYTE_LENGTH + 1);
if(strlen($message) > $maxTotalLength){
return false;
}
$message = TextFormat::clean($message, false);
foreach(explode("\n", $message) as $messagePart){
foreach(explode("\n", $message, $this->messageCounter + 1) as $messagePart){
if(trim($messagePart) !== "" && strlen($messagePart) <= self::MAX_CHAT_BYTE_LENGTH && mb_strlen($messagePart, 'UTF-8') <= self::MAX_CHAT_CHAR_LENGTH && $this->messageCounter-- > 0){
if(strpos($messagePart, './') === 0){
$messagePart = substr($messagePart, 1);

View File

@ -166,6 +166,14 @@ class PluginManager{
)));
return null;
}
$reflect = new \ReflectionClass($mainClass); //this shouldn't throw; we already checked that it exists
if(!$reflect->isInstantiable()){
$this->server->getLogger()->error($language->translate(KnownTranslationFactory::pocketmine_plugin_loadError(
$description->getName(),
KnownTranslationFactory::pocketmine_plugin_mainClassAbstract()
)));
return null;
}
$permManager = PermissionManager::getInstance();
foreach($description->getPermissions() as $permsGroup){
@ -463,8 +471,12 @@ class PluginManager{
}
public function tickSchedulers(int $currentTick) : void{
foreach($this->enabledPlugins as $p){
$p->getScheduler()->mainThreadHeartbeat($currentTick);
foreach($this->enabledPlugins as $pluginName => $p){
if(isset($this->enabledPlugins[$pluginName])){
//the plugin may have been disabled as a result of updating other plugins' schedulers, and therefore
//removed from enabledPlugins; however, foreach will still see it due to copy-on-write
$p->getScheduler()->mainThreadHeartbeat($currentTick);
}
}
}

View File

@ -64,6 +64,13 @@ class ZippedResourcePack implements ResourcePack{
if(!file_exists($zipPath)){
throw new ResourcePackException("File not found");
}
$size = filesize($zipPath);
if($size === false){
throw new ResourcePackException("Unable to determine size of file");
}
if($size === 0){
throw new ResourcePackException("Empty file, probably corrupted");
}
$archive = new \ZipArchive();
if(($openResult = $archive->open($zipPath)) !== true){

View File

@ -64,6 +64,9 @@ class ThreadManager extends \Volatile{
*/
public function getAll() : array{
$array = [];
/**
* @var Worker|Thread $thread
*/
foreach($this as $key => $thread){
$array[$key] = $thread;
}

View File

@ -23,8 +23,6 @@ declare(strict_types=1);
namespace pocketmine\utils;
use function preg_match;
trait EnumTrait{
use RegistryTrait;
use NotCloneable;
@ -70,9 +68,7 @@ trait EnumTrait{
* @throws \InvalidArgumentException
*/
private function __construct(string $enumName){
if(preg_match('/^\D[A-Za-z\d_]+$/u', $enumName, $matches) === 0){
throw new \InvalidArgumentException("Invalid enum member name \"$enumName\", should only contain letters, numbers and underscores, and must not start with a number");
}
self::verifyName($enumName);
$this->enumName = $enumName;
if(self::$nextId === null){
self::$nextId = Process::pid(); //this provides enough base entropy to prevent hardcoding

View File

@ -32,7 +32,6 @@ use function curl_getinfo;
use function curl_init;
use function curl_setopt_array;
use function explode;
use function is_int;
use function is_string;
use function preg_match;
use function socket_close;
@ -220,7 +219,6 @@ class Internet{
}
if(!is_string($raw)) throw new AssumptionFailedError("curl_exec() should return string|false when CURLOPT_RETURNTRANSFER is set");
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if(!is_int($httpCode)) throw new AssumptionFailedError("curl_getinfo(CURLINFO_HTTP_CODE) always returns int");
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$rawHeaders = substr($raw, 0, $headerSize);
$body = substr($raw, $headerSize);

View File

@ -26,17 +26,25 @@ namespace pocketmine\utils;
use function array_map;
use function count;
use function mb_strtoupper;
use function preg_match;
trait RegistryTrait{
/** @var object[] */
private static $members = null;
private static function verifyName(string $name) : void{
if(preg_match('/^(?!\d)[A-Za-z\d_]+$/u', $name) === 0){
throw new \InvalidArgumentException("Invalid member name \"$name\", should only contain letters, numbers and underscores, and must not start with a number");
}
}
/**
* Adds the given object to the registry.
*
* @throws \InvalidArgumentException
*/
private static function _registryRegister(string $name, object $member) : void{
self::verifyName($name);
$upperName = mb_strtoupper($name);
if(isset(self::$members[$upperName])){
throw new \InvalidArgumentException("\"$upperName\" is already reserved");

View File

@ -905,11 +905,6 @@ parameters:
count: 1
path: ../../../src/scheduler/TaskScheduler.php
-
message: "#^Method pocketmine\\\\thread\\\\ThreadManager\\:\\:getAll\\(\\) should return array\\<pocketmine\\\\thread\\\\Thread\\|pocketmine\\\\thread\\\\Worker\\> but returns array\\.$#"
count: 1
path: ../../../src/thread/ThreadManager.php
-
message: "#^Cannot access offset string on mixed\\.$#"
count: 3
@ -925,16 +920,6 @@ parameters:
count: 1
path: ../../../src/utils/Config.php
-
message: "#^Parameter \\#2 \\$offset of function substr expects int, mixed given\\.$#"
count: 1
path: ../../../src/utils/Internet.php
-
message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, mixed given\\.$#"
count: 1
path: ../../../src/utils/Internet.php
-
message: "#^Parameter \\#1 \\$string of function trim expects string, string\\|false given\\.$#"
count: 1

View File

@ -86,7 +86,7 @@ parameters:
path: ../../../src/world/format/io/region/RegionLoader.php
-
message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertNotSame\\(\\) with arguments stdClass, stdClass and 'Cloning registry…' will always evaluate to false\\.$#"
message: "#^Negated boolean expression is always true\\.$#"
count: 1
path: ../../phpunit/utils/CloningRegistryTraitTest.php
path: ../../../src/network/mcpe/handler/InGamePacketHandler.php