mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 19:02:59 +00:00
Compare commits
65 Commits
4.13.0
...
4.16.0-BET
Author | SHA1 | Date | |
---|---|---|---|
a39f61a33d | |||
aaec21f544 | |||
0fcd2e7894 | |||
369e0855a7 | |||
a6cf39b94e | |||
17afd38274 | |||
8f024cb382 | |||
e7209679fb | |||
da054736b1 | |||
d92173cded | |||
308cdb6863 | |||
ae50b952f1 | |||
f44946cb49 | |||
f704bfb63a | |||
9acb4d64db | |||
8234360c8d | |||
6a64486f55 | |||
6ec778d0af | |||
75bb4f8da6 | |||
efdd7a186d | |||
c4ecb3d128 | |||
b574d49d36 | |||
47e9ecd257 | |||
799739fe86 | |||
59a04c971f | |||
168af31fd7 | |||
871bd169a8 | |||
4dbcd714bd | |||
d5e92b4ae6 | |||
2a3288c4f9 | |||
9cdb641936 | |||
b56b35b10d | |||
324bc27b5a | |||
71aad310c6 | |||
38828e2b42 | |||
9a6d7b505c | |||
1e3b025916 | |||
396d64c60b | |||
d7a0f5362e | |||
c5dcd268ad | |||
910c4c4b24 | |||
2fd6e769e6 | |||
69155015c9 | |||
6854830b6e | |||
2c413768a5 | |||
fbaf8e3fc8 | |||
c62845e92a | |||
c7930ce9ec | |||
475888b031 | |||
40b90bb722 | |||
5a4550a4fc | |||
7bbc04e6de | |||
3ba662f64f | |||
5d7b99daf4 | |||
e47627f565 | |||
39207c7992 | |||
41ab698f93 | |||
e45a6d8311 | |||
8912a97be7 | |||
8d2a9ce67c | |||
811352e2ef | |||
981385cf4a | |||
cfa1e7486a | |||
3c46bf01c6 | |||
4562cfb85b |
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.3.0
|
||||
uses: docker/build-push-action@v4.0.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.3.0
|
||||
uses: docker/build-push-action@v4.0.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.3.0
|
||||
uses: docker/build-push-action@v4.0.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.3.0
|
||||
uses: docker/build-push-action@v4.0.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
3
.github/workflows/main.yml
vendored
3
.github/workflows/main.yml
vendored
@ -186,6 +186,9 @@ jobs:
|
||||
- name: Regenerate KnownTranslation APIs
|
||||
run: php build/generate-known-translation-apis.php
|
||||
|
||||
- name: Regenerate BedrockData available files constants
|
||||
run: php build/generate-bedrockdata-path-consts.php
|
||||
|
||||
- name: Verify code is unchanged
|
||||
run: |
|
||||
git diff
|
||||
|
128
build/generate-bedrockdata-path-consts.php
Normal file
128
build/generate-bedrockdata-path-consts.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?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\build\generate_bedrockdata_path_consts;
|
||||
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function dirname;
|
||||
use function fclose;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function is_file;
|
||||
use function scandir;
|
||||
use function str_replace;
|
||||
use function strtoupper;
|
||||
use const PHP_EOL;
|
||||
use const pocketmine\BEDROCK_DATA_PATH;
|
||||
use const SCANDIR_SORT_ASCENDING;
|
||||
use const STDERR;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
function constantify(string $permissionName) : string{
|
||||
return strtoupper(str_replace([".", "-"], "_", $permissionName));
|
||||
}
|
||||
|
||||
$files = scandir(BEDROCK_DATA_PATH, SCANDIR_SORT_ASCENDING);
|
||||
if($files === false){
|
||||
fwrite(STDERR, "Couldn't find any files in " . BEDROCK_DATA_PATH . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$consts = [];
|
||||
|
||||
foreach($files as $file){
|
||||
if($file === '.' || $file === '..'){
|
||||
continue;
|
||||
}
|
||||
if($file[0] === '.'){
|
||||
continue;
|
||||
}
|
||||
$path = Path::join(BEDROCK_DATA_PATH, $file);
|
||||
if(!is_file($path)){
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach([
|
||||
'README.md',
|
||||
'LICENSE',
|
||||
'composer.json',
|
||||
] as $ignored){
|
||||
if($file === $ignored){
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
$consts[] = $file;
|
||||
}
|
||||
|
||||
$output = fopen(dirname(__DIR__) . '/src/data/bedrock/BedrockDataFiles.php', 'wb');
|
||||
if($output === false){
|
||||
fwrite(STDERR, "Couldn't open output file" . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
fwrite($output, <<<'HEADER'
|
||||
<?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\data\bedrock;
|
||||
|
||||
use const pocketmine\BEDROCK_DATA_PATH;
|
||||
|
||||
final class BedrockDataFiles{
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
|
||||
HEADER
|
||||
);
|
||||
|
||||
foreach($consts as $constName => $fileName){
|
||||
fwrite($output, "\tpublic const " . constantify($fileName) . " = BEDROCK_DATA_PATH . '/$fileName';\n");
|
||||
}
|
||||
|
||||
fwrite($output, "}\n");
|
||||
fclose($output);
|
||||
|
||||
echo "Done. Don't forget to run CS fixup after generating code.\n";
|
Submodule build/php updated: c6585061ca...b2207cf70d
21
changelogs/4.14.md
Normal file
21
changelogs/4.14.md
Normal file
@ -0,0 +1,21 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.60**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.14.0
|
||||
Released 8th February 2023.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.60.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.14.1
|
||||
Released 15th February 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed all players getting kicked with `Receiving packets too fast` if a server tick takes longer than 5 seconds (e.g. because of autosave or GC).
|
||||
- Fixed players getting kicked when linking with entities.
|
31
changelogs/4.15.md
Normal file
31
changelogs/4.15.md
Normal file
@ -0,0 +1,31 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.62**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.15.0
|
||||
Released 17th February 2023.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.62.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.15.1
|
||||
Released 21st February 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed dropped items not despawning when in non-ticking chunks.
|
||||
- Fixed dropped items not despawning if an infinite pickup delay is set.
|
||||
- Fixed infinite despawn delay (never despawn) being ignored for dropped items.
|
||||
|
||||
# 4.15.2
|
||||
Released 24th February 2023.
|
||||
|
||||
## General
|
||||
- Accept Minecraft: Bedrock Edition 1.19.63 (identical protocol to 1.19.62, but different version due to Mojang mixup).
|
||||
|
||||
## Fixes
|
||||
- Fixed `World Population` timer sometimes not being stopped, causing strange results in timings reports.
|
37
changelogs/4.16-beta.md
Normal file
37
changelogs/4.16-beta.md
Normal file
@ -0,0 +1,37 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.62**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.16.0-BETA1
|
||||
## General
|
||||
- Added granular timings for packet encode, similar to the existing timings for packet decode.
|
||||
- Timings now covers several areas of the network system which were previously not counted by network timings, but were counted by total timings. This provides a better insight into the performance of the network system.
|
||||
|
||||
## Performance
|
||||
- Improved performance of packet batch handling by avoiding unnecessary object allocations.
|
||||
- Improved performance of packet broadcasting when the broadcast size is below the batch threshold. Previously, the packets would be encoded once by every recipient, but now they are encoded once and then added to the send buffer of each session in their raw form.
|
||||
- This change mostly affects servers with larger maps, where players are more widely distributed.
|
||||
|
||||
## Build system
|
||||
- Added a new script `build/generate-bedrockdata-path-consts.php`, which must be run whenever BedrockData is updated. This script generates a class of constants with the file paths of all BedrockData files.
|
||||
|
||||
## API
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Entity->getGravity() : float` - returns the entity's gravity acceleration in blocks/tick^2
|
||||
- `public Entity->setGravity(float $gravity) : void` - sets the entity's gravity acceleration in blocks/tick^2
|
||||
|
||||
## Internals
|
||||
- Now uses [`pocketmine/bedrock-data` 2.0.0](https://github.com/pmmp/BedrockData/releases/tag/2.0.0+bedrock-1.19.60).
|
||||
- This version is now used by both PM4 and PM5, reducing maintenance burden.
|
||||
- Now uses [`pocketmine/bedrock-protocol` 19.3.0](https://github.com/pmmp/BedrockProtocol/releases/tag/19.3.0+bedrock-1.19.62).
|
||||
- This version provides new APIs for handling packet batches which enabled improving performance and adding new features, such as detailed packet encode timings.
|
||||
- Crafting recipes and creative inventory data are now loaded from `recipes/legacy_recipes.json` and `recipes/legacy_creativeitems.json` respectively. Previously, these were loaded from BedrockData directly, but BedrockData 2.0 now uses a format which can't be supported in 4.x without BC breaks.
|
||||
- Added dependencies on [`pocketmine/bedrock-block-upgrade-schema`](https://github.com/pmmp/BedrockBlockUpgradeSchema) and [`pocketmine/bedrock-item-upgrade-schema`](https://github.com/pmmp/BedrockItemUpgradeSchema). These provide mapping files no longer present in BedrockData 2.0.
|
||||
- Reduced and/or eliminated most usages of `PacketBatch`, since it only appeared as a throwaway object and was therefore wasting performance.
|
||||
- `Compressor` now exposes `getCompressionThreshold()` instead of `willCompress()`, which allows determining whether a batch will be compressed without allocating it.
|
||||
- Added `pocketmine\data\bedrock\BedrockDataFiles`, an auto-generated class of constants with the file paths of all BedrockData files. This makes it easier to locate usages, detect unused files and avoid typos.
|
@ -34,8 +34,10 @@
|
||||
"adhocore/json-comment": "^1.1",
|
||||
"fgrosse/phpasn1": "^2.3",
|
||||
"netresearch/jsonmapper": "^4.0",
|
||||
"pocketmine/bedrock-data": "~1.13.0+bedrock-1.19.50",
|
||||
"pocketmine/bedrock-protocol": "~18.1.0+bedrock-1.19.50",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "^1.0.0",
|
||||
"pocketmine/bedrock-data": "~2.0.0+bedrock-1.19.60",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "^1.0.0",
|
||||
"pocketmine/bedrock-protocol": "~19.3.0+bedrock-1.19.62",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/classloader": "^0.2.0",
|
||||
@ -54,7 +56,7 @@
|
||||
"webmozart/path-util": "^2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.9.14",
|
||||
"phpstan/phpstan": "1.10.3",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
|
205
composer.lock
generated
205
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": "2c0f273b515174abfdcef4fc4ad3c262",
|
||||
"content-hash": "e771a9cf116389fef15848801d410c36",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -249,17 +249,43 @@
|
||||
"time": "2022-12-08T20:46:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-data",
|
||||
"version": "1.13.0+bedrock-1.19.50",
|
||||
"name": "pocketmine/bedrock-block-upgrade-schema",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "57337ddc9433a0e245a1ce48c51af05f0573d58d"
|
||||
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
|
||||
"reference": "a05ce434eb7f8c11058d26833bc975fe635b23b4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/57337ddc9433a0e245a1ce48c51af05f0573d58d",
|
||||
"reference": "57337ddc9433a0e245a1ce48c51af05f0573d58d",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/a05ce434eb7f8c11058d26833bc975fe635b23b4",
|
||||
"reference": "a05ce434eb7f8c11058d26833bc975fe635b23b4",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"CC0-1.0"
|
||||
],
|
||||
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
|
||||
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/1.0.0"
|
||||
},
|
||||
"time": "2023-02-01T21:09:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-data",
|
||||
"version": "2.0.0+bedrock-1.19.60",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "957e49b2381641af29f595e4f32ded3e76ce4723"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/957e49b2381641af29f595e4f32ded3e76ce4723",
|
||||
"reference": "957e49b2381641af29f595e4f32ded3e76ce4723",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -270,22 +296,48 @@
|
||||
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockData/issues",
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.19.50"
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/2.0.0+bedrock-1.19.60"
|
||||
},
|
||||
"time": "2022-11-30T16:19:59+00:00"
|
||||
"time": "2023-02-23T21:25:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "18.1.0+bedrock-1.19.50",
|
||||
"name": "pocketmine/bedrock-item-upgrade-schema",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "c34f22847a1cc362a3f1c45698576d30d1e8392f"
|
||||
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
|
||||
"reference": "7e53f77ea34ba30b1f94d3c24e64e19d3c4296e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/c34f22847a1cc362a3f1c45698576d30d1e8392f",
|
||||
"reference": "c34f22847a1cc362a3f1c45698576d30d1e8392f",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/7e53f77ea34ba30b1f94d3c24e64e19d3c4296e7",
|
||||
"reference": "7e53f77ea34ba30b1f94d3c24e64e19d3c4296e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"CC0-1.0"
|
||||
],
|
||||
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
|
||||
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.0.0"
|
||||
},
|
||||
"time": "2023-02-01T22:50:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "19.3.0+bedrock-1.19.62",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "a5bf4753c7f30f781c4541918e238f5bb637e7ad"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/a5bf4753c7f30f781c4541918e238f5bb637e7ad",
|
||||
"reference": "a5bf4753c7f30f781c4541918e238f5bb637e7ad",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -317,9 +369,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/18.1.0+bedrock-1.19.50"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/19.3.0+bedrock-1.19.62"
|
||||
},
|
||||
"time": "2023-01-20T12:35:30+00:00"
|
||||
"time": "2023-02-19T16:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -1034,16 +1086,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v5.4.19",
|
||||
"version": "v5.4.21",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "648bfaca6a494f3e22378123bcee2894045dc9d8"
|
||||
"reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/648bfaca6a494f3e22378123bcee2894045dc9d8",
|
||||
"reference": "648bfaca6a494f3e22378123bcee2894045dc9d8",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/e75960b1bbfd2b8c9e483e0d74811d555ca3de9f",
|
||||
"reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1078,7 +1130,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v5.4.19"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v5.4.21"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1094,7 +1146,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-14T19:14:44+00:00"
|
||||
"time": "2023-02-14T08:03:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
@ -1832,16 +1884,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.9.14",
|
||||
"version": "1.10.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "e5fcc96289cf737304286a9b505fbed091f02e58"
|
||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5fcc96289cf737304286a9b505fbed091f02e58",
|
||||
"reference": "e5fcc96289cf737304286a9b505fbed091f02e58",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/5419375b5891add97dc74be71e6c1c34baaddf64",
|
||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1871,7 +1923,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.9.14"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.10.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1887,25 +1939,25 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-19T10:47:09+00:00"
|
||||
"time": "2023-02-25T14:47:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "1.3.3",
|
||||
"version": "1.3.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7"
|
||||
"reference": "34ee324a2b8fcab680fbb3f3f3d6c86389df35ba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/54a24bd23e9e80ee918cdc24f909d376c2e273f7",
|
||||
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/34ee324a2b8fcab680fbb3f3f3d6c86389df35ba",
|
||||
"reference": "34ee324a2b8fcab680fbb3f3f3d6c86389df35ba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpstan": "^1.9.3"
|
||||
"phpstan/phpstan": "^1.10"
|
||||
},
|
||||
"conflict": {
|
||||
"phpunit/phpunit": "<7.0"
|
||||
@ -1937,31 +1989,32 @@
|
||||
"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.3"
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.9"
|
||||
},
|
||||
"time": "2022-12-21T15:25:00+00:00"
|
||||
"time": "2023-02-28T13:04:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
"version": "1.4.5",
|
||||
"version": "1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d"
|
||||
"reference": "b7dd96a5503919a43b3cd06a2dced9d4252492f2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d",
|
||||
"reference": "361f75b06066f3fdaba87c1f57bdb1ffc28d6f1d",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/b7dd96a5503919a43b3cd06a2dced9d4252492f2",
|
||||
"reference": "b7dd96a5503919a43b3cd06a2dced9d4252492f2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpstan": "^1.9.7"
|
||||
"phpstan/phpstan": "^1.10"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
@ -1985,29 +2038,29 @@
|
||||
"description": "Extra strict and opinionated rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.4.5"
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.0"
|
||||
},
|
||||
"time": "2023-01-11T14:16:29+00:00"
|
||||
"time": "2023-02-21T10:17:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.24",
|
||||
"version": "9.2.25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "2cf940ebc6355a9d430462811b5aaa308b174bed"
|
||||
"reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed",
|
||||
"reference": "2cf940ebc6355a9d430462811b5aaa308b174bed",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e2b40518197a8c0d4b08bc34dfff1c99c508954",
|
||||
"reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^4.14",
|
||||
"nikic/php-parser": "^4.15",
|
||||
"php": ">=7.3",
|
||||
"phpunit/php-file-iterator": "^3.0.3",
|
||||
"phpunit/php-text-template": "^2.0.2",
|
||||
@ -2056,7 +2109,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.25"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2064,7 +2117,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-26T08:26:55+00:00"
|
||||
"time": "2023-02-25T05:32:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -2309,16 +2362,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.5.28",
|
||||
"version": "9.6.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "954ca3113a03bf780d22f07bf055d883ee04b65e"
|
||||
"reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/954ca3113a03bf780d22f07bf055d883ee04b65e",
|
||||
"reference": "954ca3113a03bf780d22f07bf055d883ee04b65e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9125ee085b6d95e78277dc07aa1f46f9e0607b8d",
|
||||
"reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2360,7 +2413,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "9.5-dev"
|
||||
"dev-master": "9.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -2391,7 +2444,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.28"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2407,7 +2460,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-14T12:32:24+00:00"
|
||||
"time": "2023-02-27T13:06:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@ -2775,16 +2828,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "5.1.4",
|
||||
"version": "5.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7"
|
||||
"reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7",
|
||||
"reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
|
||||
"reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2826,7 +2879,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/environment/issues",
|
||||
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.4"
|
||||
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2834,7 +2887,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-04-03T09:37:03+00:00"
|
||||
"time": "2023-02-03T06:03:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
@ -3148,16 +3201,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/recursion-context",
|
||||
"version": "4.0.4",
|
||||
"version": "4.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/recursion-context.git",
|
||||
"reference": "cd9d8cf3c5804de4341c283ed787f099f5506172"
|
||||
"reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172",
|
||||
"reference": "cd9d8cf3c5804de4341c283ed787f099f5506172",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
|
||||
"reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3196,10 +3249,10 @@
|
||||
}
|
||||
],
|
||||
"description": "Provides functionality to recursively process PHP variables",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
||||
"homepage": "https://github.com/sebastianbergmann/recursion-context",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
|
||||
"source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4"
|
||||
"source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -3207,7 +3260,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-26T13:17:30+00:00"
|
||||
"time": "2023-02-03T06:07:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/resource-operations",
|
||||
@ -3266,16 +3319,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/type",
|
||||
"version": "3.2.0",
|
||||
"version": "3.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/type.git",
|
||||
"reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e"
|
||||
"reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e",
|
||||
"reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
|
||||
"reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -3310,7 +3363,7 @@
|
||||
"homepage": "https://github.com/sebastianbergmann/type",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/type/issues",
|
||||
"source": "https://github.com/sebastianbergmann/type/tree/3.2.0"
|
||||
"source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -3318,7 +3371,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-09-12T14:47:03+00:00"
|
||||
"time": "2023-02-03T06:13:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
|
4898
resources/legacy_creativeitems.json
Normal file
4898
resources/legacy_creativeitems.json
Normal file
File diff suppressed because it is too large
Load Diff
49988
resources/legacy_recipes.json
Normal file
49988
resources/legacy_recipes.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -37,4 +37,6 @@ define('pocketmine\PATH', dirname(__DIR__) . '/');
|
||||
define('pocketmine\RESOURCE_PATH', dirname(__DIR__) . '/resources/');
|
||||
define('pocketmine\BEDROCK_DATA_PATH', dirname(__DIR__) . '/vendor/pocketmine/bedrock-data/');
|
||||
define('pocketmine\LOCALE_DATA_PATH', dirname(__DIR__) . '/vendor/pocketmine/locale-data/');
|
||||
define('pocketmine\BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH', dirname(__DIR__) . '/vendor/pocketmine/bedrock-block-upgrade-schema/');
|
||||
define('pocketmine\BEDROCK_ITEM_UPGRADE_SCHEMA_PATH', dirname(__DIR__) . '/vendor/pocketmine/bedrock-item-upgrade-schema/');
|
||||
define('pocketmine\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__) . '/vendor/autoload.php');
|
||||
|
@ -891,6 +891,9 @@ class Server{
|
||||
if($this->configGroup->getPropertyInt("network.batch-threshold", 256) >= 0){
|
||||
$netCompressionThreshold = $this->configGroup->getPropertyInt("network.batch-threshold", 256);
|
||||
}
|
||||
if($netCompressionThreshold < 0){
|
||||
$netCompressionThreshold = null;
|
||||
}
|
||||
|
||||
$netCompressionLevel = $this->configGroup->getPropertyInt("network.compression-level", 6);
|
||||
if($netCompressionLevel < 1 || $netCompressionLevel > 9){
|
||||
@ -959,7 +962,7 @@ class Server{
|
||||
|
||||
$this->commandMap = new SimpleCommandMap($this);
|
||||
|
||||
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes.json"));
|
||||
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\RESOURCE_PATH, "legacy_recipes.json"));
|
||||
|
||||
$this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger);
|
||||
|
||||
@ -1385,7 +1388,8 @@ class Server{
|
||||
$buffer = $stream->getBuffer();
|
||||
|
||||
if($sync === null){
|
||||
$sync = !($this->networkCompressionAsync && $compressor->willCompress($buffer));
|
||||
$threshold = $compressor->getCompressionThreshold();
|
||||
$sync = !$this->networkCompressionAsync || $threshold === null || strlen($stream->getBuffer()) < $threshold;
|
||||
}
|
||||
|
||||
$promise = new CompressBatchPromise();
|
||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "4.13.0";
|
||||
public const BASE_VERSION = "4.16.0-BETA1";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
50
src/data/bedrock/BedrockDataFiles.php
Normal file
50
src/data/bedrock/BedrockDataFiles.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\bedrock;
|
||||
|
||||
use const pocketmine\BEDROCK_DATA_PATH;
|
||||
|
||||
final class BedrockDataFiles{
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
public const BANNER_PATTERNS_JSON = BEDROCK_DATA_PATH . '/banner_patterns.json';
|
||||
public const BIOME_DEFINITIONS_NBT = BEDROCK_DATA_PATH . '/biome_definitions.nbt';
|
||||
public const BIOME_DEFINITIONS_FULL_NBT = BEDROCK_DATA_PATH . '/biome_definitions_full.nbt';
|
||||
public const BIOME_ID_MAP_JSON = BEDROCK_DATA_PATH . '/biome_id_map.json';
|
||||
public const BLOCK_ID_TO_ITEM_ID_MAP_JSON = BEDROCK_DATA_PATH . '/block_id_to_item_id_map.json';
|
||||
public const BLOCK_STATE_META_MAP_JSON = BEDROCK_DATA_PATH . '/block_state_meta_map.json';
|
||||
public const CANONICAL_BLOCK_STATES_NBT = BEDROCK_DATA_PATH . '/canonical_block_states.nbt';
|
||||
public const COMMAND_ARG_TYPES_JSON = BEDROCK_DATA_PATH . '/command_arg_types.json';
|
||||
public const CREATIVEITEMS_JSON = BEDROCK_DATA_PATH . '/creativeitems.json';
|
||||
public const ENTITY_ID_MAP_JSON = BEDROCK_DATA_PATH . '/entity_id_map.json';
|
||||
public const ENTITY_IDENTIFIERS_NBT = BEDROCK_DATA_PATH . '/entity_identifiers.nbt';
|
||||
public const ITEM_TAGS_JSON = BEDROCK_DATA_PATH . '/item_tags.json';
|
||||
public const LEVEL_SOUND_ID_MAP_JSON = BEDROCK_DATA_PATH . '/level_sound_id_map.json';
|
||||
public const PARTICLE_ID_MAP_JSON = BEDROCK_DATA_PATH . '/particle_id_map.json';
|
||||
public const R12_TO_CURRENT_BLOCK_MAP_BIN = BEDROCK_DATA_PATH . '/r12_to_current_block_map.bin';
|
||||
public const R16_TO_CURRENT_ITEM_MAP_JSON = BEDROCK_DATA_PATH . '/r16_to_current_item_map.json';
|
||||
public const REQUIRED_ITEM_LIST_JSON = BEDROCK_DATA_PATH . '/required_item_list.json';
|
||||
}
|
@ -24,12 +24,11 @@ declare(strict_types=1);
|
||||
namespace pocketmine\data\bedrock;
|
||||
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
|
||||
final class LegacyBiomeIdToStringIdMap extends LegacyToStringBidirectionalIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'biome_id_map.json'));
|
||||
parent::__construct(BedrockDataFiles::BIOME_ID_MAP_JSON);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,6 @@ final class LegacyBlockIdToStringIdMap extends LegacyToStringBidirectionalIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'block_id_map.json'));
|
||||
parent::__construct(Path::join(\pocketmine\BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH, 'block_legacy_id_map.json'));
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,11 @@ declare(strict_types=1);
|
||||
namespace pocketmine\data\bedrock;
|
||||
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
|
||||
final class LegacyEntityIdToStringIdMap extends LegacyToStringBidirectionalIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'entity_id_map.json'));
|
||||
parent::__construct(BedrockDataFiles::ENTITY_ID_MAP_JSON);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,6 @@ final class LegacyItemIdToStringIdMap extends LegacyToStringBidirectionalIdMap{
|
||||
use SingletonTrait;
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'item_id_map.json'));
|
||||
parent::__construct(Path::join(\pocketmine\BEDROCK_ITEM_UPGRADE_SCHEMA_PATH, 'item_legacy_id_map.json'));
|
||||
}
|
||||
}
|
||||
|
@ -803,6 +803,15 @@ abstract class Entity{
|
||||
$this->server->broadcastPackets($this->hasSpawned, [SetActorMotionPacket::create($this->id, $this->getMotion())]);
|
||||
}
|
||||
|
||||
public function getGravity() : float{
|
||||
return $this->gravity;
|
||||
}
|
||||
|
||||
public function setGravity(float $gravity) : void{
|
||||
Utils::checkFloatNotInfOrNaN("gravity", $gravity);
|
||||
$this->gravity = $gravity;
|
||||
}
|
||||
|
||||
public function hasGravity() : bool{
|
||||
return $this->gravityEnabled;
|
||||
}
|
||||
|
@ -50,6 +50,8 @@ use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\AbilitiesData;
|
||||
use pocketmine\network\mcpe\protocol\types\AbilitiesLayer;
|
||||
use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\DeviceOS;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||
@ -60,7 +62,6 @@ use pocketmine\network\mcpe\protocol\types\GameMode;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\UpdateAbilitiesPacketLayer;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Limits;
|
||||
@ -507,14 +508,14 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
GameMode::SURVIVAL,
|
||||
$this->getAllNetworkData(),
|
||||
new PropertySyncData([], []),
|
||||
UpdateAbilitiesPacket::create(CommandPermissions::NORMAL, PlayerPermissions::VISITOR, $this->getId() /* TODO: this should be unique ID */, [
|
||||
new UpdateAbilitiesPacketLayer(
|
||||
UpdateAbilitiesPacketLayer::LAYER_BASE,
|
||||
array_fill(0, UpdateAbilitiesPacketLayer::NUMBER_OF_ABILITIES, false),
|
||||
UpdateAbilitiesPacket::create(new AbilitiesData(CommandPermissions::NORMAL, PlayerPermissions::VISITOR, $this->getId() /* TODO: this should be unique ID */, [
|
||||
new AbilitiesLayer(
|
||||
AbilitiesLayer::LAYER_BASE,
|
||||
array_fill(0, AbilitiesLayer::NUMBER_OF_ABILITIES, false),
|
||||
0.0,
|
||||
0.0
|
||||
)
|
||||
]),
|
||||
])),
|
||||
[], //TODO: entity links
|
||||
"", //device ID (we intentionally don't send this - secvuln)
|
||||
DeviceOS::UNKNOWN //we intentionally don't send this (secvuln)
|
||||
|
@ -113,33 +113,42 @@ class ItemEntity extends Entity{
|
||||
|
||||
$hasUpdate = parent::entityBaseTick($tickDiff);
|
||||
|
||||
if(!$this->isFlaggedForDespawn() && $this->pickupDelay !== self::NEVER_DESPAWN){ //Infinite delay
|
||||
if($this->isFlaggedForDespawn()){
|
||||
return $hasUpdate;
|
||||
}
|
||||
|
||||
if($this->pickupDelay !== self::NEVER_DESPAWN && $this->pickupDelay > 0){ //Infinite delay
|
||||
$hasUpdate = true;
|
||||
$this->pickupDelay -= $tickDiff;
|
||||
if($this->pickupDelay < 0){
|
||||
$this->pickupDelay = 0;
|
||||
}
|
||||
if($this->hasMovementUpdate() && $this->despawnDelay % self::MERGE_CHECK_PERIOD === 0){
|
||||
$mergeable = [$this]; //in case the merge target ends up not being this
|
||||
$mergeTarget = $this;
|
||||
foreach($this->getWorld()->getNearbyEntities($this->boundingBox->expandedCopy(0.5, 0.5, 0.5), $this) as $entity){
|
||||
if(!$entity instanceof ItemEntity || $entity->isFlaggedForDespawn()){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if($entity->isMergeable($this)){
|
||||
$mergeable[] = $entity;
|
||||
if($entity->item->getCount() > $mergeTarget->item->getCount()){
|
||||
$mergeTarget = $entity;
|
||||
}
|
||||
}
|
||||
if($this->hasMovementUpdate() && $this->despawnDelay % self::MERGE_CHECK_PERIOD === 0){
|
||||
$mergeable = [$this]; //in case the merge target ends up not being this
|
||||
$mergeTarget = $this;
|
||||
foreach($this->getWorld()->getNearbyEntities($this->boundingBox->expandedCopy(0.5, 0.5, 0.5), $this) as $entity){
|
||||
if(!$entity instanceof ItemEntity || $entity->isFlaggedForDespawn()){
|
||||
continue;
|
||||
}
|
||||
foreach($mergeable as $itemEntity){
|
||||
if($itemEntity !== $mergeTarget){
|
||||
$itemEntity->tryMergeInto($mergeTarget);
|
||||
|
||||
if($entity->isMergeable($this)){
|
||||
$mergeable[] = $entity;
|
||||
if($entity->item->getCount() > $mergeTarget->item->getCount()){
|
||||
$mergeTarget = $entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($mergeable as $itemEntity){
|
||||
if($itemEntity !== $mergeTarget){
|
||||
$itemEntity->tryMergeInto($mergeTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!$this->isFlaggedForDespawn() && $this->despawnDelay !== self::NEVER_DESPAWN){
|
||||
$hasUpdate = true;
|
||||
$this->despawnDelay -= $tickDiff;
|
||||
if($this->despawnDelay <= 0){
|
||||
$ev = new ItemDespawnEvent($this);
|
||||
@ -148,7 +157,6 @@ class ItemEntity extends Entity{
|
||||
$this->despawnDelay = self::DEFAULT_DESPAWN_DELAY;
|
||||
}else{
|
||||
$this->flagForDespawn();
|
||||
$hasUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ final class CreativeInventory{
|
||||
private array $creative = [];
|
||||
|
||||
private function __construct(){
|
||||
$creativeItems = json_decode(Filesystem::fileGetContents(Path::join(\pocketmine\BEDROCK_DATA_PATH, "creativeitems.json")), true);
|
||||
$creativeItems = json_decode(Filesystem::fileGetContents(Path::join(\pocketmine\RESOURCE_PATH, "legacy_creativeitems.json")), true);
|
||||
|
||||
foreach($creativeItems as $data){
|
||||
$item = Item::jsonDeserialize($data);
|
||||
|
@ -33,6 +33,7 @@ use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\types\ChunkPosition;
|
||||
use pocketmine\network\mcpe\serializer\ChunkSerializer;
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use pocketmine\world\format\Chunk;
|
||||
use pocketmine\world\format\io\FastChunkSerializer;
|
||||
|
||||
@ -72,7 +73,10 @@ class ChunkRequestTask extends AsyncTask{
|
||||
$subCount = ChunkSerializer::getSubChunkCount($chunk) + ChunkSerializer::LOWER_PADDING_SIZE;
|
||||
$encoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
|
||||
$payload = ChunkSerializer::serializeFullChunk($chunk, RuntimeBlockMapping::getInstance(), $encoderContext, $this->tiles);
|
||||
$this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $subCount, false, null, $payload))->getBuffer()));
|
||||
|
||||
$stream = new BinaryStream();
|
||||
PacketBatch::encodePackets($stream, $encoderContext, [LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $subCount, false, null, $payload)]);
|
||||
$this->setResult($this->compressor->compress($stream->getBuffer()));
|
||||
}
|
||||
|
||||
public function onError() : void{
|
||||
|
@ -90,6 +90,8 @@ use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
|
||||
use pocketmine\network\mcpe\protocol\TextPacket;
|
||||
use pocketmine\network\mcpe\protocol\ToastRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\TransferPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\AbilitiesData;
|
||||
use pocketmine\network\mcpe\protocol\types\AbilitiesLayer;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\command\CommandData;
|
||||
use pocketmine\network\mcpe\protocol\types\command\CommandEnum;
|
||||
@ -103,7 +105,6 @@ use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\UpdateAbilitiesPacketLayer;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
|
||||
@ -119,6 +120,7 @@ use pocketmine\player\XboxLivePlayerInfo;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use pocketmine\utils\ObjectSet;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
@ -128,7 +130,6 @@ 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;
|
||||
@ -142,7 +143,6 @@ 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;
|
||||
|
||||
@ -177,7 +177,7 @@ class NetworkSession{
|
||||
|
||||
private ?EncryptionContext $cipher = null;
|
||||
|
||||
/** @var Packet[] */
|
||||
/** @var string[] */
|
||||
private array $sendBuffer = [];
|
||||
|
||||
/**
|
||||
@ -359,59 +359,67 @@ 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{
|
||||
$payload = $this->cipher->decrypt($payload);
|
||||
}catch(DecryptionException $e){
|
||||
$this->logger->debug("Encrypted packet: " . base64_encode($payload));
|
||||
throw PacketHandlingException::wrap($e, "Packet decryption error");
|
||||
}finally{
|
||||
Timings::$playerNetworkReceiveDecrypt->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
if($this->enableCompression){
|
||||
Timings::$playerNetworkReceiveDecompress->startTiming();
|
||||
try{
|
||||
$decompressed = $this->compressor->decompress($payload);
|
||||
}catch(DecompressionException $e){
|
||||
$this->logger->debug("Failed to decompress packet: " . base64_encode($payload));
|
||||
throw PacketHandlingException::wrap($e, "Compressed packet batch decode error");
|
||||
}finally{
|
||||
Timings::$playerNetworkReceiveDecompress->stopTiming();
|
||||
}
|
||||
}else{
|
||||
$decompressed = $payload;
|
||||
}
|
||||
|
||||
Timings::$playerNetworkReceive->startTiming();
|
||||
try{
|
||||
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");
|
||||
}
|
||||
try{
|
||||
$this->handleDataPacket($packet, $buffer);
|
||||
}catch(PacketHandlingException $e){
|
||||
$this->logger->debug($packet->getName() . ": " . base64_encode($buffer));
|
||||
throw PacketHandlingException::wrap($e, "Error processing " . $packet->getName());
|
||||
if($this->incomingPacketBatchBudget <= 0){
|
||||
$this->updatePacketBudget();
|
||||
if($this->incomingPacketBatchBudget <= 0){
|
||||
throw new PacketHandlingException("Receiving packets too fast");
|
||||
}
|
||||
}
|
||||
}catch(PacketDecodeException $e){
|
||||
$this->logger->logException($e);
|
||||
throw PacketHandlingException::wrap($e, "Packet batch decode error");
|
||||
$this->incomingPacketBatchBudget--;
|
||||
|
||||
if($this->cipher !== null){
|
||||
Timings::$playerNetworkReceiveDecrypt->startTiming();
|
||||
try{
|
||||
$payload = $this->cipher->decrypt($payload);
|
||||
}catch(DecryptionException $e){
|
||||
$this->logger->debug("Encrypted packet: " . base64_encode($payload));
|
||||
throw PacketHandlingException::wrap($e, "Packet decryption error");
|
||||
}finally{
|
||||
Timings::$playerNetworkReceiveDecrypt->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
if($this->enableCompression){
|
||||
Timings::$playerNetworkReceiveDecompress->startTiming();
|
||||
try{
|
||||
$decompressed = $this->compressor->decompress($payload);
|
||||
}catch(DecompressionException $e){
|
||||
$this->logger->debug("Failed to decompress packet: " . base64_encode($payload));
|
||||
throw PacketHandlingException::wrap($e, "Compressed packet batch decode error");
|
||||
}finally{
|
||||
Timings::$playerNetworkReceiveDecompress->stopTiming();
|
||||
}
|
||||
}else{
|
||||
$decompressed = $payload;
|
||||
}
|
||||
|
||||
try{
|
||||
$stream = new BinaryStream($decompressed);
|
||||
$count = 0;
|
||||
foreach(PacketBatch::decodeRaw($stream) as $buffer){
|
||||
if(++$count > 1300){
|
||||
throw new PacketHandlingException("Too many packets in batch");
|
||||
}
|
||||
$packet = $this->packetPool->getPacket($buffer);
|
||||
if($packet === null){
|
||||
$this->logger->debug("Unknown packet: " . base64_encode($buffer));
|
||||
throw new PacketHandlingException("Unknown packet received");
|
||||
}
|
||||
try{
|
||||
$this->handleDataPacket($packet, $buffer);
|
||||
}catch(PacketHandlingException $e){
|
||||
$this->logger->debug($packet->getName() . ": " . base64_encode($buffer));
|
||||
throw PacketHandlingException::wrap($e, "Error processing " . $packet->getName());
|
||||
}
|
||||
}
|
||||
}catch(PacketDecodeException $e){
|
||||
$this->logger->logException($e);
|
||||
throw PacketHandlingException::wrap($e, "Packet batch decode error");
|
||||
}
|
||||
}finally{
|
||||
Timings::$playerNetworkReceive->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,7 +481,7 @@ class NetworkSession{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->addToSendBuffer($packet);
|
||||
$this->addToSendBuffer(self::encodePacketTimed(PacketSerializer::encoder($this->packetSerializerContext), $packet));
|
||||
if($immediate){
|
||||
$this->flushSendBuffer(true);
|
||||
}
|
||||
@ -487,34 +495,49 @@ class NetworkSession{
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function addToSendBuffer(ClientboundPacket $packet) : void{
|
||||
$timings = Timings::getSendDataPacketTimings($packet);
|
||||
public static function encodePacketTimed(PacketSerializer $serializer, ClientboundPacket $packet) : string{
|
||||
$timings = Timings::getEncodeDataPacketTimings($packet);
|
||||
$timings->startTiming();
|
||||
try{
|
||||
$this->sendBuffer[] = $packet;
|
||||
$packet->encode($serializer);
|
||||
return $serializer->getBuffer();
|
||||
}finally{
|
||||
$timings->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function addToSendBuffer(string $buffer) : void{
|
||||
$this->sendBuffer[] = $buffer;
|
||||
}
|
||||
|
||||
private function flushSendBuffer(bool $immediate = false) : void{
|
||||
if(count($this->sendBuffer) > 0){
|
||||
$syncMode = null; //automatic
|
||||
if($immediate){
|
||||
$syncMode = true;
|
||||
}elseif($this->forceAsyncCompression){
|
||||
$syncMode = false;
|
||||
}
|
||||
Timings::$playerNetworkSend->startTiming();
|
||||
try{
|
||||
$syncMode = null; //automatic
|
||||
if($immediate){
|
||||
$syncMode = true;
|
||||
}elseif($this->forceAsyncCompression){
|
||||
$syncMode = false;
|
||||
}
|
||||
|
||||
$batch = PacketBatch::fromPackets($this->packetSerializerContext, ...$this->sendBuffer);
|
||||
if($this->enableCompression){
|
||||
$promise = $this->server->prepareBatch($batch, $this->compressor, $syncMode);
|
||||
}else{
|
||||
$promise = new CompressBatchPromise();
|
||||
$promise->resolve($batch->getBuffer());
|
||||
$stream = new BinaryStream();
|
||||
PacketBatch::encodeRaw($stream, $this->sendBuffer);
|
||||
|
||||
if($this->enableCompression){
|
||||
$promise = $this->server->prepareBatch(new PacketBatch($stream->getBuffer()), $this->compressor, $syncMode);
|
||||
}else{
|
||||
$promise = new CompressBatchPromise();
|
||||
$promise->resolve($stream->getBuffer());
|
||||
}
|
||||
$this->sendBuffer = [];
|
||||
$this->queueCompressedNoBufferFlush($promise, $immediate);
|
||||
}finally{
|
||||
Timings::$playerNetworkSend->stopTiming();
|
||||
}
|
||||
$this->sendBuffer = [];
|
||||
$this->queueCompressedNoBufferFlush($promise, $immediate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -527,35 +550,45 @@ class NetworkSession{
|
||||
}
|
||||
|
||||
public function queueCompressed(CompressBatchPromise $payload, bool $immediate = false) : void{
|
||||
$this->flushSendBuffer($immediate); //Maintain ordering if possible
|
||||
$this->queueCompressedNoBufferFlush($payload, $immediate);
|
||||
Timings::$playerNetworkSend->startTiming();
|
||||
try{
|
||||
$this->flushSendBuffer($immediate); //Maintain ordering if possible
|
||||
$this->queueCompressedNoBufferFlush($payload, $immediate);
|
||||
}finally{
|
||||
Timings::$playerNetworkSend->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
private function queueCompressedNoBufferFlush(CompressBatchPromise $payload, bool $immediate = false) : void{
|
||||
if($immediate){
|
||||
//Skips all queues
|
||||
$this->sendEncoded($payload->getResult(), true);
|
||||
}else{
|
||||
$this->compressedQueue->enqueue($payload);
|
||||
$payload->onResolve(function(CompressBatchPromise $payload) : void{
|
||||
if($this->connected && $this->compressedQueue->bottom() === $payload){
|
||||
$this->compressedQueue->dequeue(); //result unused
|
||||
$this->sendEncoded($payload->getResult());
|
||||
Timings::$playerNetworkSend->startTiming();
|
||||
try{
|
||||
if($immediate){
|
||||
//Skips all queues
|
||||
$this->sendEncoded($payload->getResult(), true);
|
||||
}else{
|
||||
$this->compressedQueue->enqueue($payload);
|
||||
$payload->onResolve(function(CompressBatchPromise $payload) : void{
|
||||
if($this->connected && $this->compressedQueue->bottom() === $payload){
|
||||
$this->compressedQueue->dequeue(); //result unused
|
||||
$this->sendEncoded($payload->getResult());
|
||||
|
||||
while(!$this->compressedQueue->isEmpty()){
|
||||
/** @var CompressBatchPromise $current */
|
||||
$current = $this->compressedQueue->bottom();
|
||||
if($current->hasResult()){
|
||||
$this->compressedQueue->dequeue();
|
||||
while(!$this->compressedQueue->isEmpty()){
|
||||
/** @var CompressBatchPromise $current */
|
||||
$current = $this->compressedQueue->bottom();
|
||||
if($current->hasResult()){
|
||||
$this->compressedQueue->dequeue();
|
||||
|
||||
$this->sendEncoded($current->getResult());
|
||||
}else{
|
||||
//can't send any more queued until this one is ready
|
||||
break;
|
||||
$this->sendEncoded($current->getResult());
|
||||
}else{
|
||||
//can't send any more queued until this one is ready
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}finally{
|
||||
Timings::$playerNetworkSend->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
@ -848,33 +881,33 @@ class NetworkSession{
|
||||
|
||||
//ALL of these need to be set for the base layer, otherwise the client will cry
|
||||
$boolAbilities = [
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ALLOW_FLIGHT => $for->getAllowFlight(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_FLYING => $for->isFlying(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_NO_CLIP => !$for->hasBlockCollision(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_OPERATOR => $isOp,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_TELEPORT => $for->hasPermission(DefaultPermissionNames::COMMAND_TELEPORT_SELF),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_INVULNERABLE => $for->isCreative(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_MUTED => false,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_WORLD_BUILDER => false,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_INFINITE_RESOURCES => !$for->hasFiniteResources(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_LIGHTNING => false,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_BUILD => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_MINE => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_DOORS_AND_SWITCHES => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_OPEN_CONTAINERS => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ATTACK_PLAYERS => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ATTACK_MOBS => !$for->isSpectator(),
|
||||
AbilitiesLayer::ABILITY_ALLOW_FLIGHT => $for->getAllowFlight(),
|
||||
AbilitiesLayer::ABILITY_FLYING => $for->isFlying(),
|
||||
AbilitiesLayer::ABILITY_NO_CLIP => !$for->hasBlockCollision(),
|
||||
AbilitiesLayer::ABILITY_OPERATOR => $isOp,
|
||||
AbilitiesLayer::ABILITY_TELEPORT => $for->hasPermission(DefaultPermissionNames::COMMAND_TELEPORT_SELF),
|
||||
AbilitiesLayer::ABILITY_INVULNERABLE => $for->isCreative(),
|
||||
AbilitiesLayer::ABILITY_MUTED => false,
|
||||
AbilitiesLayer::ABILITY_WORLD_BUILDER => false,
|
||||
AbilitiesLayer::ABILITY_INFINITE_RESOURCES => !$for->hasFiniteResources(),
|
||||
AbilitiesLayer::ABILITY_LIGHTNING => false,
|
||||
AbilitiesLayer::ABILITY_BUILD => !$for->isSpectator(),
|
||||
AbilitiesLayer::ABILITY_MINE => !$for->isSpectator(),
|
||||
AbilitiesLayer::ABILITY_DOORS_AND_SWITCHES => !$for->isSpectator(),
|
||||
AbilitiesLayer::ABILITY_OPEN_CONTAINERS => !$for->isSpectator(),
|
||||
AbilitiesLayer::ABILITY_ATTACK_PLAYERS => !$for->isSpectator(),
|
||||
AbilitiesLayer::ABILITY_ATTACK_MOBS => !$for->isSpectator(),
|
||||
];
|
||||
|
||||
$this->sendDataPacket(UpdateAbilitiesPacket::create(
|
||||
$this->sendDataPacket(UpdateAbilitiesPacket::create(new AbilitiesData(
|
||||
$isOp ? CommandPermissions::OPERATOR : CommandPermissions::NORMAL,
|
||||
$isOp ? PlayerPermissions::OPERATOR : PlayerPermissions::MEMBER,
|
||||
$for->getId(),
|
||||
[
|
||||
//TODO: dynamic flying speed! FINALLY!!!!!!!!!!!!!!!!!
|
||||
new UpdateAbilitiesPacketLayer(UpdateAbilitiesPacketLayer::LAYER_BASE, $boolAbilities, 0.05, 0.1),
|
||||
new AbilitiesLayer(AbilitiesLayer::LAYER_BASE, $boolAbilities, 0.05, 0.1),
|
||||
]
|
||||
));
|
||||
)));
|
||||
}
|
||||
|
||||
public function syncAdventureSettings() : void{
|
||||
@ -1142,6 +1175,23 @@ class NetworkSession{
|
||||
$this->sendDataPacket(ToastRequestPacket::create($title, $body));
|
||||
}
|
||||
|
||||
private function updatePacketBudget() : void{
|
||||
$nowNs = hrtime(true);
|
||||
$timeSinceLastUpdateNs = $nowNs - $this->lastPacketBudgetUpdateTimeNs;
|
||||
if($timeSinceLastUpdateNs > 50_000_000){
|
||||
$ticksSinceLastUpdate = intdiv($timeSinceLastUpdateNs, 50_000_000);
|
||||
/*
|
||||
* If the server takes an abnormally long time to process a tick, add the budget for time difference to
|
||||
* compensate. This extra budget may be very large, but it will disappear the next time a normal update
|
||||
* occurs. This ensures that backlogs during a large lag spike don't cause everyone to get kicked.
|
||||
* As long as all the backlogged packets are processed before the next tick, everything should be OK for
|
||||
* clients behaving normally.
|
||||
*/
|
||||
$this->incomingPacketBatchBudget = min($this->incomingPacketBatchBudget, self::INCOMING_PACKET_BATCH_MAX_BUDGET) + (self::INCOMING_PACKET_BATCH_PER_TICK * 2 * $ticksSinceLastUpdate);
|
||||
$this->lastPacketBudgetUpdateTimeNs = $nowNs;
|
||||
}
|
||||
}
|
||||
|
||||
public function tick() : void{
|
||||
if(!$this->isConnected()){
|
||||
$this->dispose();
|
||||
@ -1169,16 +1219,5 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,21 +24,32 @@ declare(strict_types=1);
|
||||
namespace pocketmine\network\mcpe;
|
||||
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use function spl_object_id;
|
||||
use function strlen;
|
||||
|
||||
final class StandardPacketBroadcaster implements PacketBroadcaster{
|
||||
public function __construct(private Server $server){}
|
||||
|
||||
public function broadcastPackets(array $recipients, array $packets) : void{
|
||||
$buffers = [];
|
||||
$packetBufferTotalLengths = [];
|
||||
$packetBuffers = [];
|
||||
$compressors = [];
|
||||
/** @var NetworkSession[][][] $targetMap */
|
||||
$targetMap = [];
|
||||
foreach($recipients as $recipient){
|
||||
$serializerContext = $recipient->getPacketSerializerContext();
|
||||
$bufferId = spl_object_id($serializerContext);
|
||||
if(!isset($buffers[$bufferId])){
|
||||
$buffers[$bufferId] = PacketBatch::fromPackets($serializerContext, ...$packets);
|
||||
if(!isset($packetBuffers[$bufferId])){
|
||||
$packetBufferTotalLengths[$bufferId] = 0;
|
||||
$packetBuffers[$bufferId] = [];
|
||||
foreach($packets as $packet){
|
||||
$buffer = NetworkSession::encodePacketTimed(PacketSerializer::encoder($serializerContext), $packet);
|
||||
$packetBufferTotalLengths[$bufferId] += strlen($buffer);
|
||||
$packetBuffers[$bufferId][] = $buffer;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: different compressors might be compatible, it might not be necessary to split them up by object
|
||||
@ -49,20 +60,26 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
|
||||
}
|
||||
|
||||
foreach($targetMap as $bufferId => $compressorMap){
|
||||
$buffer = $buffers[$bufferId];
|
||||
foreach($compressorMap as $compressorId => $compressorTargets){
|
||||
$compressor = $compressors[$compressorId];
|
||||
if(!$compressor->willCompress($buffer->getBuffer())){
|
||||
foreach($compressorTargets as $target){
|
||||
foreach($packets as $pk){
|
||||
$target->addToSendBuffer($pk);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$promise = $this->server->prepareBatch($buffer, $compressor);
|
||||
|
||||
$threshold = $compressor->getCompressionThreshold();
|
||||
if($threshold !== null && $packetBufferTotalLengths[$bufferId] >= $threshold){
|
||||
//do not prepare shared batch unless we're sure it will be compressed
|
||||
$stream = new BinaryStream();
|
||||
PacketBatch::encodeRaw($stream, $packetBuffers[$bufferId]);
|
||||
$batchBuffer = $stream->getBuffer();
|
||||
|
||||
$promise = $this->server->prepareBatch(new PacketBatch($batchBuffer), $compressor);
|
||||
foreach($compressorTargets as $target){
|
||||
$target->queueCompressed($promise);
|
||||
}
|
||||
}else{
|
||||
foreach($compressorTargets as $target){
|
||||
foreach($packetBuffers[$bufferId] as $packetBuffer){
|
||||
$target->addToSendBuffer($packetBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
src/network/mcpe/cache/StaticPacketCache.php
vendored
6
src/network/mcpe/cache/StaticPacketCache.php
vendored
@ -23,13 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\cache;
|
||||
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket;
|
||||
use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket;
|
||||
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
|
||||
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
|
||||
class StaticPacketCache{
|
||||
use SingletonTrait;
|
||||
@ -43,8 +43,8 @@ class StaticPacketCache{
|
||||
|
||||
private static function make() : self{
|
||||
return new self(
|
||||
BiomeDefinitionListPacket::create(self::loadCompoundFromFile(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'biome_definitions.nbt'))),
|
||||
AvailableActorIdentifiersPacket::create(self::loadCompoundFromFile(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'entity_identifiers.nbt')))
|
||||
BiomeDefinitionListPacket::create(self::loadCompoundFromFile(BedrockDataFiles::BIOME_DEFINITIONS_NBT)),
|
||||
AvailableActorIdentifiersPacket::create(self::loadCompoundFromFile(BedrockDataFiles::ENTITY_IDENTIFIERS_NBT))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -24,13 +24,20 @@ declare(strict_types=1);
|
||||
namespace pocketmine\network\mcpe\compression;
|
||||
|
||||
interface Compressor{
|
||||
|
||||
public function willCompress(string $data) : bool;
|
||||
|
||||
/**
|
||||
* @throws DecompressionException
|
||||
*/
|
||||
public function decompress(string $payload) : string;
|
||||
|
||||
public function compress(string $payload) : string;
|
||||
|
||||
/**
|
||||
* Returns the minimum size of packet batch that the compressor will attempt to compress.
|
||||
*
|
||||
* The compressor's output **MUST** still be valid input for the decompressor even if the compressor input is
|
||||
* below this threshold.
|
||||
* However, it may choose to use a cheaper compression option (e.g. zlib level 0, which simply wraps the data and
|
||||
* doesn't attempt to compress it) to avoid wasting CPU time.
|
||||
*/
|
||||
public function getCompressionThreshold() : ?int;
|
||||
}
|
||||
|
@ -48,12 +48,12 @@ final class ZlibCompressor implements Compressor{
|
||||
|
||||
public function __construct(
|
||||
private int $level,
|
||||
private int $minCompressionSize,
|
||||
private ?int $minCompressionSize,
|
||||
private int $maxDecompressionSize
|
||||
){}
|
||||
|
||||
public function willCompress(string $data) : bool{
|
||||
return $this->minCompressionSize > -1 && strlen($data) >= $this->minCompressionSize;
|
||||
public function getCompressionThreshold() : ?int{
|
||||
return $this->minCompressionSize;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,11 +72,12 @@ final class ZlibCompressor implements Compressor{
|
||||
}
|
||||
|
||||
public function compress(string $payload) : string{
|
||||
$compressible = $this->minCompressionSize !== null && strlen($payload) >= $this->minCompressionSize;
|
||||
if(function_exists('libdeflate_deflate_compress')){
|
||||
return $this->willCompress($payload) ?
|
||||
return $compressible ?
|
||||
libdeflate_deflate_compress($payload, $this->level) :
|
||||
self::zlib_encode($payload, 0);
|
||||
}
|
||||
return self::zlib_encode($payload, $this->willCompress($payload) ? $this->level : 0);
|
||||
return self::zlib_encode($payload, $compressible ? $this->level : 0);
|
||||
}
|
||||
}
|
||||
|
@ -23,12 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\convert;
|
||||
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||
use pocketmine\network\mcpe\protocol\types\ItemTypeEntry;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_int;
|
||||
@ -39,7 +39,7 @@ final class GlobalItemTypeDictionary{
|
||||
use SingletonTrait;
|
||||
|
||||
private static function make() : self{
|
||||
$data = Filesystem::fileGetContents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'required_item_list.json'));
|
||||
$data = Filesystem::fileGetContents(BedrockDataFiles::REQUIRED_ITEM_LIST_JSON);
|
||||
$table = json_decode($data, true);
|
||||
if(!is_array($table)){
|
||||
throw new AssumptionFailedError("Invalid item list format");
|
||||
|
@ -23,13 +23,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\convert;
|
||||
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\data\bedrock\LegacyItemIdToStringIdMap;
|
||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use pocketmine\utils\Utils;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function array_key_exists;
|
||||
use function is_array;
|
||||
use function is_numeric;
|
||||
@ -67,7 +67,7 @@ final class ItemTranslator{
|
||||
private array $complexNetToCoreMapping = [];
|
||||
|
||||
private static function make() : self{
|
||||
$data = Filesystem::fileGetContents(Path::join(\pocketmine\BEDROCK_DATA_PATH, 'r16_to_current_item_map.json'));
|
||||
$data = Filesystem::fileGetContents(BedrockDataFiles::R16_TO_CURRENT_ITEM_MAP_JSON);
|
||||
$json = json_decode($data, true);
|
||||
if(!is_array($json) || !isset($json["simple"], $json["complex"]) || !is_array($json["simple"]) || !is_array($json["complex"])){
|
||||
throw new AssumptionFailedError("Invalid item table format");
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe\convert;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockLegacyIds;
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
|
||||
@ -32,7 +33,6 @@ use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -49,8 +49,8 @@ final class RuntimeBlockMapping{
|
||||
|
||||
private static function make() : self{
|
||||
return new self(
|
||||
Path::join(\pocketmine\BEDROCK_DATA_PATH, "canonical_block_states.nbt"),
|
||||
Path::join(\pocketmine\BEDROCK_DATA_PATH, "r12_to_current_block_map.bin")
|
||||
BedrockDataFiles::CANONICAL_BLOCK_STATES_NBT,
|
||||
BedrockDataFiles::R12_TO_CURRENT_BLOCK_MAP_BIN
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -149,6 +149,8 @@ class InGamePacketHandler extends PacketHandler{
|
||||
/** @var bool */
|
||||
public $forceMoveSync = false;
|
||||
|
||||
protected ?string $lastRequestedFullSkinId = null;
|
||||
|
||||
public function __construct(
|
||||
private Player $player,
|
||||
private NetworkSession $session,
|
||||
@ -745,6 +747,15 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{
|
||||
if($packet->skin->getFullSkinId() === $this->lastRequestedFullSkinId){
|
||||
//TODO: HACK! In 1.19.60, the client sends its skin back to us if we sent it a skin different from the one
|
||||
//it's using. We need to prevent this from causing a feedback loop.
|
||||
$this->session->getLogger()->debug("Refused duplicate skin change request");
|
||||
return true;
|
||||
}
|
||||
$this->lastRequestedFullSkinId = $packet->skin->getFullSkinId();
|
||||
|
||||
$this->session->getLogger()->debug("Processing skin change request");
|
||||
try{
|
||||
$skin = SkinAdapterSingleton::get()->fromSkinData($packet->skin);
|
||||
}catch(InvalidSkinException $e){
|
||||
|
@ -34,7 +34,6 @@ use pocketmine\network\mcpe\JwtUtils;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\LoginPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\network\mcpe\protocol\types\login\AuthenticationData;
|
||||
use pocketmine\network\mcpe\protocol\types\login\ClientData;
|
||||
use pocketmine\network\mcpe\protocol\types\login\ClientDataToSkinDataHelper;
|
||||
@ -46,6 +45,7 @@ use pocketmine\player\XboxLivePlayerInfo;
|
||||
use pocketmine\Server;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use function is_array;
|
||||
use function preg_match;
|
||||
|
||||
/**
|
||||
* Handles the initial login phase of the session. This handler is used as the initial state.
|
||||
@ -63,18 +63,6 @@ class LoginPacketHandler extends PacketHandler{
|
||||
){}
|
||||
|
||||
public function handleLogin(LoginPacket $packet) : bool{
|
||||
if(!$this->isCompatibleProtocol($packet->protocol)){
|
||||
$this->session->sendDataPacket(PlayStatusPacket::create($packet->protocol < ProtocolInfo::CURRENT_PROTOCOL ? PlayStatusPacket::LOGIN_FAILED_CLIENT : PlayStatusPacket::LOGIN_FAILED_SERVER), true);
|
||||
|
||||
//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
|
||||
$this->session->disconnect(
|
||||
$this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_disconnect_incompatibleProtocol((string) $packet->protocol)),
|
||||
false
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$extraData = $this->fetchAuthData($packet->chainDataJwt);
|
||||
|
||||
if(!Player::isValidUserName($extraData->displayName)){
|
||||
@ -84,6 +72,27 @@ class LoginPacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
$clientData = $this->parseClientData($packet->clientDataJwt);
|
||||
|
||||
//TODO: REMOVE THIS
|
||||
//Mojang forgot to bump the protocol version when they changed protocol in 1.19.62. Check the game version instead.
|
||||
if(preg_match('/^(\d+)\.(\d+)\.(\d+)/', $clientData->GameVersion, $matches) !== 1){
|
||||
throw new PacketHandlingException("Invalid game version format, expected at least 3 digits");
|
||||
}
|
||||
$major = (int) $matches[1];
|
||||
$minor = (int) $matches[2];
|
||||
$patch = (int) $matches[3];
|
||||
if($major === 1 && $minor === 19 && $patch < 62){
|
||||
$this->session->sendDataPacket(PlayStatusPacket::create(PlayStatusPacket::LOGIN_FAILED_CLIENT), true);
|
||||
|
||||
//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
|
||||
$this->session->disconnect(
|
||||
$this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_disconnect_incompatibleProtocol("$packet->protocol (< v1.19.62)")),
|
||||
false
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
try{
|
||||
$skin = SkinAdapterSingleton::get()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData));
|
||||
}catch(\InvalidArgumentException | InvalidSkinException $e){
|
||||
@ -215,8 +224,4 @@ class LoginPacketHandler extends PacketHandler{
|
||||
$this->server->getAsyncPool()->submitTask(new ProcessLoginTask($packet->chainDataJwt->chain, $packet->clientDataJwt, $authRequired, $this->authCallback));
|
||||
$this->session->setHandler(null); //drop packets received during login verification
|
||||
}
|
||||
|
||||
protected function isCompatibleProtocol(int $protocolVersion) : bool{
|
||||
return $protocolVersion === ProtocolInfo::CURRENT_PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +71,9 @@ final class SessionStartPacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
protected function isCompatibleProtocol(int $protocolVersion) : bool{
|
||||
return $protocolVersion === ProtocolInfo::CURRENT_PROTOCOL;
|
||||
//TODO: REMOVE THIS
|
||||
//1.19.63 released with an unchanged protocol, but a bumped protocol version, since they forgot to do it in the
|
||||
//previous release. Since they are functionally identical, we can accept both.
|
||||
return $protocolVersion === ProtocolInfo::CURRENT_PROTOCOL || $protocolVersion === 568;
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\network\mcpe\handler;
|
||||
|
||||
use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||
use pocketmine\network\mcpe\protocol\SetLocalPlayerAsInitializedPacket;
|
||||
|
||||
final class SpawnResponsePacketHandler extends PacketHandler{
|
||||
@ -37,6 +38,13 @@ final class SpawnResponsePacketHandler extends PacketHandler{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{
|
||||
//TODO: REMOVE THIS
|
||||
//As of 1.19.60, we receive this packet during pre-spawn for no obvious reason. The skin is still sent in the
|
||||
//login packet, so we can ignore this one. If unhandled, this packet makes a huge debug spam in the log.
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
|
||||
//the client will send this every tick once we start sending chunks, but we don't handle it in this stage
|
||||
//this is very spammy so we filter it out
|
||||
|
@ -127,6 +127,9 @@ abstract class Timings{
|
||||
/** @var TimingsHandler[] */
|
||||
private static array $packetHandleTimingMap = [];
|
||||
|
||||
/** @var TimingsHandler[] */
|
||||
private static array $packetEncodeTimingMap = [];
|
||||
|
||||
/** @var TimingsHandler[] */
|
||||
public static $packetSendTimingMap = [];
|
||||
/** @var TimingsHandler[] */
|
||||
@ -231,8 +234,7 @@ abstract class Timings{
|
||||
public static function getReceiveDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
||||
$pid = $pk->pid();
|
||||
if(!isset(self::$packetReceiveTimingMap[$pid])){
|
||||
$pkName = (new \ReflectionClass($pk))->getShortName();
|
||||
self::$packetReceiveTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "receivePacket - " . $pkName . " [0x" . dechex($pid) . "]", self::$playerNetworkReceive);
|
||||
self::$packetReceiveTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "receivePacket - " . $pk->getName() . " [0x" . dechex($pid) . "]", self::$playerNetworkReceive);
|
||||
}
|
||||
|
||||
return self::$packetReceiveTimingMap[$pid];
|
||||
@ -254,11 +256,18 @@ abstract class Timings{
|
||||
);
|
||||
}
|
||||
|
||||
public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
||||
$pid = $pk->pid();
|
||||
return self::$packetEncodeTimingMap[$pid] ??= new TimingsHandler(
|
||||
self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Encode - " . $pk->getName() . " [0x" . dechex($pid) . "]",
|
||||
self::getSendDataPacketTimings($pk)
|
||||
);
|
||||
}
|
||||
|
||||
public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
||||
$pid = $pk->pid();
|
||||
if(!isset(self::$packetSendTimingMap[$pid])){
|
||||
$pkName = (new \ReflectionClass($pk))->getShortName();
|
||||
self::$packetSendTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "sendPacket - " . $pkName . " [0x" . dechex($pid) . "]", self::$playerNetworkSend);
|
||||
self::$packetSendTimingMap[$pid] = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "sendPacket - " . $pk->getName() . " [0x" . dechex($pid) . "]", self::$playerNetworkSend);
|
||||
}
|
||||
|
||||
return self::$packetSendTimingMap[$pid];
|
||||
|
@ -3118,59 +3118,63 @@ class World implements ChunkManager{
|
||||
|
||||
Timings::$population->startTiming();
|
||||
|
||||
for($xx = -1; $xx <= 1; ++$xx){
|
||||
for($zz = -1; $zz <= 1; ++$zz){
|
||||
if($this->isChunkLocked($chunkX + $xx, $chunkZ + $zz)){
|
||||
//chunk is already in use by another generation request; queue the request for later
|
||||
return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader);
|
||||
try{
|
||||
for($xx = -1; $xx <= 1; ++$xx){
|
||||
for($zz = -1; $zz <= 1; ++$zz){
|
||||
if($this->isChunkLocked($chunkX + $xx, $chunkZ + $zz)){
|
||||
//chunk is already in use by another generation request; queue the request for later
|
||||
return $resolver?->getPromise() ?? $this->enqueuePopulationRequest($chunkX, $chunkZ, $associatedChunkLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->activeChunkPopulationTasks[$chunkHash] = true;
|
||||
if($resolver === null){
|
||||
$resolver = new PromiseResolver();
|
||||
$this->chunkPopulationRequestMap[$chunkHash] = $resolver;
|
||||
}
|
||||
|
||||
$chunkPopulationLockId = new ChunkLockId();
|
||||
|
||||
$temporaryChunkLoader = new class implements ChunkLoader{};
|
||||
for($xx = -1; $xx <= 1; ++$xx){
|
||||
for($zz = -1; $zz <= 1; ++$zz){
|
||||
$this->lockChunk($chunkX + $xx, $chunkZ + $zz, $chunkPopulationLockId);
|
||||
$this->registerChunkLoader($temporaryChunkLoader, $chunkX + $xx, $chunkZ + $zz);
|
||||
$this->activeChunkPopulationTasks[$chunkHash] = true;
|
||||
if($resolver === null){
|
||||
$resolver = new PromiseResolver();
|
||||
$this->chunkPopulationRequestMap[$chunkHash] = $resolver;
|
||||
}
|
||||
}
|
||||
|
||||
$centerChunk = $this->loadChunk($chunkX, $chunkZ);
|
||||
$adjacentChunks = $this->getAdjacentChunks($chunkX, $chunkZ);
|
||||
$task = new PopulationTask(
|
||||
$this->worldId,
|
||||
$chunkX,
|
||||
$chunkZ,
|
||||
$centerChunk,
|
||||
$adjacentChunks,
|
||||
function(Chunk $centerChunk, array $adjacentChunks) use ($chunkPopulationLockId, $chunkX, $chunkZ, $temporaryChunkLoader) : void{
|
||||
if(!$this->isLoaded()){
|
||||
return;
|
||||
$chunkPopulationLockId = new ChunkLockId();
|
||||
|
||||
$temporaryChunkLoader = new class implements ChunkLoader{
|
||||
};
|
||||
for($xx = -1; $xx <= 1; ++$xx){
|
||||
for($zz = -1; $zz <= 1; ++$zz){
|
||||
$this->lockChunk($chunkX + $xx, $chunkZ + $zz, $chunkPopulationLockId);
|
||||
$this->registerChunkLoader($temporaryChunkLoader, $chunkX + $xx, $chunkZ + $zz);
|
||||
}
|
||||
|
||||
$this->generateChunkCallback($chunkPopulationLockId, $chunkX, $chunkZ, $centerChunk, $adjacentChunks, $temporaryChunkLoader);
|
||||
}
|
||||
);
|
||||
$workerId = $this->workerPool->selectWorker();
|
||||
if(!isset($this->workerPool->getRunningWorkers()[$workerId]) && isset($this->generatorRegisteredWorkers[$workerId])){
|
||||
$this->logger->debug("Selected worker $workerId previously had generator registered, but is now offline");
|
||||
unset($this->generatorRegisteredWorkers[$workerId]);
|
||||
}
|
||||
if(!isset($this->generatorRegisteredWorkers[$workerId])){
|
||||
$this->registerGeneratorToWorker($workerId);
|
||||
}
|
||||
$this->workerPool->submitTaskToWorker($task, $workerId);
|
||||
|
||||
Timings::$population->stopTiming();
|
||||
return $resolver->getPromise();
|
||||
$centerChunk = $this->loadChunk($chunkX, $chunkZ);
|
||||
$adjacentChunks = $this->getAdjacentChunks($chunkX, $chunkZ);
|
||||
$task = new PopulationTask(
|
||||
$this->worldId,
|
||||
$chunkX,
|
||||
$chunkZ,
|
||||
$centerChunk,
|
||||
$adjacentChunks,
|
||||
function(Chunk $centerChunk, array $adjacentChunks) use ($chunkPopulationLockId, $chunkX, $chunkZ, $temporaryChunkLoader) : void{
|
||||
if(!$this->isLoaded()){
|
||||
return;
|
||||
}
|
||||
|
||||
$this->generateChunkCallback($chunkPopulationLockId, $chunkX, $chunkZ, $centerChunk, $adjacentChunks, $temporaryChunkLoader);
|
||||
}
|
||||
);
|
||||
$workerId = $this->workerPool->selectWorker();
|
||||
if(!isset($this->workerPool->getRunningWorkers()[$workerId]) && isset($this->generatorRegisteredWorkers[$workerId])){
|
||||
$this->logger->debug("Selected worker $workerId previously had generator registered, but is now offline");
|
||||
unset($this->generatorRegisteredWorkers[$workerId]);
|
||||
}
|
||||
if(!isset($this->generatorRegisteredWorkers[$workerId])){
|
||||
$this->registerGeneratorToWorker($workerId);
|
||||
}
|
||||
$this->workerPool->submitTaskToWorker($task, $workerId);
|
||||
|
||||
return $resolver->getPromise();
|
||||
}finally{
|
||||
Timings::$population->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,7 +40,7 @@ final class GeneratorManager{
|
||||
private array $list = [];
|
||||
|
||||
public function __construct(){
|
||||
$this->addGenerator(Flat::class, "flat", \Closure::fromCallable(function(string $preset) : ?InvalidGeneratorOptionsException{
|
||||
$this->addGenerator(Flat::class, "flat", function(string $preset) : ?InvalidGeneratorOptionsException{
|
||||
if($preset === ""){
|
||||
return null;
|
||||
}
|
||||
@ -50,7 +50,7 @@ final class GeneratorManager{
|
||||
}catch(InvalidGeneratorOptionsException $e){
|
||||
return $e;
|
||||
}
|
||||
}));
|
||||
});
|
||||
$this->addGenerator(Normal::class, "normal", fn() => null);
|
||||
$this->addGenerator(Normal::class, "default", fn() => null);
|
||||
$this->addGenerator(Nether::class, "hell", fn() => null);
|
||||
|
6
start.sh
6
start.sh
@ -23,7 +23,7 @@ if [ "$PHP_BINARY" == "" ]; then
|
||||
if [ -f ./bin/php7/bin/php ]; then
|
||||
export PHPRC=""
|
||||
PHP_BINARY="./bin/php7/bin/php"
|
||||
elif [[ ! -z $(type php 2> /dev/null) ]]; then
|
||||
elif [[ -n $(type php 2> /dev/null) ]]; then
|
||||
PHP_BINARY=$(type -p php)
|
||||
else
|
||||
echo "Couldn't find a PHP binary in system PATH or $PWD/bin/php7/bin"
|
||||
@ -51,12 +51,12 @@ if [ "$DO_LOOP" == "yes" ]; then
|
||||
if [ ${LOOPS} -gt 0 ]; then
|
||||
echo "Restarted $LOOPS times"
|
||||
fi
|
||||
"$PHP_BINARY" "$POCKETMINE_FILE" $@
|
||||
"$PHP_BINARY" "$POCKETMINE_FILE" "$@"
|
||||
echo "To escape the loop, press CTRL+C now. Otherwise, wait 5 seconds for the server to restart."
|
||||
echo ""
|
||||
sleep 5
|
||||
((LOOPS++))
|
||||
done
|
||||
else
|
||||
exec "$PHP_BINARY" "$POCKETMINE_FILE" $@
|
||||
exec "$PHP_BINARY" "$POCKETMINE_FILE" "$@"
|
||||
fi
|
||||
|
@ -20,11 +20,6 @@ parameters:
|
||||
count: 1
|
||||
path: ../../../src/Server.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$input of function yaml_parse expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/Server.php
|
||||
|
||||
-
|
||||
message: "#^Cannot cast mixed to int\\.$#"
|
||||
count: 2
|
||||
@ -580,11 +575,6 @@ parameters:
|
||||
count: 1
|
||||
path: ../../../src/inventory/CreativeInventory.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/inventory/CreativeInventory.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$recipe of class pocketmine\\\\event\\\\inventory\\\\CraftItemEvent constructor expects pocketmine\\\\crafting\\\\CraftingRecipe, pocketmine\\\\crafting\\\\CraftingRecipe\\|null given\\.$#"
|
||||
count: 1
|
||||
|
Reference in New Issue
Block a user