mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-13 12:55:06 +00:00
Compare commits
57 Commits
4.16.0-BET
...
4.18.0-ALP
Author | SHA1 | Date | |
---|---|---|---|
bd21feffc4 | |||
5b324f695c | |||
9caed10488 | |||
83945ff0a0 | |||
ef45180b80 | |||
941fd03998 | |||
1af8da3c1f | |||
a5985dcf7d | |||
183d1f4038 | |||
08ee825d91 | |||
337a254768 | |||
a31e3331fd | |||
acebbeed16 | |||
e0fdbe6eb1 | |||
cc8660629b | |||
e7e19abe85 | |||
5f9e0081fd | |||
b266f45152 | |||
14f141fab2 | |||
daff955bc4 | |||
0022d82779 | |||
7cad9be0d2 | |||
2f862a552a | |||
590f6dad08 | |||
9564c81582 | |||
3de7a8c27f | |||
d376399b7f | |||
e2071e59c8 | |||
8e280ebb8b | |||
fa7c38276c | |||
b13e97de3d | |||
328b87fc18 | |||
acaa1a9ce1 | |||
3aec0fa3df | |||
fa131dab12 | |||
bb4a82b1e7 | |||
93d844a281 | |||
616844696e | |||
71e3e36522 | |||
a1b42d419f | |||
ef942a627f | |||
fd8c276bd2 | |||
9783380d1a | |||
a784d93bfd | |||
a05e8b366f | |||
87a2e0460c | |||
4073c3fb39 | |||
e227e6d8bf | |||
3aa40829ae | |||
035d4b7263 | |||
3db1492c18 | |||
a523189149 | |||
f8893efb94 | |||
70f1ee3e97 | |||
eb2f0ed3d0 | |||
0edc5f8113 | |||
a382f0fd92 |
10
.github/workflows/build-docker-image.yml
vendored
10
.github/workflows/build-docker-image.yml
vendored
@ -30,20 +30,20 @@ jobs:
|
|||||||
id: tag-name
|
id: tag-name
|
||||||
run: |
|
run: |
|
||||||
VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
||||||
echo ::set-output name=TAG_NAME::$VERSION
|
echo TAG_NAME=$VERSION >> $GITHUB_OUTPUT
|
||||||
echo ::set-output name=MAJOR::$(echo $VERSION | cut -d. -f1)
|
echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT
|
||||||
echo ::set-output name=MINOR::$(echo $VERSION | cut -d. -f1-2)
|
echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Download new release information
|
- name: Download new release information
|
||||||
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
|
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
|
||||||
|
|
||||||
- name: Detect channel
|
- name: Detect channel
|
||||||
id: channel
|
id: channel
|
||||||
run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json)
|
run: echo CHANNEL=$(jq -r '.channel' new_build_info.json) >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Get name of Docker repository name
|
- name: Get name of Docker repository name
|
||||||
id: docker-repo-name
|
id: docker-repo-name
|
||||||
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
|
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build image for tag
|
- name: Build image for tag
|
||||||
uses: docker/build-push-action@v4.0.0
|
uses: docker/build-push-action@v4.0.0
|
||||||
|
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>
|
* @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 [
|
return [
|
||||||
|
"content" => "<@&$newsPingRoleId> New PocketMine-MP release: $version ($channel)",
|
||||||
"embeds" => [
|
"embeds" => [
|
||||||
[
|
[
|
||||||
"title" => "New PocketMine-MP release: $version ($channel)",
|
"title" => "New PocketMine-MP release: $version ($channel)",
|
||||||
@ -35,11 +36,11 @@ DESCRIPTION,
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(count($argv) !== 5){
|
if(count($argv) !== 6){
|
||||||
fwrite(STDERR, "Required arguments: github repo, version, API token\n");
|
fwrite(STDERR, "Required arguments: github repo, version, API token, webhook URL, ping role ID\n");
|
||||||
exit(1);
|
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: [
|
$result = Internet::getURL('https://api.github.com/repos/' . $repo . '/releases/tags/' . $tagName, extraHeaders: [
|
||||||
'Authorization: token ' . $token
|
'Authorization: token ' . $token
|
||||||
@ -86,7 +87,7 @@ $buildLogUrl = $buildInfoJson["build_log_url"];
|
|||||||
|
|
||||||
$description = $releaseInfoJson["body"];
|
$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(
|
$response = Internet::postURL(
|
||||||
$hookURL,
|
$hookURL,
|
||||||
|
4
.github/workflows/discord-release-notify.yml
vendored
4
.github/workflows/discord-release-notify.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Get actual tag name
|
- name: Get actual tag name
|
||||||
id: tag-name
|
id: tag-name
|
||||||
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Run webhook post script
|
- 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 }}
|
||||||
|
14
.github/workflows/draft-release.yml
vendored
14
.github/workflows/draft-release.yml
vendored
@ -40,7 +40,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
BUILD_NUMBER=$((2000+$GITHUB_RUN_NUMBER)) #to stay above jenkins
|
BUILD_NUMBER=$((2000+$GITHUB_RUN_NUMBER)) #to stay above jenkins
|
||||||
echo "Build number: $BUILD_NUMBER"
|
echo "Build number: $BUILD_NUMBER"
|
||||||
echo ::set-output name=BUILD_NUMBER::$BUILD_NUMBER
|
echo BUILD_NUMBER=$BUILD_NUMBER >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Minify BedrockData JSON files
|
- name: Minify BedrockData JSON files
|
||||||
run: php vendor/pocketmine/bedrock-data/.minify_json.php
|
run: php vendor/pocketmine/bedrock-data/.minify_json.php
|
||||||
@ -51,11 +51,12 @@ jobs:
|
|||||||
- name: Get PocketMine-MP release version
|
- name: Get PocketMine-MP release version
|
||||||
id: get-pm-version
|
id: get-pm-version
|
||||||
run: |
|
run: |
|
||||||
echo ::set-output name=PM_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BASE_VERSION;')
|
echo PM_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BASE_VERSION;') >> $GITHUB_OUTPUT
|
||||||
echo ::set-output name=MCPE_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;')
|
echo MCPE_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;') >> $GITHUB_OUTPUT
|
||||||
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 PM_VERSION_SHORT=$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);') >> $GITHUB_OUTPUT
|
||||||
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);')
|
echo PM_VERSION_MD=$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);') >> $GITHUB_OUTPUT
|
||||||
echo ::set-output name=CHANGELOG_SUFFIX::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;')
|
echo CHANGELOG_SUFFIX=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;') >> $GITHUB_OUTPUT
|
||||||
|
echo PRERELEASE=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "false" : "true";') >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Generate build info
|
- 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
|
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
|
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||||
commit: ${{ github.sha }}
|
commit: ${{ github.sha }}
|
||||||
draft: true
|
draft: true
|
||||||
|
prerelease: ${{ steps.get-pm-version.outputs.PRERELEASE }}
|
||||||
name: PocketMine-MP ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
name: PocketMine-MP ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||||
tag: ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
tag: ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
11
.github/workflows/main.yml
vendored
11
.github/workflows/main.yml
vendored
@ -9,12 +9,11 @@ jobs:
|
|||||||
build-php:
|
build-php:
|
||||||
name: Prepare PHP
|
name: Prepare PHP
|
||||||
runs-on: ${{ matrix.image }}
|
runs-on: ${{ matrix.image }}
|
||||||
concurrency: php-build-${{ matrix.php }}
|
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
image: [ubuntu-20.04]
|
image: [ubuntu-20.04]
|
||||||
php: [8.0.27, 8.1.14, 8.2.1]
|
php: [8.0.28, 8.1.16, 8.2.3]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Build and prepare PHP cache
|
- name: Build and prepare PHP cache
|
||||||
@ -33,7 +32,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
image: [ubuntu-20.04]
|
image: [ubuntu-20.04]
|
||||||
php: [8.0.27, 8.1.14, 8.2.1]
|
php: [8.0.28, 8.1.16, 8.2.3]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@ -72,7 +71,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
image: [ubuntu-20.04]
|
image: [ubuntu-20.04]
|
||||||
php: [8.0.27, 8.1.14, 8.2.1]
|
php: [8.0.28, 8.1.16, 8.2.3]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@ -111,7 +110,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
image: [ubuntu-20.04]
|
image: [ubuntu-20.04]
|
||||||
php: [8.0.27, 8.1.14, 8.2.1]
|
php: [8.0.28, 8.1.16, 8.2.3]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@ -152,7 +151,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
image: [ubuntu-20.04]
|
image: [ubuntu-20.04]
|
||||||
php: [8.0.27, 8.1.14, 8.2.1]
|
php: [8.0.28, 8.1.16, 8.2.3]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
59
.github/workflows/update-updater-api.yml
vendored
59
.github/workflows/update-updater-api.yml
vendored
@ -15,23 +15,68 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: pmmp/update.pmmp.io
|
repository: ${{ github.repository_owner }}/update.pmmp.io
|
||||||
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
|
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
|
||||||
|
|
||||||
- name: Get actual tag name
|
- name: Get actual tag name
|
||||||
id: tag-name
|
id: tag-name
|
||||||
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Download new release information
|
- name: Download new release information
|
||||||
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
|
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
|
||||||
|
|
||||||
- name: Detect channel
|
- name: Detect channels
|
||||||
id: channel
|
id: channel
|
||||||
run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json)
|
|
||||||
|
|
||||||
- name: Copy release information
|
|
||||||
run: |
|
run: |
|
||||||
cp new_build_info.json channels/${{ steps.channel.outputs.CHANNEL }}.json
|
CHANNEL=$(jq -r '.channel' new_build_info.json)
|
||||||
|
VERSION=${{ steps.tag-name.outputs.TAG_NAME }}
|
||||||
|
echo CHANNEL=$CHANNEL >> $GITHUB_OUTPUT
|
||||||
|
if [ "$CHANNEL" == "stable" ]; then
|
||||||
|
echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT
|
||||||
|
echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo MAJOR=$(echo $VERSION | cut -d. -f1)-$CHANNEL >> $GITHUB_OUTPUT
|
||||||
|
echo MINOR=$(echo $VERSION | cut -d. -f1-2)-$CHANNEL >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Update channel info
|
||||||
|
run: |
|
||||||
|
function version_id() {
|
||||||
|
major=$(echo $1 | cut -d. -f1)
|
||||||
|
minor=$(echo $1 | cut -d. -f2)
|
||||||
|
patch=$(echo $1 | cut -d. -f3)
|
||||||
|
echo $(((major * 1000000) + (minor * 1000) + patch))
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_channel() {
|
||||||
|
local target_file_name="$1"
|
||||||
|
local new_file_name="$2"
|
||||||
|
|
||||||
|
local old_version_id
|
||||||
|
local new_version_id
|
||||||
|
|
||||||
|
if [ ! -f "$target_file_name" ]; then
|
||||||
|
echo "Creating channel file: $target_file_name"
|
||||||
|
cp "$new_file_name" "$target_file_name"
|
||||||
|
else
|
||||||
|
old_version_id=$(version_id "$(jq -r '.base_version' "$target_file_name")")
|
||||||
|
new_version_id=$(version_id "$(jq -r '.base_version' "$new_file_name")")
|
||||||
|
|
||||||
|
echo "Old version ID: $old_version_id"
|
||||||
|
echo "New version ID: $new_version_id"
|
||||||
|
|
||||||
|
if [ $new_version_id -ge $old_version_id ]; then #suffixed versions will have the same version ID - assume they'll always be newer
|
||||||
|
echo "Updating channel file: $target_file_name ($old_version_id -> $new_version_id)"
|
||||||
|
cp "$new_file_name" "$target_file_name"
|
||||||
|
else
|
||||||
|
echo "Version $new_version_id is less than $old_version_id, not updating channel file: $target_file_name"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
update_channel "channels/${{ steps.channel.outputs.CHANNEL }}.json" "new_build_info.json"
|
||||||
|
update_channel "channels/${{ steps.channel.outputs.MAJOR }}.json" "new_build_info.json"
|
||||||
|
update_channel "channels/${{ steps.channel.outputs.MINOR }}.json" "new_build_info.json"
|
||||||
rm new_build_info.json
|
rm new_build_info.json
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Commit changes
|
||||||
|
@ -21,7 +21,7 @@ Larger contributions like feature additions should be preceded by a [Change Prop
|
|||||||
## Choosing a target branch
|
## Choosing a target branch
|
||||||
PocketMine-MP has three primary branches of development.
|
PocketMine-MP has three primary branches of development.
|
||||||
|
|
||||||
| Type of change | `stable` | `next-minor` | `next-major` |
|
| Type of change | `stable` | `minor-next` | `major-next` |
|
||||||
|:---------------|:--------:|:------------:|:------------:|
|
|:---------------|:--------:|:------------:|:------------:|
|
||||||
| Bug fixes | ✔️ | ✔️ | ✔️ |
|
| Bug fixes | ✔️ | ✔️ | ✔️ |
|
||||||
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
|
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
|
||||||
|
@ -36,11 +36,12 @@ use function fwrite;
|
|||||||
use function getopt;
|
use function getopt;
|
||||||
use function is_string;
|
use function is_string;
|
||||||
use function max;
|
use function max;
|
||||||
|
use function preg_match;
|
||||||
use function preg_replace;
|
use function preg_replace;
|
||||||
use function sleep;
|
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
use function str_pad;
|
use function str_pad;
|
||||||
use function strlen;
|
use function strlen;
|
||||||
|
use function strtolower;
|
||||||
use function system;
|
use function system;
|
||||||
use const STDERR;
|
use const STDERR;
|
||||||
use const STDIN;
|
use const STDIN;
|
||||||
@ -102,22 +103,43 @@ function main() : void{
|
|||||||
$filteredOpts[$optName] = $optValue;
|
$filteredOpts[$optName] = $optValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$channel = $filteredOpts["channel"] ?? null;
|
||||||
if(isset($filteredOpts["current"])){
|
if(isset($filteredOpts["current"])){
|
||||||
$currentVer = new VersionString($filteredOpts["current"]);
|
$currentVer = new VersionString($filteredOpts["current"]);
|
||||||
}else{
|
}else{
|
||||||
$currentVer = new VersionString(VersionInfo::BASE_VERSION);
|
$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{
|
}else{
|
||||||
$nextVer = new VersionString(sprintf(
|
$nextVer ??= new VersionString(sprintf(
|
||||||
"%u.%u.%u",
|
"%u.%u.%u",
|
||||||
$currentVer->getMajor(),
|
$currentVer->getMajor(),
|
||||||
$currentVer->getMinor(),
|
$currentVer->getMinor(),
|
||||||
$currentVer->getPatch() + 1
|
$currentVer->getPatch() + 1
|
||||||
));
|
));
|
||||||
|
$channel ??= "stable";
|
||||||
}
|
}
|
||||||
$channel = $filteredOpts["channel"] ?? VersionInfo::BUILD_CHANNEL;
|
|
||||||
|
|
||||||
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
|
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
|
||||||
echo "$currentVer will be published on release channel \"$channel\".\n";
|
echo "$currentVer will be published on release channel \"$channel\".\n";
|
||||||
@ -137,9 +159,6 @@ function main() : void{
|
|||||||
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel);
|
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel);
|
||||||
systemWrapper('git add "' . $versionInfoPath . '"', "failed to stage changes for post-release commit");
|
systemWrapper('git add "' . $versionInfoPath . '"', "failed to stage changes for post-release commit");
|
||||||
systemWrapper('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"', "failed to create post-release commit");
|
systemWrapper('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"', "failed to create post-release commit");
|
||||||
echo "pushing changes in 5 seconds\n";
|
|
||||||
sleep(5);
|
|
||||||
systemWrapper('git push origin HEAD ' . $currentVer->getBaseVersion(), "failed to push changes to remote");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
Submodule build/php updated: b2207cf70d...a464454d1e
@ -29,3 +29,10 @@ Released 24th February 2023.
|
|||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
- Fixed `World Population` timer sometimes not being stopped, causing strange results in timings reports.
|
- 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.
|
||||||
|
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.
|
14
changelogs/4.17.md
Normal file
14
changelogs/4.17.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
**For Minecraft: Bedrock Edition 1.19.70**
|
||||||
|
|
||||||
|
### 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.17.0
|
||||||
|
Released 14th March 2023.
|
||||||
|
|
||||||
|
## General
|
||||||
|
- Added support for Minecraft: Bedrock Edition 1.19.70.
|
||||||
|
- Removed support for older versions.
|
45
changelogs/4.18-alpha.md
Normal file
45
changelogs/4.18-alpha.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
**For Minecraft: Bedrock Edition 1.19.70**
|
||||||
|
|
||||||
|
### Note about API versions
|
||||||
|
Plugins which don't touch the `pocketmine\network\mcpe` namespace are 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 `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||||
|
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||||
|
|
||||||
|
### Alpha release warning
|
||||||
|
Alpha releases are **experimental**. Features introduced in these releases are subject to change or removal.
|
||||||
|
|
||||||
|
APIs which existed **prior** to this version will continue to work as normal, so plugins which use them will continue to work.
|
||||||
|
|
||||||
|
### Highlights
|
||||||
|
This version makes changes to the internal network system to improve server performance and reduce memory usage.
|
||||||
|
|
||||||
|
While these changes don't affect non-internal API, they are still significant enough to warrant a new minor version, as they may break plugins which use the internal network API (not recommended).
|
||||||
|
|
||||||
|
# 4.18.0-ALPHA1
|
||||||
|
Released 16th March 2023.
|
||||||
|
|
||||||
|
## General
|
||||||
|
- Improved server performance in congested areas of the world (lots of players and/or entities in the same area).
|
||||||
|
|
||||||
|
## API
|
||||||
|
### `pocketmine\event\server`
|
||||||
|
- The following new classes have been added:
|
||||||
|
- `DataPacketDecodeEvent` - called before a packet is decoded by a `NetworkSession`; useful to mitigate DoS attacks if PocketMine-MP hasn't been patched against new bugs yet
|
||||||
|
|
||||||
|
## Internals
|
||||||
|
- Introduced new system for broadcasting entity events to network sessions.
|
||||||
|
- This change improves performance when lots of players and/or entities are in the same area.
|
||||||
|
- New interface `EntityEventBroadcaster` and class `StandardEntityEventBroadcaster` have been added to implement this.
|
||||||
|
- All entity-specific `on*()` and `sync*()` methods have been removed from `NetworkSession` (BC break).
|
||||||
|
- `NetworkSession` now accepts an `EntityEventBroadcaster` instance in its constructor.
|
||||||
|
- `NetworkBroadcastUtils::broadcastEntityEvent()` can be used to efficiently broadcast events to unique broadcasters shared by several network sessions.
|
||||||
|
- All network sessions now share the same `PacketSerializerContext` and `PacketBroadcaster` by default.
|
||||||
|
- Previously, every session had its own context, meaning that broadcast optimisations were not used, causing significant performance losses compared to 3.x.
|
||||||
|
- This change improves performance in congested areas by allowing reuse of previously encoded packet buffers for all sessions sharing the same context.
|
||||||
|
- Packet broadcasts are automatically encoded separately per unique `PacketSerializerContext` instance. This allows, for example, a multi-version fork to have a separate context for each protocol version, to ensure maximum broadcast efficiency while encoding different packets for different versions.
|
||||||
|
- `PacketSerializerContext` is now passed in `NetworkSession::__construct()`, instead of being created by the session.
|
||||||
|
- `StandardPacketBroadcaster` is now locked to a single `PacketSerializer` context, reducing complexity.
|
||||||
|
- Introduced `NetworkBroadcastUtils::broadcastPackets()`, replacing `Server->broadcastPackets()`.
|
||||||
|
- `Server->broadcastPackets()` has been deprecated. It will be removed in a future version.
|
@ -34,10 +34,10 @@
|
|||||||
"adhocore/json-comment": "^1.1",
|
"adhocore/json-comment": "^1.1",
|
||||||
"fgrosse/phpasn1": "^2.3",
|
"fgrosse/phpasn1": "^2.3",
|
||||||
"netresearch/jsonmapper": "^4.0",
|
"netresearch/jsonmapper": "^4.0",
|
||||||
"pocketmine/bedrock-block-upgrade-schema": "^1.0.0",
|
"pocketmine/bedrock-block-upgrade-schema": "~1.1.1+bedrock-1.19.70",
|
||||||
"pocketmine/bedrock-data": "~2.0.0+bedrock-1.19.60",
|
"pocketmine/bedrock-data": "~2.1.1+bedrock-1.19.70",
|
||||||
"pocketmine/bedrock-item-upgrade-schema": "^1.0.0",
|
"pocketmine/bedrock-item-upgrade-schema": "~1.1.0+bedrock-1.19.70",
|
||||||
"pocketmine/bedrock-protocol": "~19.3.0+bedrock-1.19.62",
|
"pocketmine/bedrock-protocol": "~20.0.0+bedrock-1.19.70",
|
||||||
"pocketmine/binaryutils": "^0.2.1",
|
"pocketmine/binaryutils": "^0.2.1",
|
||||||
"pocketmine/callback-validator": "^1.0.2",
|
"pocketmine/callback-validator": "^1.0.2",
|
||||||
"pocketmine/classloader": "^0.2.0",
|
"pocketmine/classloader": "^0.2.0",
|
||||||
@ -56,7 +56,7 @@
|
|||||||
"webmozart/path-util": "^2.3"
|
"webmozart/path-util": "^2.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "1.10.3",
|
"phpstan/phpstan": "1.10.6",
|
||||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||||
"phpunit/phpunit": "^9.2"
|
"phpunit/phpunit": "^9.2"
|
||||||
|
146
composer.lock
generated
146
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "e771a9cf116389fef15848801d410c36",
|
"content-hash": "1d0c1d2fe668d85ae87110a1e3cfac05",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adhocore/json-comment",
|
"name": "adhocore/json-comment",
|
||||||
@ -250,16 +250,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-block-upgrade-schema",
|
"name": "pocketmine/bedrock-block-upgrade-schema",
|
||||||
"version": "1.0.0",
|
"version": "1.1.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
|
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
|
||||||
"reference": "a05ce434eb7f8c11058d26833bc975fe635b23b4"
|
"reference": "e0540343e649a92126a1d4071ec401a811416c76"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/a05ce434eb7f8c11058d26833bc975fe635b23b4",
|
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/e0540343e649a92126a1d4071ec401a811416c76",
|
||||||
"reference": "a05ce434eb7f8c11058d26833bc975fe635b23b4",
|
"reference": "e0540343e649a92126a1d4071ec401a811416c76",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -270,22 +270,22 @@
|
|||||||
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
|
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
|
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
|
||||||
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/1.0.0"
|
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/1.1.1"
|
||||||
},
|
},
|
||||||
"time": "2023-02-01T21:09:54+00:00"
|
"time": "2023-03-08T23:45:59+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-data",
|
"name": "pocketmine/bedrock-data",
|
||||||
"version": "2.0.0+bedrock-1.19.60",
|
"version": "2.1.1+bedrock-1.19.70",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/BedrockData.git",
|
"url": "https://github.com/pmmp/BedrockData.git",
|
||||||
"reference": "957e49b2381641af29f595e4f32ded3e76ce4723"
|
"reference": "cba0567bcb25f987f2712092f8d662056719e82d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/957e49b2381641af29f595e4f32ded3e76ce4723",
|
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/cba0567bcb25f987f2712092f8d662056719e82d",
|
||||||
"reference": "957e49b2381641af29f595e4f32ded3e76ce4723",
|
"reference": "cba0567bcb25f987f2712092f8d662056719e82d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -296,22 +296,22 @@
|
|||||||
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
|
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/BedrockData/issues",
|
"issues": "https://github.com/pmmp/BedrockData/issues",
|
||||||
"source": "https://github.com/pmmp/BedrockData/tree/2.0.0+bedrock-1.19.60"
|
"source": "https://github.com/pmmp/BedrockData/tree/2.1.1+bedrock-1.19.70"
|
||||||
},
|
},
|
||||||
"time": "2023-02-23T21:25:04+00:00"
|
"time": "2023-03-14T18:03:19+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-item-upgrade-schema",
|
"name": "pocketmine/bedrock-item-upgrade-schema",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
|
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
|
||||||
"reference": "7e53f77ea34ba30b1f94d3c24e64e19d3c4296e7"
|
"reference": "aab89a1f121a0c127557a4a0cf981330301c9c45"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/7e53f77ea34ba30b1f94d3c24e64e19d3c4296e7",
|
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/aab89a1f121a0c127557a4a0cf981330301c9c45",
|
||||||
"reference": "7e53f77ea34ba30b1f94d3c24e64e19d3c4296e7",
|
"reference": "aab89a1f121a0c127557a4a0cf981330301c9c45",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -322,22 +322,22 @@
|
|||||||
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
|
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
|
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
|
||||||
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.0.0"
|
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.1.0"
|
||||||
},
|
},
|
||||||
"time": "2023-02-01T22:50:02+00:00"
|
"time": "2023-03-08T22:27:13+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-protocol",
|
"name": "pocketmine/bedrock-protocol",
|
||||||
"version": "19.3.0+bedrock-1.19.62",
|
"version": "20.0.0+bedrock-1.19.70",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||||
"reference": "a5bf4753c7f30f781c4541918e238f5bb637e7ad"
|
"reference": "4892a5020187da805d7b46ab522d8185b0283726"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/a5bf4753c7f30f781c4541918e238f5bb637e7ad",
|
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/4892a5020187da805d7b46ab522d8185b0283726",
|
||||||
"reference": "a5bf4753c7f30f781c4541918e238f5bb637e7ad",
|
"reference": "4892a5020187da805d7b46ab522d8185b0283726",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -351,7 +351,7 @@
|
|||||||
"ramsey/uuid": "^4.1"
|
"ramsey/uuid": "^4.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "1.9.13",
|
"phpstan/phpstan": "1.10.1",
|
||||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||||
"phpunit/phpunit": "^9.5"
|
"phpunit/phpunit": "^9.5"
|
||||||
@ -369,9 +369,9 @@
|
|||||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/19.3.0+bedrock-1.19.62"
|
"source": "https://github.com/pmmp/BedrockProtocol/tree/20.0.0+bedrock-1.19.70"
|
||||||
},
|
},
|
||||||
"time": "2023-02-19T16:11:03+00:00"
|
"time": "2023-03-14T17:06:38+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/binaryutils",
|
"name": "pocketmine/binaryutils",
|
||||||
@ -780,16 +780,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/raklib",
|
"name": "pocketmine/raklib",
|
||||||
"version": "0.14.5",
|
"version": "0.14.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/RakLib.git",
|
"url": "https://github.com/pmmp/RakLib.git",
|
||||||
"reference": "85b4e5cb7117d37e010eeadb3ff53b21276c6f48"
|
"reference": "aeca667d5ecc4cc18fded612f29e3511bbf62f42"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/85b4e5cb7117d37e010eeadb3ff53b21276c6f48",
|
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/aeca667d5ecc4cc18fded612f29e3511bbf62f42",
|
||||||
"reference": "85b4e5cb7117d37e010eeadb3ff53b21276c6f48",
|
"reference": "aeca667d5ecc4cc18fded612f29e3511bbf62f42",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -801,7 +801,7 @@
|
|||||||
"pocketmine/log": "^0.3.0 || ^0.4.0"
|
"pocketmine/log": "^0.3.0 || ^0.4.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "1.7.7",
|
"phpstan/phpstan": "1.9.17",
|
||||||
"phpstan/phpstan-strict-rules": "^1.0"
|
"phpstan/phpstan-strict-rules": "^1.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -817,9 +817,9 @@
|
|||||||
"description": "A RakNet server implementation written in PHP",
|
"description": "A RakNet server implementation written in PHP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/RakLib/issues",
|
"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",
|
"name": "pocketmine/raklib-ipc",
|
||||||
@ -1658,16 +1658,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "myclabs/deep-copy",
|
"name": "myclabs/deep-copy",
|
||||||
"version": "1.11.0",
|
"version": "1.11.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||||
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
|
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
|
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||||
"reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
|
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1705,7 +1705,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
|
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1713,20 +1713,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2022-03-03T13:19:32+00:00"
|
"time": "2023-03-08T13:26:56+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/php-parser",
|
"name": "nikic/php-parser",
|
||||||
"version": "v4.15.3",
|
"version": "v4.15.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||||
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039"
|
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039",
|
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
|
||||||
"reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039",
|
"reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1767,9 +1767,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3"
|
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4"
|
||||||
},
|
},
|
||||||
"time": "2023-01-16T22:05:37+00:00"
|
"time": "2023-03-05T19:49:14+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
@ -1884,16 +1884,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan",
|
"name": "phpstan/phpstan",
|
||||||
"version": "1.10.3",
|
"version": "1.10.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpstan.git",
|
"url": "https://github.com/phpstan/phpstan.git",
|
||||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64"
|
"reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/5419375b5891add97dc74be71e6c1c34baaddf64",
|
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/50d089a3e0904b0fe7e2cf2d4fd37d427d64235a",
|
||||||
"reference": "5419375b5891add97dc74be71e6c1c34baaddf64",
|
"reference": "50d089a3e0904b0fe7e2cf2d4fd37d427d64235a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1923,7 +1923,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpstan/issues",
|
"issues": "https://github.com/phpstan/phpstan/issues",
|
||||||
"source": "https://github.com/phpstan/phpstan/tree/1.10.3"
|
"source": "https://github.com/phpstan/phpstan/tree/1.10.6"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1939,20 +1939,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-02-25T14:47:13+00:00"
|
"time": "2023-03-09T16:55:12+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan-phpunit",
|
"name": "phpstan/phpstan-phpunit",
|
||||||
"version": "1.3.9",
|
"version": "1.3.10",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||||
"reference": "34ee324a2b8fcab680fbb3f3f3d6c86389df35ba"
|
"reference": "4cc5c6cc38e56bce7ea47c4091814e516d172dc3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/34ee324a2b8fcab680fbb3f3f3d6c86389df35ba",
|
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/4cc5c6cc38e56bce7ea47c4091814e516d172dc3",
|
||||||
"reference": "34ee324a2b8fcab680fbb3f3f3d6c86389df35ba",
|
"reference": "4cc5c6cc38e56bce7ea47c4091814e516d172dc3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1989,9 +1989,9 @@
|
|||||||
"description": "PHPUnit extensions and rules for PHPStan",
|
"description": "PHPUnit extensions and rules for PHPStan",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
||||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.9"
|
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.10"
|
||||||
},
|
},
|
||||||
"time": "2023-02-28T13:04:23+00:00"
|
"time": "2023-03-02T10:25:13+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan-strict-rules",
|
"name": "phpstan/phpstan-strict-rules",
|
||||||
@ -2044,16 +2044,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "9.2.25",
|
"version": "9.2.26",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954"
|
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e2b40518197a8c0d4b08bc34dfff1c99c508954",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
|
||||||
"reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954",
|
"reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -2075,8 +2075,8 @@
|
|||||||
"phpunit/phpunit": "^9.3"
|
"phpunit/phpunit": "^9.3"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-pcov": "*",
|
"ext-pcov": "PHP extension that provides line coverage",
|
||||||
"ext-xdebug": "*"
|
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
@ -2109,7 +2109,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.25"
|
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -2117,7 +2117,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-02-25T05:32:00+00:00"
|
"time": "2023-03-06T12:58:08+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
@ -2362,16 +2362,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "9.6.4",
|
"version": "9.6.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d"
|
"reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9125ee085b6d95e78277dc07aa1f46f9e0607b8d",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86e761949019ae83f49240b2f2123fb5ab3b2fc5",
|
||||||
"reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d",
|
"reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -2404,8 +2404,8 @@
|
|||||||
"sebastian/version": "^3.0.2"
|
"sebastian/version": "^3.0.2"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-soap": "*",
|
"ext-soap": "To be able to generate mocks based on WSDL files",
|
||||||
"ext-xdebug": "*"
|
"ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
"phpunit"
|
"phpunit"
|
||||||
@ -2444,7 +2444,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.4"
|
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -2460,7 +2460,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-02-27T13:06:37+00:00"
|
"time": "2023-03-09T06:34:10+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/cli-parser",
|
"name": "sebastian/cli-parser",
|
||||||
|
@ -49,6 +49,7 @@ use function ini_get;
|
|||||||
use function ini_set;
|
use function ini_set;
|
||||||
use function intdiv;
|
use function intdiv;
|
||||||
use function is_array;
|
use function is_array;
|
||||||
|
use function is_float;
|
||||||
use function is_object;
|
use function is_object;
|
||||||
use function is_resource;
|
use function is_resource;
|
||||||
use function is_string;
|
use function is_string;
|
||||||
@ -519,6 +520,8 @@ class MemoryManager{
|
|||||||
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||||
}elseif(is_resource($from)){
|
}elseif(is_resource($from)){
|
||||||
$data = "(resource) " . print_r($from, true);
|
$data = "(resource) " . print_r($from, true);
|
||||||
|
}elseif(is_float($from)){
|
||||||
|
$data = "(float) $from";
|
||||||
}else{
|
}else{
|
||||||
$data = $from;
|
$data = $from;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,6 @@ use pocketmine\event\player\PlayerCreationEvent;
|
|||||||
use pocketmine\event\player\PlayerDataSaveEvent;
|
use pocketmine\event\player\PlayerDataSaveEvent;
|
||||||
use pocketmine\event\player\PlayerLoginEvent;
|
use pocketmine\event\player\PlayerLoginEvent;
|
||||||
use pocketmine\event\server\CommandEvent;
|
use pocketmine\event\server\CommandEvent;
|
||||||
use pocketmine\event\server\DataPacketSendEvent;
|
|
||||||
use pocketmine\event\server\QueryRegenerateEvent;
|
use pocketmine\event\server\QueryRegenerateEvent;
|
||||||
use pocketmine\lang\KnownTranslationFactory;
|
use pocketmine\lang\KnownTranslationFactory;
|
||||||
use pocketmine\lang\Language;
|
use pocketmine\lang\Language;
|
||||||
@ -54,13 +53,19 @@ use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
|||||||
use pocketmine\network\mcpe\compression\CompressBatchTask;
|
use pocketmine\network\mcpe\compression\CompressBatchTask;
|
||||||
use pocketmine\network\mcpe\compression\Compressor;
|
use pocketmine\network\mcpe\compression\Compressor;
|
||||||
use pocketmine\network\mcpe\compression\ZlibCompressor;
|
use pocketmine\network\mcpe\compression\ZlibCompressor;
|
||||||
|
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
|
||||||
use pocketmine\network\mcpe\encryption\EncryptionContext;
|
use pocketmine\network\mcpe\encryption\EncryptionContext;
|
||||||
|
use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||||
|
use pocketmine\network\mcpe\NetworkBroadcastUtils;
|
||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
use pocketmine\network\mcpe\PacketBroadcaster;
|
use pocketmine\network\mcpe\PacketBroadcaster;
|
||||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||||
|
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||||
use pocketmine\network\mcpe\raklib\RakLibInterface;
|
use pocketmine\network\mcpe\raklib\RakLibInterface;
|
||||||
|
use pocketmine\network\mcpe\StandardEntityEventBroadcaster;
|
||||||
|
use pocketmine\network\mcpe\StandardPacketBroadcaster;
|
||||||
use pocketmine\network\Network;
|
use pocketmine\network\Network;
|
||||||
use pocketmine\network\NetworkInterfaceStartException;
|
use pocketmine\network\NetworkInterfaceStartException;
|
||||||
use pocketmine\network\query\DedicatedQueryNetworkInterface;
|
use pocketmine\network\query\DedicatedQueryNetworkInterface;
|
||||||
@ -1169,10 +1174,18 @@ class Server{
|
|||||||
return !$anyWorldFailedToLoad;
|
return !$anyWorldFailedToLoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function startupPrepareConnectableNetworkInterfaces(string $ip, int $port, bool $ipV6, bool $useQuery) : bool{
|
private function startupPrepareConnectableNetworkInterfaces(
|
||||||
|
string $ip,
|
||||||
|
int $port,
|
||||||
|
bool $ipV6,
|
||||||
|
bool $useQuery,
|
||||||
|
PacketBroadcaster $packetBroadcaster,
|
||||||
|
EntityEventBroadcaster $entityEventBroadcaster,
|
||||||
|
PacketSerializerContext $packetSerializerContext
|
||||||
|
) : bool{
|
||||||
$prettyIp = $ipV6 ? "[$ip]" : $ip;
|
$prettyIp = $ipV6 ? "[$ip]" : $ip;
|
||||||
try{
|
try{
|
||||||
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6));
|
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext));
|
||||||
}catch(NetworkInterfaceStartException $e){
|
}catch(NetworkInterfaceStartException $e){
|
||||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
|
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
|
||||||
$ip,
|
$ip,
|
||||||
@ -1198,11 +1211,15 @@ class Server{
|
|||||||
private function startupPrepareNetworkInterfaces() : bool{
|
private function startupPrepareNetworkInterfaces() : bool{
|
||||||
$useQuery = $this->configGroup->getConfigBool("enable-query", true);
|
$useQuery = $this->configGroup->getConfigBool("enable-query", true);
|
||||||
|
|
||||||
|
$packetSerializerContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
|
||||||
|
$packetBroadcaster = new StandardPacketBroadcaster($this, $packetSerializerContext);
|
||||||
|
$entityEventBroadcaster = new StandardEntityEventBroadcaster($packetBroadcaster);
|
||||||
|
|
||||||
if(
|
if(
|
||||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery) ||
|
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext) ||
|
||||||
(
|
(
|
||||||
$this->configGroup->getConfigBool("enable-ipv6", true) &&
|
$this->configGroup->getConfigBool("enable-ipv6", true) &&
|
||||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery)
|
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext)
|
||||||
)
|
)
|
||||||
){
|
){
|
||||||
return false;
|
return false;
|
||||||
@ -1334,46 +1351,10 @@ class Server{
|
|||||||
/**
|
/**
|
||||||
* @param Player[] $players
|
* @param Player[] $players
|
||||||
* @param ClientboundPacket[] $packets
|
* @param ClientboundPacket[] $packets
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
public function broadcastPackets(array $players, array $packets) : bool{
|
public function broadcastPackets(array $players, array $packets) : bool{
|
||||||
if(count($packets) === 0){
|
return NetworkBroadcastUtils::broadcastPackets($players, $packets);
|
||||||
throw new \InvalidArgumentException("Cannot broadcast empty list of packets");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Timings::$broadcastPackets->time(function() use ($players, $packets) : bool{
|
|
||||||
/** @var NetworkSession[] $recipients */
|
|
||||||
$recipients = [];
|
|
||||||
foreach($players as $player){
|
|
||||||
if($player->isConnected()){
|
|
||||||
$recipients[] = $player->getNetworkSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(count($recipients) === 0){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ev = new DataPacketSendEvent($recipients, $packets);
|
|
||||||
$ev->call();
|
|
||||||
if($ev->isCancelled()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$recipients = $ev->getTargets();
|
|
||||||
|
|
||||||
/** @var PacketBroadcaster[] $broadcasters */
|
|
||||||
$broadcasters = [];
|
|
||||||
/** @var NetworkSession[][] $broadcasterTargets */
|
|
||||||
$broadcasterTargets = [];
|
|
||||||
foreach($recipients as $recipient){
|
|
||||||
$broadcaster = $recipient->getBroadcaster();
|
|
||||||
$broadcasters[spl_object_id($broadcaster)] = $broadcaster;
|
|
||||||
$broadcasterTargets[spl_object_id($broadcaster)][] = $recipient;
|
|
||||||
}
|
|
||||||
foreach($broadcasters as $broadcaster){
|
|
||||||
$broadcaster->broadcastPackets($broadcasterTargets[spl_object_id($broadcaster)], $packets);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1381,9 +1362,10 @@ class Server{
|
|||||||
*
|
*
|
||||||
* @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null).
|
* @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{
|
try{
|
||||||
Timings::$playerNetworkSendCompress->startTiming();
|
$timings->startTiming();
|
||||||
|
|
||||||
$buffer = $stream->getBuffer();
|
$buffer = $stream->getBuffer();
|
||||||
|
|
||||||
@ -1402,7 +1384,7 @@ class Server{
|
|||||||
|
|
||||||
return $promise;
|
return $promise;
|
||||||
}finally{
|
}finally{
|
||||||
Timings::$playerNetworkSendCompress->stopTiming();
|
$timings->stopTiming();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +31,9 @@ use function str_repeat;
|
|||||||
|
|
||||||
final class VersionInfo{
|
final class VersionInfo{
|
||||||
public const NAME = "PocketMine-MP";
|
public const NAME = "PocketMine-MP";
|
||||||
public const BASE_VERSION = "4.16.0-BETA2";
|
public const BASE_VERSION = "4.18.0-ALPHA1";
|
||||||
public const IS_DEVELOPMENT_BUILD = false;
|
public const IS_DEVELOPMENT_BUILD = false;
|
||||||
public const BUILD_CHANNEL = "beta";
|
public const BUILD_CHANNEL = "alpha";
|
||||||
|
|
||||||
private function __construct(){
|
private function __construct(){
|
||||||
//NOOP
|
//NOOP
|
||||||
|
@ -34,7 +34,7 @@ class RedMushroomBlock extends Opaque{
|
|||||||
protected MushroomBlockType $mushroomBlockType;
|
protected MushroomBlockType $mushroomBlockType;
|
||||||
|
|
||||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
|
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
|
||||||
$this->mushroomBlockType = MushroomBlockType::PORES();
|
$this->mushroomBlockType = MushroomBlockType::ALL_CAP();
|
||||||
parent::__construct($idInfo, $name, $breakInfo);
|
parent::__construct($idInfo, $name, $breakInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +42,11 @@ class RedMushroomBlock extends Opaque{
|
|||||||
return MushroomBlockTypeIdMap::getInstance()->toId($this->mushroomBlockType);
|
return MushroomBlockTypeIdMap::getInstance()->toId($this->mushroomBlockType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function writeStateToItemMeta() : int{
|
||||||
|
//these blocks always drop as all-cap, but may exist in other forms in the inventory (particularly creative)
|
||||||
|
return BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_CAP;
|
||||||
|
}
|
||||||
|
|
||||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||||
$type = MushroomBlockTypeIdMap::getInstance()->fromId($stateMeta);
|
$type = MushroomBlockTypeIdMap::getInstance()->fromId($stateMeta);
|
||||||
if($type === null){
|
if($type === null){
|
||||||
|
@ -44,6 +44,8 @@ use pocketmine\nbt\tag\DoubleTag;
|
|||||||
use pocketmine\nbt\tag\FloatTag;
|
use pocketmine\nbt\tag\FloatTag;
|
||||||
use pocketmine\nbt\tag\ListTag;
|
use pocketmine\nbt\tag\ListTag;
|
||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
|
use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||||
|
use pocketmine\network\mcpe\NetworkBroadcastUtils;
|
||||||
use pocketmine\network\mcpe\protocol\AddActorPacket;
|
use pocketmine\network\mcpe\protocol\AddActorPacket;
|
||||||
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
|
use pocketmine\network\mcpe\protocol\MoveActorAbsolutePacket;
|
||||||
use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
|
use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
|
||||||
@ -785,7 +787,7 @@ abstract class Entity{
|
|||||||
$this->spawnTo($player);
|
$this->spawnTo($player);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
$this->server->broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
|
NetworkBroadcastUtils::broadcastPackets($this->hasSpawned, [MoveActorAbsolutePacket::create(
|
||||||
$this->id,
|
$this->id,
|
||||||
$this->getOffsetPosition($this->location),
|
$this->getOffsetPosition($this->location),
|
||||||
$this->location->pitch,
|
$this->location->pitch,
|
||||||
@ -800,7 +802,7 @@ abstract class Entity{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function broadcastMotion() : void{
|
protected function broadcastMotion() : void{
|
||||||
$this->server->broadcastPackets($this->hasSpawned, [SetActorMotionPacket::create($this->id, $this->getMotion())]);
|
NetworkBroadcastUtils::broadcastPackets($this->hasSpawned, [SetActorMotionPacket::create($this->id, $this->getMotion())]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getGravity() : float{
|
public function getGravity() : float{
|
||||||
@ -1537,7 +1539,7 @@ abstract class Entity{
|
|||||||
$id = spl_object_id($player);
|
$id = spl_object_id($player);
|
||||||
if(isset($this->hasSpawned[$id])){
|
if(isset($this->hasSpawned[$id])){
|
||||||
if($send){
|
if($send){
|
||||||
$player->getNetworkSession()->onEntityRemoved($this);
|
$player->getNetworkSession()->getEntityEventBroadcaster()->onEntityRemoved([$player->getNetworkSession()], $this);
|
||||||
}
|
}
|
||||||
unset($this->hasSpawned[$id]);
|
unset($this->hasSpawned[$id]);
|
||||||
}
|
}
|
||||||
@ -1548,9 +1550,11 @@ abstract class Entity{
|
|||||||
* player moves, viewers will once again be able to see the entity.
|
* player moves, viewers will once again be able to see the entity.
|
||||||
*/
|
*/
|
||||||
public function despawnFromAll() : void{
|
public function despawnFromAll() : void{
|
||||||
foreach($this->hasSpawned as $player){
|
NetworkBroadcastUtils::broadcastEntityEvent(
|
||||||
$this->despawnFrom($player);
|
$this->hasSpawned,
|
||||||
}
|
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onEntityRemoved($recipients, $this)
|
||||||
|
);
|
||||||
|
$this->hasSpawned = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1624,9 +1628,7 @@ abstract class Entity{
|
|||||||
$targets = $targets ?? $this->hasSpawned;
|
$targets = $targets ?? $this->hasSpawned;
|
||||||
$data = $data ?? $this->getAllNetworkData();
|
$data = $data ?? $this->getAllNetworkData();
|
||||||
|
|
||||||
foreach($targets as $p){
|
NetworkBroadcastUtils::broadcastEntityEvent($targets, fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->syncActorData($recipients, $this, $data));
|
||||||
$p->getNetworkSession()->syncActorData($this, $data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1680,7 +1682,7 @@ abstract class Entity{
|
|||||||
* @param Player[]|null $targets
|
* @param Player[]|null $targets
|
||||||
*/
|
*/
|
||||||
public function broadcastAnimation(Animation $animation, ?array $targets = null) : void{
|
public function broadcastAnimation(Animation $animation, ?array $targets = null) : void{
|
||||||
$this->server->broadcastPackets($targets ?? $this->getViewers(), $animation->encode());
|
NetworkBroadcastUtils::broadcastPackets($targets ?? $this->getViewers(), $animation->encode());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1689,7 +1691,7 @@ abstract class Entity{
|
|||||||
*/
|
*/
|
||||||
public function broadcastSound(Sound $sound, ?array $targets = null) : void{
|
public function broadcastSound(Sound $sound, ?array $targets = null) : void{
|
||||||
if(!$this->silent){
|
if(!$this->silent){
|
||||||
$this->server->broadcastPackets($targets ?? $this->getViewers(), $sound->encode($this->location));
|
NetworkBroadcastUtils::broadcastPackets($targets ?? $this->getViewers(), $sound->encode($this->location));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,8 @@ use pocketmine\nbt\tag\ListTag;
|
|||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
||||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||||
|
use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||||
|
use pocketmine\network\mcpe\NetworkBroadcastUtils;
|
||||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||||
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||||
@ -174,7 +176,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
|||||||
* @param Player[]|null $targets
|
* @param Player[]|null $targets
|
||||||
*/
|
*/
|
||||||
public function sendSkin(?array $targets = null) : void{
|
public function sendSkin(?array $targets = null) : void{
|
||||||
$this->server->broadcastPackets($targets ?? $this->hasSpawned, [
|
NetworkBroadcastUtils::broadcastPackets($targets ?? $this->hasSpawned, [
|
||||||
PlayerSkinPacket::create($this->getUniqueId(), "", "", SkinAdapterSingleton::get()->toSkinData($this->skin))
|
PlayerSkinPacket::create($this->getUniqueId(), "", "", SkinAdapterSingleton::get()->toSkinData($this->skin))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -189,9 +191,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function emote(string $emoteId) : void{
|
public function emote(string $emoteId) : void{
|
||||||
foreach($this->getViewers() as $player){
|
NetworkBroadcastUtils::broadcastEntityEvent(
|
||||||
$player->getNetworkSession()->onEmote($this, $emoteId);
|
$this->getViewers(),
|
||||||
}
|
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onEmote($recipients, $this, $emoteId)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHungerManager() : HungerManager{
|
public function getHungerManager() : HungerManager{
|
||||||
@ -270,11 +273,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
|||||||
$this->xpManager = new ExperienceManager($this);
|
$this->xpManager = new ExperienceManager($this);
|
||||||
|
|
||||||
$this->inventory = new PlayerInventory($this);
|
$this->inventory = new PlayerInventory($this);
|
||||||
$syncHeldItem = function() : void{
|
$syncHeldItem = fn() => NetworkBroadcastUtils::broadcastEntityEvent(
|
||||||
foreach($this->getViewers() as $viewer){
|
$this->getViewers(),
|
||||||
$viewer->getNetworkSession()->onMobMainHandItemChange($this);
|
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobMainHandItemChange($recipients, $this)
|
||||||
}
|
);
|
||||||
};
|
|
||||||
$this->inventory->getListeners()->add(new CallbackInventoryListener(
|
$this->inventory->getListeners()->add(new CallbackInventoryListener(
|
||||||
function(Inventory $unused, int $slot, Item $unused2) use ($syncHeldItem) : void{
|
function(Inventory $unused, int $slot, Item $unused2) use ($syncHeldItem) : void{
|
||||||
if($slot === $this->inventory->getHeldItemIndex()){
|
if($slot === $this->inventory->getHeldItemIndex()){
|
||||||
@ -315,11 +317,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
|||||||
if($offHand !== null){
|
if($offHand !== null){
|
||||||
$this->offHandInventory->setItem(0, Item::nbtDeserialize($offHand));
|
$this->offHandInventory->setItem(0, Item::nbtDeserialize($offHand));
|
||||||
}
|
}
|
||||||
$this->offHandInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(function() : void{
|
$this->offHandInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(fn() => NetworkBroadcastUtils::broadcastEntityEvent(
|
||||||
foreach($this->getViewers() as $viewer){
|
$this->getViewers(),
|
||||||
$viewer->getNetworkSession()->onMobOffHandItemChange($this);
|
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobOffHandItemChange($recipients, $this)
|
||||||
}
|
)));
|
||||||
}));
|
|
||||||
|
|
||||||
$enderChestInventoryTag = $nbt->getListTag(self::TAG_ENDER_CHEST_INVENTORY);
|
$enderChestInventoryTag = $nbt->getListTag(self::TAG_ENDER_CHEST_INVENTORY);
|
||||||
if($enderChestInventoryTag !== null){
|
if($enderChestInventoryTag !== null){
|
||||||
@ -333,11 +334,10 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->inventory->setHeldItemIndex($nbt->getInt(self::TAG_SELECTED_INVENTORY_SLOT, 0));
|
$this->inventory->setHeldItemIndex($nbt->getInt(self::TAG_SELECTED_INVENTORY_SLOT, 0));
|
||||||
$this->inventory->getHeldItemIndexChangeListeners()->add(function(int $oldIndex) : void{
|
$this->inventory->getHeldItemIndexChangeListeners()->add(fn() => NetworkBroadcastUtils::broadcastEntityEvent(
|
||||||
foreach($this->getViewers() as $viewer){
|
$this->getViewers(),
|
||||||
$viewer->getNetworkSession()->onMobMainHandItemChange($this);
|
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobMainHandItemChange($recipients, $this)
|
||||||
}
|
));
|
||||||
});
|
|
||||||
|
|
||||||
$this->hungerManager->setFood((float) $nbt->getInt(self::TAG_FOOD_LEVEL, (int) $this->hungerManager->getFood()));
|
$this->hungerManager->setFood((float) $nbt->getInt(self::TAG_FOOD_LEVEL, (int) $this->hungerManager->getFood()));
|
||||||
$this->hungerManager->setExhaustion($nbt->getFloat(self::TAG_FOOD_EXHAUSTION_LEVEL, $this->hungerManager->getExhaustion()));
|
$this->hungerManager->setExhaustion($nbt->getFloat(self::TAG_FOOD_EXHAUSTION_LEVEL, $this->hungerManager->getExhaustion()));
|
||||||
@ -490,11 +490,12 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function sendSpawnPacket(Player $player) : void{
|
protected function sendSpawnPacket(Player $player) : void{
|
||||||
|
$networkSession = $player->getNetworkSession();
|
||||||
if(!($this instanceof Player)){
|
if(!($this instanceof Player)){
|
||||||
$player->getNetworkSession()->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))]));
|
$networkSession->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))]));
|
||||||
}
|
}
|
||||||
|
|
||||||
$player->getNetworkSession()->sendDataPacket(AddPlayerPacket::create(
|
$networkSession->sendDataPacket(AddPlayerPacket::create(
|
||||||
$this->getUniqueId(),
|
$this->getUniqueId(),
|
||||||
$this->getName(),
|
$this->getName(),
|
||||||
$this->getId(),
|
$this->getId(),
|
||||||
@ -524,11 +525,12 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
|||||||
//TODO: Hack for MCPE 1.2.13: DATA_NAMETAG is useless in AddPlayerPacket, so it has to be sent separately
|
//TODO: Hack for MCPE 1.2.13: DATA_NAMETAG is useless in AddPlayerPacket, so it has to be sent separately
|
||||||
$this->sendData([$player], [EntityMetadataProperties::NAMETAG => new StringMetadataProperty($this->getNameTag())]);
|
$this->sendData([$player], [EntityMetadataProperties::NAMETAG => new StringMetadataProperty($this->getNameTag())]);
|
||||||
|
|
||||||
$player->getNetworkSession()->onMobArmorChange($this);
|
$entityEventBroadcaster = $networkSession->getEntityEventBroadcaster();
|
||||||
$player->getNetworkSession()->onMobOffHandItemChange($this);
|
$entityEventBroadcaster->onMobArmorChange([$networkSession], $this);
|
||||||
|
$entityEventBroadcaster->onMobOffHandItemChange([$networkSession], $this);
|
||||||
|
|
||||||
if(!($this instanceof Player)){
|
if(!($this instanceof Player)){
|
||||||
$player->getNetworkSession()->sendDataPacket(PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($this->uuid)]));
|
$networkSession->sendDataPacket(PlayerListPacket::remove([PlayerListEntry::createRemovalEntry($this->uuid)]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,8 @@ use pocketmine\nbt\tag\CompoundTag;
|
|||||||
use pocketmine\nbt\tag\FloatTag;
|
use pocketmine\nbt\tag\FloatTag;
|
||||||
use pocketmine\nbt\tag\ListTag;
|
use pocketmine\nbt\tag\ListTag;
|
||||||
use pocketmine\nbt\tag\ShortTag;
|
use pocketmine\nbt\tag\ShortTag;
|
||||||
|
use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||||
|
use pocketmine\network\mcpe\NetworkBroadcastUtils;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||||
@ -143,13 +145,10 @@ abstract class Living extends Entity{
|
|||||||
|
|
||||||
$this->armorInventory = new ArmorInventory($this);
|
$this->armorInventory = new ArmorInventory($this);
|
||||||
//TODO: load/save armor inventory contents
|
//TODO: load/save armor inventory contents
|
||||||
$this->armorInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(
|
$this->armorInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(fn() => NetworkBroadcastUtils::broadcastEntityEvent(
|
||||||
function(Inventory $unused) : void{
|
$this->getViewers(),
|
||||||
foreach($this->getViewers() as $viewer){
|
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobArmorChange($recipients, $this)
|
||||||
$viewer->getNetworkSession()->onMobArmorChange($this);
|
)));
|
||||||
}
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
$health = $this->getMaxHealth();
|
$health = $this->getMaxHealth();
|
||||||
|
|
||||||
@ -850,7 +849,8 @@ abstract class Living extends Entity{
|
|||||||
protected function sendSpawnPacket(Player $player) : void{
|
protected function sendSpawnPacket(Player $player) : void{
|
||||||
parent::sendSpawnPacket($player);
|
parent::sendSpawnPacket($player);
|
||||||
|
|
||||||
$player->getNetworkSession()->onMobArmorChange($this);
|
$networkSession = $player->getNetworkSession();
|
||||||
|
$networkSession->getEntityEventBroadcaster()->onMobArmorChange([$networkSession], $this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function syncNetworkData(EntityMetadataCollection $properties) : void{
|
protected function syncNetworkData(EntityMetadataCollection $properties) : void{
|
||||||
|
@ -35,6 +35,8 @@ use pocketmine\item\Item;
|
|||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||||
|
use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||||
|
use pocketmine\network\mcpe\NetworkBroadcastUtils;
|
||||||
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
|
use pocketmine\network\mcpe\protocol\AddItemActorPacket;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||||
@ -328,9 +330,10 @@ class ItemEntity extends Entity{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->getViewers() as $viewer){
|
NetworkBroadcastUtils::broadcastEntityEvent(
|
||||||
$viewer->getNetworkSession()->onPlayerPickUpItem($player, $this);
|
$this->getViewers(),
|
||||||
}
|
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onPickUpItem($recipients, $player, $this)
|
||||||
|
);
|
||||||
|
|
||||||
$inventory = $ev->getInventory();
|
$inventory = $ev->getInventory();
|
||||||
if($inventory !== null){
|
if($inventory !== null){
|
||||||
|
@ -33,6 +33,8 @@ use pocketmine\event\entity\ProjectileHitEvent;
|
|||||||
use pocketmine\item\VanillaItems;
|
use pocketmine\item\VanillaItems;
|
||||||
use pocketmine\math\RayTraceResult;
|
use pocketmine\math\RayTraceResult;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
|
use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||||
|
use pocketmine\network\mcpe\NetworkBroadcastUtils;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
|
||||||
@ -196,9 +198,10 @@ class Arrow extends Projectile{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($this->getViewers() as $viewer){
|
NetworkBroadcastUtils::broadcastEntityEvent(
|
||||||
$viewer->getNetworkSession()->onPlayerPickUpItem($player, $this);
|
$this->getViewers(),
|
||||||
}
|
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onPickUpItem($recipients, $player, $this)
|
||||||
|
);
|
||||||
|
|
||||||
$ev->getInventory()?->addItem($ev->getItem());
|
$ev->getInventory()?->addItem($ev->getItem());
|
||||||
$this->flagForDespawn();
|
$this->flagForDespawn();
|
||||||
|
54
src/event/server/DataPacketDecodeEvent.php
Normal file
54
src/event/server/DataPacketDecodeEvent.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?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\event\server;
|
||||||
|
|
||||||
|
use pocketmine\event\Cancellable;
|
||||||
|
use pocketmine\event\CancellableTrait;
|
||||||
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called before a packet is decoded and handled by the network session.
|
||||||
|
* Cancelling this event will drop the packet without decoding it, minimizing wasted CPU time.
|
||||||
|
*/
|
||||||
|
class DataPacketDecodeEvent extends ServerEvent implements Cancellable{
|
||||||
|
use CancellableTrait;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private NetworkSession $origin,
|
||||||
|
private int $packetId,
|
||||||
|
private string $packetBuffer
|
||||||
|
){}
|
||||||
|
|
||||||
|
public function getOrigin() : NetworkSession{
|
||||||
|
return $this->origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPacketId() : int{
|
||||||
|
return $this->packetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPacketBuffer() : string{
|
||||||
|
return $this->packetBuffer;
|
||||||
|
}
|
||||||
|
}
|
93
src/network/mcpe/EntityEventBroadcaster.php
Normal file
93
src/network/mcpe/EntityEventBroadcaster.php
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\network\mcpe;
|
||||||
|
|
||||||
|
use pocketmine\entity\Attribute;
|
||||||
|
use pocketmine\entity\effect\EffectInstance;
|
||||||
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\entity\Human;
|
||||||
|
use pocketmine\entity\Living;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class allows broadcasting entity events to many viewers on the server network.
|
||||||
|
*/
|
||||||
|
interface EntityEventBroadcaster{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
* @param Attribute[] $attributes
|
||||||
|
*/
|
||||||
|
public function syncAttributes(array $recipients, Living $entity, array $attributes) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
* @param MetadataProperty[] $properties
|
||||||
|
*
|
||||||
|
* @phpstan-param array<int, MetadataProperty> $properties
|
||||||
|
*/
|
||||||
|
public function syncActorData(array $recipients, Entity $entity, array $properties) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
*/
|
||||||
|
public function onEntityEffectAdded(array $recipients, Living $entity, EffectInstance $effect, bool $replacesOldEffect) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
*/
|
||||||
|
public function onEntityEffectRemoved(array $recipients, Living $entity, EffectInstance $effect) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
*/
|
||||||
|
public function onEntityRemoved(array $recipients, Entity $entity) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: expand this to more than just humans
|
||||||
|
*
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
*/
|
||||||
|
public function onMobMainHandItemChange(array $recipients,Human $mob) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
*/
|
||||||
|
public function onMobOffHandItemChange(array $recipients, Human $mob) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
*/
|
||||||
|
public function onMobArmorChange(array $recipients, Living $mob) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
*/
|
||||||
|
public function onPickUpItem(array $recipients, Entity $collector, Entity $pickedUp) : void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
*/
|
||||||
|
public function onEmote(array $recipients, Human $from, string $emoteId) : void;
|
||||||
|
}
|
103
src/network/mcpe/NetworkBroadcastUtils.php
Normal file
103
src/network/mcpe/NetworkBroadcastUtils.php
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\network\mcpe;
|
||||||
|
|
||||||
|
use pocketmine\event\server\DataPacketSendEvent;
|
||||||
|
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||||
|
use pocketmine\player\Player;
|
||||||
|
use pocketmine\timings\Timings;
|
||||||
|
use function count;
|
||||||
|
use function spl_object_id;
|
||||||
|
|
||||||
|
final class NetworkBroadcastUtils{
|
||||||
|
|
||||||
|
private function __construct(){
|
||||||
|
//NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Player[] $recipients
|
||||||
|
* @param ClientboundPacket[] $packets
|
||||||
|
*/
|
||||||
|
public static function broadcastPackets(array $recipients, array $packets) : bool{
|
||||||
|
if(count($packets) === 0){
|
||||||
|
throw new \InvalidArgumentException("Cannot broadcast empty list of packets");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Timings::$broadcastPackets->time(function() use ($recipients, $packets) : bool{
|
||||||
|
/** @var NetworkSession[] $sessions */
|
||||||
|
$sessions = [];
|
||||||
|
foreach($recipients as $player){
|
||||||
|
if($player->isConnected()){
|
||||||
|
$sessions[] = $player->getNetworkSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(count($sessions) === 0){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ev = new DataPacketSendEvent($sessions, $packets);
|
||||||
|
$ev->call();
|
||||||
|
if($ev->isCancelled()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$sessions = $ev->getTargets();
|
||||||
|
|
||||||
|
/** @var PacketBroadcaster[] $uniqueBroadcasters */
|
||||||
|
$uniqueBroadcasters = [];
|
||||||
|
/** @var NetworkSession[][] $broadcasterTargets */
|
||||||
|
$broadcasterTargets = [];
|
||||||
|
foreach($sessions as $recipient){
|
||||||
|
$broadcaster = $recipient->getBroadcaster();
|
||||||
|
$uniqueBroadcasters[spl_object_id($broadcaster)] = $broadcaster;
|
||||||
|
$broadcasterTargets[spl_object_id($broadcaster)][spl_object_id($recipient)] = $recipient;
|
||||||
|
}
|
||||||
|
foreach($uniqueBroadcasters as $broadcaster){
|
||||||
|
$broadcaster->broadcastPackets($broadcasterTargets[spl_object_id($broadcaster)], $packets);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Player[] $recipients
|
||||||
|
* @phpstan-param \Closure(EntityEventBroadcaster, array<int, NetworkSession>) : void $callback
|
||||||
|
*/
|
||||||
|
public static function broadcastEntityEvent(array $recipients, \Closure $callback) : void{
|
||||||
|
$uniqueBroadcasters = [];
|
||||||
|
$broadcasterTargets = [];
|
||||||
|
|
||||||
|
foreach($recipients as $recipient){
|
||||||
|
$session = $recipient->getNetworkSession();
|
||||||
|
$broadcaster = $session->getEntityEventBroadcaster();
|
||||||
|
$uniqueBroadcasters[spl_object_id($broadcaster)] = $broadcaster;
|
||||||
|
$broadcasterTargets[spl_object_id($broadcaster)][spl_object_id($session)] = $session;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($uniqueBroadcasters as $k => $broadcaster){
|
||||||
|
$callback($broadcaster, $broadcasterTargets[$k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,13 +23,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\network\mcpe;
|
namespace pocketmine\network\mcpe;
|
||||||
|
|
||||||
use pocketmine\data\bedrock\EffectIdMap;
|
|
||||||
use pocketmine\entity\Attribute;
|
|
||||||
use pocketmine\entity\effect\EffectInstance;
|
use pocketmine\entity\effect\EffectInstance;
|
||||||
use pocketmine\entity\Entity;
|
|
||||||
use pocketmine\entity\Human;
|
|
||||||
use pocketmine\entity\Living;
|
|
||||||
use pocketmine\event\player\PlayerDuplicateLoginEvent;
|
use pocketmine\event\player\PlayerDuplicateLoginEvent;
|
||||||
|
use pocketmine\event\server\DataPacketDecodeEvent;
|
||||||
use pocketmine\event\server\DataPacketReceiveEvent;
|
use pocketmine\event\server\DataPacketReceiveEvent;
|
||||||
use pocketmine\event\server\DataPacketSendEvent;
|
use pocketmine\event\server\DataPacketSendEvent;
|
||||||
use pocketmine\form\Form;
|
use pocketmine\form\Form;
|
||||||
@ -43,7 +39,6 @@ use pocketmine\network\mcpe\cache\ChunkCache;
|
|||||||
use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
||||||
use pocketmine\network\mcpe\compression\Compressor;
|
use pocketmine\network\mcpe\compression\Compressor;
|
||||||
use pocketmine\network\mcpe\compression\DecompressionException;
|
use pocketmine\network\mcpe\compression\DecompressionException;
|
||||||
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
|
|
||||||
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
||||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||||
use pocketmine\network\mcpe\encryption\DecryptionException;
|
use pocketmine\network\mcpe\encryption\DecryptionException;
|
||||||
@ -62,10 +57,6 @@ use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
|
|||||||
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
|
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||||
use pocketmine\network\mcpe\protocol\DisconnectPacket;
|
use pocketmine\network\mcpe\protocol\DisconnectPacket;
|
||||||
use pocketmine\network\mcpe\protocol\EmotePacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\MobEffectPacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
|
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
|
||||||
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
|
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
|
||||||
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
|
use pocketmine\network\mcpe\protocol\NetworkChunkPublisherUpdatePacket;
|
||||||
@ -74,19 +65,16 @@ use pocketmine\network\mcpe\protocol\PacketDecodeException;
|
|||||||
use pocketmine\network\mcpe\protocol\PacketPool;
|
use pocketmine\network\mcpe\protocol\PacketPool;
|
||||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||||
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
|
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
|
||||||
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||||
use pocketmine\network\mcpe\protocol\ServerboundPacket;
|
use pocketmine\network\mcpe\protocol\ServerboundPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
|
use pocketmine\network\mcpe\protocol\ServerToClientHandshakePacket;
|
||||||
use pocketmine\network\mcpe\protocol\SetActorDataPacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
|
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
|
||||||
use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
|
use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
|
||||||
use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket;
|
use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket;
|
||||||
use pocketmine\network\mcpe\protocol\SetTimePacket;
|
use pocketmine\network\mcpe\protocol\SetTimePacket;
|
||||||
use pocketmine\network\mcpe\protocol\SetTitlePacket;
|
use pocketmine\network\mcpe\protocol\SetTitlePacket;
|
||||||
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\TextPacket;
|
use pocketmine\network\mcpe\protocol\TextPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ToastRequestPacket;
|
use pocketmine\network\mcpe\protocol\ToastRequestPacket;
|
||||||
use pocketmine\network\mcpe\protocol\TransferPacket;
|
use pocketmine\network\mcpe\protocol\TransferPacket;
|
||||||
@ -98,16 +86,10 @@ use pocketmine\network\mcpe\protocol\types\command\CommandEnum;
|
|||||||
use pocketmine\network\mcpe\protocol\types\command\CommandParameter;
|
use pocketmine\network\mcpe\protocol\types\command\CommandParameter;
|
||||||
use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
|
use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
|
||||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\Attribute as NetworkAttribute;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\entity\PropertySyncData;
|
|
||||||
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\PlayerListEntry;
|
||||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||||
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
||||||
use pocketmine\network\mcpe\protocol\UpdateAdventureSettingsPacket;
|
use pocketmine\network\mcpe\protocol\UpdateAdventureSettingsPacket;
|
||||||
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
|
|
||||||
use pocketmine\network\NetworkSessionManager;
|
use pocketmine\network\NetworkSessionManager;
|
||||||
use pocketmine\network\PacketHandlingException;
|
use pocketmine\network\PacketHandlingException;
|
||||||
use pocketmine\permission\DefaultPermissionNames;
|
use pocketmine\permission\DefaultPermissionNames;
|
||||||
@ -135,7 +117,6 @@ use function hrtime;
|
|||||||
use function in_array;
|
use function in_array;
|
||||||
use function intdiv;
|
use function intdiv;
|
||||||
use function json_encode;
|
use function json_encode;
|
||||||
use function ksort;
|
|
||||||
use function min;
|
use function min;
|
||||||
use function strcasecmp;
|
use function strcasecmp;
|
||||||
use function strlen;
|
use function strlen;
|
||||||
@ -144,7 +125,6 @@ use function substr;
|
|||||||
use function time;
|
use function time;
|
||||||
use function ucfirst;
|
use function ucfirst;
|
||||||
use const JSON_THROW_ON_ERROR;
|
use const JSON_THROW_ON_ERROR;
|
||||||
use const SORT_NUMERIC;
|
|
||||||
|
|
||||||
class NetworkSession{
|
class NetworkSession{
|
||||||
private const INCOMING_PACKET_BATCH_PER_TICK = 2; //usually max 1 per tick, but transactions may arrive separately
|
private const INCOMING_PACKET_BATCH_PER_TICK = 2; //usually max 1 per tick, but transactions may arrive separately
|
||||||
@ -188,8 +168,6 @@ class NetworkSession{
|
|||||||
private bool $forceAsyncCompression = true;
|
private bool $forceAsyncCompression = true;
|
||||||
private bool $enableCompression = false; //disabled until handshake completed
|
private bool $enableCompression = false; //disabled until handshake completed
|
||||||
|
|
||||||
private PacketSerializerContext $packetSerializerContext;
|
|
||||||
|
|
||||||
private ?InventoryManager $invManager = null;
|
private ?InventoryManager $invManager = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -202,8 +180,10 @@ class NetworkSession{
|
|||||||
private Server $server,
|
private Server $server,
|
||||||
private NetworkSessionManager $manager,
|
private NetworkSessionManager $manager,
|
||||||
private PacketPool $packetPool,
|
private PacketPool $packetPool,
|
||||||
|
private PacketSerializerContext $packetSerializerContext,
|
||||||
private PacketSender $sender,
|
private PacketSender $sender,
|
||||||
private PacketBroadcaster $broadcaster,
|
private PacketBroadcaster $broadcaster,
|
||||||
|
private EntityEventBroadcaster $entityEventBroadcaster,
|
||||||
private Compressor $compressor,
|
private Compressor $compressor,
|
||||||
private string $ip,
|
private string $ip,
|
||||||
private int $port
|
private int $port
|
||||||
@ -212,9 +192,6 @@ class NetworkSession{
|
|||||||
|
|
||||||
$this->compressedQueue = new \SplQueue();
|
$this->compressedQueue = new \SplQueue();
|
||||||
|
|
||||||
//TODO: allow this to be injected
|
|
||||||
$this->packetSerializerContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
|
|
||||||
|
|
||||||
$this->disposeHooks = new ObjectSet();
|
$this->disposeHooks = new ObjectSet();
|
||||||
|
|
||||||
$this->connectTime = time();
|
$this->connectTime = time();
|
||||||
@ -278,10 +255,10 @@ class NetworkSession{
|
|||||||
|
|
||||||
$effectManager = $this->player->getEffects();
|
$effectManager = $this->player->getEffects();
|
||||||
$effectManager->getEffectAddHooks()->add($effectAddHook = function(EffectInstance $effect, bool $replacesOldEffect) : void{
|
$effectManager->getEffectAddHooks()->add($effectAddHook = function(EffectInstance $effect, bool $replacesOldEffect) : void{
|
||||||
$this->onEntityEffectAdded($this->player, $effect, $replacesOldEffect);
|
$this->entityEventBroadcaster->onEntityEffectAdded([$this], $this->player, $effect, $replacesOldEffect);
|
||||||
});
|
});
|
||||||
$effectManager->getEffectRemoveHooks()->add($effectRemoveHook = function(EffectInstance $effect) : void{
|
$effectManager->getEffectRemoveHooks()->add($effectRemoveHook = function(EffectInstance $effect) : void{
|
||||||
$this->onEntityEffectRemoved($this->player, $effect);
|
$this->entityEventBroadcaster->onEntityEffectRemoved([$this], $this->player, $effect);
|
||||||
});
|
});
|
||||||
$this->disposeHooks->add(static function() use ($effectManager, $effectAddHook, $effectRemoveHook) : void{
|
$this->disposeHooks->add(static function() use ($effectManager, $effectAddHook, $effectRemoveHook) : void{
|
||||||
$effectManager->getEffectAddHooks()->remove($effectAddHook);
|
$effectManager->getEffectAddHooks()->remove($effectAddHook);
|
||||||
@ -431,32 +408,45 @@ class NetworkSession{
|
|||||||
throw new PacketHandlingException("Unexpected non-serverbound packet");
|
throw new PacketHandlingException("Unexpected non-serverbound packet");
|
||||||
}
|
}
|
||||||
|
|
||||||
$timings = Timings::getDecodeDataPacketTimings($packet);
|
$timings = Timings::getReceiveDataPacketTimings($packet);
|
||||||
$timings->startTiming();
|
$timings->startTiming();
|
||||||
try{
|
|
||||||
$stream = PacketSerializer::decoder($buffer, 0, $this->packetSerializerContext);
|
|
||||||
try{
|
|
||||||
$packet->decode($stream);
|
|
||||||
}catch(PacketDecodeException $e){
|
|
||||||
throw PacketHandlingException::wrap($e);
|
|
||||||
}
|
|
||||||
if(!$stream->feof()){
|
|
||||||
$remains = substr($stream->getBuffer(), $stream->getOffset());
|
|
||||||
$this->logger->debug("Still " . strlen($remains) . " bytes unread in " . $packet->getName() . ": " . bin2hex($remains));
|
|
||||||
}
|
|
||||||
}finally{
|
|
||||||
$timings->stopTiming();
|
|
||||||
}
|
|
||||||
|
|
||||||
$timings = Timings::getHandleDataPacketTimings($packet);
|
|
||||||
$timings->startTiming();
|
|
||||||
try{
|
try{
|
||||||
//TODO: I'm not sure DataPacketReceiveEvent should be included in the handler timings, but it needs to be
|
$ev = new DataPacketDecodeEvent($this, $packet->pid(), $buffer);
|
||||||
//included for now to ensure the receivePacket timings are counted the way they were before
|
$ev->call();
|
||||||
|
if($ev->isCancelled()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$decodeTimings = Timings::getDecodeDataPacketTimings($packet);
|
||||||
|
$decodeTimings->startTiming();
|
||||||
|
try{
|
||||||
|
$stream = PacketSerializer::decoder($buffer, 0, $this->packetSerializerContext);
|
||||||
|
try{
|
||||||
|
$packet->decode($stream);
|
||||||
|
}catch(PacketDecodeException $e){
|
||||||
|
throw PacketHandlingException::wrap($e);
|
||||||
|
}
|
||||||
|
if(!$stream->feof()){
|
||||||
|
$remains = substr($stream->getBuffer(), $stream->getOffset());
|
||||||
|
$this->logger->debug("Still " . strlen($remains) . " bytes unread in " . $packet->getName() . ": " . bin2hex($remains));
|
||||||
|
}
|
||||||
|
}finally{
|
||||||
|
$decodeTimings->stopTiming();
|
||||||
|
}
|
||||||
|
|
||||||
$ev = new DataPacketReceiveEvent($this, $packet);
|
$ev = new DataPacketReceiveEvent($this, $packet);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled() && ($this->handler === null || !$packet->handle($this->handler))){
|
if(!$ev->isCancelled()){
|
||||||
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
|
$handlerTimings = Timings::getHandleDataPacketTimings($packet);
|
||||||
|
$handlerTimings->startTiming();
|
||||||
|
try{
|
||||||
|
if($this->handler === null || !$packet->handle($this->handler)){
|
||||||
|
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
|
||||||
|
}
|
||||||
|
}finally{
|
||||||
|
$handlerTimings->stopTiming();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}finally{
|
}finally{
|
||||||
$timings->stopTiming();
|
$timings->stopTiming();
|
||||||
@ -528,7 +518,7 @@ class NetworkSession{
|
|||||||
PacketBatch::encodeRaw($stream, $this->sendBuffer);
|
PacketBatch::encodeRaw($stream, $this->sendBuffer);
|
||||||
|
|
||||||
if($this->enableCompression){
|
if($this->enableCompression){
|
||||||
$promise = $this->server->prepareBatch(new PacketBatch($stream->getBuffer()), $this->compressor, $syncMode);
|
$promise = $this->server->prepareBatch(new PacketBatch($stream->getBuffer()), $this->compressor, $syncMode, Timings::$playerNetworkSendCompressSessionBuffer);
|
||||||
}else{
|
}else{
|
||||||
$promise = new CompressBatchPromise();
|
$promise = new CompressBatchPromise();
|
||||||
$promise->resolve($stream->getBuffer());
|
$promise->resolve($stream->getBuffer());
|
||||||
@ -545,6 +535,8 @@ class NetworkSession{
|
|||||||
|
|
||||||
public function getBroadcaster() : PacketBroadcaster{ return $this->broadcaster; }
|
public function getBroadcaster() : PacketBroadcaster{ return $this->broadcaster; }
|
||||||
|
|
||||||
|
public function getEntityEventBroadcaster() : EntityEventBroadcaster{ return $this->entityEventBroadcaster; }
|
||||||
|
|
||||||
public function getCompressor() : Compressor{
|
public function getCompressor() : Compressor{
|
||||||
return $this->compressor;
|
return $this->compressor;
|
||||||
}
|
}
|
||||||
@ -815,7 +807,7 @@ class NetworkSession{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onServerRespawn() : void{
|
public function onServerRespawn() : void{
|
||||||
$this->syncAttributes($this->player, $this->player->getAttributeMap()->getAll());
|
$this->entityEventBroadcaster->syncAttributes([$this], $this->player, $this->player->getAttributeMap()->getAll());
|
||||||
$this->player->sendData(null);
|
$this->player->sendData(null);
|
||||||
|
|
||||||
$this->syncAbilities($this->player);
|
$this->syncAbilities($this->player);
|
||||||
@ -924,41 +916,6 @@ class NetworkSession{
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Attribute[] $attributes
|
|
||||||
*/
|
|
||||||
public function syncAttributes(Living $entity, array $attributes) : void{
|
|
||||||
if(count($attributes) > 0){
|
|
||||||
$this->sendDataPacket(UpdateAttributesPacket::create($entity->getId(), array_map(function(Attribute $attr) : NetworkAttribute{
|
|
||||||
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []);
|
|
||||||
}, $attributes), 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param MetadataProperty[] $properties
|
|
||||||
* @phpstan-param array<int, MetadataProperty> $properties
|
|
||||||
*/
|
|
||||||
public function syncActorData(Entity $entity, array $properties) : void{
|
|
||||||
//TODO: HACK! as of 1.18.10, the client responds differently to the same data ordered in different orders - for
|
|
||||||
//example, sending HEIGHT in the list before FLAGS when unsetting the SWIMMING flag results in a hitbox glitch
|
|
||||||
ksort($properties, SORT_NUMERIC);
|
|
||||||
$this->sendDataPacket(SetActorDataPacket::create($entity->getId(), $properties, new PropertySyncData([], []), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onEntityEffectAdded(Living $entity, EffectInstance $effect, bool $replacesOldEffect) : void{
|
|
||||||
//TODO: we may need yet another effect <=> ID map in the future depending on protocol changes
|
|
||||||
$this->sendDataPacket(MobEffectPacket::add($entity->getId(), $replacesOldEffect, EffectIdMap::getInstance()->toId($effect->getType()), $effect->getAmplifier(), $effect->isVisible(), $effect->getDuration()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onEntityEffectRemoved(Living $entity, EffectInstance $effect) : void{
|
|
||||||
$this->sendDataPacket(MobEffectPacket::remove($entity->getId(), EffectIdMap::getInstance()->toId($effect->getType())));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onEntityRemoved(Entity $entity) : void{
|
|
||||||
$this->sendDataPacket(RemoveActorPacket::create($entity->getId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function syncAvailableCommands() : void{
|
public function syncAvailableCommands() : void{
|
||||||
$commandData = [];
|
$commandData = [];
|
||||||
foreach($this->server->getCommandMap()->getCommands() as $name => $command){
|
foreach($this->server->getCommandMap()->getCommands() as $name => $command){
|
||||||
@ -1094,36 +1051,6 @@ class NetworkSession{
|
|||||||
return $this->invManager;
|
return $this->invManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: expand this to more than just humans
|
|
||||||
*/
|
|
||||||
public function onMobMainHandItemChange(Human $mob) : void{
|
|
||||||
//TODO: we could send zero for slot here because remote players don't need to know which slot was selected
|
|
||||||
$inv = $mob->getInventory();
|
|
||||||
$this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItemInHand())), $inv->getHeldItemIndex(), $inv->getHeldItemIndex(), ContainerIds::INVENTORY));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onMobOffHandItemChange(Human $mob) : void{
|
|
||||||
$inv = $mob->getOffHandInventory();
|
|
||||||
$this->sendDataPacket(MobEquipmentPacket::create($mob->getId(), ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItem(0))), 0, 0, ContainerIds::OFFHAND));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onMobArmorChange(Living $mob) : void{
|
|
||||||
$inv = $mob->getArmorInventory();
|
|
||||||
$converter = TypeConverter::getInstance();
|
|
||||||
$this->sendDataPacket(MobArmorEquipmentPacket::create(
|
|
||||||
$mob->getId(),
|
|
||||||
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getHelmet())),
|
|
||||||
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getChestplate())),
|
|
||||||
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getLeggings())),
|
|
||||||
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getBoots()))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onPlayerPickUpItem(Player $collector, Entity $pickedUp) : void{
|
|
||||||
$this->sendDataPacket(TakeItemActorPacket::create($collector->getId(), $pickedUp->getId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Player[] $players
|
* @param Player[] $players
|
||||||
*/
|
*/
|
||||||
@ -1167,10 +1094,6 @@ class NetworkSession{
|
|||||||
$this->sendDataPacket(SetTitlePacket::setAnimationTimes($fadeIn, $stay, $fadeOut));
|
$this->sendDataPacket(SetTitlePacket::setAnimationTimes($fadeIn, $stay, $fadeOut));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onEmote(Human $from, string $emoteId) : void{
|
|
||||||
$this->sendDataPacket(EmotePacket::create($from->getId(), $emoteId, EmotePacket::FLAG_SERVER));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onToastNotification(string $title, string $body) : void{
|
public function onToastNotification(string $title, string $body) : void{
|
||||||
$this->sendDataPacket(ToastRequestPacket::create($title, $body));
|
$this->sendDataPacket(ToastRequestPacket::create($title, $body));
|
||||||
}
|
}
|
||||||
@ -1210,7 +1133,7 @@ class NetworkSession{
|
|||||||
$this->player->doChunkRequests();
|
$this->player->doChunkRequests();
|
||||||
|
|
||||||
$dirtyAttributes = $this->player->getAttributeMap()->needSend();
|
$dirtyAttributes = $this->player->getAttributeMap()->needSend();
|
||||||
$this->syncAttributes($this->player, $dirtyAttributes);
|
$this->entityEventBroadcaster->syncAttributes([$this], $this->player, $dirtyAttributes);
|
||||||
foreach($dirtyAttributes as $attribute){
|
foreach($dirtyAttributes as $attribute){
|
||||||
//TODO: we might need to send these to other players in the future
|
//TODO: we might need to send these to other players in the future
|
||||||
//if that happens, this will need to become more complex than a flag on the attribute itself
|
//if that happens, this will need to become more complex than a flag on the attribute itself
|
||||||
|
143
src/network/mcpe/StandardEntityEventBroadcaster.php
Normal file
143
src/network/mcpe/StandardEntityEventBroadcaster.php
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* ____ _ _ __ __ _ __ __ ____
|
||||||
|
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||||
|
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||||
|
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||||
|
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* @author PocketMine Team
|
||||||
|
* @link http://www.pocketmine.net/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace pocketmine\network\mcpe;
|
||||||
|
|
||||||
|
use pocketmine\data\bedrock\EffectIdMap;
|
||||||
|
use pocketmine\entity\Attribute;
|
||||||
|
use pocketmine\entity\effect\EffectInstance;
|
||||||
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\entity\Human;
|
||||||
|
use pocketmine\entity\Living;
|
||||||
|
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||||
|
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\EmotePacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\MobEffectPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\RemoveActorPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\SetActorDataPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\TakeItemActorPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\entity\Attribute as NetworkAttribute;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\entity\PropertySyncData;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
|
||||||
|
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||||
|
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
|
||||||
|
use function array_map;
|
||||||
|
use function count;
|
||||||
|
use function ksort;
|
||||||
|
use const SORT_NUMERIC;
|
||||||
|
|
||||||
|
final class StandardEntityEventBroadcaster implements EntityEventBroadcaster{
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private StandardPacketBroadcaster $broadcaster
|
||||||
|
){}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param NetworkSession[] $recipients
|
||||||
|
*/
|
||||||
|
private function sendDataPacket(array $recipients, ClientboundPacket $packet) : void{
|
||||||
|
$this->broadcaster->broadcastPackets($recipients, [$packet]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function syncAttributes(array $recipients, Living $entity, array $attributes) : void{
|
||||||
|
if(count($attributes) > 0){
|
||||||
|
$this->sendDataPacket($recipients, UpdateAttributesPacket::create(
|
||||||
|
$entity->getId(),
|
||||||
|
array_map(fn(Attribute $attr) => new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []), $attributes),
|
||||||
|
0
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function syncActorData(array $recipients, Entity $entity, array $properties) : void{
|
||||||
|
//TODO: HACK! as of 1.18.10, the client responds differently to the same data ordered in different orders - for
|
||||||
|
//example, sending HEIGHT in the list before FLAGS when unsetting the SWIMMING flag results in a hitbox glitch
|
||||||
|
ksort($properties, SORT_NUMERIC);
|
||||||
|
$this->sendDataPacket($recipients, SetActorDataPacket::create($entity->getId(), $properties, new PropertySyncData([], []), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onEntityEffectAdded(array $recipients, Living $entity, EffectInstance $effect, bool $replacesOldEffect) : void{
|
||||||
|
//TODO: we may need yet another effect <=> ID map in the future depending on protocol changes
|
||||||
|
$this->sendDataPacket($recipients, MobEffectPacket::add(
|
||||||
|
$entity->getId(),
|
||||||
|
$replacesOldEffect,
|
||||||
|
EffectIdMap::getInstance()->toId($effect->getType()),
|
||||||
|
$effect->getAmplifier(),
|
||||||
|
$effect->isVisible(),
|
||||||
|
$effect->getDuration()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onEntityEffectRemoved(array $recipients, Living $entity, EffectInstance $effect) : void{
|
||||||
|
$this->sendDataPacket($recipients, MobEffectPacket::remove($entity->getId(), EffectIdMap::getInstance()->toId($effect->getType())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onEntityRemoved(array $recipients, Entity $entity) : void{
|
||||||
|
$this->sendDataPacket($recipients, RemoveActorPacket::create($entity->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onMobMainHandItemChange(array $recipients, Human $mob) : void{
|
||||||
|
//TODO: we could send zero for slot here because remote players don't need to know which slot was selected
|
||||||
|
$inv = $mob->getInventory();
|
||||||
|
$this->sendDataPacket($recipients, MobEquipmentPacket::create(
|
||||||
|
$mob->getId(),
|
||||||
|
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItemInHand())),
|
||||||
|
$inv->getHeldItemIndex(),
|
||||||
|
$inv->getHeldItemIndex(),
|
||||||
|
ContainerIds::INVENTORY
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onMobOffHandItemChange(array $recipients, Human $mob) : void{
|
||||||
|
$inv = $mob->getOffHandInventory();
|
||||||
|
$this->sendDataPacket($recipients, MobEquipmentPacket::create(
|
||||||
|
$mob->getId(),
|
||||||
|
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($inv->getItem(0))),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
ContainerIds::OFFHAND
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onMobArmorChange(array $recipients, Living $mob) : void{
|
||||||
|
$inv = $mob->getArmorInventory();
|
||||||
|
$converter = TypeConverter::getInstance();
|
||||||
|
$this->sendDataPacket($recipients, MobArmorEquipmentPacket::create(
|
||||||
|
$mob->getId(),
|
||||||
|
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getHelmet())),
|
||||||
|
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getChestplate())),
|
||||||
|
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getLeggings())),
|
||||||
|
ItemStackWrapper::legacy($converter->coreItemStackToNet($inv->getBoots()))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onPickUpItem(array $recipients, Entity $collector, Entity $pickedUp) : void{
|
||||||
|
$this->sendDataPacket($recipients, TakeItemActorPacket::create($collector->getId(), $pickedUp->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onEmote(array $recipients, Human $from, string $emoteId) : void{
|
||||||
|
$this->sendDataPacket($recipients, EmotePacket::create($from->getId(), $emoteId, EmotePacket::FLAG_SERVER));
|
||||||
|
}
|
||||||
|
}
|
@ -25,60 +25,65 @@ namespace pocketmine\network\mcpe;
|
|||||||
|
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||||
|
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
|
use pocketmine\timings\Timings;
|
||||||
use pocketmine\utils\BinaryStream;
|
use pocketmine\utils\BinaryStream;
|
||||||
|
use function count;
|
||||||
|
use function log;
|
||||||
use function spl_object_id;
|
use function spl_object_id;
|
||||||
use function strlen;
|
use function strlen;
|
||||||
|
|
||||||
final class StandardPacketBroadcaster implements PacketBroadcaster{
|
final class StandardPacketBroadcaster implements PacketBroadcaster{
|
||||||
public function __construct(private Server $server){}
|
public function __construct(
|
||||||
|
private Server $server,
|
||||||
|
private PacketSerializerContext $protocolContext
|
||||||
|
){}
|
||||||
|
|
||||||
public function broadcastPackets(array $recipients, array $packets) : void{
|
public function broadcastPackets(array $recipients, array $packets) : void{
|
||||||
$packetBufferTotalLengths = [];
|
|
||||||
$packetBuffers = [];
|
|
||||||
$compressors = [];
|
$compressors = [];
|
||||||
/** @var NetworkSession[][][] $targetMap */
|
|
||||||
$targetMap = [];
|
/** @var NetworkSession[][] $targetsByCompressor */
|
||||||
|
$targetsByCompressor = [];
|
||||||
foreach($recipients as $recipient){
|
foreach($recipients as $recipient){
|
||||||
$serializerContext = $recipient->getPacketSerializerContext();
|
if($recipient->getPacketSerializerContext() !== $this->protocolContext){
|
||||||
$bufferId = spl_object_id($serializerContext);
|
throw new \InvalidArgumentException("Only recipients with the same protocol context as the broadcaster can be broadcast to by this broadcaster");
|
||||||
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
|
//TODO: different compressors might be compatible, it might not be necessary to split them up by object
|
||||||
$compressor = $recipient->getCompressor();
|
$compressor = $recipient->getCompressor();
|
||||||
$compressors[spl_object_id($compressor)] = $compressor;
|
$compressors[spl_object_id($compressor)] = $compressor;
|
||||||
|
|
||||||
$targetMap[$bufferId][spl_object_id($compressor)][] = $recipient;
|
$targetsByCompressor[spl_object_id($compressor)][] = $recipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($targetMap as $bufferId => $compressorMap){
|
$totalLength = 0;
|
||||||
foreach($compressorMap as $compressorId => $compressorTargets){
|
$packetBuffers = [];
|
||||||
$compressor = $compressors[$compressorId];
|
foreach($packets as $packet){
|
||||||
|
$buffer = NetworkSession::encodePacketTimed(PacketSerializer::encoder($this->protocolContext), $packet);
|
||||||
|
//varint length prefix + packet buffer
|
||||||
|
$totalLength += (((int) log(strlen($buffer), 128)) + 1) + strlen($buffer);
|
||||||
|
$packetBuffers[] = $buffer;
|
||||||
|
}
|
||||||
|
|
||||||
$threshold = $compressor->getCompressionThreshold();
|
foreach($targetsByCompressor as $compressorId => $compressorTargets){
|
||||||
if($threshold !== null && $packetBufferTotalLengths[$bufferId] >= $threshold){
|
$compressor = $compressors[$compressorId];
|
||||||
//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);
|
$threshold = $compressor->getCompressionThreshold();
|
||||||
foreach($compressorTargets as $target){
|
if(count($compressorTargets) > 1 && $threshold !== null && $totalLength >= $threshold){
|
||||||
$target->queueCompressed($promise);
|
//do not prepare shared batch unless we're sure it will be compressed
|
||||||
}
|
$stream = new BinaryStream();
|
||||||
}else{
|
PacketBatch::encodeRaw($stream, $packetBuffers);
|
||||||
foreach($compressorTargets as $target){
|
$batchBuffer = $stream->getBuffer();
|
||||||
foreach($packetBuffers[$bufferId] as $packetBuffer){
|
|
||||||
$target->addToSendBuffer($packetBuffer);
|
$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 as $packetBuffer){
|
||||||
|
$target->addToSendBuffer($packetBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,7 @@ use pocketmine\data\bedrock\BedrockDataFiles;
|
|||||||
use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap;
|
use pocketmine\data\bedrock\LegacyBlockIdToStringIdMap;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
|
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
use pocketmine\utils\BinaryStream;
|
||||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
|
||||||
use pocketmine\utils\Filesystem;
|
use pocketmine\utils\Filesystem;
|
||||||
use pocketmine\utils\SingletonTrait;
|
use pocketmine\utils\SingletonTrait;
|
||||||
|
|
||||||
@ -55,14 +54,14 @@ final class RuntimeBlockMapping{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function __construct(string $canonicalBlockStatesFile, string $r12ToCurrentBlockMapFile){
|
public function __construct(string $canonicalBlockStatesFile, string $r12ToCurrentBlockMapFile){
|
||||||
$stream = PacketSerializer::decoder(
|
$stream = new BinaryStream(Filesystem::fileGetContents($canonicalBlockStatesFile));
|
||||||
Filesystem::fileGetContents($canonicalBlockStatesFile),
|
|
||||||
0,
|
|
||||||
new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())
|
|
||||||
);
|
|
||||||
$list = [];
|
$list = [];
|
||||||
|
$nbtReader = new NetworkNbtSerializer();
|
||||||
while(!$stream->feof()){
|
while(!$stream->feof()){
|
||||||
$list[] = $stream->getNbtCompoundRoot();
|
$offset = $stream->getOffset();
|
||||||
|
$blockState = $nbtReader->read($stream->getBuffer(), $offset)->mustGetCompoundTag();
|
||||||
|
$stream->setOffset($offset);
|
||||||
|
$list[] = $blockState;
|
||||||
}
|
}
|
||||||
$this->bedrockKnownStates = $list;
|
$this->bedrockKnownStates = $list;
|
||||||
|
|
||||||
@ -73,14 +72,10 @@ final class RuntimeBlockMapping{
|
|||||||
$legacyIdMap = LegacyBlockIdToStringIdMap::getInstance();
|
$legacyIdMap = LegacyBlockIdToStringIdMap::getInstance();
|
||||||
/** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */
|
/** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */
|
||||||
$legacyStateMap = [];
|
$legacyStateMap = [];
|
||||||
$legacyStateMapReader = PacketSerializer::decoder(
|
$legacyStateMapReader = new BinaryStream(Filesystem::fileGetContents($r12ToCurrentBlockMapFile));
|
||||||
Filesystem::fileGetContents($r12ToCurrentBlockMapFile),
|
|
||||||
0,
|
|
||||||
new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary())
|
|
||||||
);
|
|
||||||
$nbtReader = new NetworkNbtSerializer();
|
$nbtReader = new NetworkNbtSerializer();
|
||||||
while(!$legacyStateMapReader->feof()){
|
while(!$legacyStateMapReader->feof()){
|
||||||
$id = $legacyStateMapReader->getString();
|
$id = $legacyStateMapReader->get($legacyStateMapReader->getUnsignedVarInt());
|
||||||
$meta = $legacyStateMapReader->getLShort();
|
$meta = $legacyStateMapReader->getLShort();
|
||||||
|
|
||||||
$offset = $legacyStateMapReader->getOffset();
|
$offset = $legacyStateMapReader->getOffset();
|
||||||
|
@ -25,7 +25,6 @@ namespace pocketmine\network\mcpe\handler;
|
|||||||
|
|
||||||
use pocketmine\entity\InvalidSkinException;
|
use pocketmine\entity\InvalidSkinException;
|
||||||
use pocketmine\event\player\PlayerPreLoginEvent;
|
use pocketmine\event\player\PlayerPreLoginEvent;
|
||||||
use pocketmine\lang\KnownTranslationFactory;
|
|
||||||
use pocketmine\lang\KnownTranslationKeys;
|
use pocketmine\lang\KnownTranslationKeys;
|
||||||
use pocketmine\network\mcpe\auth\ProcessLoginTask;
|
use pocketmine\network\mcpe\auth\ProcessLoginTask;
|
||||||
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
||||||
@ -33,7 +32,6 @@ use pocketmine\network\mcpe\JwtException;
|
|||||||
use pocketmine\network\mcpe\JwtUtils;
|
use pocketmine\network\mcpe\JwtUtils;
|
||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
use pocketmine\network\mcpe\protocol\LoginPacket;
|
use pocketmine\network\mcpe\protocol\LoginPacket;
|
||||||
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
|
|
||||||
use pocketmine\network\mcpe\protocol\types\login\AuthenticationData;
|
use pocketmine\network\mcpe\protocol\types\login\AuthenticationData;
|
||||||
use pocketmine\network\mcpe\protocol\types\login\ClientData;
|
use pocketmine\network\mcpe\protocol\types\login\ClientData;
|
||||||
use pocketmine\network\mcpe\protocol\types\login\ClientDataToSkinDataHelper;
|
use pocketmine\network\mcpe\protocol\types\login\ClientDataToSkinDataHelper;
|
||||||
@ -45,7 +43,6 @@ use pocketmine\player\XboxLivePlayerInfo;
|
|||||||
use pocketmine\Server;
|
use pocketmine\Server;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use function is_array;
|
use function is_array;
|
||||||
use function preg_match;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the initial login phase of the session. This handler is used as the initial state.
|
* Handles the initial login phase of the session. This handler is used as the initial state.
|
||||||
@ -73,26 +70,6 @@ class LoginPacketHandler extends PacketHandler{
|
|||||||
|
|
||||||
$clientData = $this->parseClientData($packet->clientDataJwt);
|
$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{
|
try{
|
||||||
$skin = SkinAdapterSingleton::get()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData));
|
$skin = SkinAdapterSingleton::get()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData));
|
||||||
}catch(\InvalidArgumentException | InvalidSkinException $e){
|
}catch(\InvalidArgumentException | InvalidSkinException $e){
|
||||||
|
@ -114,7 +114,7 @@ class PreSpawnPacketHandler extends PacketHandler{
|
|||||||
$this->session->sendDataPacket(StaticPacketCache::getInstance()->getBiomeDefs());
|
$this->session->sendDataPacket(StaticPacketCache::getInstance()->getBiomeDefs());
|
||||||
|
|
||||||
$this->session->getLogger()->debug("Sending attributes");
|
$this->session->getLogger()->debug("Sending attributes");
|
||||||
$this->session->syncAttributes($this->player, $this->player->getAttributeMap()->getAll());
|
$this->session->getEntityEventBroadcaster()->syncAttributes([$this->session], $this->player, $this->player->getAttributeMap()->getAll());
|
||||||
|
|
||||||
$this->session->getLogger()->debug("Sending available commands");
|
$this->session->getLogger()->debug("Sending available commands");
|
||||||
$this->session->syncAvailableCommands();
|
$this->session->syncAvailableCommands();
|
||||||
@ -125,7 +125,7 @@ class PreSpawnPacketHandler extends PacketHandler{
|
|||||||
|
|
||||||
$this->session->getLogger()->debug("Sending effects");
|
$this->session->getLogger()->debug("Sending effects");
|
||||||
foreach($this->player->getEffects()->all() as $effect){
|
foreach($this->player->getEffects()->all() as $effect){
|
||||||
$this->session->onEntityEffectAdded($this->player, $effect, false);
|
$this->session->getEntityEventBroadcaster()->onEntityEffectAdded([$this->session], $this->player, $effect, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->session->getLogger()->debug("Sending actor metadata");
|
$this->session->getLogger()->debug("Sending actor metadata");
|
||||||
|
@ -71,9 +71,6 @@ final class SessionStartPacketHandler extends PacketHandler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function isCompatibleProtocol(int $protocolVersion) : bool{
|
protected function isCompatibleProtocol(int $protocolVersion) : bool{
|
||||||
//TODO: REMOVE THIS
|
return $protocolVersion === ProtocolInfo::CURRENT_PROTOCOL;
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,12 @@ namespace pocketmine\network\mcpe\raklib;
|
|||||||
use pocketmine\network\AdvancedNetworkInterface;
|
use pocketmine\network\AdvancedNetworkInterface;
|
||||||
use pocketmine\network\mcpe\compression\ZlibCompressor;
|
use pocketmine\network\mcpe\compression\ZlibCompressor;
|
||||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||||
|
use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
use pocketmine\network\mcpe\PacketBroadcaster;
|
use pocketmine\network\mcpe\PacketBroadcaster;
|
||||||
use pocketmine\network\mcpe\protocol\PacketPool;
|
use pocketmine\network\mcpe\protocol\PacketPool;
|
||||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||||
use pocketmine\network\mcpe\StandardPacketBroadcaster;
|
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||||
use pocketmine\network\Network;
|
use pocketmine\network\Network;
|
||||||
use pocketmine\network\NetworkInterfaceStartException;
|
use pocketmine\network\NetworkInterfaceStartException;
|
||||||
use pocketmine\network\PacketHandlingException;
|
use pocketmine\network\PacketHandlingException;
|
||||||
@ -78,10 +79,16 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
|||||||
|
|
||||||
private SleeperNotifier $sleeper;
|
private SleeperNotifier $sleeper;
|
||||||
|
|
||||||
private PacketBroadcaster $broadcaster;
|
private PacketBroadcaster $packetBroadcaster;
|
||||||
|
private EntityEventBroadcaster $entityEventBroadcaster;
|
||||||
|
private PacketSerializerContext $packetSerializerContext;
|
||||||
|
|
||||||
public function __construct(Server $server, string $ip, int $port, bool $ipV6){
|
public function __construct(Server $server, string $ip, int $port, bool $ipV6, PacketBroadcaster $packetBroadcaster, EntityEventBroadcaster $entityEventBroadcaster, PacketSerializerContext $packetSerializerContext){
|
||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
|
$this->packetBroadcaster = $packetBroadcaster;
|
||||||
|
$this->packetSerializerContext = $packetSerializerContext;
|
||||||
|
$this->entityEventBroadcaster = $entityEventBroadcaster;
|
||||||
|
|
||||||
$this->rakServerId = mt_rand(0, PHP_INT_MAX);
|
$this->rakServerId = mt_rand(0, PHP_INT_MAX);
|
||||||
|
|
||||||
$this->sleeper = new SleeperNotifier();
|
$this->sleeper = new SleeperNotifier();
|
||||||
@ -105,8 +112,6 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
|||||||
$this->interface = new UserToRakLibThreadMessageSender(
|
$this->interface = new UserToRakLibThreadMessageSender(
|
||||||
new PthreadsChannelWriter($mainToThreadBuffer)
|
new PthreadsChannelWriter($mainToThreadBuffer)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->broadcaster = new StandardPacketBroadcaster($this->server);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start() : void{
|
public function start() : void{
|
||||||
@ -166,8 +171,10 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
|||||||
$this->server,
|
$this->server,
|
||||||
$this->network->getSessionManager(),
|
$this->network->getSessionManager(),
|
||||||
PacketPool::getInstance(),
|
PacketPool::getInstance(),
|
||||||
|
$this->packetSerializerContext,
|
||||||
new RakLibPacketSender($sessionId, $this),
|
new RakLibPacketSender($sessionId, $this),
|
||||||
$this->broadcaster,
|
$this->packetBroadcaster,
|
||||||
|
$this->entityEventBroadcaster,
|
||||||
ZlibCompressor::getInstance(), //TODO: this shouldn't be hardcoded, but we might need the RakNet protocol version to select it
|
ZlibCompressor::getInstance(), //TODO: this shouldn't be hardcoded, but we might need the RakNet protocol version to select it
|
||||||
$address,
|
$address,
|
||||||
$port
|
$port
|
||||||
|
@ -52,6 +52,10 @@ abstract class Timings{
|
|||||||
public static $playerNetworkSend;
|
public static $playerNetworkSend;
|
||||||
/** @var TimingsHandler */
|
/** @var TimingsHandler */
|
||||||
public static $playerNetworkSendCompress;
|
public static $playerNetworkSendCompress;
|
||||||
|
|
||||||
|
public static TimingsHandler $playerNetworkSendCompressBroadcast;
|
||||||
|
public static TimingsHandler $playerNetworkSendCompressSessionBuffer;
|
||||||
|
|
||||||
/** @var TimingsHandler */
|
/** @var TimingsHandler */
|
||||||
public static $playerNetworkSendEncrypt;
|
public static $playerNetworkSendEncrypt;
|
||||||
/** @var TimingsHandler */
|
/** @var TimingsHandler */
|
||||||
@ -153,6 +157,8 @@ abstract class Timings{
|
|||||||
|
|
||||||
self::$playerNetworkSend = new TimingsHandler("Player Network Send");
|
self::$playerNetworkSend = new TimingsHandler("Player Network Send");
|
||||||
self::$playerNetworkSendCompress = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Compression", self::$playerNetworkSend);
|
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::$playerNetworkSendEncrypt = new TimingsHandler(self::INCLUDED_BY_OTHER_TIMINGS_PREFIX . "Player Network Send - Encryption", self::$playerNetworkSend);
|
||||||
|
|
||||||
self::$playerNetworkReceive = new TimingsHandler("Player Network Receive");
|
self::$playerNetworkReceive = new TimingsHandler("Player Network Receive");
|
||||||
|
@ -65,6 +65,7 @@ use pocketmine\math\Vector3;
|
|||||||
use pocketmine\nbt\tag\IntTag;
|
use pocketmine\nbt\tag\IntTag;
|
||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||||
|
use pocketmine\network\mcpe\NetworkBroadcastUtils;
|
||||||
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
|
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
|
||||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||||
@ -685,7 +686,7 @@ class World implements ChunkManager{
|
|||||||
$this->broadcastPacketToViewers($pos, $e);
|
$this->broadcastPacketToViewers($pos, $e);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
$this->server->broadcastPackets($this->filterViewersForPosition($pos, $players), $pk);
|
NetworkBroadcastUtils::broadcastPackets($this->filterViewersForPosition($pos, $players), $pk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -711,7 +712,7 @@ class World implements ChunkManager{
|
|||||||
$this->broadcastPacketToViewers($pos, $e);
|
$this->broadcastPacketToViewers($pos, $e);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
$this->server->broadcastPackets($this->filterViewersForPosition($pos, $ev->getRecipients()), $pk);
|
NetworkBroadcastUtils::broadcastPackets($this->filterViewersForPosition($pos, $ev->getRecipients()), $pk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1021,7 +1022,7 @@ class World implements ChunkManager{
|
|||||||
World::getXZ($index, $chunkX, $chunkZ);
|
World::getXZ($index, $chunkX, $chunkZ);
|
||||||
$chunkPlayers = $this->getChunkPlayers($chunkX, $chunkZ);
|
$chunkPlayers = $this->getChunkPlayers($chunkX, $chunkZ);
|
||||||
if(count($chunkPlayers) > 0){
|
if(count($chunkPlayers) > 0){
|
||||||
$this->server->broadcastPackets($chunkPlayers, $entries);
|
NetworkBroadcastUtils::broadcastPackets($chunkPlayers, $entries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,11 +490,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/command/defaults/TimingsCommand.php
|
path: ../../../src/command/defaults/TimingsCommand.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Call to function is_resource\\(\\) with resource will always evaluate to true\\.$#"
|
|
||||||
count: 2
|
|
||||||
path: ../../../src/console/ConsoleReader.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#"
|
message: "#^Parameter \\#1 \\$path of static method pocketmine\\\\utils\\\\Filesystem\\:\\:cleanPath\\(\\) expects string, mixed given\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@ -650,21 +645,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/network/mcpe/NetworkSession.php
|
path: ../../../src/network/mcpe/NetworkSession.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\#1 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:onEntityEffectAdded\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/network/mcpe/NetworkSession.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\#1 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:onEntityEffectRemoved\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/network/mcpe/NetworkSession.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Parameter \\#1 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:syncAttributes\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/network/mcpe/NetworkSession.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Parameter \\#1 \\$for of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:syncAbilities\\(\\) expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
message: "#^Parameter \\#1 \\$for of method pocketmine\\\\network\\\\mcpe\\\\NetworkSession\\:\\:syncAbilities\\(\\) expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
||||||
count: 2
|
count: 2
|
||||||
@ -685,6 +665,21 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/network/mcpe/NetworkSession.php
|
path: ../../../src/network/mcpe/NetworkSession.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Parameter \\#2 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\EntityEventBroadcaster\\:\\:onEntityEffectAdded\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/network/mcpe/NetworkSession.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Parameter \\#2 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\EntityEventBroadcaster\\:\\:onEntityEffectRemoved\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/network/mcpe/NetworkSession.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Parameter \\#2 \\$entity of method pocketmine\\\\network\\\\mcpe\\\\EntityEventBroadcaster\\:\\:syncAttributes\\(\\) expects pocketmine\\\\entity\\\\Living, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/network/mcpe/NetworkSession.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Parameter \\#2 \\$player of class pocketmine\\\\network\\\\mcpe\\\\handler\\\\PreSpawnPacketHandler constructor expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
message: "#^Parameter \\#2 \\$player of class pocketmine\\\\network\\\\mcpe\\\\handler\\\\PreSpawnPacketHandler constructor expects pocketmine\\\\player\\\\Player, pocketmine\\\\player\\\\Player\\|null given\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
Reference in New Issue
Block a user