mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-08 10:53:05 +00:00
Compare commits
108 Commits
5.0.0-ALPH
...
4.16.0
Author | SHA1 | Date | |
---|---|---|---|
fa131dab12 | |||
bb4a82b1e7 | |||
93d844a281 | |||
616844696e | |||
71e3e36522 | |||
a1b42d419f | |||
ef942a627f | |||
fd8c276bd2 | |||
9783380d1a | |||
a784d93bfd | |||
a05e8b366f | |||
87a2e0460c | |||
4073c3fb39 | |||
e227e6d8bf | |||
3aa40829ae | |||
035d4b7263 | |||
3db1492c18 | |||
a523189149 | |||
f8893efb94 | |||
70f1ee3e97 | |||
eb2f0ed3d0 | |||
14e7d3e143 | |||
6d636fc2c7 | |||
a39f61a33d | |||
aaec21f544 | |||
0edc5f8113 | |||
a382f0fd92 | |||
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 | |||
cb1aac3cd4 | |||
3dd1a14fb7 | |||
63c3127248 | |||
96c32d24ba | |||
d64a9d8b52 | |||
92c29b8172 | |||
0ac9584bbb | |||
fe12e8d944 | |||
7529953f0a | |||
00dbb6855a | |||
7eca3e8081 | |||
b58d7fc82a | |||
ceea8220a9 | |||
18013e9551 | |||
bd3e9e1cad | |||
6173471cca | |||
608fcd6cd7 | |||
ce9b25e97a |
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
|
||||
|
11
.github/workflows/discord-release-embed.php
vendored
11
.github/workflows/discord-release-embed.php
vendored
@ -18,8 +18,9 @@ require dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
/**
|
||||
* @phpstan-return array<string, mixed>
|
||||
*/
|
||||
function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl) : array{
|
||||
function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl, int $newsPingRoleId) : array{
|
||||
return [
|
||||
"content" => "<@&$newsPingRoleId> New PocketMine-MP release: $version ($channel)",
|
||||
"embeds" => [
|
||||
[
|
||||
"title" => "New PocketMine-MP release: $version ($channel)",
|
||||
@ -35,11 +36,11 @@ DESCRIPTION,
|
||||
];
|
||||
}
|
||||
|
||||
if(count($argv) !== 5){
|
||||
fwrite(STDERR, "Required arguments: github repo, version, API token\n");
|
||||
if(count($argv) !== 6){
|
||||
fwrite(STDERR, "Required arguments: github repo, version, API token, webhook URL, ping role ID\n");
|
||||
exit(1);
|
||||
}
|
||||
[, $repo, $tagName, $token, $hookURL] = $argv;
|
||||
[, $repo, $tagName, $token, $hookURL, $newsPingRoleId] = $argv;
|
||||
|
||||
$result = Internet::getURL('https://api.github.com/repos/' . $repo . '/releases/tags/' . $tagName, extraHeaders: [
|
||||
'Authorization: token ' . $token
|
||||
@ -86,7 +87,7 @@ $buildLogUrl = $buildInfoJson["build_log_url"];
|
||||
|
||||
$description = $releaseInfoJson["body"];
|
||||
|
||||
$discordPayload = generateDiscordEmbed($buildInfoJson["base_version"], $buildInfoJson["channel"], $description, $detailsUrl, $sourceUrl, $pharDownloadUrl, $buildLogUrl);
|
||||
$discordPayload = generateDiscordEmbed($buildInfoJson["base_version"], $buildInfoJson["channel"], $description, $detailsUrl, $sourceUrl, $pharDownloadUrl, $buildLogUrl, (int) $newsPingRoleId);
|
||||
|
||||
$response = Internet::postURL(
|
||||
$hookURL,
|
||||
|
4
.github/workflows/discord-release-notify.yml
vendored
4
.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.23.0
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
@ -35,4 +35,4 @@ jobs:
|
||||
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
||||
|
||||
- name: Run webhook post script
|
||||
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }}
|
||||
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }} ${{ secrets.DISCORD_NEWS_PING_ROLE_ID }}
|
||||
|
4
.github/workflows/draft-release.yml
vendored
4
.github/workflows/draft-release.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.23.0
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
@ -56,6 +56,7 @@ jobs:
|
||||
echo ::set-output name=PM_VERSION_SHORT::$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);')
|
||||
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);')
|
||||
echo ::set-output name=CHANGELOG_SUFFIX::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;')
|
||||
echo ::set-output name=PRERELEASE::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "false" : "true";')
|
||||
|
||||
- name: Generate build info
|
||||
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} ${{ github.run_id }} > build_info.json
|
||||
@ -75,6 +76,7 @@ jobs:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||
commit: ${{ github.sha }}
|
||||
draft: true
|
||||
prerelease: ${{ steps.get-pm-version.outputs.PRERELEASE }}
|
||||
name: PocketMine-MP ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||
tag: ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
@ -185,6 +185,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
|
||||
@ -200,7 +203,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.23.0
|
||||
uses: shivammathur/setup-php@2.24.0
|
||||
with:
|
||||
php-version: 8.0
|
||||
tools: php-cs-fixer:3.11
|
||||
|
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";
|
@ -36,11 +36,13 @@ use function fwrite;
|
||||
use function getopt;
|
||||
use function is_string;
|
||||
use function max;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function sleep;
|
||||
use function sprintf;
|
||||
use function str_pad;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function system;
|
||||
use const STDERR;
|
||||
use const STDIN;
|
||||
@ -102,22 +104,43 @@ function main() : void{
|
||||
$filteredOpts[$optName] = $optValue;
|
||||
}
|
||||
|
||||
$channel = $filteredOpts["channel"] ?? null;
|
||||
if(isset($filteredOpts["current"])){
|
||||
$currentVer = new VersionString($filteredOpts["current"]);
|
||||
}else{
|
||||
$currentVer = new VersionString(VersionInfo::BASE_VERSION);
|
||||
}
|
||||
if(isset($filteredOpts["next"])){
|
||||
$nextVer = new VersionString($filteredOpts["next"]);
|
||||
|
||||
$nextVer = isset($filteredOpts["next"]) ? new VersionString($filteredOpts["next"]) : null;
|
||||
|
||||
$suffix = $currentVer->getSuffix();
|
||||
if($suffix !== ""){
|
||||
if($channel === "stable"){
|
||||
fwrite(STDERR, "error: cannot release a suffixed build into the stable channel\n");
|
||||
exit(1);
|
||||
}
|
||||
if(preg_match('/^([A-Za-z]+)(\d+)$/', $suffix, $matches) !== 1){
|
||||
echo "error: invalid current version suffix \"$suffix\"; aborting\n";
|
||||
exit(1);
|
||||
}
|
||||
$nextVer ??= new VersionString(sprintf(
|
||||
"%u.%u.%u-%s%u",
|
||||
$currentVer->getMajor(),
|
||||
$currentVer->getMinor(),
|
||||
$currentVer->getPatch(),
|
||||
$matches[1],
|
||||
((int) $matches[2]) + 1
|
||||
));
|
||||
$channel ??= strtolower($matches[1]);
|
||||
}else{
|
||||
$nextVer = new VersionString(sprintf(
|
||||
$nextVer ??= new VersionString(sprintf(
|
||||
"%u.%u.%u",
|
||||
$currentVer->getMajor(),
|
||||
$currentVer->getMinor(),
|
||||
$currentVer->getPatch() + 1
|
||||
));
|
||||
$channel ??= "stable";
|
||||
}
|
||||
$channel = $filteredOpts["channel"] ?? VersionInfo::BUILD_CHANNEL;
|
||||
|
||||
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
|
||||
echo "$currentVer will be published on release channel \"$channel\".\n";
|
||||
|
Submodule build/php updated: b479ec438f...b2207cf70d
@ -104,3 +104,16 @@ Released 18th January 2023.
|
||||
## 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).
|
||||
|
||||
# 4.12.11
|
||||
Released 22nd January 2023.
|
||||
|
||||
## General
|
||||
- Code is now tested and analysed using PHP 8.2 in addition to 8.1 and 8.0.
|
||||
|
||||
## Fixes
|
||||
- Fixed pthreads 5.0.0 incorrectly being treated as compatible.
|
||||
- Fixed deprecation errors on PHP 8.2.
|
||||
|
||||
## Documentation
|
||||
- Updated documentation in `PlayerPreLoginEvent`.
|
||||
|
94
changelogs/4.13.md
Normal file
94
changelogs/4.13.md
Normal file
@ -0,0 +1,94 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.50**
|
||||
|
||||
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.13.0
|
||||
Released 30th January 2023.
|
||||
|
||||
## Gameplay
|
||||
- Death message is now shown on the death screen when a player dies.
|
||||
- Armour damage is now only increased if the armour reduced the damage taken.
|
||||
- Implemented Swift Sneak enchantment.
|
||||
- Fixed incorrect collision box calculation of walls and glass/bars when connected. Note: Client-side, wall connections are still broken; this only fixes projectile flight server-side.
|
||||
|
||||
## Performance
|
||||
- Improved performance of chunk selection for chunk random ticking using a cache. This improves performance of chunk random ticking by 10-20%.
|
||||
|
||||
## Localization
|
||||
- Added localized description for the `/dumpmemory` command.
|
||||
|
||||
## Permissions
|
||||
- Added the following new core permissions:
|
||||
- `pocketmine.command.effect.other` - allows the player to use the `/effect` command on other players (default operator only)
|
||||
- `pocketmine.command.effect.self` - allows the player to use the `/effect` command on themselves (default operator only)
|
||||
- `pocketmine.command.enchant.other` - allows the player to use the `/enchant` command on other players (default operator only)
|
||||
- `pocketmine.command.enchant.self` - allows the player to use the `/enchant` command on themselves (default operator only)
|
||||
- `pocketmine.command.gamemode.other` - allows the player to use the `/gamemode` command on other players (default operator only)
|
||||
- `pocketmine.command.gamemode.self` - allows the player to use the `/gamemode` command on themselves (default operator only)
|
||||
- `pocketmine.command.give.other` - allows the player to use the `/give` command on other players (default operator only)
|
||||
- `pocketmine.command.give.self` - allows the player to use the `/give` command on themselves (default operator only)
|
||||
- `pocketmine.command.spawnpoint.other` - allows the player to use the `/spawnpoint` command on other players (default operator only)
|
||||
- `pocketmine.command.spawnpoint.self` - allows the player to use the `/spawnpoint` command on themselves (default operator only)
|
||||
- `pocketmine.command.teleport.other` - allows the player to use the `/teleport` command on other players (default operator only)
|
||||
- `pocketmine.command.teleport.self` - allows the player to use the `/teleport` command on themselves (default operator only)
|
||||
- `pocketmine.command.title.other` - allows the player to use the `/title` command on other players (default operator only)
|
||||
- `pocketmine.command.title.self` - allows the player to use the `/title` command on themselves (default operator only)
|
||||
|
||||
## Internals
|
||||
- Decoupled `Player->sendMessage()` and `Player->sendTranslation()`.
|
||||
- Refactored resource pack loading in `ResourcePackManager` to make it easier to understand.
|
||||
- Client-aware translation processing has been moved to `NetworkSession` due to being client-specific.
|
||||
- Replaced hardcoded strings with constants in various places.
|
||||
- `NetworkSession` destructive cleanup is now deferred to the next session tick. This fixes various `InventoryManager` crashes when kicking players during events.
|
||||
- Updated code using `strpos()` to use `str_starts_with()`, `str_ends_with()` and `str_contains()` where appropriate.
|
||||
- Added documentation for some internal methods.
|
||||
|
||||
## API
|
||||
### `pocketmine\command`
|
||||
- The following new API methods have been added:
|
||||
- `protected VanillaCommand->fetchPermittedPlayerTarget(...) : ?Player` - fetches a player target according to the given sender permissions, or null if not found or not permitted
|
||||
|
||||
### `pocketmine\entity`
|
||||
- The following new API methods have been added:
|
||||
- `public Living->getDisplayName() : string` - the name of the entity to be shown in death messages, commands etc.
|
||||
|
||||
### `pocketmine\event\world`
|
||||
- The following new classes have been added:
|
||||
- `WorldSoundEvent` - called when a sound is played in a world
|
||||
- `WorldParticleEvent` - called when a particle is spawned in a world
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Item->onInteractEntity(Player $player, Entity $entity, Vector3 $clickVector) : bool` - called when a player interacts with an entity with this item in hand
|
||||
|
||||
### `pocketmine\lang`
|
||||
- `Language->translate()` and `Language->translateString()` no longer parse nested translation in the "base text". This was never intended behaviour, and didn't work beyond the first level anyway.
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following new interfaces have been added:
|
||||
- `PlayerDataProvider` - implemented by classes which want to offer storage for player data
|
||||
- The following new classes have been added:
|
||||
- `DatFilePlayerDataProvider` - the default player data provider, which stores `.dat` files in the `players` folder
|
||||
- `PlayerDataLoadException` - thrown when an error occurs while loading player data
|
||||
- `PlayerDataSaveException` - thrown when an error occurs while saving player data
|
||||
- The following API methods have been deprecated:
|
||||
- `Player->sendTranslation()` - use `Player->sendMessage()` instead with a `Translatable` message
|
||||
|
||||
### `pocketmine\resourcepacks`
|
||||
- The following new API methods have been added:
|
||||
- `public ResourcePackManager->setResourceStack(list<ResourcePack> $resourceStack) : void` - sets the list of resource packs to be applied by players
|
||||
- `public ResourcePackManager->setPackEncryptionKey(string $id, ?string $key) : void` - sets the encryption key to be used for a resource pack
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new API methods have been added:
|
||||
- `public static Filesystem::fileGetContents(...) : string` - a wrapper around `file_get_contents()` which throws an exception on failure
|
||||
|
||||
### `pocketmine\world`
|
||||
- The following new API methods have been added:
|
||||
- `public World->requestSafeSpawn(?Vector3 $spawn = null) : Promise<Position>` - an async version of `getSafeSpawn()` which generates all the needed chunks before returning
|
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.
|
38
changelogs/4.15.md
Normal file
38
changelogs/4.15.md
Normal file
@ -0,0 +1,38 @@
|
||||
**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.
|
||||
|
||||
# 4.15.3
|
||||
Released 7th March 2023.
|
||||
|
||||
## Fixes
|
||||
- Fixed `/dumpmemory` crash when any object contained an `INF` or `NaN` float value.
|
||||
- Updated RakLib for security fixes.
|
45
changelogs/4.16-beta.md
Normal file
45
changelogs/4.16-beta.md
Normal file
@ -0,0 +1,45 @@
|
||||
**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
|
||||
Released 4th March 2023.
|
||||
|
||||
## 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.
|
||||
|
||||
# 4.16.0-BETA2
|
||||
Released 4th March 2023.
|
||||
|
||||
## General
|
||||
- Fixed incorrect release channel for 4.16.0-BETA1.
|
41
changelogs/4.16.md
Normal file
41
changelogs/4.16.md
Normal file
@ -0,0 +1,41 @@
|
||||
**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
|
||||
Released 7th March 2023.
|
||||
|
||||
## General
|
||||
- Added granular timings for packet encode, similar to the existing timings for packet decode.
|
||||
- Split `Player Network Send - Compression` timings into two timers, one for `Session Buffer` compression and one for `Broadcast` compression.
|
||||
- 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.
|
||||
- Improved performance of packet broadcasting when the broadcast has only one recipient (allow the session to compress the packet with the rest of its buffer).
|
||||
|
||||
## 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,14 +34,16 @@
|
||||
"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.0.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",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
"pocketmine/errorhandler": "^0.6.0",
|
||||
"pocketmine/locale-data": "~2.17.0",
|
||||
"pocketmine/locale-data": "~2.18.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/log-pthreads": "^0.4.0",
|
||||
"pocketmine/math": "^0.4.0",
|
||||
@ -54,7 +56,7 @@
|
||||
"webmozart/path-util": "^2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.9.13",
|
||||
"phpstan/phpstan": "1.10.4",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
|
249
composer.lock
generated
249
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": "1b14016d1d20b9f4c79c59bafabd1e73",
|
||||
"content-hash": "2230c1697e4d7d490f5957b3a80d80a7",
|
||||
"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.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "57337ddc9433a0e245a1ce48c51af05f0573d58d"
|
||||
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
|
||||
"reference": "78c965a2316986ac0eaf3235d75efb187127e7a2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/57337ddc9433a0e245a1ce48c51af05f0573d58d",
|
||||
"reference": "57337ddc9433a0e245a1ce48c51af05f0573d58d",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/78c965a2316986ac0eaf3235d75efb187127e7a2",
|
||||
"reference": "78c965a2316986ac0eaf3235d75efb187127e7a2",
|
||||
"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.1.0"
|
||||
},
|
||||
"time": "2023-03-06T17:53:36+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.0.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": "b558ec883bd967dd3339f513cba62d2fbcd63349"
|
||||
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
|
||||
"reference": "7e53f77ea34ba30b1f94d3c24e64e19d3c4296e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/b558ec883bd967dd3339f513cba62d2fbcd63349",
|
||||
"reference": "b558ec883bd967dd3339f513cba62d2fbcd63349",
|
||||
"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": {
|
||||
@ -299,7 +351,7 @@
|
||||
"ramsey/uuid": "^4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.9.4",
|
||||
"phpstan/phpstan": "1.9.13",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
@ -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.0.0+bedrock-1.19.50"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/19.3.0+bedrock-1.19.62"
|
||||
},
|
||||
"time": "2023-01-06T21:47:35+00:00"
|
||||
"time": "2023-02-19T16:11:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -537,16 +589,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/locale-data",
|
||||
"version": "2.17.0",
|
||||
"version": "2.18.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Language.git",
|
||||
"reference": "a2c7071117c98ccc0e333994271cab1072eb3c06"
|
||||
"reference": "da25bfe9ee4822a84feb9b7e620c56ad4000aed0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/a2c7071117c98ccc0e333994271cab1072eb3c06",
|
||||
"reference": "a2c7071117c98ccc0e333994271cab1072eb3c06",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/da25bfe9ee4822a84feb9b7e620c56ad4000aed0",
|
||||
"reference": "da25bfe9ee4822a84feb9b7e620c56ad4000aed0",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -554,9 +606,9 @@
|
||||
"description": "Language resources used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/Language/issues",
|
||||
"source": "https://github.com/pmmp/Language/tree/2.17.0"
|
||||
"source": "https://github.com/pmmp/Language/tree/2.18.3"
|
||||
},
|
||||
"time": "2023-01-13T17:22:45+00:00"
|
||||
"time": "2023-01-17T21:43:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/log",
|
||||
@ -728,16 +780,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib",
|
||||
"version": "0.14.5",
|
||||
"version": "0.14.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/RakLib.git",
|
||||
"reference": "85b4e5cb7117d37e010eeadb3ff53b21276c6f48"
|
||||
"reference": "aeca667d5ecc4cc18fded612f29e3511bbf62f42"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/85b4e5cb7117d37e010eeadb3ff53b21276c6f48",
|
||||
"reference": "85b4e5cb7117d37e010eeadb3ff53b21276c6f48",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/aeca667d5ecc4cc18fded612f29e3511bbf62f42",
|
||||
"reference": "aeca667d5ecc4cc18fded612f29e3511bbf62f42",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -749,7 +801,7 @@
|
||||
"pocketmine/log": "^0.3.0 || ^0.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.7.7",
|
||||
"phpstan/phpstan": "1.9.17",
|
||||
"phpstan/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
@ -765,9 +817,9 @@
|
||||
"description": "A RakNet server implementation written in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/RakLib/issues",
|
||||
"source": "https://github.com/pmmp/RakLib/tree/0.14.5"
|
||||
"source": "https://github.com/pmmp/RakLib/tree/0.14.6"
|
||||
},
|
||||
"time": "2022-08-25T16:16:44+00:00"
|
||||
"time": "2023-03-07T15:10:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib-ipc",
|
||||
@ -1034,16 +1086,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v5.4.13",
|
||||
"version": "v5.4.21",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "ac09569844a9109a5966b9438fc29113ce77cf51"
|
||||
"reference": "e75960b1bbfd2b8c9e483e0d74811d555ca3de9f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/ac09569844a9109a5966b9438fc29113ce77cf51",
|
||||
"reference": "ac09569844a9109a5966b9438fc29113ce77cf51",
|
||||
"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.13"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v5.4.21"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1094,7 +1146,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-09-21T19:53:16+00:00"
|
||||
"time": "2023-02-14T08:03:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
@ -1665,16 +1717,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.15.2",
|
||||
"version": "v4.15.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc"
|
||||
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
|
||||
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
|
||||
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1715,9 +1767,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4"
|
||||
},
|
||||
"time": "2022-11-12T15:38:23+00:00"
|
||||
"time": "2023-03-05T19:49:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@ -1832,16 +1884,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.9.13",
|
||||
"version": "1.10.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "a0922426da3a7d0d9334e99a363f7f9f6e23e84f"
|
||||
"reference": "8d39218664b45a4a42d5be66d2b63dcf8c149982"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/a0922426da3a7d0d9334e99a363f7f9f6e23e84f",
|
||||
"reference": "a0922426da3a7d0d9334e99a363f7f9f6e23e84f",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8d39218664b45a4a42d5be66d2b63dcf8c149982",
|
||||
"reference": "8d39218664b45a4a42d5be66d2b63dcf8c149982",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1871,7 +1923,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.9.13"
|
||||
"source": "https://github.com/phpstan/phpstan/tree/1.10.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1887,25 +1939,25 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-01-18T15:26:53+00:00"
|
||||
"time": "2023-03-06T13:39:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "1.3.3",
|
||||
"version": "1.3.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "54a24bd23e9e80ee918cdc24f909d376c2e273f7"
|
||||
"reference": "4cc5c6cc38e56bce7ea47c4091814e516d172dc3"
|
||||
},
|
||||
"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/4cc5c6cc38e56bce7ea47c4091814e516d172dc3",
|
||||
"reference": "4cc5c6cc38e56bce7ea47c4091814e516d172dc3",
|
||||
"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.10"
|
||||
},
|
||||
"time": "2022-12-21T15:25:00+00:00"
|
||||
"time": "2023-03-02T10:25:13+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.23",
|
||||
"version": "9.2.26",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c"
|
||||
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
|
||||
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
|
||||
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
|
||||
"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",
|
||||
@ -2022,8 +2075,8 @@
|
||||
"phpunit/phpunit": "^9.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-pcov": "*",
|
||||
"ext-xdebug": "*"
|
||||
"ext-pcov": "PHP extension that provides line coverage",
|
||||
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -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.23"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2064,7 +2117,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-28T12:41:10+00:00"
|
||||
"time": "2023-03-06T12:58:08+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');
|
||||
|
@ -49,6 +49,7 @@ use function ini_get;
|
||||
use function ini_set;
|
||||
use function intdiv;
|
||||
use function is_array;
|
||||
use function is_float;
|
||||
use function is_object;
|
||||
use function is_resource;
|
||||
use function is_string;
|
||||
@ -71,7 +72,7 @@ use const SORT_NUMERIC;
|
||||
class MemoryManager{
|
||||
private const DEFAULT_CHECK_RATE = Server::TARGET_TICKS_PER_SECOND;
|
||||
private const DEFAULT_CONTINUOUS_TRIGGER_RATE = Server::TARGET_TICKS_PER_SECOND * 2;
|
||||
private const DEEFAULT_TICKS_PER_GC = 30 * 60 * Server::TARGET_TICKS_PER_SECOND;
|
||||
private const DEFAULT_TICKS_PER_GC = 30 * 60 * Server::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
private int $memoryLimit;
|
||||
private int $globalMemoryLimit;
|
||||
@ -139,7 +140,7 @@ class MemoryManager{
|
||||
$this->continuousTrigger = $config->getPropertyBool("memory.continuous-trigger", true);
|
||||
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
|
||||
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", self::DEEFAULT_TICKS_PER_GC);
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", self::DEFAULT_TICKS_PER_GC);
|
||||
$this->garbageCollectionTrigger = $config->getPropertyBool("memory.garbage-collection.low-memory-trigger", true);
|
||||
$this->garbageCollectionAsync = $config->getPropertyBool("memory.garbage-collection.collect-async-worker", true);
|
||||
|
||||
@ -519,6 +520,8 @@ class MemoryManager{
|
||||
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||
}elseif(is_resource($from)){
|
||||
$data = "(resource) " . print_r($from, true);
|
||||
}elseif(is_float($from)){
|
||||
$data = "(float) $from";
|
||||
}else{
|
||||
$data = $from;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
@ -1378,14 +1381,16 @@ class Server{
|
||||
*
|
||||
* @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null).
|
||||
*/
|
||||
public function prepareBatch(PacketBatch $stream, Compressor $compressor, ?bool $sync = null) : CompressBatchPromise{
|
||||
public function prepareBatch(PacketBatch $stream, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise{
|
||||
$timings ??= Timings::$playerNetworkSendCompress;
|
||||
try{
|
||||
Timings::$playerNetworkSendCompress->startTiming();
|
||||
$timings->startTiming();
|
||||
|
||||
$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();
|
||||
@ -1398,7 +1403,7 @@ class Server{
|
||||
|
||||
return $promise;
|
||||
}finally{
|
||||
Timings::$playerNetworkSendCompress->stopTiming();
|
||||
$timings->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,9 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "4.13.0-BETA2";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BUILD_CHANNEL = "beta";
|
||||
public const BASE_VERSION = "4.16.0";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
|
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);
|
||||
|
@ -1629,6 +1629,10 @@ final class KnownTranslationFactory{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_DISCONNECT_ERROR_LOGINTIMEOUT, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_disconnect_error_respawn() : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_DISCONNECT_ERROR_RESPAWN, []);
|
||||
}
|
||||
|
||||
public static function pocketmine_disconnect_incompatibleProtocol(Translatable|string $param0) : Translatable{
|
||||
return new Translatable(KnownTranslationKeys::POCKETMINE_DISCONNECT_INCOMPATIBLEPROTOCOL, [
|
||||
0 => $param0,
|
||||
|
@ -354,6 +354,7 @@ final class KnownTranslationKeys{
|
||||
public const POCKETMINE_DISCONNECT_ERROR_BADPACKET = "pocketmine.disconnect.error.badPacket";
|
||||
public const POCKETMINE_DISCONNECT_ERROR_INTERNAL = "pocketmine.disconnect.error.internal";
|
||||
public const POCKETMINE_DISCONNECT_ERROR_LOGINTIMEOUT = "pocketmine.disconnect.error.loginTimeout";
|
||||
public const POCKETMINE_DISCONNECT_ERROR_RESPAWN = "pocketmine.disconnect.error.respawn";
|
||||
public const POCKETMINE_DISCONNECT_INCOMPATIBLEPROTOCOL = "pocketmine.disconnect.incompatibleProtocol";
|
||||
public const POCKETMINE_DISCONNECT_INVALIDSESSION = "pocketmine.disconnect.invalidSession";
|
||||
public const POCKETMINE_DISCONNECT_INVALIDSESSION_BADSIGNATURE = "pocketmine.disconnect.invalidSession.badSignature";
|
||||
|
@ -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, Timings::$playerNetworkSendCompressSessionBuffer);
|
||||
}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,34 @@ 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\timings\Timings;
|
||||
use pocketmine\utils\BinaryStream;
|
||||
use function count;
|
||||
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 +62,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(count($compressorTargets) > 1 && $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, timings: Timings::$playerNetworkSendCompressBroadcast);
|
||||
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
|
||||
|
@ -52,6 +52,10 @@ abstract class Timings{
|
||||
public static $playerNetworkSend;
|
||||
/** @var TimingsHandler */
|
||||
public static $playerNetworkSendCompress;
|
||||
|
||||
public static TimingsHandler $playerNetworkSendCompressBroadcast;
|
||||
public static TimingsHandler $playerNetworkSendCompressSessionBuffer;
|
||||
|
||||
/** @var TimingsHandler */
|
||||
public static $playerNetworkSendEncrypt;
|
||||
/** @var TimingsHandler */
|
||||
@ -127,6 +131,9 @@ abstract class Timings{
|
||||
/** @var TimingsHandler[] */
|
||||
private static array $packetHandleTimingMap = [];
|
||||
|
||||
/** @var TimingsHandler[] */
|
||||
private static array $packetEncodeTimingMap = [];
|
||||
|
||||
/** @var TimingsHandler[] */
|
||||
public static $packetSendTimingMap = [];
|
||||
/** @var TimingsHandler[] */
|
||||
@ -150,6 +157,8 @@ abstract class Timings{
|
||||
|
||||
self::$playerNetworkSend = new TimingsHandler("Player Network Send");
|
||||
self::$playerNetworkSendCompress = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Compression", self::$playerNetworkSend);
|
||||
self::$playerNetworkSendCompressBroadcast = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Compression (Broadcast)", self::$playerNetworkSendCompress);
|
||||
self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress);
|
||||
self::$playerNetworkSendEncrypt = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Encryption", self::$playerNetworkSend);
|
||||
|
||||
self::$playerNetworkReceive = new TimingsHandler("Player Network Receive");
|
||||
@ -231,8 +240,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 +262,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
|
||||
|
@ -5,11 +5,6 @@ parameters:
|
||||
count: 2
|
||||
path: ../../../build/make-release.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$pharPath of function pocketmine\\\\build\\\\server_phar\\\\buildPhar expects string, array\\<int, mixed\\>\\|string\\|false given\\.$#"
|
||||
count: 1
|
||||
path: ../../../build/server-phar.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$strings of function pocketmine\\\\build\\\\server_phar\\\\preg_quote_array expects array\\<string\\>, array\\<int, string\\|false\\> given\\.$#"
|
||||
count: 1
|
||||
@ -25,16 +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 array\\<int, mixed\\>\\|string\\|false to string\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/ServerConfigGroup.php
|
||||
|
||||
-
|
||||
message: "#^Cannot cast mixed to int\\.$#"
|
||||
count: 2
|
||||
@ -590,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
|
||||
@ -1315,11 +1295,6 @@ parameters:
|
||||
count: 3
|
||||
path: ../../../src/world/light/SkyLightUpdate.php
|
||||
|
||||
-
|
||||
message: "#^Only numeric types are allowed in \\+, int\\|false given on the left side\\.$#"
|
||||
count: 1
|
||||
path: ../../../src/world/light/SkyLightUpdate.php
|
||||
|
||||
-
|
||||
message: "#^Only numeric types are allowed in \\-, int\\|null given on the right side\\.$#"
|
||||
count: 1
|
||||
|
Reference in New Issue
Block a user