mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 03:06:55 +00:00
Compare commits
71 Commits
Author | SHA1 | Date | |
---|---|---|---|
2f5e08067d | |||
a8556dff02 | |||
664089861a | |||
6c0254c1eb | |||
0bb9fb09cc | |||
ab21fcdd67 | |||
b03df4f1e6 | |||
0a2a6e2b3a | |||
0eb751c1c9 | |||
b59b1e491e | |||
95e8c68fde | |||
7e16f9be8f | |||
768650cee0 | |||
c2c529e2da | |||
ba18a81e88 | |||
39218017ca | |||
f4a1d69075 | |||
cbeae906e1 | |||
b25e8e26f0 | |||
a79be994de | |||
e26c8b9e9f | |||
4e9c3e101d | |||
d295e1be54 | |||
2f3fcef97c | |||
c5056e0a43 | |||
a47aa50477 | |||
f7930a3a0b | |||
bb7df60a4d | |||
992cb06da6 | |||
bb3f87f862 | |||
fc77b14760 | |||
52b6f1a492 | |||
0233e74f4f | |||
dd355c58d8 | |||
267032cff9 | |||
6cecd690b2 | |||
91e38d1f97 | |||
653178c1fd | |||
eb06535ed1 | |||
f9bcc8e862 | |||
f43ca405d4 | |||
d146175d27 | |||
3baa5ab712 | |||
c02bead12b | |||
e9ca25c1cb | |||
a513cca582 | |||
9a47c1d401 | |||
433f5451d7 | |||
64e505defb | |||
33d1755eae | |||
fc63c54116 | |||
db07976aab | |||
0e4b79ea77 | |||
588c9b114b | |||
b095f606c1 | |||
b312e93176 | |||
61933624d2 | |||
90beaeaeb4 | |||
466f7e98ed | |||
59be901efe | |||
5d2b0acfc8 | |||
7d1d62042c | |||
17dde140a5 | |||
1e5597f0d5 | |||
97ef209c5f | |||
1305fd5fb2 | |||
7a137f932f | |||
63e8b1cf3a | |||
65bce762ff | |||
529700bb8b | |||
437fa615b8 |
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@ -6,6 +6,12 @@ updates:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
#only allow patch updates for locale-data - this has to be updated manually due to codegen
|
||||
- dependency-name: pocketmine/locale-data
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- "version-update:semver-minor"
|
||||
|
||||
- package-ecosystem: gitsubmodule
|
||||
directory: "/"
|
||||
|
8
.github/workflows/build-docker-image.yml
vendored
8
.github/workflows/build-docker-image.yml
vendored
@ -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.2.0
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
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.2.0
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
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.2.0
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
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.2.0
|
||||
uses: docker/build-push-action@v3.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.22.0
|
||||
uses: shivammathur/setup-php@2.23.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
|
2
.github/workflows/draft-release.yml
vendored
2
.github/workflows/draft-release.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.22.0
|
||||
uses: shivammathur/setup-php@2.23.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
|
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -195,10 +195,12 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.22.0
|
||||
uses: shivammathur/setup-php@2.23.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
tools: php-cs-fixer:3.11
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Run PHP-CS-Fixer
|
||||
run: php-cs-fixer fix --dry-run --diff --ansi
|
||||
|
Submodule build/php updated: 27cc1fcdfa...6b605ed7c4
@ -30,3 +30,77 @@ Released 15th December 2022.
|
||||
|
||||
## Dependencies
|
||||
- Updated BedrockProtocol to [17.1.0](https://github.com/pmmp/BedrockProtocol/releases/tag/17.1.0+bedrock-1.19.50). This adds some missing `LevelSoundEvent` constants and fixes the values for `ContainerUIIds`.
|
||||
|
||||
# 4.12.3
|
||||
Released 28th December 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed unauthenticated connections taking up player count slots, preventing players from joining.
|
||||
- Fixed a possible crash in `World->tickChunk()` when plugins unload chunks during some events.
|
||||
- `/gamemode` will now report a failure to change game mode if the player is already in the requested game mode.
|
||||
|
||||
# 4.12.4
|
||||
Released 3rd January 2023.
|
||||
|
||||
## Fixes
|
||||
- Added workarounds for an active exploit being used to deny service to servers.
|
||||
|
||||
# 4.12.5
|
||||
Released 6th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Removed a workaround for an old client bug in custom form responses. The code contained a denial-of-service vulnerability.
|
||||
|
||||
# 4.12.6
|
||||
Released 7th January 2023.
|
||||
|
||||
## Changes
|
||||
- Added a new security measure to `NetworkSession` to detect and ban players who flood the server with packets.
|
||||
|
||||
# 4.12.7
|
||||
Released 8th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed players getting kicked when the server lags for too long.
|
||||
- Fixed players getting kicked when a debugging session is active and a breakpoint is hit.
|
||||
|
||||
# 4.12.8
|
||||
Released 9th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed players getting kicked during PvP.
|
||||
- Fixed players randomly getting kicked on Windows (improper rate limit handling wrt. 15ms timer resolution).
|
||||
|
||||
# 4.12.9
|
||||
Released 16th January 2023.
|
||||
|
||||
## Improvements
|
||||
### Timings
|
||||
- Added new timers:
|
||||
- `Server Mid-Tick Processing` - time spent processing Snooze interrupts between ticks (e.g. incoming network packets)
|
||||
- `Server Tick Update Cycle` - time spent processing regular per-tick updates (e.g. entity movement, world updates, etc.) (`Server->tick()`)
|
||||
- `Full Server Tick` timer now counts the total of `Server Mid-Tick Processing` and `Server Tick Update Cycle`, which generates more accurate performance metrics.
|
||||
- Previously, this timer only counted the time spent during regular per-tick updates, and the time recorded by `Server Mid-Tick Processing` was not included in the report at all.
|
||||
|
||||
## Fixes
|
||||
- Fixed blocks such as pressure plates being able to be placed without the correct supporting blocks if the clicked block was solid.
|
||||
- Pressure plates now self-destruct when the block below them is removed.
|
||||
- Fixed being unable to place blocks by clicking on the side of a bell (when the click doesn't result in ringing the bell).
|
||||
- Fixed various rotation-aware blocks (e.g. stairs) behaving incorrectly when placed by clicking on the side of a replaceable block (e.g. tall grass).
|
||||
- Fixed banners being able to be placed on top of blocks such as skulls.
|
||||
- Fixed server-side collision boxes of walls and glass (which should connect, but didn't). Note that wall connections still don't show client side - this just fixes the collision boxes.
|
||||
- Fixed `PlayerInteractEvent` with `LEFT_CLICK` sometimes firing before `BlockBreakEvent` when breaking blocks.
|
||||
|
||||
## Other changes
|
||||
- Increased packet batch budget for player sessions.
|
||||
|
||||
# 4.12.10
|
||||
Released 18th January 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed reported server load not including the time spent processing Snooze interrupts between ticks (e.g. incoming network packets).
|
||||
- Fixed `Connection Handler` entry in timings report not including time spent receiving packets.
|
||||
|
||||
## Note about server load & performance
|
||||
This version will report higher apparent server load than previous versions. The actual performance of the server is unchanged; the previous reported load was inaccurate.
|
||||
These bugs have been present for nearly 5 years (ever since the first introduction of Snooze in 3.0.0).
|
||||
|
@ -54,7 +54,7 @@
|
||||
"webmozart/path-util": "^2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.9.3",
|
||||
"phpstan/phpstan": "1.9.12",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
|
170
composer.lock
generated
170
composer.lock
generated
@ -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": "4c222172c7114c112009b3513c017df5",
|
||||
"content-hash": "1c5a3de092db3cda702d3f39d3da246c",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -123,24 +123,24 @@
|
||||
},
|
||||
{
|
||||
"name": "fgrosse/phpasn1",
|
||||
"version": "v2.4.0",
|
||||
"version": "v2.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fgrosse/PHPASN1.git",
|
||||
"reference": "eef488991d53e58e60c9554b09b1201ca5ba9296"
|
||||
"reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/eef488991d53e58e60c9554b09b1201ca5ba9296",
|
||||
"reference": "eef488991d53e58e60c9554b09b1201ca5ba9296",
|
||||
"url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/42060ed45344789fb9f21f9f1864fc47b9e3507b",
|
||||
"reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0"
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "~2.0",
|
||||
"phpunit/phpunit": "^6.3 || ^7.0 || ^8.0"
|
||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "BCmath is the fallback extension for big integer calculations",
|
||||
@ -192,9 +192,10 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/fgrosse/PHPASN1/issues",
|
||||
"source": "https://github.com/fgrosse/PHPASN1/tree/v2.4.0"
|
||||
"source": "https://github.com/fgrosse/PHPASN1/tree/v2.5.0"
|
||||
},
|
||||
"time": "2021-12-11T12:41:06+00:00"
|
||||
"abandoned": true,
|
||||
"time": "2022-12-19T11:08:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
@ -851,42 +852,53 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/collection",
|
||||
"version": "1.2.2",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/collection.git",
|
||||
"reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a"
|
||||
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/cccc74ee5e328031b15640b51056ee8d3bb66c0a",
|
||||
"reference": "cccc74ee5e328031b15640b51056ee8d3bb66c0a",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4",
|
||||
"reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.3 || ^8",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"symfony/polyfill-php81": "^1.23"
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/captainhook": "^5.3",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
|
||||
"ergebnis/composer-normalize": "^2.6",
|
||||
"fakerphp/faker": "^1.5",
|
||||
"hamcrest/hamcrest-php": "^2",
|
||||
"jangregor/phpstan-prophecy": "^0.8",
|
||||
"mockery/mockery": "^1.3",
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"ergebnis/composer-normalize": "^2.28.3",
|
||||
"fakerphp/faker": "^1.21",
|
||||
"hamcrest/hamcrest-php": "^2.0",
|
||||
"jangregor/phpstan-prophecy": "^1.0",
|
||||
"mockery/mockery": "^1.5",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||
"phpcsstandards/phpcsutils": "^1.0.0-rc1",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpstan/extension-installer": "^1",
|
||||
"phpstan/phpstan": "^0.12.32",
|
||||
"phpstan/phpstan-mockery": "^0.12.5",
|
||||
"phpstan/phpstan-phpunit": "^0.12.11",
|
||||
"phpunit/phpunit": "^8.5 || ^9",
|
||||
"psy/psysh": "^0.10.4",
|
||||
"slevomat/coding-standard": "^6.3",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"vimeo/psalm": "^4.4"
|
||||
"phpstan/extension-installer": "^1.2",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpstan/phpstan-mockery": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/plugin-mockery": "^1.1",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"ramsey/coding-standard": "^2.0.3",
|
||||
"ramsey/conventional-commits": "^1.3",
|
||||
"vimeo/psalm": "^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"captainhook": {
|
||||
"force-install": true
|
||||
},
|
||||
"ramsey/conventional-commits": {
|
||||
"configFile": "conventional-commits.json"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ramsey\\Collection\\": "src/"
|
||||
@ -914,7 +926,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/collection/issues",
|
||||
"source": "https://github.com/ramsey/collection/tree/1.2.2"
|
||||
"source": "https://github.com/ramsey/collection/tree/1.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -926,27 +938,27 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-10-10T03:01:02+00:00"
|
||||
"time": "2022-12-27T19:12:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "4.6.0",
|
||||
"version": "4.7.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "ad63bc700e7d021039e30ce464eba384c4a1d40f"
|
||||
"reference": "433b2014e3979047db08a17a205f410ba3869cf2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/ad63bc700e7d021039e30ce464eba384c4a1d40f",
|
||||
"reference": "ad63bc700e7d021039e30ce464eba384c4a1d40f",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/433b2014e3979047db08a17a205f410ba3869cf2",
|
||||
"reference": "433b2014e3979047db08a17a205f410ba3869cf2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.8.8 || ^0.9 || ^0.10",
|
||||
"ext-json": "*",
|
||||
"php": "^8.0",
|
||||
"ramsey/collection": "^1.0"
|
||||
"ramsey/collection": "^1.2 || ^2.0"
|
||||
},
|
||||
"replace": {
|
||||
"rhumsaa/uuid": "self.version"
|
||||
@ -1006,7 +1018,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/uuid/issues",
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.6.0"
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.7.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1018,7 +1030,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-05T23:03:38+00:00"
|
||||
"time": "2023-01-12T18:13:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
@ -1524,30 +1536,30 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.4.1",
|
||||
"version": "1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
|
||||
"reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"reference": "0a0fa9780f5d4e507415a065172d26a98d02047b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^9",
|
||||
"doctrine/coding-standard": "^9 || ^11",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpbench/phpbench": "^0.16 || ^1",
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpstan/phpstan-phpunit": "^1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||
"vimeo/psalm": "^4.22"
|
||||
"vimeo/psalm": "^4.30 || ^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -1574,7 +1586,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/instantiator/issues",
|
||||
"source": "https://github.com/doctrine/instantiator/tree/1.4.1"
|
||||
"source": "https://github.com/doctrine/instantiator/tree/1.5.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1590,7 +1602,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-03-03T08:28:38+00:00"
|
||||
"time": "2022-12-30T00:15:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
@ -1820,16 +1832,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.9.3",
|
||||
"version": "1.9.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "709999b91448d4f2bb07daffffedc889b33e461c"
|
||||
"reference": "44a338ff0d5572c13fd77dfd91addb96e48c29f8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/709999b91448d4f2bb07daffffedc889b33e461c",
|
||||
"reference": "709999b91448d4f2bb07daffffedc889b33e461c",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/44a338ff0d5572c13fd77dfd91addb96e48c29f8",
|
||||
"reference": "44a338ff0d5572c13fd77dfd91addb96e48c29f8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1859,7 +1871,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.9.3"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.9.12"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1875,20 +1887,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-13T10:28:10+00:00"
|
||||
"time": "2023-01-17T10:44:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "1.3.2",
|
||||
"version": "1.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "cd9c6938f8bbfcb6da3ed5a3c7ea60873825d088"
|
||||
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/cd9c6938f8bbfcb6da3ed5a3c7ea60873825d088",
|
||||
"reference": "cd9c6938f8bbfcb6da3ed5a3c7ea60873825d088",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/54a24bd23e9e80ee918cdc24f909d376c2e273f7",
|
||||
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1925,27 +1937,27 @@
|
||||
"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.3.2"
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.3"
|
||||
},
|
||||
"time": "2022-12-13T15:08:22+00:00"
|
||||
"time": "2022-12-21T15:25:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
"version": "1.4.4",
|
||||
"version": "1.4.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6"
|
||||
"reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6",
|
||||
"reference": "23e5f377ee6395a1a04842d3d6ed4bd25e7b44a6",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d",
|
||||
"reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpstan": "^1.8.6"
|
||||
"phpstan/phpstan": "^1.9.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
@ -1973,22 +1985,22 @@
|
||||
"description": "Extra strict and opinionated rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.4"
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.5"
|
||||
},
|
||||
"time": "2022-09-21T11:38:17+00:00"
|
||||
"time": "2023-01-11T14:16:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.21",
|
||||
"version": "9.2.23",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "3f893e19712bb0c8bc86665d1562e9fd509c4ef0"
|
||||
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/3f893e19712bb0c8bc86665d1562e9fd509c4ef0",
|
||||
"reference": "3f893e19712bb0c8bc86665d1562e9fd509c4ef0",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
|
||||
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2044,7 +2056,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.21"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.23"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2052,7 +2064,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-14T13:26:54+00:00"
|
||||
"time": "2022-12-28T12:41:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -2297,20 +2309,20 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.5.27",
|
||||
"version": "9.5.28",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "a2bc7ffdca99f92d959b3f2270529334030bba38"
|
||||
"reference": "954ca3113a03bf780d22f07bf055d883ee04b65e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a2bc7ffdca99f92d959b3f2270529334030bba38",
|
||||
"reference": "a2bc7ffdca99f92d959b3f2270529334030bba38",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/954ca3113a03bf780d22f07bf055d883ee04b65e",
|
||||
"reference": "954ca3113a03bf780d22f07bf055d883ee04b65e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.3.1",
|
||||
"doctrine/instantiator": "^1.3.1 || ^2",
|
||||
"ext-dom": "*",
|
||||
"ext-json": "*",
|
||||
"ext-libxml": "*",
|
||||
@ -2379,7 +2391,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.27"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.28"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2395,7 +2407,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-09T07:31:23+00:00"
|
||||
"time": "2023-01-14T12:32:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
@ -186,7 +186,7 @@ class Server{
|
||||
|
||||
private static ?Server $instance = null;
|
||||
|
||||
private SleeperHandler $tickSleeper;
|
||||
private TimeTrackingSleeperHandler $tickSleeper;
|
||||
|
||||
private BanList $banByName;
|
||||
|
||||
@ -781,7 +781,8 @@ class Server{
|
||||
self::$instance = $this;
|
||||
$this->startTime = microtime(true);
|
||||
|
||||
$this->tickSleeper = new SleeperHandler();
|
||||
Timings::init();
|
||||
$this->tickSleeper = new TimeTrackingSleeperHandler(Timings::$serverInterrupts);
|
||||
|
||||
$this->signalHandler = new SignalHandler(function() : void{
|
||||
$this->logger->info("Received signal interrupt, stopping the server");
|
||||
@ -961,7 +962,6 @@ class Server{
|
||||
)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
|
||||
Timings::init();
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool("settings.enable-profiling", false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", 20);
|
||||
|
||||
@ -1865,14 +1865,16 @@ class Server{
|
||||
Timings::$serverTick->stopTiming();
|
||||
|
||||
$now = microtime(true);
|
||||
$this->currentTPS = min(20, 1 / max(0.001, $now - $tickTime));
|
||||
$this->currentUse = min(1, ($now - $tickTime) / 0.05);
|
||||
$totalTickTimeSeconds = $now - $tickTime + ($this->tickSleeper->getNotificationProcessingTime() / 1_000_000_000);
|
||||
$this->currentTPS = min(20, 1 / max(0.001, $totalTickTimeSeconds));
|
||||
$this->currentUse = min(1, $totalTickTimeSeconds / 0.05);
|
||||
|
||||
TimingsHandler::tick($this->currentTPS <= $this->profilingTickRate);
|
||||
|
||||
$idx = $this->tickCounter % 20;
|
||||
$this->tickAverage[$idx] = $this->currentTPS;
|
||||
$this->useAverage[$idx] = $this->currentUse;
|
||||
$this->tickSleeper->resetNotificationProcessingTime();
|
||||
|
||||
if(($this->nextTick - $tickTime) < -1){
|
||||
$this->nextTick = $tickTime;
|
||||
|
64
src/TimeTrackingSleeperHandler.php
Normal file
64
src/TimeTrackingSleeperHandler.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use function hrtime;
|
||||
|
||||
/**
|
||||
* Custom Snooze sleeper handler which captures notification processing time.
|
||||
* @internal
|
||||
*/
|
||||
final class TimeTrackingSleeperHandler extends SleeperHandler{
|
||||
|
||||
private int $notificationProcessingTimeNs = 0;
|
||||
|
||||
public function __construct(
|
||||
private TimingsHandler $timings
|
||||
){
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in nanoseconds spent processing notifications since the last reset.
|
||||
*/
|
||||
public function getNotificationProcessingTime() : int{ return $this->notificationProcessingTimeNs; }
|
||||
|
||||
/**
|
||||
* Resets the notification processing time tracker to zero.
|
||||
*/
|
||||
public function resetNotificationProcessingTime() : void{ $this->notificationProcessingTimeNs = 0; }
|
||||
|
||||
public function processNotifications() : void{
|
||||
$startTime = hrtime(true);
|
||||
$this->timings->startTiming();
|
||||
try{
|
||||
parent::processNotifications();
|
||||
}finally{
|
||||
$this->notificationProcessingTimeNs += hrtime(true) - $startTime;
|
||||
$this->timings->stopTiming();
|
||||
}
|
||||
}
|
||||
}
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "4.12.2";
|
||||
public const BASE_VERSION = "4.12.10";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
@ -112,7 +112,14 @@ abstract class BaseBanner extends Transparent{
|
||||
return SupportType::NONE();
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
return $block->isSolid();
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
|
||||
return false;
|
||||
}
|
||||
if($item instanceof ItemBanner){
|
||||
$this->color = $item->getColor();
|
||||
$this->setPatterns($item->getPatterns());
|
||||
@ -124,7 +131,7 @@ abstract class BaseBanner extends Transparent{
|
||||
abstract protected function getSupportingFace() : int;
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->getSide($this->getSupportingFace())->getId() === BlockLegacyIds::AIR){
|
||||
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
@ -114,14 +114,13 @@ final class Bell extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
//TODO: this isn't the actual logic, but it's the closest approximation we can support for now
|
||||
return $block->isSolid();
|
||||
private function canBeSupportedBy(Block $block, int $face) : bool{
|
||||
return !$block->getSupportType($face)->equals(SupportType::NONE());
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face === Facing::UP){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->down()))){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->down()), Facing::UP)){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
@ -129,18 +128,18 @@ final class Bell extends Transparent{
|
||||
}
|
||||
$this->setAttachmentType(BellAttachmentType::FLOOR());
|
||||
}elseif($face === Facing::DOWN){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->up()))){
|
||||
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->up()), Facing::DOWN)){
|
||||
return false;
|
||||
}
|
||||
$this->setAttachmentType(BellAttachmentType::CEILING());
|
||||
}else{
|
||||
$this->setFacing($face);
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide(Facing::opposite($face))))){
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide(Facing::opposite($face))), $face)){
|
||||
$this->setAttachmentType(BellAttachmentType::ONE_WALL());
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide($face)))){
|
||||
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide($face)), Facing::opposite($face))){
|
||||
$this->setAttachmentType(BellAttachmentType::TWO_WALLS());
|
||||
}
|
||||
}
|
||||
@ -149,10 +148,10 @@ final class Bell extends Transparent{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(
|
||||
($this->attachmentType->equals(BellAttachmentType::CEILING()) && !$this->canBeSupportedBy($this->getSide(Facing::UP))) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && !$this->canBeSupportedBy($this->getSide(Facing::DOWN))) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) && !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)))) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::TWO_WALLS()) && (!$this->canBeSupportedBy($this->getSide($this->facing)) || !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)))))
|
||||
($this->attachmentType->equals(BellAttachmentType::CEILING()) && !$this->canBeSupportedBy($this->getSide(Facing::UP), Facing::DOWN)) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && !$this->canBeSupportedBy($this->getSide(Facing::DOWN), Facing::UP)) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) && !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::TWO_WALLS()) && (!$this->canBeSupportedBy($this->getSide($this->facing), Facing::opposite($this->facing)) || !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)))
|
||||
){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
@ -161,21 +160,20 @@ final class Bell extends Transparent{
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$faceHit = Facing::opposite($player->getHorizontalFacing());
|
||||
if($this->attachmentType->equals(BellAttachmentType::CEILING())){
|
||||
$this->ring($faceHit);
|
||||
}
|
||||
if($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)){
|
||||
$this->ring($faceHit);
|
||||
}
|
||||
if(
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
|
||||
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
|
||||
$this->attachmentType->equals(BellAttachmentType::CEILING()) ||
|
||||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)) ||
|
||||
(
|
||||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
|
||||
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
|
||||
)
|
||||
){
|
||||
$this->ring($faceHit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function ring(int $faceHit) : void{
|
||||
|
@ -253,6 +253,14 @@ class Block{
|
||||
* Generates a block transaction to set all blocks affected by placing this block. Usually this is just the block
|
||||
* itself, but may be multiple blocks in some cases (such as doors).
|
||||
*
|
||||
* @param BlockTransaction $tx Blocks to be set should be added to this transaction (do not modify thr world directly)
|
||||
* @param Item $item Item used to place the block
|
||||
* @param Block $blockReplace Block expected to be replaced
|
||||
* @param Block $blockClicked Block that was clicked using the item
|
||||
* @param int $face Face of the clicked block which was clicked
|
||||
* @param Vector3 $clickVector Exact position inside the clicked block where the click occurred, relative to the block's position
|
||||
* @param Player|null $player Player who placed the block, or null if it was not a player
|
||||
*
|
||||
* @return bool whether the placement should go ahead
|
||||
*/
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
|
@ -61,7 +61,7 @@ abstract class Button extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->canBeSupportedBy($blockClicked, $face)){
|
||||
if($this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ class ItemFrame extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face === Facing::DOWN || $face === Facing::UP || !$blockClicked->isSolid()){
|
||||
if($face === Facing::DOWN || $face === Facing::UP || !$blockReplace->getSide(Facing::opposite($face))->isSolid()){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ class Ladder extends Transparent{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->canBeSupportedBy($blockClicked, $face) && Facing::axis($face) !== Axis::Y){
|
||||
if($this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face) && Facing::axis($face) !== Axis::Y){
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ class Lever extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockClicked, $face)){
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ abstract class PressurePlate extends Transparent{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->canBeSupportedBy($blockClicked)){
|
||||
if($this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
return false;
|
||||
@ -55,5 +55,11 @@ abstract class PressurePlate extends Transparent{
|
||||
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE());
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class Thin extends Transparent{
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$side = $this->getSide($facing);
|
||||
if($side instanceof Thin || $side->isFullCube()){
|
||||
if($side instanceof Thin || $side instanceof Wall || $side->isFullCube()){
|
||||
$this->connections[$facing] = true;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
|
@ -65,7 +65,6 @@ class Torch extends Flowable{
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$below = $this->getSide(Facing::DOWN);
|
||||
$face = Facing::opposite($this->facing);
|
||||
|
||||
if(!$this->canBeSupportedBy($this->getSide($face), $this->facing)){
|
||||
@ -74,10 +73,7 @@ class Torch extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($blockClicked->canBeReplaced() && $this->canBeSupportedBy($blockClicked->getSide(Facing::DOWN), Facing::UP)){
|
||||
$this->facing = Facing::UP;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}elseif($face !== Facing::DOWN && $this->canBeSupportedBy($blockClicked, $face)){
|
||||
if($face !== Facing::DOWN && $this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}else{
|
||||
|
@ -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->isFullCube() || Facing::axis($face) === Axis::Y){
|
||||
if(!$blockReplace->getSide(Facing::opposite($face))->isFullCube() || Facing::axis($face) === Axis::Y){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ class Wall extends Transparent{
|
||||
|
||||
foreach(Facing::HORIZONTAL as $facing){
|
||||
$block = $this->getSide($facing);
|
||||
if($block instanceof static || $block instanceof FenceGate || ($block->isSolid() && !$block->isTransparent())){
|
||||
if($block instanceof static || $block instanceof FenceGate || $block instanceof Thin || ($block->isSolid() && !$block->isTransparent())){
|
||||
$this->connections[$facing] = $facing;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
|
@ -113,7 +113,7 @@ final class WallCoralFan extends BaseCoral{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$axis = Facing::axis($face);
|
||||
if(($axis !== Axis::X && $axis !== Axis::Z) || !$this->canBeSupportedBy($blockClicked, $face)){
|
||||
if(($axis !== Axis::X && $axis !== Axis::Z) || !$this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
|
||||
return false;
|
||||
}
|
||||
$this->facing = $face;
|
||||
|
@ -39,19 +39,23 @@ class WaterLily extends Flowable{
|
||||
return [AxisAlignedBB::one()->contract(1 / 16, 0, 1 / 16)->trim(Facing::UP, 63 / 64)];
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($blockClicked instanceof Water){
|
||||
$up = $blockClicked->getSide(Facing::UP);
|
||||
if($up->canBeReplaced()){
|
||||
return parent::place($tx, $item, $up, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
}
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return !$blockReplace instanceof Water && parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
}
|
||||
|
||||
return false;
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
return $block instanceof Water;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){
|
||||
return false;
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if(!($this->getSide(Facing::DOWN) instanceof Water)){
|
||||
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,11 @@ class GamemodeCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
if($target->getGamemode()->equals($gameMode)){
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_failure($target->getName()));
|
||||
return true;
|
||||
}
|
||||
|
||||
$target->setGamemode($gameMode);
|
||||
if(!$gameMode->equals($target->getGamemode())){
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_gamemode_failure($target->getName()));
|
||||
|
@ -34,9 +34,15 @@ use function usort;
|
||||
class CraftingManager{
|
||||
use DestructorCallbackTrait;
|
||||
|
||||
/** @var ShapedRecipe[][] */
|
||||
/**
|
||||
* @var ShapedRecipe[][]
|
||||
* @phpstan-var array<string, list<ShapedRecipe>>
|
||||
*/
|
||||
protected $shapedRecipes = [];
|
||||
/** @var ShapelessRecipe[][] */
|
||||
/**
|
||||
* @var ShapelessRecipe[][]
|
||||
* @phpstan-var array<string, list<ShapelessRecipe>>
|
||||
*/
|
||||
protected $shapelessRecipes = [];
|
||||
|
||||
/**
|
||||
@ -133,6 +139,7 @@ class CraftingManager{
|
||||
|
||||
/**
|
||||
* @return ShapelessRecipe[][]
|
||||
* @phpstan-return array<string, list<ShapelessRecipe>>
|
||||
*/
|
||||
public function getShapelessRecipes() : array{
|
||||
return $this->shapelessRecipes;
|
||||
@ -140,6 +147,7 @@ class CraftingManager{
|
||||
|
||||
/**
|
||||
* @return ShapedRecipe[][]
|
||||
* @phpstan-return array<string, list<ShapedRecipe>>
|
||||
*/
|
||||
public function getShapedRecipes() : array{
|
||||
return $this->shapedRecipes;
|
||||
|
@ -33,13 +33,13 @@ final class PotionTypeIdMap{
|
||||
* @var PotionType[]
|
||||
* @phpstan-var array<int, PotionType>
|
||||
*/
|
||||
private array $idToEnum;
|
||||
private array $idToEnum = [];
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
private array $enumToId;
|
||||
private array $enumToId = [];
|
||||
|
||||
private function __construct(){
|
||||
$this->register(PotionTypeIds::WATER, PotionType::WATER());
|
||||
|
@ -31,6 +31,10 @@ class HandlerList{
|
||||
/** @var RegisteredListener[][] */
|
||||
private array $handlerSlots = [];
|
||||
|
||||
/**
|
||||
* @phpstan-template TEvent of Event
|
||||
* @phpstan-param class-string<TEvent> $class
|
||||
*/
|
||||
public function __construct(
|
||||
private string $class,
|
||||
private ?HandlerList $parentList
|
||||
|
@ -80,6 +80,10 @@ class Network{
|
||||
return $this->sessionManager->getSessionCount();
|
||||
}
|
||||
|
||||
public function getValidConnectionCount() : int{
|
||||
return $this->sessionManager->getValidSessionCount();
|
||||
}
|
||||
|
||||
public function tick() : void{
|
||||
foreach($this->interfaces as $interface){
|
||||
$interface->tick();
|
||||
|
@ -32,12 +32,25 @@ class NetworkSessionManager{
|
||||
/** @var NetworkSession[] */
|
||||
private array $sessions = [];
|
||||
|
||||
/** @var NetworkSession[] */
|
||||
private array $pendingLoginSessions = [];
|
||||
|
||||
/**
|
||||
* Adds a network session to the manager. This should only be called on session creation.
|
||||
*/
|
||||
public function add(NetworkSession $session) : void{
|
||||
$idx = spl_object_id($session);
|
||||
$this->sessions[$idx] = $session;
|
||||
$this->pendingLoginSessions[$idx] = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the session as having sent a login request. After this point, they are counted towards the total player
|
||||
* count.
|
||||
*/
|
||||
public function markLoginReceived(NetworkSession $session) : void{
|
||||
$idx = spl_object_id($session);
|
||||
unset($this->pendingLoginSessions[$idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,15 +60,24 @@ class NetworkSessionManager{
|
||||
public function remove(NetworkSession $session) : void{
|
||||
$idx = spl_object_id($session);
|
||||
unset($this->sessions[$idx]);
|
||||
unset($this->pendingLoginSessions[$idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of known connected sessions.
|
||||
* Returns the number of known connected sessions, including sessions which have not yet sent a login request.
|
||||
*/
|
||||
public function getSessionCount() : int{
|
||||
return count($this->sessions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of connected sessions which have either sent a login request, or have already completed the
|
||||
* login sequence.
|
||||
*/
|
||||
public function getValidSessionCount() : int{
|
||||
return count($this->sessions) - count($this->pendingLoginSessions);
|
||||
}
|
||||
|
||||
/** @return NetworkSession[] */
|
||||
public function getSessions() : array{ return $this->sessions; }
|
||||
|
||||
|
@ -128,20 +128,39 @@ use function array_values;
|
||||
use function base64_encode;
|
||||
use function bin2hex;
|
||||
use function count;
|
||||
use function function_exists;
|
||||
use function get_class;
|
||||
use function hrtime;
|
||||
use function in_array;
|
||||
use function intdiv;
|
||||
use function json_encode;
|
||||
use function ksort;
|
||||
use function min;
|
||||
use function strcasecmp;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
use function time;
|
||||
use function ucfirst;
|
||||
use function xdebug_is_debugger_active;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
class NetworkSession{
|
||||
private const INCOMING_PACKET_BATCH_PER_TICK = 2; //usually max 1 per tick, but transactions may arrive separately
|
||||
private const INCOMING_PACKET_BATCH_MAX_BUDGET = 100 * self::INCOMING_PACKET_BATCH_PER_TICK; //enough to account for a 5-second lag spike
|
||||
|
||||
/**
|
||||
* At most this many more packets can be received. If this reaches zero, any additional packets received will cause
|
||||
* the player to be kicked from the server.
|
||||
* This number is increased every tick up to a maximum limit.
|
||||
*
|
||||
* @see self::INCOMING_PACKET_BATCH_PER_TICK
|
||||
* @see self::INCOMING_PACKET_BATCH_MAX_BUDGET
|
||||
*/
|
||||
private int $incomingPacketBatchBudget = self::INCOMING_PACKET_BATCH_MAX_BUDGET;
|
||||
private int $lastPacketBudgetUpdateTimeNs;
|
||||
|
||||
private \PrefixedLogger $logger;
|
||||
private ?Player $player = null;
|
||||
private ?PlayerInfo $info = null;
|
||||
@ -199,6 +218,7 @@ class NetworkSession{
|
||||
$this->disposeHooks = new ObjectSet();
|
||||
|
||||
$this->connectTime = time();
|
||||
$this->lastPacketBudgetUpdateTimeNs = hrtime(true);
|
||||
|
||||
$this->setHandler(new SessionStartPacketHandler(
|
||||
$this->server,
|
||||
@ -229,6 +249,7 @@ class NetworkSession{
|
||||
$this->info = $info;
|
||||
$this->logger->info("Player: " . TextFormat::AQUA . $info->getUsername() . TextFormat::RESET);
|
||||
$this->logger->setPrefix($this->getLogPrefix());
|
||||
$this->manager->markLoginReceived($this);
|
||||
},
|
||||
function(bool $isAuthenticated, bool $authRequired, ?string $error, ?string $clientPubKey) : void{
|
||||
$this->setAuthenticationStatus($isAuthenticated, $authRequired, $error, $clientPubKey);
|
||||
@ -338,6 +359,17 @@ class NetworkSession{
|
||||
return;
|
||||
}
|
||||
|
||||
if($this->incomingPacketBatchBudget <= 0){
|
||||
if(!function_exists('xdebug_is_debugger_active') || !xdebug_is_debugger_active()){
|
||||
throw new PacketHandlingException("Receiving packets too fast");
|
||||
}else{
|
||||
//when a debugging session is active, the server may halt at any point for an indefinite length of time,
|
||||
//in which time the client will continue to send packets
|
||||
$this->incomingPacketBatchBudget = self::INCOMING_PACKET_BATCH_MAX_BUDGET;
|
||||
}
|
||||
}
|
||||
$this->incomingPacketBatchBudget--;
|
||||
|
||||
if($this->cipher !== null){
|
||||
Timings::$playerNetworkReceiveDecrypt->startTiming();
|
||||
try{
|
||||
@ -365,7 +397,7 @@ class NetworkSession{
|
||||
}
|
||||
|
||||
try{
|
||||
foreach((new PacketBatch($decompressed))->getPackets($this->packetPool, $this->packetSerializerContext, 500) as [$packet, $buffer]){
|
||||
foreach((new PacketBatch($decompressed))->getPackets($this->packetPool, $this->packetSerializerContext, 1300) as [$packet, $buffer]){
|
||||
if($packet === null){
|
||||
$this->logger->debug("Unknown packet: " . base64_encode($buffer));
|
||||
throw new PacketHandlingException("Unknown packet received");
|
||||
@ -1128,5 +1160,16 @@ class NetworkSession{
|
||||
}
|
||||
|
||||
$this->flushSendBuffer();
|
||||
|
||||
$nowNs = hrtime(true);
|
||||
$timeSinceLastUpdateNs = $nowNs - $this->lastPacketBudgetUpdateTimeNs;
|
||||
if($timeSinceLastUpdateNs > 50_000_000){
|
||||
$ticksSinceLastUpdate = intdiv($timeSinceLastUpdateNs, 50_000_000);
|
||||
$this->incomingPacketBatchBudget = min(
|
||||
$this->incomingPacketBatchBudget + (self::INCOMING_PACKET_BATCH_PER_TICK * 2 * $ticksSinceLastUpdate),
|
||||
self::INCOMING_PACKET_BATCH_MAX_BUDGET
|
||||
);
|
||||
$this->lastPacketBudgetUpdateTimeNs = $nowNs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,6 +175,7 @@ class TypeConverter{
|
||||
$nbt = new CompoundTag();
|
||||
}
|
||||
$nbt->setInt(self::DAMAGE_TAG, $itemStack->getDamage());
|
||||
$meta = 0;
|
||||
}elseif($isBlockItem && $itemStack->getMeta() !== 0){
|
||||
//TODO HACK: This foul-smelling code ensures that we can correctly deserialize an item when the
|
||||
//client sends it back to us, because as of 1.16.220, blockitems quietly discard their metadata
|
||||
@ -183,6 +184,7 @@ class TypeConverter{
|
||||
$nbt = new CompoundTag();
|
||||
}
|
||||
$nbt->setInt(self::PM_META_TAG, $itemStack->getMeta());
|
||||
$meta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,6 @@ use function array_push;
|
||||
use function base64_encode;
|
||||
use function count;
|
||||
use function fmod;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_bool;
|
||||
use function is_infinite;
|
||||
@ -122,12 +121,9 @@ use function json_encode;
|
||||
use function max;
|
||||
use function mb_strlen;
|
||||
use function microtime;
|
||||
use function preg_match;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
use function trim;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
|
||||
/**
|
||||
@ -252,18 +248,11 @@ class InGamePacketHandler extends PacketHandler{
|
||||
|
||||
$packetHandled = true;
|
||||
|
||||
$useItemTransaction = $packet->getItemInteractionData();
|
||||
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();
|
||||
if($blockActions !== null){
|
||||
if(count($blockActions) > 100){
|
||||
throw new PacketHandlingException("Too many block actions in PlayerAuthInputPacket");
|
||||
}
|
||||
foreach($blockActions as $k => $blockAction){
|
||||
$actionHandled = false;
|
||||
if($blockAction instanceof PlayerBlockActionStopBreak){
|
||||
@ -279,6 +268,20 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
}
|
||||
|
||||
$useItemTransaction = $packet->getItemInteractionData();
|
||||
if($useItemTransaction !== null){
|
||||
if(count($useItemTransaction->getTransactionData()->getActions()) > 100){
|
||||
throw new PacketHandlingException("Too many actions in item use transaction");
|
||||
}
|
||||
$this->inventoryManager->addPredictedSlotChanges($useItemTransaction->getTransactionData()->getActions());
|
||||
if(!$this->handleUseItemTransaction($useItemTransaction->getTransactionData())){
|
||||
$packetHandled = false;
|
||||
$this->session->getLogger()->debug("Unhandled transaction in PlayerAuthInputPacket (type " . $useItemTransaction->getTransactionData()->getActionType() . ")");
|
||||
}else{
|
||||
$this->inventoryManager->syncMismatchedPredictedSlotChanges();
|
||||
}
|
||||
}
|
||||
|
||||
return $packetHandled;
|
||||
}
|
||||
|
||||
@ -310,6 +313,10 @@ class InGamePacketHandler extends PacketHandler{
|
||||
public function handleInventoryTransaction(InventoryTransactionPacket $packet) : bool{
|
||||
$result = true;
|
||||
|
||||
if(count($packet->trData->getActions()) > 100){
|
||||
throw new PacketHandlingException("Too many actions in inventory transaction");
|
||||
}
|
||||
|
||||
$this->inventoryManager->addPredictedSlotChanges($packet->trData->getActions());
|
||||
|
||||
if($packet->trData instanceof NormalTransactionData){
|
||||
@ -864,60 +871,17 @@ class InGamePacketHandler extends PacketHandler{
|
||||
//TODO: make APIs for this to allow plugins to use this information
|
||||
return $this->player->onFormSubmit($packet->formId, null);
|
||||
}elseif($packet->formData !== null){
|
||||
return $this->player->onFormSubmit($packet->formId, self::stupid_json_decode($packet->formData, true));
|
||||
try{
|
||||
$responseData = json_decode($packet->formData, true, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR);
|
||||
}catch(\JsonException $e){
|
||||
throw PacketHandlingException::wrap($e, "Failed to decode form response data");
|
||||
}
|
||||
return $this->player->onFormSubmit($packet->formId, $responseData);
|
||||
}else{
|
||||
throw new PacketHandlingException("Expected either formData or cancelReason to be set in ModalFormResponsePacket");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hack to work around a stupid bug in Minecraft W10 which causes empty strings to be sent unquoted in form responses.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws PacketHandlingException
|
||||
*/
|
||||
private static function stupid_json_decode(string $json, bool $assoc = false){
|
||||
if(preg_match('/^\[(.+)\]$/s', $json, $matches) > 0){
|
||||
$raw = $matches[1];
|
||||
$lastComma = -1;
|
||||
$newParts = [];
|
||||
$inQuotes = false;
|
||||
for($i = 0, $len = strlen($raw); $i <= $len; ++$i){
|
||||
if($i === $len || ($raw[$i] === "," && !$inQuotes)){
|
||||
$part = substr($raw, $lastComma + 1, $i - ($lastComma + 1));
|
||||
if(trim($part) === ""){ //regular parts will have quotes or something else that makes them non-empty
|
||||
$part = '""';
|
||||
}
|
||||
$newParts[] = $part;
|
||||
$lastComma = $i;
|
||||
}elseif($raw[$i] === '"'){
|
||||
if(!$inQuotes){
|
||||
$inQuotes = true;
|
||||
}else{
|
||||
$backslashes = 0;
|
||||
for(; $backslashes < $i && $raw[$i - $backslashes - 1] === "\\"; ++$backslashes){}
|
||||
if(($backslashes % 2) === 0){ //unescaped quote
|
||||
$inQuotes = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$fixed = "[" . implode(",", $newParts) . "]";
|
||||
try{
|
||||
return json_decode($fixed, $assoc, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR);
|
||||
}catch(\JsonException $e){
|
||||
throw PacketHandlingException::wrap($e, "Failed to fix JSON (original: $json, modified: $fixed)");
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
return json_decode($json, $assoc, self::MAX_FORM_RESPONSE_DEPTH, JSON_THROW_ON_ERROR);
|
||||
}catch(\JsonException $e){
|
||||
throw PacketHandlingException::wrap($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function handleServerSettingsRequest(ServerSettingsRequestPacket $packet) : bool{
|
||||
return false; //TODO: GUI stuff
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ class LoginPacketHandler extends PacketHandler{
|
||||
$this->session->getPort(),
|
||||
$this->server->requiresAuthentication()
|
||||
);
|
||||
if($this->server->getNetwork()->getConnectionCount() > $this->server->getMaxPlayers()){
|
||||
if($this->server->getNetwork()->getValidConnectionCount() > $this->server->getMaxPlayers()){
|
||||
$ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_SERVER_FULL, KnownTranslationKeys::DISCONNECTIONSCREEN_SERVERFULL);
|
||||
}
|
||||
if(!$this->server->isWhitelisted($playerInfo->getUsername())){
|
||||
|
@ -36,6 +36,8 @@ use pocketmine\network\NetworkInterfaceStartException;
|
||||
use pocketmine\network\PacketHandlingException;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\snooze\SleeperNotifier;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use pocketmine\utils\Utils;
|
||||
use raklib\generic\SocketException;
|
||||
use raklib\protocol\EncapsulatedPacket;
|
||||
@ -110,7 +112,12 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
|
||||
public function start() : void{
|
||||
$this->server->getTickSleeper()->addNotifier($this->sleeper, function() : void{
|
||||
while($this->eventReceiver->handle($this));
|
||||
Timings::$connection->startTiming();
|
||||
try{
|
||||
while($this->eventReceiver->handle($this));
|
||||
}finally{
|
||||
Timings::$connection->stopTiming();
|
||||
}
|
||||
});
|
||||
$this->server->getLogger()->debug("Waiting for RakLib to start...");
|
||||
try{
|
||||
|
@ -2448,7 +2448,7 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$this->cursorInventory = new PlayerCursorInventory($this);
|
||||
$this->craftingGrid = new PlayerCraftingInventory($this);
|
||||
|
||||
$this->addPermanentInventories($this->inventory, $this->armorInventory, $this->cursorInventory, $this->offHandInventory);
|
||||
$this->addPermanentInventories($this->inventory, $this->armorInventory, $this->cursorInventory, $this->offHandInventory, $this->craftingGrid);
|
||||
|
||||
//TODO: more windows
|
||||
}
|
||||
|
@ -41,6 +41,8 @@ abstract class Timings{
|
||||
/** @var TimingsHandler */
|
||||
public static $serverTick;
|
||||
/** @var TimingsHandler */
|
||||
public static $serverInterrupts;
|
||||
/** @var TimingsHandler */
|
||||
public static $memoryManager;
|
||||
/** @var TimingsHandler */
|
||||
public static $garbageCollector;
|
||||
@ -140,7 +142,8 @@ abstract class Timings{
|
||||
self::$initialized = true;
|
||||
|
||||
self::$fullTick = new TimingsHandler("Full Server Tick");
|
||||
self::$serverTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Full Server Tick", self::$fullTick);
|
||||
self::$serverTick = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Server Tick Update Cycle", self::$fullTick);
|
||||
self::$serverInterrupts = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Server Mid-Tick Processing", self::$fullTick);
|
||||
self::$memoryManager = new TimingsHandler("Memory Manager");
|
||||
self::$garbageCollector = new TimingsHandler("Garbage Collector", self::$memoryManager);
|
||||
self::$titleTick = new TimingsHandler("Console Title Tick");
|
||||
|
@ -58,6 +58,7 @@ use pocketmine\item\StringToItemParser;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
@ -1222,7 +1223,8 @@ class World implements ChunkManager{
|
||||
private function tickChunk(int $chunkX, int $chunkZ) : void{
|
||||
$chunk = $this->getChunk($chunkX, $chunkZ);
|
||||
if($chunk === null){
|
||||
throw new \InvalidArgumentException("Chunk is not loaded");
|
||||
//the chunk may have been unloaded during a previous chunk's update (e.g. during BlockGrowEvent)
|
||||
return;
|
||||
}
|
||||
foreach($this->getChunkEntities($chunkX, $chunkZ) as $entity){
|
||||
$entity->onRandomUpdate();
|
||||
@ -1320,7 +1322,9 @@ class World implements ChunkManager{
|
||||
|
||||
/**
|
||||
* Notify the blocks at and around the position that the block at the position may have changed.
|
||||
* This will cause onNeighbourBlockUpdate() to be called for these blocks.
|
||||
* This will cause onNearbyBlockChange() to be called for these blocks.
|
||||
*
|
||||
* @see Block::onNearbyBlockChange()
|
||||
*/
|
||||
public function notifyNeighbourBlockUpdate(Vector3 $pos) : void{
|
||||
$this->tryAddToNeighbourUpdateQueue($pos);
|
||||
@ -1952,6 +1956,10 @@ class World implements ChunkManager{
|
||||
|
||||
if($hand->canBePlacedAt($blockClicked, $clickVector, $face, true)){
|
||||
$blockReplace = $blockClicked;
|
||||
//TODO: while this mimics the vanilla behaviour with replaceable blocks, we should really pass some other
|
||||
//value like NULL and let place() deal with it. This will look like a bug to anyone who doesn't know about
|
||||
//the vanilla behaviour.
|
||||
$face = Facing::UP;
|
||||
$hand->position($this, $blockReplace->getPosition()->x, $blockReplace->getPosition()->y, $blockReplace->getPosition()->z);
|
||||
}elseif(!$hand->canBePlacedAt($blockReplace, $clickVector, $face, false)){
|
||||
return false;
|
||||
|
@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\handler;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class StupidJsonDecodeTest extends TestCase{
|
||||
/**
|
||||
* @var \Closure
|
||||
* @phpstan-var \Closure(string $json, bool $assoc=) : mixed
|
||||
*/
|
||||
private $stupidJsonDecodeFunc;
|
||||
|
||||
public function setUp() : void{
|
||||
$this->stupidJsonDecodeFunc = (new \ReflectionMethod(InGamePacketHandler::class, 'stupid_json_decode'))->getClosure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[][]
|
||||
* @phpstan-return list<array{string,mixed}>
|
||||
*/
|
||||
public function stupidJsonDecodeProvider() : array{
|
||||
return [
|
||||
["[\n \"a\",\"b,c,d,e\\\" \",,0,1,2, false, 0.001]", ['a', 'b,c,d,e" ', '', 0, 1, 2, false, 0.001]],
|
||||
["0", 0],
|
||||
["false", false],
|
||||
["null", null],
|
||||
['["\",,\"word","a\",,\"word2",]', ['",,"word', 'a",,"word2', '']],
|
||||
['["\",,\"word","a\",,\"word2",""]', ['",,"word', 'a",,"word2', '']],
|
||||
['["Hello,, PocketMine"]', ['Hello,, PocketMine']],
|
||||
['[,]', ['', '']],
|
||||
['[]', []]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider stupidJsonDecodeProvider
|
||||
*
|
||||
* @param mixed $expect
|
||||
*
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function testStupidJsonDecode(string $brokenJson, $expect) : void{
|
||||
$decoded = ($this->stupidJsonDecodeFunc)($brokenJson, true);
|
||||
self::assertEquals($expect, $decoded);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user