Compare commits

..

2 Commits

Author SHA1 Message Date
15ffab659c Release 3.28.0 2022-02-08 20:09:52 +00:00
ca76a928c1 Protocol changes for 1.18.10 2022-02-08 20:06:46 +00:00
1866 changed files with 86614 additions and 153887 deletions

View File

@ -6,19 +6,3 @@ updates:
interval: daily
time: "10:00"
open-pull-requests-limit: 10
ignore:
#only allow patch updates for locale-data - this has to be updated manually due to codegen
- dependency-name: pocketmine/locale-data
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
- package-ecosystem: gitsubmodule
directory: "/"
schedule:
interval: daily
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

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

View File

@ -1,101 +0,0 @@
<?php
declare(strict_types=1);
namespace pocketmine;
use pocketmine\utils\Internet;
use function dirname;
use function fwrite;
use function is_array;
use function json_decode;
use function json_encode;
use const JSON_THROW_ON_ERROR;
use const STDERR;
require dirname(__DIR__, 2) . '/vendor/autoload.php';
/**
* @phpstan-return array<string, mixed>
*/
function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl, int $newsPingRoleId) : array{
return [
"content" => "<@&$newsPingRoleId> New PocketMine-MP release: $version ($channel)",
"embeds" => [
[
"title" => "New PocketMine-MP release: $version ($channel)",
"description" => <<<DESCRIPTION
$description
[Details]($detailsUrl) | [Source Code]($sourceUrl) | [Build Log]($buildLogUrl) | [Download]($pharDownloadUrl)
DESCRIPTION,
"url" => $detailsUrl,
"color" => $channel === "stable" ? 0x57ab5a : 0xc69026
]
]
];
}
if(count($argv) !== 6){
fwrite(STDERR, "Required arguments: github repo, version, API token, webhook URL, ping role ID\n");
exit(1);
}
[, $repo, $tagName, $token, $hookURL, $newsPingRoleId] = $argv;
$result = Internet::getURL('https://api.github.com/repos/' . $repo . '/releases/tags/' . $tagName, extraHeaders: [
'Authorization: token ' . $token
]);
if($result === null){
fwrite(STDERR, "failed to access GitHub API\n");
return;
}
if($result->getCode() !== 200){
fwrite(STDERR, "Error accessing GitHub API: " . $result->getCode() . "\n");
fwrite(STDERR, $result->getBody() . "\n");
exit(1);
}
$releaseInfoJson = json_decode($result->getBody(), true, JSON_THROW_ON_ERROR);
if(!is_array($releaseInfoJson)){
fwrite(STDERR, "Invalid release JSON returned from GitHub API\n");
exit(1);
}
$buildInfoPath = 'https://github.com/' . $repo . '/releases/download/' . $tagName . '/build_info.json';
$buildInfoResult = Internet::getURL($buildInfoPath, extraHeaders: [
'Authorization: token ' . $token
]);
if($buildInfoResult === null){
fwrite(STDERR, "missing build_info.json\n");
exit(1);
}
if($buildInfoResult->getCode() !== 200){
fwrite(STDERR, "error accessing build_info.json: " . $buildInfoResult->getCode() . "\n");
fwrite(STDERR, $buildInfoResult->getBody() . "\n");
exit(1);
}
$buildInfoJson = json_decode($buildInfoResult->getBody(), true, JSON_THROW_ON_ERROR);
if(!is_array($buildInfoJson)){
fwrite(STDERR, "invalid build_info.json\n");
exit(1);
}
$detailsUrl = $buildInfoJson["details_url"];
$sourceUrl = $buildInfoJson["source_url"];
$pharDownloadUrl = $buildInfoJson["download_url"];
$buildLogUrl = $buildInfoJson["build_log_url"];
$description = $releaseInfoJson["body"];
$discordPayload = generateDiscordEmbed($buildInfoJson["base_version"], $buildInfoJson["channel"], $description, $detailsUrl, $sourceUrl, $pharDownloadUrl, $buildLogUrl, (int) $newsPingRoleId);
$response = Internet::postURL(
$hookURL,
json_encode($discordPayload, JSON_THROW_ON_ERROR),
extraHeaders: ['Content-Type: application/json']
);
if($response?->getCode() !== 204){
fwrite(STDERR, "failed to send Discord webhook\n");
fwrite(STDERR, $response?->getBody() ?? "no response body\n");
exit(1);
}

View File

@ -1,38 +0,0 @@
name: Notify Discord webhook of release
on:
release:
types:
- published
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.24.0
with:
php-version: 8.0
- name: Restore Composer package cache
uses: actions/cache@v3
with:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
key: "composer-v2-cache-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
- name: Install Composer dependencies
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
- name: Get actual tag name
id: tag-name
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
- 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 }} ${{ secrets.DISCORD_NEWS_PING_ROLE_ID }}

View File

@ -13,17 +13,17 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
submodules: true
- name: Setup PHP
uses: shivammathur/setup-php@2.24.0
uses: shivammathur/setup-php@2.12.0
with:
php-version: 8.0
- name: Restore Composer package cache
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
@ -40,10 +40,33 @@ jobs:
run: |
BUILD_NUMBER=$((2000+$GITHUB_RUN_NUMBER)) #to stay above jenkins
echo "Build number: $BUILD_NUMBER"
echo BUILD_NUMBER=$BUILD_NUMBER >> $GITHUB_OUTPUT
echo ::set-output name=BUILD_NUMBER::$BUILD_NUMBER
- name: Minify BedrockData JSON files
run: php vendor/pocketmine/bedrock-data/.minify_json.php
run: php src/pocketmine/resources/vanilla/.minify_json.php
- name: Run preprocessor
run: |
PM_PREPROCESSOR_PATH="$GITHUB_WORKSPACE/build/preprocessor"
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path=src --multisize || (echo "Preprocessor exited with code $?" && exit 1)
#dump the diff of preprocessor replacements to a patch in case it has bugs
git diff > preprocessor_diff.patch
VENDOR_PM="$GITHUB_WORKSPACE/vendor"
VENDOR_PM_BACKUP="$GITHUB_WORKSPACE/vendor-before-preprocess"
cp -r "$VENDOR_PM" "$VENDOR_PM_BACKUP"
for f in $(ls $VENDOR_PM/pocketmine); do
echo "Processing directory \"$f\"..."
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path="$VENDOR_PM/pocketmine/$f/src" --multisize || (echo "Preprocessor exited with code $?" && exit 1)
echo "Checking for changes in \"$f\"..."
DIFF=$(git diff --no-index "$VENDOR_PM_BACKUP/pocketmine/$f" "$VENDOR_PM/pocketmine/$f" || true)
if [ "$DIFF" != "" ]; then
PATCH="$GITHUB_WORKSPACE/preprocessor_diff_$f.patch"
echo "$DIFF" > "$PATCH"
echo "Generated patch file \"$PATCH\""
else
echo "No diff generated for \"$f\" (preprocessor made no changes)"
fi
done
- name: Build PocketMine-MP.phar
run: php -dphar.readonly=0 build/server-phar.php --git ${{ github.sha }} --build ${{ steps.build-number.outputs.BUILD_NUMBER }}
@ -51,18 +74,16 @@ jobs:
- name: Get PocketMine-MP release version
id: get-pm-version
run: |
echo PM_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BASE_VERSION;') >> $GITHUB_OUTPUT
echo MCPE_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;') >> $GITHUB_OUTPUT
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 PM_VERSION_MD=$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);') >> $GITHUB_OUTPUT
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
echo ::set-output name=PM_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\BASE_VERSION;')
echo ::set-output name=MCPE_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;')
echo ::set-output name=PM_VERSION_SHORT::$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\BASE_VERSION); array_pop($v); echo implode(".", $v);')
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\BASE_VERSION);')
- 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 }} > build_info.json
- name: Upload release artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v2
with:
name: release_artifacts
path: |
@ -71,16 +92,28 @@ jobs:
${{ github.workspace }}/build_info.json
- name: Create draft release
uses: ncipollo/release-action@v1.12.0
uses: ncipollo/release-action@v1.8.6
with:
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
commit: ${{ github.sha }}
draft: true
prerelease: ${{ steps.get-pm-version.outputs.PRERELEASE }}
name: PocketMine-MP ${{ steps.get-pm-version.outputs.PM_VERSION }}
tag: ${{ steps.get-pm-version.outputs.PM_VERSION }}
token: ${{ secrets.GITHUB_TOKEN }}
body: |
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}${{ steps.get-pm-version.outputs.CHANGELOG_SUFFIX }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
Please see the [changelogs](/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
## WARNING
The 3.x line of releases is now OBSOLETE. It will be discontinued after **March 1st, 2022**.
Please prepare to upgrade to 4.0 or newer before that date.
- name: Upload preprocessor diffs
uses: actions/upload-artifact@v2
if: always()
with:
name: preprocessor_diffs
path: ${{ github.workspace }}/preprocessor_diff*.patch

View File

@ -13,15 +13,14 @@ jobs:
strategy:
matrix:
image: [ubuntu-20.04]
php: [8.0.28, 8.1.18, 8.2.5]
php: [8.0.11]
steps:
- name: Build and prepare PHP cache
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
pm-version-major: "4"
phpstan:
name: PHPStan analysis
@ -32,23 +31,22 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.28, 8.1.18, 8.2.5]
php: [8.0.11]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Setup PHP
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
pm-version-major: "4"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
@ -71,23 +69,22 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.28, 8.1.18, 8.2.5]
php: [8.0.11]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Setup PHP
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
pm-version-major: "4"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
@ -110,25 +107,24 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.28, 8.1.18, 8.2.5]
php: [8.0.11]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
submodules: true
- name: Setup PHP
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
pm-version-major: "4"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
@ -143,31 +139,32 @@ jobs:
- name: Run integration tests
run: ./tests/travis.sh -t4
codegen:
name: Generated Code consistency checks
preprocessor:
name: Preprocessor tests
needs: build-php
runs-on: ${{ matrix.image }}
strategy:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.28, 8.1.18, 8.2.5]
php: [8.0.11]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
submodules: true
- name: Setup PHP
uses: pmmp/setup-php-action@c7fb29d83535320922068087c7285bdedbbfa3c2
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
pm-version-major: "4"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache
uses: actions/cache@v3
uses: actions/cache@v2
with:
path: |
~/.cache/composer/files
@ -179,19 +176,37 @@ jobs:
- name: Install Composer dependencies
run: php composer.phar install --no-dev --prefer-dist --no-interaction
- name: Regenerate registry annotations
run: php build/generate-registry-annotations.php src
- name: Regenerate KnownTranslation APIs
run: php build/generate-known-translation-apis.php
- name: Regenerate BedrockData available files constants
run: php build/generate-bedrockdata-path-consts.php
- name: Verify code is unchanged
- name: Run preprocessor
run: |
git diff
git diff --quiet
PM_PREPROCESSOR_PATH="$GITHUB_WORKSPACE/build/preprocessor"
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path=src --multisize || (echo "Preprocessor exited with code $?" && exit 1)
#dump the diff of preprocessor replacements to a patch in case it has bugs
git diff > preprocessor_diff.patch
VENDOR_PM="$GITHUB_WORKSPACE/vendor"
VENDOR_PM_BACKUP="$GITHUB_WORKSPACE/vendor-before-preprocess"
cp -r "$VENDOR_PM" "$VENDOR_PM_BACKUP"
for f in $(ls $VENDOR_PM/pocketmine); do
echo "Processing directory \"$f\"..."
php "$PM_PREPROCESSOR_PATH/PreProcessor.php" --path="$VENDOR_PM/pocketmine/$f/src" --multisize || (echo "Preprocessor exited with code $?" && exit 1)
echo "Checking for changes in \"$f\"..."
DIFF=$(git diff --no-index "$VENDOR_PM_BACKUP/pocketmine/$f" "$VENDOR_PM/pocketmine/$f" || true)
if [ "$DIFF" != "" ]; then
PATCH="$GITHUB_WORKSPACE/preprocessor_diff_$f.patch"
echo "$DIFF" > "$PATCH"
echo "Generated patch file \"$PATCH\""
else
echo "No diff generated for \"$f\" (preprocessor made no changes)"
fi
done
- name: Upload preprocessor diffs
uses: actions/upload-artifact@v2
if: always()
with:
name: preprocessor_diffs_${{ matrix.php }}_${{ matrix.image }}
path: ${{ github.workspace }}/preprocessor_diff*.patch
codestyle:
name: Code Style checks
@ -200,15 +215,13 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.24.0
uses: shivammathur/setup-php@2.15.0
with:
php-version: 8.0
tools: php-cs-fixer:3.16
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tools: php-cs-fixer:3.2
- name: Run PHP-CS-Fixer
run: php-cs-fixer fix --dry-run --diff --ansi
run: php-cs-fixer fix --dry-run --diff

View File

@ -8,19 +8,12 @@ jobs:
support:
runs-on: ubuntu-latest
steps:
- uses: dessant/support-requests@v3
- uses: dessant/support-requests@v2
with:
github-token: ${{ github.token }}
support-label: "Support request"
issue-comment: >
Hi, we only accept **bug reports** on this issue tracker, but this issue looks like a support request.
Instead of creating an issue, try the following:
- Check our [Documentation](https://doc.pmmp.io) to see if you can find answers there
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG) or our [Forums](https://forums.pmmp.io)
Thanks, but this issue tracker is not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue).
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)

View File

@ -22,9 +22,7 @@
declare(strict_types=1);
const VERSIONS = [
"8.0",
"8.1",
"8.2"
"8.0"
];
$workflowFile = file_get_contents(__DIR__ . '/main.yml');

View File

@ -13,70 +13,25 @@ jobs:
- name: Install jq
run: sudo apt update && sudo apt install jq -y
- uses: actions/checkout@v3
- uses: actions/checkout@v2
with:
repository: ${{ github.repository_owner }}/update.pmmp.io
repository: pmmp/update.pmmp.io
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
- name: Get actual tag name
id: tag-name
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
- name: Download new release information
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
- name: Detect channels
- name: Detect channel
id: channel
run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json)
- name: Copy release information
run: |
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"
cp new_build_info.json channels/${{ steps.channel.outputs.CHANNEL }}.json
rm new_build_info.json
- name: Commit changes

3
.gitignore vendored
View File

@ -1,7 +1,5 @@
players/*
worlds/*
world_conversion_backups/*
backups/*
plugin_data/*
plugins/*
bin*/*
@ -12,7 +10,6 @@ crashdumps/*
*.phar
server.properties
/pocketmine.yml
/plugin_list.yml
memory_dumps/*
resource_packs/
server.lock

9
.gitmodules vendored
View File

@ -1,6 +1,15 @@
[submodule "src/pocketmine/lang/locale"]
path = src/pocketmine/lang/locale
url = https://github.com/pmmp/Language.git
[submodule "tests/preprocessor"]
path = build/preprocessor
url = https://github.com/pmmp/preprocessor.git
[submodule "tests/plugins/DevTools"]
path = tests/plugins/DevTools
url = https://github.com/pmmp/DevTools.git
[submodule "build/php"]
path = build/php
url = https://github.com/pmmp/php-build-scripts.git
[submodule "src/pocketmine/resources/vanilla"]
path = src/pocketmine/resources/vanilla
url = https://github.com/pmmp/BedrockData.git

View File

@ -62,11 +62,6 @@
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Shell Script">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="neon">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />

View File

@ -16,6 +16,6 @@
* @link http://www.pocketmine.net/
*
*
*/
*/
declare(strict_types=1);

View File

@ -4,8 +4,9 @@ $finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/src')
->in(__DIR__ . '/build')
->in(__DIR__ . '/tests')
->in(__DIR__ . '/tools')
->notPath('plugins/DevTools')
->notPath('preprocessor')
->notContains('#ifndef COMPILE') //preprocessor will break if these are changed
->notName('PocketMine.php');
return (new PhpCsFixer\Config)
@ -42,41 +43,11 @@ return (new PhpCsFixer\Config)
'import_functions' => true,
'import_classes' => null,
],
'header_comment' => [
'comment_type' => 'comment',
'header' => <<<BODY
____ _ _ __ __ _ __ __ ____
| _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
| |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
| __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
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/
BODY,
'location' => 'after_open'
],
'indentation_type' => true,
'logical_operators' => true,
'native_constant_invocation' => [
'scope' => 'namespaced'
],
'native_function_invocation' => [
'scope' => 'namespaced',
'include' => ['@all'],
],
'new_with_braces' => [
'named_class' => true,
'anonymous_class' => false,
],
'no_closing_tag' => true,
'no_empty_phpdoc' => true,
'no_extra_blank_lines' => true,
@ -95,12 +66,6 @@ BODY,
],
'sort_algorithm' => 'alpha'
],
'phpdoc_align' => [
'align' => 'vertical',
'tags' => [
'param',
]
],
'phpdoc_line_span' => [
'property' => 'single',
'method' => null,

View File

@ -14,15 +14,20 @@ Because PocketMine-MP requires several non-standard PHP extensions and configura
If you use a custom binary, you'll need to replace `composer` usages in this guide with `path/to/your/php path/to/your/composer.phar`.
## Setting up environment
1. `git clone https://github.com/pmmp/PocketMine-MP.git`
1. `git clone --recursive https://github.com/pmmp/PocketMine-MP.git`
2. `composer install`
## Checking out a different branch to build
1. `git checkout <branch to checkout>`
2. Re-run `composer install` to synchronize dependencies.
2. `git submodule update --init`
3. Re-run `composer install` to synchronize dependencies.
## Optimizing for release builds
1. Add the flags `--no-dev --classmap-authoritative` to your `composer install` command. This will reduce build size and improve autoloading speed.
2. Preprocess the source code by running `build/preprocessor/PreProcessor.php`. Usage instructions are provided in `build/preprocessor/README.md`.
### Note
Preprocessor requires that the `cpp` (c preprocessor) is available in your PATH.
## Building `PocketMine-MP.phar`
Run `composer make-server` using your preferred PHP binary. It'll drop a `PocketMine-MP.phar` into the current working directory.
@ -36,4 +41,4 @@ Fatal error: Uncaught BadMethodCallException: unable to create temporary file in
You can work around it by setting `ulimit -n` to some bigger number, e.g. `8192`, or by updating your PHP version to at least 8.0.3.
## Running PocketMine-MP from source code
Run `src/PocketMine.php` using your preferred PHP binary.
Run `src/pocketmine/PocketMine.php` using your preferred PHP binary.

View File

@ -18,37 +18,6 @@ Larger contributions like feature additions should be preceded by a [Change Prop
## Other things you'll need
- [git](https://git-scm.com/)
## Choosing a target branch
PocketMine-MP has three primary branches of development.
| Type of change | `stable` | `minor-next` | `major-next` |
|:--------------------------------------------------------------------------------------------|:--------:|:-------------------------------:|:------------:|
| Bug fixes | ✔️ | ✔️ | ✔️ |
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
| Cleaning up code | ❌ | ✔️ | ✔️ |
| Changing code formatting or style | ❌ | ✔️ | ✔️ |
| Addition of new core features | ❌ | 🟡 Only if non-disruptive | ✔️ |
| Changing core behaviour (e.g. making something use threads) | ❌ | ✔️ | ✔️ |
| Addition of new configuration options | ❌ | 🟡 Only if optional | ✔️ |
| Addition of new API classes, methods or constants | ❌ | ✔️ | ✔️ |
| Deprecating API classes, methods or constants | ❌ | ✔️ | ✔️ |
| Adding optional parameters to an API method | ❌ | ✔️ | ✔️ |
| Changing API behaviour | ❌ | 🟡 Only if backwards-compatible | ✔️ |
| Removal of API | ❌ | ❌ | ✔️ |
| Backwards-incompatible API change (e.g. renaming a method) | ❌ | ❌ | ✔️ |
| Backwards-incompatible internals change (e.g. changing things in `pocketmine\network\mcpe`) | ❌ | ✔️ | ✔️ |
### Notes
- **Non-disruptive** means that usage should not be significantly altered by the change.
- Examples of **non-disruptive** changes include adding new commands, or gameplay features like blocks and items.
- Examples of **disruptive** changes include changing the way the server is run, world format changes (since those require downtime for the user to convert their world).
- **API** includes all public and protected classes, functions and constants (unless marked as `@internal`).
- Private members are not part of the API, **unless in a trait**.
- The `pocketmine\network\mcpe` package is considered implicitly `@internal` in its entirety (see its [README](src/network/mcpe/README.md) for more details).
- Minecraft's protocol changes are considered necessary internal changes, and are **not** subject to the same rules.
- Protocol changes must always be released in a new minor version, since they disrupt user experience by requiring a client update.
- BC-breaking changes to the internal network API are allowed, but only in new minor versions. This ensures that plugins which use the internal network API will not break (though they shouldn't use such API anyway).
## Making a pull request
The basic procedure to create a pull request is:
1. [Fork the repository on GitHub](https://github.com/pmmp/PocketMine-MP/fork). This gives you your own copy of the repository to make changes to.

View File

@ -1,29 +1,19 @@
<p align="center">
<a href="https://pmmp.io">
<!--[if IE]>
<img src="https://github.com/pmmp/PocketMine-MP/blob/stable/.github/readme/pocketmine.png" alt="The PocketMine-MP logo" title="PocketMine" loading="eager" />
<![endif]-->
<picture>
<source srcset="https://github.com/pmmp/PocketMine-MP/raw/stable/.github/readme/pocketmine-dark.png" media="(prefers-color-scheme: dark)">
<img src="https://github.com/pmmp/PocketMine-MP/raw/stable/.github/readme/pocketmine.png" loading="eager" />
</picture>
</a><br>
<a href="https://pmmp.io"><img src="http://cdn.pocketmine.net/img/PocketMine-MP-h.png"></img></a><br>
<b>A highly customisable, open source server software for Minecraft: Bedrock Edition written in PHP</b>
</p>
<p align="center">
<a href="https://github.com/pmmp/PocketMine-MP/actions/workflows/main.yml"><img src="https://github.com/pmmp/PocketMine-MP/workflows/CI/badge.svg" alt="CI" /></a>
<a href="https://github.com/pmmp/PocketMine-MP/releases/latest"><img alt="GitHub release (latest SemVer)" src="https://img.shields.io/github/v/release/pmmp/PocketMine-MP?label=release&sort=semver"></a>
<img src="https://github.com/pmmp/PocketMine-MP/workflows/CI/badge.svg" alt="CI" />
<img alt="GitHub release (latest SemVer)" src="https://img.shields.io/github/v/release/pmmp/PocketMine-MP?label=release&sort=semver">
<a href="https://hub.docker.com/r/pmmp/pocketmine-mp"><img src="https://img.shields.io/docker/v/pmmp/pocketmine-mp?logo=docker&label=image" alt="Docker image version (latest semver)" /></a>
<a href="https://discord.gg/bmSAZBG"><img src="https://img.shields.io/discord/373199722573201408?label=discord&color=7289DA&logo=discord" alt="Discord" /></a>
<br>
<a href="https://github.com/pmmp/PocketMine-MP/releases"><img alt="GitHub all releases" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/total?label=downloads%40total"></a>
<a href="https://github.com/pmmp/PocketMine-MP/releases/latest"><img alt="GitHub release (latest by SemVer)" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/latest/total?sort=semver"></a>
</p>
## Getting started
- [Documentation](http://pmmp.readthedocs.org/)
- [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html)
- [Docker image](https://github.com/pmmp/PocketMine-MP/pkgs/container/pocketmine-mp)
- [Docker image](https://hub.docker.com/r/pmmp/pocketmine-mp)
- [Plugin repository](https://poggit.pmmp.io/plugins)
## Discussion/Help
@ -34,8 +24,7 @@
## For developers
* [Building and running from source](BUILDING.md)
* [Developer documentation](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers
* [Latest release API documentation](https://apidoc.pmmp.io) - Doxygen API documentation generated for each release
* [Latest bleeding-edge API documentation](https://apidoc-dev.pmmp.io) - Doxygen API documentation generated weekly from `major-next` branch
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development
* [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
* [Contributing Guidelines](CONTRIBUTING.md)

View File

@ -7,11 +7,10 @@ GitHub is public and anyone can see the issues you post on the issue tracker, in
**WARNING: You may put live servers at risk by reporting a vulnerability on the GitHub issue tracker.**
**Contact us** by sending an email to [**security@pmmp.io**](mailto:security@pmmp.io). Include the following information:
**Contact us** by sending an email to [**team@pmmp.io**](mailto:team@pmmp.io?subject=Security%20Vulnerability%20in%20PocketMine-MP). Include the following information:
- Version of PocketMine-MP
- Detailed description of the vulnerability (e.g. how to exploit it, what the effects are)
- Your GitHub username, if you wish to be credited for reporting the problem in the security advisory
Please note that we can't guarantee a reply to every email.

View File

@ -1,128 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\build\generate_bedrockdata_path_consts;
use Symfony\Component\Filesystem\Path;
use function dirname;
use function fclose;
use function fopen;
use function fwrite;
use function is_file;
use function scandir;
use function str_replace;
use function strtoupper;
use const PHP_EOL;
use const pocketmine\BEDROCK_DATA_PATH;
use const SCANDIR_SORT_ASCENDING;
use const STDERR;
require dirname(__DIR__) . '/vendor/autoload.php';
function constantify(string $permissionName) : string{
return strtoupper(str_replace([".", "-"], "_", $permissionName));
}
$files = scandir(BEDROCK_DATA_PATH, SCANDIR_SORT_ASCENDING);
if($files === false){
fwrite(STDERR, "Couldn't find any files in " . BEDROCK_DATA_PATH . PHP_EOL);
exit(1);
}
$consts = [];
foreach($files as $file){
if($file === '.' || $file === '..'){
continue;
}
if($file[0] === '.'){
continue;
}
$path = Path::join(BEDROCK_DATA_PATH, $file);
if(!is_file($path)){
continue;
}
foreach([
'README.md',
'LICENSE',
'composer.json',
] as $ignored){
if($file === $ignored){
continue 2;
}
}
$consts[] = $file;
}
$output = fopen(dirname(__DIR__) . '/src/data/bedrock/BedrockDataFiles.php', 'wb');
if($output === false){
fwrite(STDERR, "Couldn't open output file" . PHP_EOL);
exit(1);
}
fwrite($output, <<<'HEADER'
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock;
use const pocketmine\BEDROCK_DATA_PATH;
final class BedrockDataFiles{
private function __construct(){
//NOOP
}
HEADER
);
foreach($consts as $constName => $fileName){
fwrite($output, "\tpublic const " . constantify($fileName) . " = BEDROCK_DATA_PATH . '/$fileName';\n");
}
fwrite($output, "}\n");
fclose($output);
echo "Done. Don't forget to run CS fixup after generating code.\n";

View File

@ -17,28 +17,27 @@
* @link http://www.pocketmine.net/
*
*
*/
*/
declare(strict_types=1);
require dirname(__DIR__) . '/vendor/autoload.php';
if(count($argv) !== 6){
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number> <github actions run ID>\n");
if(count($argv) !== 5){
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number>");
exit(1);
}
echo json_encode([
"php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION),
"base_version" => \pocketmine\VersionInfo::BASE_VERSION,
"base_version" => \pocketmine\BASE_VERSION,
"build" => (int) $argv[4],
"is_dev" => \pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD,
"channel" => \pocketmine\VersionInfo::BUILD_CHANNEL,
"is_dev" => \pocketmine\IS_DEVELOPMENT_BUILD,
"channel" => \pocketmine\BUILD_CHANNEL,
"git_commit" => $argv[1],
"mcpe_version" => \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK,
"date" => time(), //TODO: maybe we should embed this in VersionInfo?
"details_url" => "https://github.com/$argv[3]/releases/tag/$argv[2]",
"download_url" => "https://github.com/$argv[3]/releases/download/$argv[2]/PocketMine-MP.phar",
"source_url" => "https://github.com/$argv[3]/tree/$argv[2]",
"build_log_url" => "https://github.com/$argv[3]/actions/runs/$argv[5]",
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n";
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";

View File

@ -1,193 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\build\generate_known_translation_apis;
use pocketmine\lang\Translatable;
use pocketmine\utils\Utils;
use Symfony\Component\Filesystem\Path;
use function array_map;
use function count;
use function dirname;
use function file_put_contents;
use function fwrite;
use function implode;
use function is_numeric;
use function ksort;
use function ob_get_clean;
use function ob_start;
use function parse_ini_file;
use function preg_match_all;
use function str_replace;
use function strtoupper;
use const INI_SCANNER_RAW;
use const SORT_NUMERIC;
use const SORT_STRING;
use const STDERR;
require dirname(__DIR__) . '/vendor/autoload.php';
function constantify(string $permissionName) : string{
return strtoupper(str_replace([".", "-"], "_", $permissionName));
}
function functionify(string $permissionName) : string{
return str_replace([".", "-"], "_", $permissionName);
}
const SHARED_HEADER = <<<'HEADER'
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\lang;
HEADER;
/**
* @param string[] $languageDefinitions
* @phpstan-param array<string, string> $languageDefinitions
*/
function generate_known_translation_keys(array $languageDefinitions) : void{
ob_start();
echo SHARED_HEADER;
echo <<<'HEADER'
/**
* This class contains constants for all the translations known to PocketMine-MP as per the used version of pmmp/Language.
* This class is generated automatically, do NOT modify it by hand.
*
* @internal
*/
final class KnownTranslationKeys{
HEADER;
ksort($languageDefinitions, SORT_STRING);
foreach(Utils::stringifyKeys($languageDefinitions) as $k => $_){
echo "\tpublic const ";
echo constantify($k);
echo " = \"" . $k . "\";\n";
}
echo "}\n";
file_put_contents(dirname(__DIR__) . '/src/lang/KnownTranslationKeys.php', ob_get_clean());
echo "Done generating KnownTranslationKeys.\n";
}
/**
* @param string[] $languageDefinitions
* @phpstan-param array<string, string> $languageDefinitions
*/
function generate_known_translation_factory(array $languageDefinitions) : void{
ob_start();
echo SHARED_HEADER;
echo <<<'HEADER'
/**
* This class contains factory methods for all the translations known to PocketMine-MP as per the used version of
* pmmp/Language.
* This class is generated automatically, do NOT modify it by hand.
*
* @internal
*/
final class KnownTranslationFactory{
HEADER;
ksort($languageDefinitions, SORT_STRING);
$parameterRegex = '/{%(.+?)}/';
$translationContainerClass = (new \ReflectionClass(Translatable::class))->getShortName();
foreach(Utils::stringifyKeys($languageDefinitions) as $key => $value){
$parameters = [];
$allParametersPositional = true;
if(preg_match_all($parameterRegex, $value, $matches) > 0){
foreach($matches[1] as $parameterName){
if(is_numeric($parameterName)){
$parameters[$parameterName] = "param$parameterName";
}else{
$parameters[$parameterName] = $parameterName;
$allParametersPositional = false;
}
}
}
if($allParametersPositional){
ksort($parameters, SORT_NUMERIC);
}
echo "\tpublic static function " .
functionify($key) .
"(" . implode(", ", array_map(fn(string $paramName) => "$translationContainerClass|string \$$paramName", $parameters)) . ") : $translationContainerClass{\n";
echo "\t\treturn new $translationContainerClass(KnownTranslationKeys::" . constantify($key) . ", [";
foreach($parameters as $parameterKey => $parameterName){
echo "\n\t\t\t";
if(!is_numeric($parameterKey)){
echo "\"$parameterKey\"";
}else{
echo $parameterKey;
}
echo " => \$$parameterName,";
}
if(count($parameters) !== 0){
echo "\n\t\t";
}
echo "]);\n\t}\n\n";
}
echo "}\n";
file_put_contents(dirname(__DIR__) . '/src/lang/KnownTranslationFactory.php', ob_get_clean());
echo "Done generating KnownTranslationFactory.\n";
}
$lang = parse_ini_file(Path::join(\pocketmine\LOCALE_DATA_PATH, "eng.ini"), false, INI_SCANNER_RAW);
if($lang === false){
fwrite(STDERR, "Missing language files!\n");
exit(1);
}
generate_known_translation_keys($lang);
generate_known_translation_factory($lang);

View File

@ -1,132 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\build\update_registry_annotations;
use function basename;
use function class_exists;
use function count;
use function dirname;
use function file_get_contents;
use function file_put_contents;
use function fwrite;
use function implode;
use function is_dir;
use function ksort;
use function mb_strtoupper;
use function preg_match;
use function sprintf;
use function str_ends_with;
use function str_replace;
use const SORT_STRING;
use const STDERR;
if(count($argv) !== 2){
fwrite(STDERR, "Provide a path to process\n");
exit(1);
}
/**
* @param object[] $members
*/
function generateMethodAnnotations(string $namespaceName, array $members) : string{
$selfName = basename(__FILE__);
$lines = ["/**"];
$lines[] = " * This doc-block is generated automatically, do not modify it manually.";
$lines[] = " * This must be regenerated whenever registry members are added, removed or changed.";
$lines[] = " * @see build/$selfName";
$lines[] = " * @generate-registry-docblock";
$lines[] = " *";
static $lineTmpl = " * @method static %2\$s %s()";
$memberLines = [];
foreach($members as $name => $member){
$reflect = new \ReflectionClass($member);
while($reflect !== false && $reflect->isAnonymous()){
$reflect = $reflect->getParentClass();
}
if($reflect === false){
$typehint = "object";
}elseif($reflect->getNamespaceName() === $namespaceName){
$typehint = $reflect->getShortName();
}else{
$typehint = '\\' . $reflect->getName();
}
$accessor = mb_strtoupper($name);
$memberLines[$accessor] = sprintf($lineTmpl, $accessor, $typehint);
}
ksort($memberLines, SORT_STRING);
foreach($memberLines as $line){
$lines[] = $line;
}
$lines[] = " */";
return implode("\n", $lines);
}
function processFile(string $file) : void{
$contents = file_get_contents($file);
if($contents === false){
throw new \RuntimeException("Failed to get contents of $file");
}
if(preg_match("/(*ANYCRLF)^namespace (.+);$/m", $contents, $matches) !== 1 || preg_match('/(*ANYCRLF)^((final|abstract)\s+)?class /m', $contents) !== 1){
return;
}
$shortClassName = basename($file, ".php");
$className = $matches[1] . "\\" . $shortClassName;
if(!class_exists($className)){
return;
}
$reflect = new \ReflectionClass($className);
$docComment = $reflect->getDocComment();
if($docComment === false || preg_match("/(*ANYCRLF)^\s*\*\s*@generate-registry-docblock$/m", $docComment) !== 1){
return;
}
echo "Found registry in $file\n";
$replacement = generateMethodAnnotations($matches[1], $className::getAll());
$newContents = str_replace($docComment, $replacement, $contents);
if($newContents !== $contents){
echo "Writing changed file $file\n";
file_put_contents($file, $newContents);
}else{
echo "No changes made to file $file\n";
}
}
require dirname(__DIR__) . '/vendor/autoload.php';
if(is_dir($argv[1])){
/** @var string $file */
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $file){
if(!str_ends_with($file, ".php")){
continue;
}
processFile($file);
}
}else{
processFile($argv[1]);
}

View File

@ -17,32 +17,31 @@
* @link http://www.pocketmine.net/
*
*
*/
*/
declare(strict_types=1);
namespace pocketmine\build\make_release;
use pocketmine\utils\Filesystem;
use pocketmine\utils\Utils;
use pocketmine\utils\VersionString;
use pocketmine\VersionInfo;
use function array_keys;
use function array_map;
use function dirname;
use function fgets;
use function file_get_contents;
use function file_put_contents;
use function fwrite;
use function getopt;
use function is_string;
use function max;
use function preg_match;
use function preg_replace;
use function sleep;
use function sprintf;
use function str_pad;
use function strlen;
use function strtolower;
use function system;
use const pocketmine\BASE_VERSION;
use const pocketmine\BUILD_CHANNEL;
use const STDERR;
use const STDIN;
use const STDOUT;
@ -51,7 +50,7 @@ use const STR_PAD_LEFT;
require_once dirname(__DIR__) . '/vendor/autoload.php';
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev, string $channel) : void{
$versionInfo = Filesystem::fileGetContents($versionInfoPath);
$versionInfo = file_get_contents($versionInfoPath);
$versionInfo = preg_replace(
$pattern = '/^([\t ]*public )?const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m',
'$1const BASE_VERSION = "' . $newVersion . '";',
@ -76,17 +75,9 @@ const ACCEPTED_OPTS = [
"channel" => "Release channel to post this build into"
];
function systemWrapper(string $command, string $errorMessage) : void{
system($command, $result);
if($result !== 0){
echo "error: $errorMessage; aborting\n";
exit(1);
}
}
function main() : void{
$filteredOpts = [];
foreach(Utils::stringifyKeys(getopt("", ["current:", "next:", "channel:", "help"])) as $optName => $optValue){
foreach(getopt("", ["current:", "next:", "channel:", "help"]) as $optName => $optValue){
if($optName === "help"){
fwrite(STDOUT, "Options:\n");
@ -103,62 +94,43 @@ function main() : void{
$filteredOpts[$optName] = $optValue;
}
$channel = $filteredOpts["channel"] ?? null;
if(isset($filteredOpts["current"])){
$currentVer = new VersionString($filteredOpts["current"]);
}else{
$currentVer = new VersionString(VersionInfo::BASE_VERSION);
$currentVer = new VersionString(BASE_VERSION);
}
$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]);
if(isset($filteredOpts["next"])){
$nextVer = new VersionString($filteredOpts["next"]);
}else{
$nextVer ??= new VersionString(sprintf(
$nextVer = new VersionString(sprintf(
"%u.%u.%u",
$currentVer->getMajor(),
$currentVer->getMinor(),
$currentVer->getPatch() + 1
));
$channel ??= "stable";
}
$channel = $filteredOpts["channel"] ?? BUILD_CHANNEL;
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
echo "$currentVer will be published on release channel \"$channel\".\n";
echo "please add appropriate notes to the changelog and press enter...";
fgets(STDIN);
systemWrapper('git add "' . dirname(__DIR__) . '/changelogs"', "failed to stage changelog changes");
system('git add "' . dirname(__DIR__) . '/changelogs"');
system('git diff --cached --quiet "' . dirname(__DIR__) . '/changelogs"', $result);
if($result === 0){
echo "error: no changelog changes detected; aborting\n";
exit(1);
}
$versionInfoPath = dirname(__DIR__) . '/src/VersionInfo.php';
$versionInfoPath = dirname(__DIR__) . '/src/pocketmine/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel);
systemWrapper('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"', "failed to create release commit");
systemWrapper('git tag ' . $currentVer->getBaseVersion(), "failed to create release tag");
system('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"');
system('git tag ' . $currentVer->getBaseVersion());
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel);
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");
system('git add "' . $versionInfoPath . '"');
system('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"');
echo "pushing changes in 5 seconds\n";
sleep(5);
system('git push origin HEAD ' . $currentVer->getBaseVersion());
}
main();

1
build/preprocessor Submodule

Submodule build/preprocessor added at 1b9304de61

View File

@ -17,7 +17,7 @@
* @link http://www.pocketmine.net/
*
*
*/
*/
declare(strict_types=1);
@ -40,13 +40,12 @@ use function rtrim;
use function sprintf;
use function str_replace;
use function unlink;
use const DIRECTORY_SEPARATOR;
use const PHP_EOL;
require dirname(__DIR__) . '/vendor/autoload.php';
/**
* @param string[] $strings
* @param string[] $strings
*
* @return string[]
*/
@ -151,7 +150,6 @@ function main() : void{
$opts["out"] ?? getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar",
dirname(__DIR__) . DIRECTORY_SEPARATOR,
[
'resources',
'src',
'vendor'
],
@ -170,7 +168,7 @@ if(!is_readable($tmpDir) or !is_writable($tmpDir)){
exit(1);
}
require("phar://" . __FILE__ . "/src/PocketMine.php");
require("phar://" . __FILE__ . "/src/pocketmine/PocketMine.php");
__HALT_COMPILER();
STUB
,

10
changelogs/3.28.md Normal file
View File

@ -0,0 +1,10 @@
**For Minecraft: Bedrock Edition 1.18.10**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 3.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.
# 3.28.0
- Added support for Minecraft: Bedrock Edition 1.18.10.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,166 +0,0 @@
**For Minecraft: Bedrock Edition 1.18.0**
### 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.1.0-BETA1
Released 22nd January 2022.
## General
- Game mode names (e.g. `survival`, `creative`) may now be used for the `gamemode` property in `server.properties`.
- Increased default maximum render distance to 16 chunks. Players with a render distance smaller than this will notice no difference.
- The setup wizard now prompts for a maximum render distance value.
- The setup wizard now prompts for an IPv6 port selection. Previously it would always use 19133.
- `chunk-ticking.disable-block-ticking` now accepts block names like those used in the `/give` command.
- The `/clear` command now behaves more like vanilla:
- The order of inventories is now the same as Bedrock.
- The cursor and offhand inventories are now cleared if necessary.
## Technical
- `PlayerAuthInputPacket` is now used instead of `MovePlayerPacket` for processing movements. This improves position and rotation accuracy.
- `&&` and `||` are now always used instead of `and` and `or`.
- New version of `pocketmine/errorhandler` is used by this version, adding support for `ErrorToExceptionHandler::trap()`. This enables reliably capturing `E_WARNING` and `E_NOTICE` from functions such as `yaml_parse()` and friends.
- New dependency versions are required by this version:
- `pocketmine/bedrock-protocol` has been updated from 7.1.0 to [7.3.0](https://github.com/pmmp/BedrockProtocol/releases/tag/7.3.0%2Bbedrock-1.18.0).
- `pocketmine/errorhandler` has been updated from 0.3.0 to [0.6.0](https://github.com/pmmp/ErrorHandler/releases/tag/0.6.0).
## API
### Block
- The following classes have been added:
- `Lectern`
- `Pumpkin`
- The following public API methods have been added:
- `Block->getTypeId() : int` - returns an integer which uniquely identifies the block type, ignoring things like facing, colour etc.
- `VanillaBlocks::LECTERN()`
### Entity
- The following classes have been added:
- `animation\ItemEntityStackSizeChangeAnimation`
- The following public API methods have been added:
- `object\ItemEntity->isMergeable(object\ItemEntity $other) : bool`
- `object\ItemEntity->setStackSize(int $size) : void`
- `object\ItemEntity->tryMergeInto(object\ItemEntity $other) : bool`
- `ExperienceManager->canAttractXpOrbs() : bool`
- `ExperienceManager->setCanAttractXpOrbs(bool $v = true) : void`
- `Entity->getSize() : EntitySizeInfo`
- `Living->isGliding() : bool`
- `Living->isSwimming() : bool`
- `Living->setGliding(bool $value = true) : void`
- `Living->setSwimming(bool $value = true) : void`
- The following protected API methods have been added:
- `Entity->getBlocksIntersected(float $inset) : \Generator<int, Block, void, void>`
### Event
- `BlockSpreadEvent` is now called when fire spreads to the positions of blocks it burns away.
- `BlockFormEvent` is now called when concrete powder turns into concrete due to contact with water.
- The following classes have been added:
- `BlockMeltEvent` - called when ice or snow melts
- `ChestPairEvent` - called when two chests try to form a pair
- `PlayerToggleGlideEvent` - called when a player starts or stops gliding
- `PlayerToggleSwimEvent` - called when a player starts or stops swimming
### Item
- The following public API methods have been added:
- `SplashPotion->getType() : PotionType`
- `VanillaItems::AIR()`
- The following API methods have been deprecated:
- `ItemFactory::air()` - use `VanillaItems::AIR()` instead
### Player
- The following public API methods have been added:
- `Player->hasBlockCollision() : bool`
- `Player->setHasBlockCollision(bool $value)` - allows controlling spectator-like no-clip behaviour without changing game mode
- `Player->toggleSwim(bool $swim) : bool` - called by the network system when the client tries to start/stop swimming
- `Player->toggleGlide(bool $glide) : bool` - called by the network system when the client tries to start/stop gliding
### Server
- The following public API constants have been added:
- `Server::DEFAULT_SERVER_NAME`
- `Server::DEFAULT_MAX_PLAYERS`
- `Server::DEFAULT_PORT_IPV4`
- `Server::DEFAULT_PORT_IPV6`
- `Server::DEFAULT_MAX_VIEW_DISTANCE`
### Utils
- Config parsing errors are now always represented by `ConfigLoadException` and include the path to the file in the message.
- Added `TextFormat::MINECOIN_GOLD`, and support for it to the various `TextFormat` methods.
- The following public API methods have been added:
- `Utils::assumeNotFalse()` - static analysis crutch to silence PHPStan errors without using `ignoreErrors` or `@phpstan-ignore-line`, which are both too coarse.
- The following public API properties have been added:
- `Terminal::$COLOR_MINECOIN_GOLD`
- The following classes have been added:
- `ConfigLoadException`
- Fixed `Random->nextSignedInt()` to actually return a signed int. Previously it would return any integer value between 0 and 4,294,957,295.
- Fixed `Random->nextSignedFloat()` to return a float between `-1.0` and `1.0`. Previously it would return any value between `0.0` and `2.0`.
- `VersionString->getNumber()` output is now structured differently to fix overflow issues caused by the old format.
### World
- The following classes have been added:
- `sound\ItemUseOnBlockSound`
- `sound\LecternPlaceBookSound`
## Gameplay
### Blocks
- Fire now spreads.
- Implemented lectern blocks.
- Added missing sounds for hoeing grass and dirt.
- Added missing sounds for using a shovel on grass to create grass path.
- Pumpkins can now be carved using shears.
### Items
- Dropped items of the same type now merge with each other.
### Misc
- Implemented player swimming.
# 4.1.0-BETA2
Released 27th January 2022.
## API
### Block
- The following API methods have been added:
- `utils\BrewingStandSlot->getSlotNumber() : int`
- `utils\FurnaceType->getCookSound() : Sound`
- The following API constants have been added:
- `tile\BrewingStand::BREW_TIME_TICKS`
### Crafting
- The following API methods have been added:
- `CraftingManager->getPotionContainerChangeRecipes() : array<int, array<string, PotionContainerChangeRecipe>>`
- `CraftingManager->getPotionTypeRecipes() : array<string, array<string, PotionTypeRecipe>>`
- `CraftingManager->registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void`
- `CraftingManager->registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void`
- The following classes have been added:
- `BrewingRecipe`
- `PotionContainerChangeRecipe`
- `PotionTypeRecipe`
### Event
- The following classes have been added:
- `BrewItemEvent` - called when a brewing stand finishes brewing potions; this is called up to 3 times (once for each brewing slot, as needed)
- `BrewingFuelUseEvent` - called when a brewing stand consumes blaze powder
- `PlayerViewDistanceChangeEvent` - called whenever a player alters their render distance or requests one for the first time when connecting
### World
#### Sound
- The following classes have been added:
- `BlastFurnaceSound` - the sound made by a blast furnace during smelting
- `FurnaceSound` - the sound made by a regular furnace during cooking or smelting
- `PotionFinishBrewingSound` - the sound made by a brewing stand when a potion finishes being brewed
- `SmokerSound` - the sound made by a smoker during cooking
## Gameplay
### Blocks
- Brewing stands can now be used for brewing potions.
- The visual appearance of a brewing stand now updates correctly when the contents of its inventory changes (adding/removing potions).
- Added missing sounds for furnace, blast furnace and smoker.
- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe.
- Cobwebs now drop themselves when mined using shears.
- The correct amount of fall damage is now taken when falling from a height onto hay bales.
- Fixed block updating bug introduced by beta1 which caused crops and other plants to never grow.
### Misc
- Added a workaround for client hitbox size bug after swimming which caused the player to be able to fit into one-block-tall gaps.

View File

@ -1,142 +0,0 @@
**For Minecraft: Bedrock Edition 1.18.0**
### 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.1.0
Released 7th February 2022.
## General
- Game mode names (e.g. `survival`, `creative`) may now be used for the `gamemode` property in `server.properties`.
- Increased default maximum render distance to 16 chunks. Players with a render distance smaller than this will notice no difference.
- The setup wizard now prompts for a maximum render distance value.
- The setup wizard now prompts for an IPv6 port selection. Previously it would always use 19133.
- `chunk-ticking.disable-block-ticking` now accepts block names like those used in the `/give` command.
- The `/clear` command now behaves more like vanilla:
- The order of inventories is now the same as Bedrock.
- The cursor and offhand inventories are now cleared if necessary.
## Technical
- `PlayerAuthInputPacket` is now used instead of `MovePlayerPacket` for processing movements. This improves position and rotation accuracy.
- `&&` and `||` are now always used instead of `and` and `or`.
- New version of `pocketmine/errorhandler` is used by this version, adding support for `ErrorToExceptionHandler::trap()`. This enables reliably capturing `E_WARNING` and `E_NOTICE` from functions such as `yaml_parse()` and friends.
- New dependency versions are required by this version:
- `pocketmine/bedrock-protocol` has been updated from 7.1.0 to [7.3.0](https://github.com/pmmp/BedrockProtocol/releases/tag/7.3.0%2Bbedrock-1.18.0).
- `pocketmine/errorhandler` has been updated from 0.3.0 to [0.6.0](https://github.com/pmmp/ErrorHandler/releases/tag/0.6.0).
## API
### Block
- The following classes have been added:
- `Lectern`
- `Pumpkin`
- The following public API methods have been added:
- `Block->getTypeId() : int` - returns an integer which uniquely identifies the block type, ignoring things like facing, colour etc.
- `VanillaBlocks::LECTERN()`
- `utils\BrewingStandSlot->getSlotNumber() : int`
- `utils\FurnaceType->getCookSound() : Sound`
- The following API constants have been added:
- `tile\BrewingStand::BREW_TIME_TICKS`
### Crafting
- The following API methods have been added:
- `CraftingManager->getPotionContainerChangeRecipes() : array<int, array<string, PotionContainerChangeRecipe>>`
- `CraftingManager->getPotionTypeRecipes() : array<string, array<string, PotionTypeRecipe>>`
- `CraftingManager->registerPotionContainerChangeRecipe(PotionContainerChangeRecipe $recipe) : void`
- `CraftingManager->registerPotionTypeRecipe(PotionTypeRecipe $recipe) : void`
- The following classes have been added:
- `BrewingRecipe`
- `PotionContainerChangeRecipe`
- `PotionTypeRecipe`
### Entity
- The following classes have been added:
- `animation\ItemEntityStackSizeChangeAnimation`
- The following public API methods have been added:
- `object\ItemEntity->isMergeable(object\ItemEntity $other) : bool`
- `object\ItemEntity->setStackSize(int $size) : void`
- `object\ItemEntity->tryMergeInto(object\ItemEntity $other) : bool`
- `ExperienceManager->canAttractXpOrbs() : bool`
- `ExperienceManager->setCanAttractXpOrbs(bool $v = true) : void`
- `Entity->getSize() : EntitySizeInfo`
- `Living->isGliding() : bool`
- `Living->isSwimming() : bool`
- `Living->setGliding(bool $value = true) : void`
- `Living->setSwimming(bool $value = true) : void`
- The following protected API methods have been added:
- `Entity->getBlocksIntersected(float $inset) : \Generator<int, Block, void, void>`
### Event
- `BlockSpreadEvent` is now called when fire spreads to the positions of blocks it burns away.
- `BlockFormEvent` is now called when concrete powder turns into concrete due to contact with water.
- The following classes have been added:
- `BlockMeltEvent` - called when ice or snow melts
- `BrewItemEvent` - called when a brewing stand finishes brewing potions; this is called up to 3 times (once for each brewing slot, as needed)
- `BrewingFuelUseEvent` - called when a brewing stand consumes blaze powder
- `ChestPairEvent` - called when two chests try to form a pair
- `PlayerToggleGlideEvent` - called when a player starts or stops gliding
- `PlayerToggleSwimEvent` - called when a player starts or stops swimming
- `PlayerViewDistanceChangeEvent` - called whenever a player alters their render distance or requests one for the first time when connecting
### Item
- The following public API methods have been added:
- `SplashPotion->getType() : PotionType`
- `VanillaItems::AIR()`
- The following API methods have been deprecated:
- `ItemFactory::air()` - use `VanillaItems::AIR()` instead
### Player
- The following public API methods have been added:
- `Player->hasBlockCollision() : bool`
- `Player->setHasBlockCollision(bool $value)` - allows controlling spectator-like no-clip behaviour without changing game mode
- `Player->toggleSwim(bool $swim) : bool` - called by the network system when the client tries to start/stop swimming
- `Player->toggleGlide(bool $glide) : bool` - called by the network system when the client tries to start/stop gliding
### Server
- The following public API constants have been added:
- `Server::DEFAULT_SERVER_NAME`
- `Server::DEFAULT_MAX_PLAYERS`
- `Server::DEFAULT_PORT_IPV4`
- `Server::DEFAULT_PORT_IPV6`
- `Server::DEFAULT_MAX_VIEW_DISTANCE`
### Utils
- Config parsing errors are now always represented by `ConfigLoadException` and include the path to the file in the message.
- Added `TextFormat::MINECOIN_GOLD`, and support for it to the various `TextFormat` methods.
- The following public API methods have been added:
- `Utils::assumeNotFalse()` - static analysis crutch to silence PHPStan errors without using `ignoreErrors` or `@phpstan-ignore-line`, which are both too coarse.
- The following public API properties have been added:
- `Terminal::$COLOR_MINECOIN_GOLD`
- The following classes have been added:
- `ConfigLoadException`
- Fixed `Random->nextSignedInt()` to actually return a signed int. Previously it would return any integer value between 0 and 4,294,957,295.
- Fixed `Random->nextSignedFloat()` to return a float between `-1.0` and `1.0`. Previously it would return any value between `0.0` and `2.0`.
- `VersionString->getNumber()` output is now structured differently to fix overflow issues caused by the old format.
### World
- The following classes have been added:
- `sound\BlastFurnaceSound` - the sound made by a blast furnace during smelting
- `sound\FurnaceSound` - the sound made by a regular furnace during cooking or smelting
- `sound\ItemUseOnBlockSound`
- `sound\LecternPlaceBookSound`
- `sound\PotionFinishBrewingSound` - the sound made by a brewing stand when a potion finishes being brewed
- `sound\SmokerSound` - the sound made by a smoker during cooking
## Gameplay
### Blocks
- Fire now spreads.
- Implemented lectern blocks.
- Added missing sounds for hoeing grass and dirt.
- Added missing sounds for using a shovel on grass to create grass path.
- Pumpkins can now be carved using shears.
- Brewing stands can now be used for brewing potions.
- The visual appearance of a brewing stand now updates correctly when the contents of its inventory changes (adding/removing potions).
- Added missing sounds for furnace, blast furnace and smoker.
- Fixed ender chest not dropping itself when mined with a Silk Touch pickaxe.
- Cobwebs now drop themselves when mined using shears.
- The correct amount of fall damage is now taken when falling from a height onto hay bales.
### Items
- Dropped items of the same type now merge with each other.

View File

@ -1,53 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.40**
### 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.10.0
Released 26th October 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.40.
- Removed support for older versions.
## Fixes
- Fixed incorrect command descriptions showing in `/help` when multiple commands use the same name. Previously, the most recently registered command would show, even though it wouldn't actually be invoked.
- Fixed splash potions affecting players in spectator mode.
- Fixed `World->addParticle()` sending particles to players who couldn't possibly see them when a list of targets was used.
- Fixed `World->addSound()` sending sounds to players who couldn't possibly hear them when a list of targets was used.
## Documentation
- Improved type information available for various API methods in `World`.
# 4.10.1
Released 7th November 2022.
## Fixes
- Fixed spawning in the void if spawn terrain in a world is solid at the default spawn position.
- Fixed totems of undying activating when the player has 1 HP remaining.
- Fixed durable items such as tools becoming unbreakable when in stacks larger than 1. Now, the durability correctly resets when the tool breaks.
- TPS below 12 now correctly shows as red in `/status`. Previously, it showed as orange due to a condition ordering bug.
- Improved handling of missing arguments in user-defined `pocketmine.yml` command aliases. Previously, missing arguments would be filled with an empty string, which caused a variety of unexpected behaviour.
## Internals
- Added validation for the array given to `BaseInventory->setContents()` to ensure that it contains only `Item` instances.
- Silenced `PlayerAuthInputPacket` spam when the session is in the "spawn response" state.
- Updated to PHPStan 1.9.
# 4.10.2
Released 25th November 2022.
## Fixes
- Fixed crashes on macOS and Linux when using console colours without the `TERM` environment variable set.
- Fixed crashdumps not being generated when error messages contained invalid UTF-8 characters.
## Documentation
- Clarified documentation of caching behaviour for `Internet::getIP()`.
- Added and improved documentation for many `Inventory` methods.
- Rewritten documentation for `PlayerCreationEvent` with warnings and more detail.
## Internals
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.

View File

@ -1,92 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.40**
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.11.0-BETA1
Released 7th November 2022.
## General
- Packet receive timings have now been split into two subcategories - Decode and Handle.
- Console command entry can now be disabled via the `console.enable-input` setting in `pocketmine.yml`.
- Best suited for headless servers (e.g. in a Docker container) where the console will never be used anyway.
- Disabling the console reader slightly reduces memory usage, because console reading currently requires an additional subprocess.
- Console command output now appears on the terminal only, and is not written to the log file.
- The output from console commands now appears with a `Command output |` prefix, instead of as a log message.
- Introduced validation for the `--data` and `--plugins` command line options.
- Encrypted resource packs are now supported, by means of adding a `.key` file alongside the pack in the `resource_packs` folder.
- e.g. `MyEncryptedPack.zip` -> `MyEncryptedPack.zip.key`
## Gameplay
- Fixed supporting blocks of dead bush to be in line with vanilla.
- Sugarcane can now be grown using bonemeal on any part of the sugarcane. Previously, it only worked when used on the bottom block.
- Fixed modifier values for Instant Damage and Regeneration effects.
## API
### General
- Plugins are now always disabled before their dependencies, to ensure that they are able to shutdown properly (e.g. a core plugin depending on a database plugin may want to save data to a DB during `onDisable()`).
- [`webmozart/path-util`](https://packagist.org/packages/webmozart/path-util) has been deprecated, and will be dropped in favour of [`symfony/filesystem`](https://packagist.org/packages/symfony/filesystem) in PM5.
- To prepare for this change, simply replace any usage of `Webmozart\PathUtil\Path` with `Symfony\Component\Filesystem\Path`, which is available as a dependency in this release.
### `pocketmine`
- The following API methods are now deprecated:
- `Server->getPlayerByPrefix()`
### `pocketmine\entity`
- `EntitySpawnEvent` and `ItemSpawnEvent` are now fired on the first tick after the entity is added to the world. Previously, these events were called directly from the entity constructor, making it impossible to get properties like velocity which are often set after the entity is created.
- The following API methods are now deprecated:
- `Living->hasLineOfSight()`
### `pocketmine\item`
- The following new API methods have been added:
- `public Armor->clearCustomColor() : $this`
### `pocketmine\inventory\transaction`
- Introduced a `TransactionBuilder` class. This makes it less of a hassle to build an `InventoryTransaction` server-side, since the regular `Inventory` API methods can be used, rather than having to manually create `SlotChangeAction`s.
### `pocketmine\player`
- The following new API methods have been added:
- `public Player->sendToastNotification(string $title, string $body) : void` - makes a grey box appear at the top of the player's screen containing the specified message
### `pocketmine\utils`
- The following new API methods have been added:
- `public static TextFormat::addBase(string $baseFormat, string $string) : string` - used for coloured log messages, changes the base formatting of a string by inserting the given formatting codes after every RESET code
## Internals
- Improved performance of `ContainerTrait` dropping items on block destroy. (24e72ec109c1442b09558df89b6833cf2f2e0ec7)
- Avoid repeated calls to `Position->getWorld()` (use local variables). (2940547026db40ce76deb46e992870de3ead79ad)
- Revamped the way `InventoryManager` handles fake inventory slot mappings for stuff like crafting tables. (e90abecf38d9c57635fa0497514bba7e546a2469)
- Console polling is now done on the main thread (no longer a performance concern).
- Console reader subprocess should now automatically die if the server main process is killed, instead of persisting as a zombie.
- `ConsoleCommandSender` is no longer responsible for relaying broadcast messages to `MainLogger`. A new `BroadcastLoggerForwarder` has been added, which is subscribed to the appropriate server broadcast channels in order to relay messages. This ensures that chat messages and command audit messages are logged.
- `DelegateInventory` now uses `WeakReference` to track its inventory listener. This allows the delegate to be reused.
# 4.11.0-BETA2
Released 13th November 2022.
## Configuration
- The `chunk-ticking.per-tick` setting is now deprecated, and will be removed in a future release.
- The functionality of this setting has been removed, since it caused more problems than it solved.
- Setting it to zero will still disable chunk ticking (for now), but this should now be done by setting `chunk-ticking.tick-radius` to `0` instead.
## Gameplay
- Improved chunk random ticking:
- Removed the limit on chunks ticked per tick, and its associated config option is no longer respected.
- This change significantly improves crop and plant growth with large numbers of players, but may cause higher CPU usage.
- This limit was causing a linear decrease in chunk ticking speed with larger numbers of players, leading to worsened gameplay experience.
- Every chunk within the configured tick radius of a player will be ticked. Previously, chunks were randomly selected from the radius.
- Implemented Darkness effect.
## API
### `pocketmine\world`
- The following new API methods have been added:
- `public World->getChunkTickRadius() : int` - returns the world's simulation radius
- `public World->setChunkTickRadius(int $radius) : void` - sets the world's simulation radius
## Internals
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.

View File

@ -1,106 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.40**
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.11.0
Released 25th November 2022.
## General
- Packet receive timings have now been split into two subcategories - Decode and Handle.
- Console command entry can now be disabled via the `console.enable-input` setting in `pocketmine.yml`.
- Best suited for headless servers (e.g. in a Docker container) where the console will never be used anyway.
- Disabling the console reader slightly reduces memory usage, because console reading currently requires an additional subprocess.
- Console command output now appears on the terminal only, and is not written to the log file.
- The output from console commands now appears with a `Command output |` prefix, instead of as a log message.
- User-defined `pocketmine.yml` custom commands now use a generic description which makes clear the command is config-defined.
- Introduced validation for the `--data` and `--plugins` command line options.
- Encrypted resource packs are now supported, by means of adding a `.key` file alongside the pack in the `resource_packs` folder.
- e.g. `MyEncryptedPack.zip` -> `MyEncryptedPack.zip.key`
- The file must contain the raw key bytes, and must not end with a newline.
## Configuration
- The `chunk-ticking.per-tick` setting is now deprecated, and will be removed in a future release.
- The functionality of this setting has been removed, since it caused more problems than it solved.
- Setting it to zero will still disable chunk ticking (for now), but this should now be done by setting `chunk-ticking.tick-radius` to `0` instead.
## Gameplay
- Fixed supporting blocks of dead bush to be in line with vanilla.
- Sugarcane can now be grown using bonemeal on any part of the sugarcane. Previously, it only worked when used on the bottom block.
- Fixed missing sounds when adding, rotating, or removing items in item frames.
- Fixed modifier values for Instant Damage and Regeneration effects.
- Implemented Darkness effect.
- Improved chunk random ticking:
- Removed the limit on chunks ticked per tick, and its associated config option is no longer respected.
- This change significantly improves crop and plant growth with large numbers of players.
- This limit was causing a linear decrease in chunk ticking speed with larger numbers of players, leading to worsened gameplay experience.
- **Warning: This change will result in increased CPU usage if players are spread over a very large area.**
- Every chunk within the configured tick radius of a player will be ticked. Previously, chunks were randomly selected from the radius.
## API
### General
- Plugins are now always disabled before their dependencies, to ensure that they are able to shutdown properly (e.g. a core plugin depending on a database plugin may want to save data to a DB during `onDisable()`).
- [`webmozart/path-util`](https://packagist.org/packages/webmozart/path-util) has been deprecated, and will be dropped in favour of [`symfony/filesystem`](https://packagist.org/packages/symfony/filesystem) in PM5.
- To prepare for this change, simply replace any usage of `Webmozart\PathUtil\Path` with `Symfony\Component\Filesystem\Path`, which is available as a dependency in this release.
### `pocketmine`
- The following API methods are now deprecated:
- `Server->getPlayerByPrefix()`
### `pocketmine\entity`
- `EntitySpawnEvent` and `ItemSpawnEvent` are now fired on the first tick after the entity is added to the world. Previously, these events were called directly from the entity constructor, making it impossible to get properties like velocity which are often set after the entity is created.
- The following API methods are now deprecated:
- `Living->hasLineOfSight()`
### `pocketmine\event\block`
- The following new classes have been added:
- `BlockDeathEvent` - event called when coral or coral blocks die due to lack of water
### `pocketmine\item`
- The following new API methods have been added:
- `public Armor->clearCustomColor() : $this`
### `pocketmine\inventory\transaction`
- Introduced a `TransactionBuilder` class. This makes it less of a hassle to build an `InventoryTransaction` server-side, since the regular `Inventory` API methods can be used, rather than having to manually create `SlotChangeAction`s.
### `pocketmine\lang`
- The following new API methods have been added:
- `public Language->getAll() : array<string, string>`
### `pocketmine\player`
- The following new API methods have been added:
- `public Player->sendToastNotification(string $title, string $body) : void` - makes a grey box appear at the top of the player's screen containing the specified message
### `pocketmine\utils`
- The following new API methods have been added:
- `public static TextFormat::addBase(string $baseFormat, string $string) : string` - used for coloured log messages, changes the base formatting of a string by inserting the given formatting codes after every RESET code
### `pocketmine\world`
- The following new API methods have been added:
- `public World->getChunkTickRadius() : int` - returns the world's simulation radius
- `public World->setChunkTickRadius(int $radius) : void` - sets the world's simulation radius
### `pocketmine\world\sound`
- The following new classes have been added:
- `ItemFrameAddItemSound`
- `ItemFrameRemoveItemSound`
- `ItemFrameRotateItemSound`
## Internals
- Improved performance of `ContainerTrait` dropping items on block destroy. ([link](https://github.com/pmmp/PocketMine-MP/commits/24e72ec109c1442b09558df89b6833cf2f2e0ec7))
- Avoid repeated calls to `Position->getWorld()` (use local variables). ([link](https://github.com/pmmp/PocketMine-MP/commit/2940547026db40ce76deb46e992870de3ead79ad))
- Revamped the way `InventoryManager` handles fake inventory slot mappings for stuff like crafting tables. ([link](https://github.com/pmmp/PocketMine-MP/commit/e90abecf38d9c57635fa0497514bba7e546a2469))
- Inventories are now mapped on a per-slot basis. This means that more than one inventory can be mapped to the same window ID, which is necessary for correctly handling "UI" inventories like crafting tables.
- `InventoryManager->getWindow(int $windowId) : ?Inventory` is replaced by `locateWindowAndSlot` (see below).
- Added `InventoryManager->locateWindowAndSlot(int $windowId, int $netSlotId) : array{Inventory, int}` - accepts a window ID and absolute slot ID, and returns the associated inventory and the slot relative to the inventory's own start (for use with `getItem()` etc.).
- Slot offset mapping for "UI" inventories is now handled in `InventoryManager->createComplexSlotMapping()` instead of in `TypeConverter`.
- Console polling is now done on the main thread (no longer a performance concern). ([link](https://github.com/pmmp/PocketMine-MP/commit/b3f03d7ae645de67a54b7300c09b94eeca16298e))
- Console reader subprocess should now automatically die if the server main process is killed, instead of persisting as a zombie. ([link](https://github.com/pmmp/PocketMine-MP/commit/2585160ca2c4df5758b8b980331307402ff9f0fb))
- `ConsoleCommandSender` is no longer responsible for relaying broadcast messages to `MainLogger`. A new `BroadcastLoggerForwarder` has been added, which is subscribed to the appropriate server broadcast channels in order to relay messages. This ensures that chat messages and command audit messages are logged. ([link](https://github.com/pmmp/PocketMine-MP/commit/83e5b0adb6fa0dddec377182bb1c7945ac8f7820))
- `DelegateInventory` now uses `WeakReference` to track its inventory listener. This allows the delegate to be reused. ([link](https://github.com/pmmp/PocketMine-MP/commit/3feaa18f6c10c3a99c0deca75f57ec2d74b92ab4))
- Non-arrow projectile damage is now unscaled. Scaling according to velocity is only applied to arrows. This currently doesn't cause any observable change in behaviour, but is required for future additions.

View File

@ -1,119 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.50**
### 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.12.0
Released 30th November 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.50.
- Removed support for older versions.
# 4.12.1
Released 4th December 2022.
## Fixes
- Fixed items glitching when dragging a stack of items across the crafting grid (desync issues).
# 4.12.2
Released 15th December 2022.
## Fixes
- Folder used for plugins (optionally specified by `--plugins`) is no longer required to be writable.
- Fixed broken writable check for server data folder (`is_writable()` broken on NFS and similar filesystems).
- `Filesystem::createLockFile()` exceptions now include more information about why the lock file could not be created.
- Fixed client-side item predictions not being rolled back when cancelling events such as `PlayerItemUseEvent`.
## Dependencies
- Updated BedrockProtocol to [17.1.0](https://github.com/pmmp/BedrockProtocol/releases/tag/17.1.0+bedrock-1.19.50). This adds some missing `LevelSoundEvent` constants and fixes the values for `ContainerUIIds`.
# 4.12.3
Released 28th December 2022.
## Fixes
- Fixed unauthenticated connections taking up player count slots, preventing players from joining.
- Fixed a possible crash in `World->tickChunk()` when plugins unload chunks during some events.
- `/gamemode` will now report a failure to change game mode if the player is already in the requested game mode.
# 4.12.4
Released 3rd January 2023.
## Fixes
- Added workarounds for an active exploit being used to deny service to servers.
# 4.12.5
Released 6th January 2023.
## Fixes
- Removed a workaround for an old client bug in custom form responses. The code contained a denial-of-service vulnerability.
# 4.12.6
Released 7th January 2023.
## Changes
- Added a new security measure to `NetworkSession` to detect and ban players who flood the server with packets.
# 4.12.7
Released 8th January 2023.
## Fixes
- Fixed players getting kicked when the server lags for too long.
- Fixed players getting kicked when a debugging session is active and a breakpoint is hit.
# 4.12.8
Released 9th January 2023.
## Fixes
- Fixed players getting kicked during PvP.
- Fixed players randomly getting kicked on Windows (improper rate limit handling wrt. 15ms timer resolution).
# 4.12.9
Released 16th January 2023.
## Improvements
### Timings
- Added new timers:
- `Server Mid-Tick Processing` - time spent processing Snooze interrupts between ticks (e.g. incoming network packets)
- `Server Tick Update Cycle` - time spent processing regular per-tick updates (e.g. entity movement, world updates, etc.) (`Server->tick()`)
- `Full Server Tick` timer now counts the total of `Server Mid-Tick Processing` and `Server Tick Update Cycle`, which generates more accurate performance metrics.
- Previously, this timer only counted the time spent during regular per-tick updates, and the time recorded by `Server Mid-Tick Processing` was not included in the report at all.
## Fixes
- Fixed blocks such as pressure plates being able to be placed without the correct supporting blocks if the clicked block was solid.
- Pressure plates now self-destruct when the block below them is removed.
- Fixed being unable to place blocks by clicking on the side of a bell (when the click doesn't result in ringing the bell).
- Fixed various rotation-aware blocks (e.g. stairs) behaving incorrectly when placed by clicking on the side of a replaceable block (e.g. tall grass).
- Fixed banners being able to be placed on top of blocks such as skulls.
- Fixed server-side collision boxes of walls and glass (which should connect, but didn't). Note that wall connections still don't show client side - this just fixes the collision boxes.
- Fixed `PlayerInteractEvent` with `LEFT_CLICK` sometimes firing before `BlockBreakEvent` when breaking blocks.
## Other changes
- Increased packet batch budget for player sessions.
# 4.12.10
Released 18th January 2023.
## Fixes
- Fixed reported server load not including the time spent processing Snooze interrupts between ticks (e.g. incoming network packets).
- Fixed `Connection Handler` entry in timings report not including time spent receiving packets.
## Note about server load & performance
This version will report higher apparent server load than previous versions. The actual performance of the server is unchanged; the previous reported load was inaccurate.
These bugs have been present for nearly 5 years (ever since the first introduction of Snooze in 3.0.0).
# 4.12.11
Released 22nd January 2023.
## General
- Code is now tested and analysed using PHP 8.2 in addition to 8.1 and 8.0.
## Fixes
- Fixed pthreads 5.0.0 incorrectly being treated as compatible.
- Fixed deprecation errors on PHP 8.2.
## Documentation
- Updated documentation in `PlayerPreLoginEvent`.

View File

@ -1,94 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.50**
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.13.0-BETA1
Released 18th January 2023.
## Gameplay
- Death message is now shown on the death screen when a player dies.
- Armour damage is now only increased if the armour reduced the damage taken.
- Implemented Swift Sneak enchantment.
- Fixed incorrect collision box calculation of walls and glass/bars when connected. Note: Client-side, wall connections are still broken; this only fixes projectile flight server-side.
## Performance
- Improved performance of chunk selection for chunk random ticking using a cache. This improves performance of chunk random ticking by 10-20%.
## Localization
- Added localized description for the `/dumpmemory` command.
## Permissions
- Added the following new core permissions:
- `pocketmine.command.effect.other` - allows the player to use the `/effect` command on other players (default operator only)
- `pocketmine.command.effect.self` - allows the player to use the `/effect` command on themselves (default operator only)
- `pocketmine.command.enchant.other` - allows the player to use the `/enchant` command on other players (default operator only)
- `pocketmine.command.enchant.self` - allows the player to use the `/enchant` command on themselves (default operator only)
- `pocketmine.command.gamemode.other` - allows the player to use the `/gamemode` command on other players (default operator only)
- `pocketmine.command.gamemode.self` - allows the player to use the `/gamemode` command on themselves (default operator only)
- `pocketmine.command.give.other` - allows the player to use the `/give` command on other players (default operator only)
- `pocketmine.command.give.self` - allows the player to use the `/give` command on themselves (default operator only)
- `pocketmine.command.spawnpoint.other` - allows the player to use the `/spawnpoint` command on other players (default operator only)
- `pocketmine.command.spawnpoint.self` - allows the player to use the `/spawnpoint` command on themselves (default operator only)
- `pocketmine.command.teleport.other` - allows the player to use the `/teleport` command on other players (default operator only)
- `pocketmine.command.teleport.self` - allows the player to use the `/teleport` command on themselves (default operator only)
- `pocketmine.command.title.other` - allows the player to use the `/title` command on other players (default operator only)
- `pocketmine.command.title.self` - allows the player to use the `/title` command on themselves (default operator only)
## Internals
- Decoupled `Player->sendMessage()` and `Player->sendTranslation()`.
- Refactored resource pack loading in `ResourcePackManager` to make it easier to understand.
- Client-aware translation processing has been moved to `NetworkSession` due to being client-specific.
- Replaced hardcoded strings with constants in various places.
- `NetworkSession` destructive cleanup is now deferred to the next session tick. This fixes various `InventoryManager` crashes when kicking players during events.
- Updated code using `strpos()` to use `str_starts_with()`, `str_ends_with()` and `str_contains()` where appropriate.
- Added documentation for some internal methods.
## API
### `pocketmine\command`
- The following new API methods have been added:
- `protected VanillaCommand->fetchPermittedPlayerTarget(...) : ?Player` - fetches a player target according to the given sender permissions, or null if not found or not permitted
### `pocketmine\entity`
- The following new API methods have been added:
- `public Living->getDisplayName() : string` - the name of the entity to be shown in death messages, commands etc.
### `pocketmine\event\world`
- The following new classes have been added:
- `WorldSoundEvent` - called when a sound is played in a world
- `WorldParticleEvent` - called when a particle is spawned in a world
### `pocketmine\item`
- The following new API methods have been added:
- `public Item->onInteractEntity(Player $player, Entity $entity, Vector3 $clickVector) : bool` - called when a player interacts with an entity with this item in hand
### `pocketmine\lang`
- `Language->translate()` and `Language->translateString()` no longer parse nested translation in the "base text". This was never intended behaviour, and didn't work beyond the first level anyway.
### `pocketmine\player`
- The following new interfaces have been added:
- `PlayerDataProvider` - implemented by classes which want to offer storage for player data
- The following new classes have been added:
- `DatFilePlayerDataProvider` - the default player data provider, which stores `.dat` files in the `players` folder
- `PlayerDataLoadException` - thrown when an error occurs while loading player data
- `PlayerDataSaveException` - thrown when an error occurs while saving player data
- The following API methods have been deprecated:
- `Player->sendTranslation()` - use `Player->sendMessage()` instead with a `Translatable` message
### `pocketmine\resourcepacks`
- The following new API methods have been added:
- `public ResourcePackManager->setResourceStack(list<ResourcePack> $resourceStack) : void` - sets the list of resource packs to be applied by players
- `public ResourcePackManager->setPackEncryptionKey(string $id, ?string $key) : void` - sets the encryption key to be used for a resource pack
### `pocketmine\utils`
- The following new API methods have been added:
- `public static Filesystem::fileGetContents(...) : string` - a wrapper around `file_get_contents()` which throws an exception on failure
### `pocketmine\world`
- The following new API methods have been added:
- `public World->requestSafeSpawn(?Vector3 $spawn = null) : Promise<Position>` - an async version of `getSafeSpawn()` which generates all the needed chunks before returning

View File

@ -1,94 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.50**
This is a minor feature release for PocketMine-MP, introducing some new features and improvements.
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.13.0
Released 30th January 2023.
## Gameplay
- Death message is now shown on the death screen when a player dies.
- Armour damage is now only increased if the armour reduced the damage taken.
- Implemented Swift Sneak enchantment.
- Fixed incorrect collision box calculation of walls and glass/bars when connected. Note: Client-side, wall connections are still broken; this only fixes projectile flight server-side.
## Performance
- Improved performance of chunk selection for chunk random ticking using a cache. This improves performance of chunk random ticking by 10-20%.
## Localization
- Added localized description for the `/dumpmemory` command.
## Permissions
- Added the following new core permissions:
- `pocketmine.command.effect.other` - allows the player to use the `/effect` command on other players (default operator only)
- `pocketmine.command.effect.self` - allows the player to use the `/effect` command on themselves (default operator only)
- `pocketmine.command.enchant.other` - allows the player to use the `/enchant` command on other players (default operator only)
- `pocketmine.command.enchant.self` - allows the player to use the `/enchant` command on themselves (default operator only)
- `pocketmine.command.gamemode.other` - allows the player to use the `/gamemode` command on other players (default operator only)
- `pocketmine.command.gamemode.self` - allows the player to use the `/gamemode` command on themselves (default operator only)
- `pocketmine.command.give.other` - allows the player to use the `/give` command on other players (default operator only)
- `pocketmine.command.give.self` - allows the player to use the `/give` command on themselves (default operator only)
- `pocketmine.command.spawnpoint.other` - allows the player to use the `/spawnpoint` command on other players (default operator only)
- `pocketmine.command.spawnpoint.self` - allows the player to use the `/spawnpoint` command on themselves (default operator only)
- `pocketmine.command.teleport.other` - allows the player to use the `/teleport` command on other players (default operator only)
- `pocketmine.command.teleport.self` - allows the player to use the `/teleport` command on themselves (default operator only)
- `pocketmine.command.title.other` - allows the player to use the `/title` command on other players (default operator only)
- `pocketmine.command.title.self` - allows the player to use the `/title` command on themselves (default operator only)
## Internals
- Decoupled `Player->sendMessage()` and `Player->sendTranslation()`.
- Refactored resource pack loading in `ResourcePackManager` to make it easier to understand.
- Client-aware translation processing has been moved to `NetworkSession` due to being client-specific.
- Replaced hardcoded strings with constants in various places.
- `NetworkSession` destructive cleanup is now deferred to the next session tick. This fixes various `InventoryManager` crashes when kicking players during events.
- Updated code using `strpos()` to use `str_starts_with()`, `str_ends_with()` and `str_contains()` where appropriate.
- Added documentation for some internal methods.
## API
### `pocketmine\command`
- The following new API methods have been added:
- `protected VanillaCommand->fetchPermittedPlayerTarget(...) : ?Player` - fetches a player target according to the given sender permissions, or null if not found or not permitted
### `pocketmine\entity`
- The following new API methods have been added:
- `public Living->getDisplayName() : string` - the name of the entity to be shown in death messages, commands etc.
### `pocketmine\event\world`
- The following new classes have been added:
- `WorldSoundEvent` - called when a sound is played in a world
- `WorldParticleEvent` - called when a particle is spawned in a world
### `pocketmine\item`
- The following new API methods have been added:
- `public Item->onInteractEntity(Player $player, Entity $entity, Vector3 $clickVector) : bool` - called when a player interacts with an entity with this item in hand
### `pocketmine\lang`
- `Language->translate()` and `Language->translateString()` no longer parse nested translation in the "base text". This was never intended behaviour, and didn't work beyond the first level anyway.
### `pocketmine\player`
- The following new interfaces have been added:
- `PlayerDataProvider` - implemented by classes which want to offer storage for player data
- The following new classes have been added:
- `DatFilePlayerDataProvider` - the default player data provider, which stores `.dat` files in the `players` folder
- `PlayerDataLoadException` - thrown when an error occurs while loading player data
- `PlayerDataSaveException` - thrown when an error occurs while saving player data
- The following API methods have been deprecated:
- `Player->sendTranslation()` - use `Player->sendMessage()` instead with a `Translatable` message
### `pocketmine\resourcepacks`
- The following new API methods have been added:
- `public ResourcePackManager->setResourceStack(list<ResourcePack> $resourceStack) : void` - sets the list of resource packs to be applied by players
- `public ResourcePackManager->setPackEncryptionKey(string $id, ?string $key) : void` - sets the encryption key to be used for a resource pack
### `pocketmine\utils`
- The following new API methods have been added:
- `public static Filesystem::fileGetContents(...) : string` - a wrapper around `file_get_contents()` which throws an exception on failure
### `pocketmine\world`
- The following new API methods have been added:
- `public World->requestSafeSpawn(?Vector3 $spawn = null) : Promise<Position>` - an async version of `getSafeSpawn()` which generates all the needed chunks before returning

View File

@ -1,21 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.60**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.14.0
Released 8th February 2023.
## General
- Added support for Minecraft: Bedrock Edition 1.19.60.
- Removed support for older versions.
# 4.14.1
Released 15th February 2023.
## Fixes
- Fixed all players getting kicked with `Receiving packets too fast` if a server tick takes longer than 5 seconds (e.g. because of autosave or GC).
- Fixed players getting kicked when linking with entities.

View File

@ -1,38 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.62**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.15.0
Released 17th February 2023.
## General
- Added support for Minecraft: Bedrock Edition 1.19.62.
- Removed support for older versions.
# 4.15.1
Released 21st February 2023.
## Fixes
- Fixed dropped items not despawning when in non-ticking chunks.
- Fixed dropped items not despawning if an infinite pickup delay is set.
- Fixed infinite despawn delay (never despawn) being ignored for dropped items.
# 4.15.2
Released 24th February 2023.
## General
- Accept Minecraft: Bedrock Edition 1.19.63 (identical protocol to 1.19.62, but different version due to Mojang mixup).
## Fixes
- Fixed `World Population` timer sometimes not being stopped, causing strange results in timings reports.
# 4.15.3
Released 7th March 2023.
## Fixes
- Fixed `/dumpmemory` crash when any object contained an `INF` or `NaN` float value.
- Updated RakLib for security fixes.

View File

@ -1,45 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.62**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.16.0-BETA1
Released 4th March 2023.
## General
- Added granular timings for packet encode, similar to the existing timings for packet decode.
- Timings now covers several areas of the network system which were previously not counted by network timings, but were counted by total timings. This provides a better insight into the performance of the network system.
## Performance
- Improved performance of packet batch handling by avoiding unnecessary object allocations.
- Improved performance of packet broadcasting when the broadcast size is below the batch threshold. Previously, the packets would be encoded once by every recipient, but now they are encoded once and then added to the send buffer of each session in their raw form.
- This change mostly affects servers with larger maps, where players are more widely distributed.
## Build system
- Added a new script `build/generate-bedrockdata-path-consts.php`, which must be run whenever BedrockData is updated. This script generates a class of constants with the file paths of all BedrockData files.
## API
### `pocketmine\entity`
- The following new API methods have been added:
- `public Entity->getGravity() : float` - returns the entity's gravity acceleration in blocks/tick^2
- `public Entity->setGravity(float $gravity) : void` - sets the entity's gravity acceleration in blocks/tick^2
## Internals
- Now uses [`pocketmine/bedrock-data` 2.0.0](https://github.com/pmmp/BedrockData/releases/tag/2.0.0+bedrock-1.19.60).
- This version is now used by both PM4 and PM5, reducing maintenance burden.
- Now uses [`pocketmine/bedrock-protocol` 19.3.0](https://github.com/pmmp/BedrockProtocol/releases/tag/19.3.0+bedrock-1.19.62).
- This version provides new APIs for handling packet batches which enabled improving performance and adding new features, such as detailed packet encode timings.
- Crafting recipes and creative inventory data are now loaded from `recipes/legacy_recipes.json` and `recipes/legacy_creativeitems.json` respectively. Previously, these were loaded from BedrockData directly, but BedrockData 2.0 now uses a format which can't be supported in 4.x without BC breaks.
- Added dependencies on [`pocketmine/bedrock-block-upgrade-schema`](https://github.com/pmmp/BedrockBlockUpgradeSchema) and [`pocketmine/bedrock-item-upgrade-schema`](https://github.com/pmmp/BedrockItemUpgradeSchema). These provide mapping files no longer present in BedrockData 2.0.
- Reduced and/or eliminated most usages of `PacketBatch`, since it only appeared as a throwaway object and was therefore wasting performance.
- `Compressor` now exposes `getCompressionThreshold()` instead of `willCompress()`, which allows determining whether a batch will be compressed without allocating it.
- Added `pocketmine\data\bedrock\BedrockDataFiles`, an auto-generated class of constants with the file paths of all BedrockData files. This makes it easier to locate usages, detect unused files and avoid typos.
# 4.16.0-BETA2
Released 4th March 2023.
## General
- Fixed incorrect release channel for 4.16.0-BETA1.

View File

@ -1,41 +0,0 @@
**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.

View File

@ -1,39 +0,0 @@
**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.
# 4.17.1
Released 22nd March 2023.
## General
- Docker images for PocketMine-MP are now published on [GitHub Container Registry](https://github.com/pmmp/PocketMine-MP/pkgs/container/pocketmine-mp). The Docker Hub images will stop being maintained in the future.
- Updated translations.
## Fixes
- Fixed server crash on empty packets in certain cases.
- Fixed mushroom blocks dropping the wrong items when broken with a silk-touch tool.
- Fixed mushroom blocks giving the wrong items when block-picked.
- Fixed missing ability flag `PRIVILEGED_BUILDER`.
## Internals
- `update-updater-api.yml` workflow now uses `github.repository_owner` to make it easier to test the workflow on forks.
- Added version-specific channels to `update.pmmp.io`, such as `4`, `4.18-beta`, `4.17`, etc.
- Replaced deprecated `::set-output` commands in GitHub Actions workflows.
- `build/make-release.php` no longer automatically pushes changes, to avoid accidents when testing release workflows on forks.
# 4.17.2
Released 29th March 2023.
## Fixes
- Fixed players being unable to join due to the appearance of a new `x5t` field in the JWT header of Xbox Live authentication tokens.

View File

@ -1,91 +0,0 @@
**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.
# 4.18.0-ALPHA2
Released 21st March 2023.
## General
- Included more sections of the network system in Player Network Send timings.
- Changed the names of some timings to make them more user-friendly.
- Removed packet IDs from `receivePacket` and `sendPacket` timings, as they were not very useful.
- Added new specialized timers for the following:
- Item entity base ticking (merging)
- Player movement processing
- Entity movement processing (collision checking section)
- Projectile movement (all)
- Projectile movement processing (ray tracing section)
## API
### `pocketmine\crafting`
- The following new API methods have been added:
- `CraftingManager->getCraftingRecipeIndex() : array<int, CraftingRecipe>` - returns a list of all crafting recipes
- `CraftingManager->getCraftingRecipeFromIndex(int $index) : ?CraftingRecipe` - returns the crafting recipe at the given index, or null if it doesn't exist
### `pocketmine\inventory\transaction`
- The following API methods have changed signatures:
- `CraftingTransaction->__construct()` now accepts additional arguments `?CraftingRecipe $recipe = null, ?int $repetitions = null`
- The following new API methods have been added:
- `TransactionBuilderInventory->getActualInventory() : Inventory` - returns the actual inventory that this inventory is a proxy for
## Internals
### Network
- Introduced support for the `ItemStackRequest` Minecraft: Bedrock network protocol.
- This fixes a large number of inventory- and crafting-related bugs.
- This also improves server security by closing off many code pathways that might have been used for exploits. `TypeConverter->netItemStackToCore()` is no longer used in server code, and remains for tool usage only.
- This system is also significantly more bandwidth-efficient and has lower overhead than the legacy system.
- This now opens the gateway to easily implement lots of gameplay features which have been missing for a long time, such as enchanting, anvils, looms, and more.
- Significant changes have been made to `pocketmine\network\mcpe\InventoryManager` internals. These shouldn't affect plugins, but may affect plugins which use internal network API.
- **No changes have been made to the plugin `InventoryTransaction` API**.
- This system has been implemented as a shim for the existing PocketMine-MP transaction system to preserve plugin compatibility. Plugins using `InventoryTransactionEvent` should continue to work seamlessly.
- The `InventoryTransaction` API will be redesigned in a future major version to make use of the new information provided by the `ItemStackRequest` system.
- `InventoryTransactionPacket` is no longer sent by the client for "regular" inventory actions. However, it is still sent when dropping items, interacting with blocks, and using items.
- Inventory slot and content syncing is now buffered until the end of the tick. This reduces outbound network usage when the client performs multiple transactions in a single tick (e.g. crafting a stack of items).
- Renamed some `InventoryManager` internal properties to make them easier to understand.
- `TypeConverter->createInventoryAction()` has been removed.
- Packet batch limit has been lowered to `100` packets. With the introduction of `ItemStackRequest`, this is more than sufficient for normal gameplay.
### Other
- Use `Vector3::zero()` instead of `new Vector3()` in some places.

View File

@ -1,123 +0,0 @@
**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.
### Highlights
This version significantly improves server performance with many players and/or entities by making changes to the internal network system.
It also introduces support for the newer `ItemStackRequest` protocol, which fixes many bugs and improves server security.
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
Released 25th March 2023.
## General
- Significantly improved server performance in congested areas of the world (lots of players and/or entities in the same area).
- Included more sections of the network system in `Player Network Send` performance timings.
- Changed the names of some performance timings to make them more user-friendly.
- Removed packet IDs from `receivePacket` and `sendPacket` performance timings, as they were not very useful.
- Added new specialized performance timings for the following:
- Item entity base ticking (merging)
- Player movement processing
- Entity movement processing (collision checking section)
- Projectile movement (all)
- Projectile movement processing (ray tracing section)
## API
### `pocketmine\crafting`
- The following new API methods have been added:
- `CraftingManager->getCraftingRecipeIndex() : array<int, CraftingRecipe>` - returns a list of all crafting recipes
- `CraftingManager->getCraftingRecipeFromIndex(int $index) : ?CraftingRecipe` - returns the crafting recipe at the given index, or null if it doesn't exist
### `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
### `pocketmine\inventory\transaction`
- The following API methods have changed signatures:
- `CraftingTransaction->__construct()` now accepts additional arguments `?CraftingRecipe $recipe = null, ?int $repetitions = null`
- The following new API methods have been added:
- `TransactionBuilderInventory->getActualInventory() : Inventory` - returns the actual inventory that this inventory is a proxy for
## Internals
### Network
- 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` (internals backwards compatibility break, not covered by API version guarantee).
- `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.
- Introduced support for the `ItemStackRequest` Minecraft: Bedrock network protocol.
- This fixes a large number of inventory- and crafting-related bugs.
- This also improves server security by closing off many code pathways that might have been used for exploits. `TypeConverter->netItemStackToCore()` is no longer used in server code, and remains for tool usage only.
- This system is also significantly more bandwidth-efficient and has lower overhead than the legacy system.
- This now opens the gateway to easily implement lots of gameplay features which have been missing for a long time, such as enchanting, anvils, looms, and more.
- Significant changes have been made to `pocketmine\network\mcpe\InventoryManager` internals. These shouldn't affect plugins, but may affect plugins which use internal network API.
- **No changes have been made to the plugin `InventoryTransaction` API**.
- This system has been implemented as a shim for the existing PocketMine-MP transaction system to preserve plugin compatibility. Plugins using `InventoryTransactionEvent` should continue to work seamlessly.
- The `InventoryTransaction` API will be redesigned in a future major version to make use of the new information provided by the `ItemStackRequest` system.
- `InventoryTransactionPacket` is no longer sent by the client for "regular" inventory actions. However, it is still sent when dropping items, interacting with blocks, and using items.
- Inventory slot and content syncing is now buffered until the end of the tick. This reduces outbound network usage when the client performs multiple transactions in a single tick (e.g. crafting a stack of items).
- Renamed some `InventoryManager` internal properties to make them easier to understand.
- `TypeConverter->createInventoryAction()` has been removed.
- Packet batch limit has been lowered to `100` packets. With the introduction of `ItemStackRequest`, this is more than sufficient for normal gameplay.
### Other
- Use `Vector3::zero()` instead of `new Vector3()` in some places.
# 4.18.1
Released 27th March 2023.
## General
- `RakLibInterface` now logs the name of the currently active session if a crash occurs when processing a packet. This makes it easier to reproduce bugs, which is important to be able to fix them.
- Added more detailed debugging information to `InventoryManager->syncSelectedHotbarSlot()`.
## Fixes
- Fixed server crash when attempting to drop more of an item from a stack than available in the inventory.
- Fixed packet processing errors when editing writable books.
- Fixed packet processing errors when shift-clicking on the recipe book to craft recipes which draw from a large number of inventory slots.
# 4.18.2
Released 29th March 2023.
## Fixes
- Fixed players being unable to join due to the appearance of a new `x5t` field in the JWT header of Xbox Live authentication tokens.
- Fixed items' durability appearing to reset when moving them around in the inventory.
# 4.18.3
Released 5th April 2023.
## Fixes
- Fixed Average Players not being shown on timings reports when custom player classes are used.
- Fixed incorrect tick violation calculation in timings reports.
- Fixed not being able to add or remove items from the offhand slot.
- Fixed creative inventory item count corruption when taking items (some players would see 64x items in the creative inventory after rejoining or changing gamemode).
- Fixed not being able to drop items directly from the creative inventory on mobile.
- Fixed `DataPacketReceiveEvent` not being called for packets sent by `EntityEventBroadcaster`.
- `CreativeInventory::getItem()` and `CreativeInventory::getAll()` now return cloned itemstacks, to prevent accidental modification of the creative inventory.
# 4.18.4
Released 10th April 2023.
## Fixes
- Fixed movement becoming broken when the player moves at high speed (e.g. due to high levels of the Speed effect).
- Updated dependencies to get fixes in `pocketmine/nbt` and `pocketmine/bedrock-protocol`.
## Internals
### Network
- Game packets are now rate-limited in a similar manner to packet batches. This helps to more effectively mitigate certain types of DoS attacks.
- Added a new class `PacketRateLimiter`, implementing functionality previously baked directly into `NetworkSession` in a more generic way to allow reuse.

View File

@ -1,111 +0,0 @@
**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.
### Highlights
This version introduces support for a new, more advanced version of Timings.
This improved system provides more detail than the old system, and supports being displayed in a tree view, making it much easier to see which timers contribute to which other timers.
In addition, some minor performance improvements have been made, along with a couple of minor API additions.
# 4.19.0
Released 11th April 2023.
## General
- Updated the Timings system.
- Timings records now include parent information, allowing them to be displayed in a tree view (e.g. https://timings.pmmp.io/?id=303556).
- Timings records now include additional information, such as Peak (max time spent on any single tick), and Ticks (number of ticks the timer was active on).
- New timings have been added for every event.
- A new timer `Player Network Send - Pre-Spawn Game Data` has been added, and covers most of the time spent handling `ResourcePackClientResponsePacket`, giving a clearer picture of what's happening.
- Improved performance of the plugin event system.
- By introducing some caching, the event system now has 90% less overhead than in previous versions.
- Improved performance of the random chunk ticking system.
- The selection of ticked random chunks, and their validation for ticking, is now cached. This significantly reduces the overhead of chunk selection.
- Factions servers and other game modes with big maps and sparsely populated areas will see the most benefit from this change.
- Real-world performance benefit of this change is anywhere from 0-20%, depending on server type and configuration.
- The `timings paste` command now logs a debug message with the server response on failure to paste a timings report.
## API
### `pocketmine\entity\object`
- The following API constants have been added:
- `ExperienceOrb::DEFAULT_DESPAWN_DELAY` - the default delay in ticks before an experience orb despawns
- `ExperienceOrb::NEVER_DESPAWN` - magic value for `setDespawnDelay()` to make an experience orb never despawn
- `ExperienceOrb::MAX_DESPAWN_DELAY` - the maximum delay in ticks before an experience orb despawns
- The following API methods have been added:
- `public ExperienceOrb->getDespawnDelay() : int` - returns the delay in ticks before this experience orb despawns
- `public ExperienceOrb->setDespawnDelay(int $despawnDelay) : void` - sets the delay in ticks before this experience orb despawns
- The following properties have been deprecated
- `ExperienceOrb->age` - superseded by despawn delay methods
### `pocketmine\event`
- The following API methods have been added:
- `public HandlerList->getListenerList() : list<RegisteredListener>` - returns an ordered list of handlers to be called for the event
### `pocketmine\player`
- The following API methods have behavioural changes:
- `ChunkSelector->selectChunks()` now yields the distance in chunks from the center as the key, instead of an incrementing integer.
- The following classes have been deprecated:
- `PlayerChunkLoader` (this was technically internal, but never marked as such)
### `pocketmine\timings`
- The following API constants have been deprecated:
- `Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX` - this is superseded by timings group support (see `Timings::GROUP_BREAKDOWN`)
- The following API constants have been added:
- `Timings::GROUP_BREAKDOWN` - this group makes a timer appear in the `Minecraft - Breakdown` section of a timings report
- The following API methods have been added:
- `public TimingsHandler->getGroup() : string` - returns the name of the table in which this timer will appear in a timings report
- The following API methods have changed signatures:
- `TimingsHandler->__construct()` now accepts an additional, optional `string $group` parameter, which defaults to `Minecraft`.
### `pocketmine\world`
#### Highlights
Ticking chunks is now done using the `ChunkTicker` system, which has a much more fine-grained API than the old `TickingChunkLoader` system, as well as better performance.
It works similarly to the `ChunkLoader` system, in that chunks will be ticked as long as at least one `ChunkTicker` is registered for them.
#### API changes
- The following classes have been deprecated:
- `TickingChunkLoader` - this has been superseded by the more powerful and performant `ChunkTicker` APIs
- The following classes have been added:
- `ChunkTicker` - an opaque object used for `registerTickingChunk()` to instruct the `World` that we want a chunk to be ticked
- The following API methods have been added:
- `public World->registerTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - registers a chunk to be ticked by the given `ChunkTicker`
- `public World->unregisterTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - unregisters a chunk from being ticked by the given `ChunkTicker`
# 4.19.1
Released 14th April 2023.
## Fixes
- Fixed inventory rollbacks when spreading items in ender chests.
- Fixed inventory rollbacks when shift-clicking to craft and the outputs would have been split across multiple inventory slots.
- Fixed incorrect spawn terrain generation for newly created worlds.
- Fixed `chunk-ticking.tick-radius` not disabling chunk ticking when set to `0`.
- Fixed chunks not being ticked if they previously left a player's simulation distance without leaving their view distance.
- Fixed height of collision boxes for Grass Path and Farmland blocks.
# 4.19.2
Released 14th April 2023.
## Fixes
- Fixed player timings duplication leading to extremely large timings reports when timings runs for a long time with many players.
- Packet timings are now indexed by class FQN instead of packet ID. This prevents erroneous timer reuse on packet ID reuse (e.g. multi version servers).
- Fixed entity timings being shared by different classes with the same short name. This led to incorrect timings being reported for some entities when custom entities were used.
# 4.19.3
Released 21st April 2023.
## General
- Error IDs for `Packet processing error` disconnects are now split into 4-character chunks to make them easier to type (since they can't be copied from the disconnection screen of a client).
## Fixes
- Fixed entity-block intersections being checked twice per tick. Besides wasting CPU time, this may have caused unexpected behaviour during entity-block interactions with blocks like water or cacti.
- Fixed performance issue in network inventory synchronization due item NBT being prepared twice.
- Fixed `tools/simulate-chunk-selector.php` argument parsing being completely broken (weird behaviour of PHP `getopt()`).
## Internals
- `TimingsHandler->stopTiming()` now logs an error message if a subtimer wasn't stopped, rather than throwing an exception.
- Due to interactions between `try...finally` and unexpected errors, throwing exceptions made it difficult for plugin developers to debug errors in their plugins, since it obscured the original error.

View File

@ -1,121 +0,0 @@
**For Minecraft: Bedrock Edition 1.18.10**
### 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.2.0
- Added support for Minecraft: Bedrock Edition 1.18.10.
# 4.2.1
Released 19th February 2022.
## General
- Improved performance of `Item::nbtSerialize()` - this will improve performance during world saves.
- Added more missing changes to the 4.0.0 changelog.
## Fixes
- Fixed multiple players being able to sleep in the same bed.
- Fixed hitbox not resetting properly after swimming or gliding.
# 4.2.2
Released 2nd March 2022.
## Fixes
- Fixed crash in `/dumpmemory` due to usage of non-printable string keys in `CraftingManager`. Array contents in memory dumps are now rendered as prettified key-value pairs.
- Fixed output directory for `/dumpmemory`.
- `PlayerInventory->isHotbarSlot()` now correctly returns `false` when given `9`.
- Fixed ghost items left in the inventory when dropping tools while mining.
# 4.2.3
Released 9th March 2022.
## Technical
- Now analysed using PHPStan 1.4.8.
- Now using `pocketmine/bedrock-protocol` [`8.0.1`](https://github.com/pmmp/BedrockProtocol/releases/tag/8.0.1%2Bbedrock-1.18.10).
## Fixes
### Core
- Fixed a memory leak and other bugs related to plugins disabling themselves during `onEnable()`.
### Gameplay
- Sweet berry bushes now absorb fall damage.
- Fixed mycelium spreading onto coarse dirt.
- Fixed blocks placed during `Block->onIncinerate()` getting overwritten.
- Fixed shulker boxes being unopenable when underwater.
- Fixed invisible fire on top of transparent non-flammable blocks.
### API
- Various APIs accepting `Vector3`, `Position` or `Location` no longer accept objects containing `INF` or `NaN` in any component. Previously, this was allowed, but would cause lots of obscure crashes later on.
- `Entity->setRotation()` no longer accepts `INF` or `NaN`.
- Fixed missing bounds check for `ItemFrame->setItemDropChance()`.
# 4.2.4
Released 18th March 2022.
## Fixes
- Fixed a crash when handling out-of-bounds meta values on the network.
# 4.2.5
Released 28th March 2022.
## General
- The layout of the human-readable part of crashdumps has been changed in an effort to improve the useful information density. It is hoped that this change will cause more useful information to be provided when people paste crash traces on Discord, since all the most important information is now at the top of the file.
- Version, git hash, PHP version and OS have been moved to the top of the crashdump.
- Backtrace has been moved above code sample.
- Docker images are now built by GitHub Actions (first live test).
## Technical
- The methods of `Inventory` and `BaseInventory` have been rearranged to improve coherency.
## Fixes
### API
- Enum members of enums created using `EnumTrait` are now able to have single-character names.
- Registry members of registries created using `RegistryTrait` or `CloningRegistryTrait` now have their names checked for invalid characters.
- `Entity::__construct()` now uses a guard variable to prevent it from being called multiple times unintentionally. This is necessary because `Entity::__construct()` has side effects.
- Fixed `PlayerItemHeldEvent` not being called when the content of the held slot was changed (e.g. replacing the held item via inventory menu).
### Gameplay
- Reduced the appearance of ghost items in unsupported gameplay scenarios using client prediction information. This fixes, for example, the appearance of ghost items when right-clicking on a filled flower pot.
# 4.2.6
Released 1st April 2022.
## Fixes
- Fixed buffer length underflow crash in `LoginPacket` handling.
# 4.2.7
Released 15th April 2022.
## General
- Added lots more documentation (in comments) about the `aliases` section in `pocketmine.yml`. You can read about this feature in the `aliases` section of the [updated `pocketmine.yml` template](/resources/pocketmine.yml).
- Improved wording of documentation of `PlayerPreLoginEvent`.
## Fixes
- Fixed core server crash when a plugin causes another plugin to be disabled during a scheduled task.
- Fixed core server crash when loading a plugin with an abstract main class.
- Fixed ghost items in many interaction situations (most notably, using projectiles while looking at an entity or block).
- Implemented a workaround for a client teleport bug which led to player positions not updating properly when using ender pearls.
- Fixed buggy movement when teleporting the player during `PlayerToggleSneakEvent`, `PlayerToggleSprintEvent`, `PlayerToggleSwimEvent` and `PlayerToggleGlideEvent`.
# 4.2.8
Released 17th April 2022.
## Fixes
- Fixed a memory leak in RakLib which could result in a server crash when players stay online for a long time.
- Fixed server crash when attempting to load a corrupted empty resource pack.
- Fixed users with the same name with differerently cased letters being able to duplicate items (userdata is matched by case-insensitive name).
# 4.2.9
Released 19th April 2022.
## Fixes
- Fixed several potential crashes when deserializing item NBT (due to insufficient validation of input data).
# 4.2.10
Released 20th April 2022.
## Fixes
- Fixed performance issue when chat messages received from the client contain many newlines. This security vulnerability was disclosed publicly necessitating a priority fix.

View File

@ -1,66 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.80**
### 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.
### Interim releases
If you're upgrading from 4.17.x directly to 4.20.x, please also read the following changelogs, as the interim releases contain important changes:
- [4.18.0](https://github.com/pmmp/PocketMine-MP/blob/4.20.0/changelogs/4.18.md#4180) - major performance improvements, internal network changes, minor API additions
- [4.19.0](https://github.com/pmmp/PocketMine-MP/blob/4.20.0/changelogs/4.19.md#4190) - minor performance improvements, improved timings system, minor API additions
# 4.20.0
Released 26th April 2023.
## General
- Added support for Minecraft: Bedrock Edition 1.19.80.
- Removed support for older versions.
## Fixes
- Fixed packet processing error when attempting to use a stonecutter.
- Fixed armor slots containing ghost items when cancelling right-click to equip armor.
- Fixed crash in `HandlerList->getListenersByPriority()` when no listeners are registered at the given priority.
## API
### `pocketmine\block`
- The following API methods have been added:
- `public BaseSign->getEditorEntityRuntimeId() : int` - returns the entity runtime ID of the player currently editing this sign, or `null` if none
- `public BaseSign->setEditorEntityRuntimeId(?int $editorEntityRuntimeId) : $this` - sets the entity runtime ID of the player currently editing this sign
### `pocketmine\player`
- The following API methods have been added:
- `public Player->openSignEditor(Vector3 $position) : void` - opens the client-side sign editor GUI for the given position
# 4.20.1
Released 27th April 2023.
## Fixes
- Fixed server crash when firing a bow while holding arrows in the offhand slot.
## Internals
- `ItemStackContainerIdTranslator::translate()` now requires an additional `int $slotId` parameter and returns `array{int, int}` (translated window ID, translated slot ID) to be used with `InventoryManager->locateWindowAndSlot()`.
- `InventoryManager->locateWindowAndSlot()` now checks if the translated slot actually exists in the requested inventory, and returns `null` if not. Previously, it would return potentially invalid slot IDs without checking them, potentially leading to crashes.
# 4.20.2
Released 4th May 2023.
## Fixes
- Fixed all types of wooden logs appearing as oak in the inventory.
- Fixed a performance issue in `BaseInventory->canAddItem()` (missing `continue` causing useless logic to run).
# 4.20.3
Released 6th May 2023.
## Improvements
- Reduced memory usage of `RuntimeBlockMapping` from 25 MB to 9 MB. Since every thread has its own copy of the block map, this saves a substantial amount of memory.
## Fixes
- Fixed players falling through blocks in spectator mode.
- Fixed timings reports getting bloated by prolific usage of `PluginManager->registerEvent()`.
- This was caused by creating a new timings handler for each call, regardless of whether a timer already existed for the given event and callback.
- Fixed `Full Server Tick` and other records being missing from timings reports.
- This was caused by timings handler depth not getting reset when timings was disabled and later re-enabled.

View File

@ -1,77 +0,0 @@
**For Minecraft: Bedrock Edition 1.18.30**
### 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.3.0
Released 20th April 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.18.30.
- Removed support for older versions.
# 4.3.1
Released 23rd April 2022.
## Fixes
- Updated BedrockProtocol dependency to fix incorrect command argument types.
- Creative players no longer die in the void.
# 4.3.2
Released 10th May 2022.
## Fixes
- Fixed an assertion failure in certain edge cases during world generation.
- Fixed `Entity::setNameTagVisible()` not immediately showing results to players already online.
## Documentation
- Added more documentation in the template `pocketmine.yml` for the `aliases` config section.
- Removed useless doc comment in `PlayerChangeSkinEvent`.
# 4.3.3
Released 16th May 2022.
## General
- Improved display of parameters in exception stack trace logs.
- Exception stack traces now include names for dynamic named arguments (i.e. arguments that don't match any parameter of the function), if any were given.
- Note: Named arguments which do match parameters are not shown this way, since PHP reduces them to positional arguments for performance reasons.
## Fixes
- Fixed server crash when chunks are unloaded during chunk generation callbacks
- Fixed dead coral fan items placing coral fans in the wrong orientation.
- Fixed max stack size of boat items.
# 4.3.4
Released 22nd May 2022.
## Fixes
- Fixed `difficulty` in `server.properties` having no effect - it's now applied to newly generated worlds.
- Note: this setting still doesn't behave the same way as vanilla due to potential disruption to existing servers.
- Fixed paintings not working in newly generated worlds and some other cases.
- Fixed inventory window switching breaking the inventory UI in some cases (e.g. pressing E while clicking a chest).
- Fixed minecart items incorrectly stacking.
- Fixed incorrect light levels in translucent blocks at the top of the world.
- Fixed teleporting sleeping players causing broken behaviour on the sleeping player's client.
- Fixed `EntityExplodeEvent->setYield()` accepting values outside the range 0-100.
- Fixed `ExplosionPrimeEvent->setForce()` accepting negative values (later resulting in crashes).
## Documentation
- Updated documentation for the following events:
- `CommandEvent`
- `EntityDespawnEvent`
- `EntityExplodeEvent`
- `EntitySpawnEvent`
- `ExplosionPrimeEvent`
- `InventoryTransactionEvent`
- `ItemDespawnEvent`
- `ItemSpawnEvent`
- `PlayerCommandPreprocessEvent`
- `PlayerDropItemEvent`
- `PlayerItemHeldEvent`
- `PlayerKickEvent`
- `PlayerQuitEvent`
- `PlayerTransferEvent`
- `UpdateNotifyEvent`

View File

@ -1,77 +0,0 @@
**For Minecraft: Bedrock Edition 1.18.30**
### 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.4.0-BETA1
Released 25th May 2022.
## General
- The server will now shut itself down if any of the following errors occur during startup:
- Any plugin fails to load or enable (plugins loaded by other plugins post-startup are **not** affected by this change) (**PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)**)
- The motivation for this change is to prevent situations where plugins failing to load could result in adverse outcomes, such as a world protection plugin leaving a lobby unprotected from griefing.
- If you encounter this problem, remove the offending plugin(s) or prevent it from loading using `plugin_list.yml`.
- See **PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)** for more detail on this change.
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to load (worlds loaded by plugins are **not** affected by this change)
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to generate (e.g. due to invalid generator settings)
- Enabling the server whitelist while the server is running (e.g. using `/whitelist on`) will now kick any non-whitelisted players currently on the server (**PR [#4774](https://github.com/pmmp/PocketMine-MP/pull/4774)**).
- Help for commands (`/help <name of command>`) now displays a list of aliases of that command.
- A CRITICAL log message is now generated if a plugin disables itself when enabling, in case the plugin doesn't emit any error of its own.
- The `/give` command now shows the alias used to find the given item in the success message, instead of the item ID/meta.
## Fixes
- Block placement has been fixed in many places where it previously didn't work correctly (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**):
- torches on top of slabs, upside-down stairs
- torches on the back face of stairs
- flower pots on top of fences
- the list goes on and on ...
- Fixed backslash escapes not getting properly removed from commands in some cases.
- Fixed aliases defined in the `aliases` section of `pocketmine.yml` not being treated as quote-aware.
## Gameplay
- Plants in flower pots can now be removed by right-clicking on the flower pot.
- Leaves now have a 2% chance of dropping sticks when destroyed by hand (**PR [#5019](https://github.com/pmmp/PocketMine-MP/pull/5019)**).
- Food exhaustion now matches Bedrock 1.18.30 (**PR [#5034](https://github.com/pmmp/PocketMine-MP/pull/5034)**).
- Implemented Stonecutter block (**PR [#4732](https://github.com/pmmp/PocketMine-MP/pull/4732)**).
## API
### Block
- Added `Block->getSupportType(Facing) : SupportType` (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
- This is used to determine the kind of support a block face can provide to a block (e.g. a torch) placed on it.
- Added `utils\SupportType` enum (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
- `tile\Spawnable->isDirty()` and `tile\Spawnable->setDirty()` are now `@deprecated`.
### Command
- Added `CommandStringHelper::parseQuoteAware()`. This static method contains the code used by `SimpleCommandMap` used to parse quoted command arguments.
### Entity
- Added `Human::emote()` (**PR [#4610](https://github.com/pmmp/PocketMine-MP/pull/4610)**)
### Event
- `PlayerCommandPreprocessEvent` is now `@deprecated`, since its functionality is entirely replaced by other, general-purpose events.
- Use `CommandEvent` to intercept commands.
- Use `PlayerChatEvent` to intercept chat messages.
- To convert a chat message into a command, pass it directly to `Server->dispatchCommand()` with the player as sender.
- Added `PlayerPostChunkSendEvent` (**PR [#4937](https://github.com/pmmp/PocketMine-MP/pull/4937)**).
- Added `PlayerDeathEvent->setKeepXp()` (**PR [#4015](https://github.com/pmmp/PocketMine-MP/pull/4015)**).
- `InventoryCloseEvent` is now called **after** the target window has been removed. This fixes various feedback loops caused by trying to open new windows to a player while there was one still active.
- As a side effect, this now means that `Player->getCurrentWindow()` will return `null` during `InventoryCloseEvent`. Use `InventoryCloseEvent->getInventory()` instead.
### Item
- `StringToItemParser` now recognizes `cod`, `raw_cod` and `cooked_cod` aliases.
### Plugin
- `DisablePluginException` may now be thrown from `Plugin::onEnable()` to make the server gracefully disable the plugin (without crashing) (**PR [#4780](https://github.com/pmmp/PocketMine-MP/pull/4780)**).
- `PluginManager->registerEvent()` now returns the `RegisteredListener` created for the handler, to permit unregistering it later.
## Internals
- Private property declarations now use typed properties (PHP 7.4) and promoted constructor properties (PHP 8.0) wherever possible.
- Protected and public properties remain unchanged, since they can't be changed without breaking subclasses.
- Promoted constructor properties are only used when it's consistently possible to promote most or all properties in a class.
- Simplified and improved legibility of `FormattedCommandAlias`.
- Added unit tests for the quote-aware command parser used by `SimpleCommandMap`.
- Various hardcoded values in `block` package classes have been moved to private constants to improve readability.
- Added various constants used in the `LevelDB` world provider.

View File

@ -1,97 +0,0 @@
**For Minecraft: Bedrock Edition 1.18.30**
### 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.4.0
Released 1st June 2022.
## General
- The server will now shut itself down if any of the following errors occur during startup:
- Any plugin fails to load or enable (plugins loaded by other plugins post-startup are **not** affected by this change) (**PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)**)
- The motivation for this change is to prevent situations where plugins failing to load could result in adverse outcomes, such as a world protection plugin leaving a lobby unprotected from griefing.
- If you encounter this problem, remove the offending plugin(s) or prevent it from loading using `plugin_list.yml`.
- See **PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)** for more detail on this change.
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to load (worlds loaded by plugins are **not** affected by this change)
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to generate (e.g. due to invalid generator settings)
- Enabling the server whitelist while the server is running (e.g. using `/whitelist on`) will now kick any non-whitelisted players currently on the server (**PR [#4774](https://github.com/pmmp/PocketMine-MP/pull/4774)**).
- Help for commands (`/help <name of command>`) now displays a list of aliases of that command.
- A CRITICAL log message is now generated if a plugin disables itself when enabling, in case the plugin doesn't emit any error of its own.
- The `/give` command now shows the alias used to find the given item in the success message, instead of the item ID/meta.
## Fixes
- Block placement has been fixed in many places where it previously didn't work correctly (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**):
- torches on top of slabs, upside-down stairs
- torches on the back face of stairs
- flower pots on top of fences
- the list goes on and on ...
- Fixed backslash escapes not getting properly removed from commands in some cases.
- Fixed aliases defined in the `aliases` section of `pocketmine.yml` not being treated as quote-aware.
## Gameplay
- Plants in flower pots can now be removed by right-clicking on the flower pot.
- Leaves now have a 2% chance of dropping sticks when destroyed by hand (**PR [#5019](https://github.com/pmmp/PocketMine-MP/pull/5019)**).
- Food exhaustion now matches Bedrock 1.18.30 (**PR [#5034](https://github.com/pmmp/PocketMine-MP/pull/5034)**).
- Implemented Stonecutter block (**PR [#4732](https://github.com/pmmp/PocketMine-MP/pull/4732)**).
## API
### Block
- Added `Block->getSupportType(Facing) : SupportType` (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
- This is used to determine the kind of support a block face can provide to a block (e.g. a torch) placed on it.
- Added `utils\SupportType` enum (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
- `tile\Spawnable->isDirty()` and `tile\Spawnable->setDirty()` are now `@deprecated`.
### Command
- Added `CommandStringHelper::parseQuoteAware()`. This static method contains the code used by `SimpleCommandMap` used to parse quoted command arguments.
### Entity
- Added `Human::emote()` (**PR [#4610](https://github.com/pmmp/PocketMine-MP/pull/4610)**)
### Event
- `PlayerCommandPreprocessEvent` is now `@deprecated`, since its functionality is entirely replaced by other, general-purpose events.
- Use `CommandEvent` to intercept commands.
- Use `PlayerChatEvent` to intercept chat messages.
- To convert a chat message into a command, pass it directly to `Server->dispatchCommand()` with the player as sender.
- Added `PlayerPostChunkSendEvent` (**PR [#4937](https://github.com/pmmp/PocketMine-MP/pull/4937)**).
- Added `PlayerDeathEvent->setKeepXp()` (**PR [#4015](https://github.com/pmmp/PocketMine-MP/pull/4015)**).
- `InventoryCloseEvent` is now called **after** the target window has been removed. This fixes various feedback loops caused by trying to open new windows to a player while there was one still active.
- As a side effect, this now means that `Player->getCurrentWindow()` will return `null` during `InventoryCloseEvent`. Use `InventoryCloseEvent->getInventory()` instead.
### Item
- `StringToItemParser` now recognizes `cod`, `raw_cod` and `cooked_cod` aliases.
### Plugin
- `DisablePluginException` may now be thrown from `Plugin::onEnable()` to make the server gracefully disable the plugin (without crashing) (**PR [#4780](https://github.com/pmmp/PocketMine-MP/pull/4780)**).
- `PluginManager->registerEvent()` now returns the `RegisteredListener` created for the handler, to permit unregistering it later.
## Internals
- Private property declarations now use typed properties (PHP 7.4) and promoted constructor properties (PHP 8.0) wherever possible.
- Protected and public properties remain unchanged, since they can't be changed without breaking subclasses.
- Promoted constructor properties are only used when it's consistently possible to promote most or all properties in a class.
- Simplified and improved legibility of `FormattedCommandAlias`.
- Added unit tests for the quote-aware command parser used by `SimpleCommandMap`.
- Various hardcoded values in `block` package classes have been moved to private constants to improve readability.
- Added various constants used in the `LevelDB` world provider.
# 4.4.1
Released 5th June 2022.
## General
- The server process will now exit with an error code if plugins, worlds or network interfaces failed to start.
## Fixes
- Fixed graylisted plugins preventing the server from starting.
- Fixed `composer make-devtools` command.
- Fixed the `Maximum memory (manager)` units being incorrectly displayed in `/status`.
- Fixed `Player->removeCurrentWindow()` breaking inventory windows.
# 4.4.2
Released 7th June 2022.
## Fixes
- Fixed a crash when arbitrary item IDs appeared in network items in some cases.
- Fixed saved paintings being deleted when loaded from disk (regression from 4.3.4).
- Fixed max stack size of fishing rods.

View File

@ -1,28 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.0**
### 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.5.0
Released 7th June 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.0.
- Removed support for older versions.
# 4.5.1
Released 8th June 2022.
## Fixes
- Fixed commands defined in `pocketmine.yml` `aliases` not passing the correct arguments.
- Updated BedrockProtocol to fix command argument types displayed on client-side command suggestions.
# 4.5.2
Released 29th June 2022.
## Fixes
- Fixed terrain getting redrawn when flying in spectator mode (or when using `Player->setHasBlockCollision(false)`).
- Fixed skulls with the `noDrops` flag set being treated as unknown blocks.

View File

@ -1,42 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.10**
### 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.6.0
Released 13th July 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.10.
- Removed support for older versions.
# 4.6.1
Released 22nd July 2022.
## Tools
- `build/generate-registry-annotations.php` now supports processing single files (useful for PhpStorm file watchers).
## API
- Updated documentation for `AsyncTask`.
## Fixes
- Fixed incorrect items being displayed in item frames.
- Fixed books not showing in lecterns.
- Fixed incorrect damage interval of Wither status effect.
- Fixed incorrect fire ticks when being set on fire by lava (8 seconds in Bedrock instead of 15).
- `Entity->attack()` now cancels damage from `FIRE` and `FIRE_TICK` damage causes if the entity is fireproof.
- Fixed inventory windows getting force-closed when the client attempts to use an enchanting table or anvil.
# 4.6.2
Released 6th August 2022.
## Core
- Improved server-side performance of `PlayerAuthInputPacket` handler.
- Improved client-side performance of `FloatingTextParticle` by using an invisible falling block entity. This offered a roughly 5x performance improvement over using tiny invisible players in local testing.
## Fixes
- Fixed assert failures and debug spam on debug Minecraft clients related to abilities in `AddPlayerPacket`.
- Fixed crash in `ReversePriorityQueue` on PHP 8.1 by adding `#[ReturnTypeWillChange]` attribute.

View File

@ -1,46 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.20**
### 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.7.0
Released 9th August 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.20.
- Removed support for older versions.
# 4.7.1
Released 14th August 2022.
## Fixes
- Fixed server crash when loading items from disk which have negative meta values.
- Fixed Turtle Master potions not giving any effects.
- Unimplemented items are no longer craftable.
- Fixed incorrect items appearing in item frames (due to an obsolete workaround for 1.19.10).
# 4.7.2
Released 16th August 2022.
## Fixes
- Fixed crash when processing player skins with invalid geometry data.
- Fixed spectator players being able to pick blocks using mousewheel click.
- Improved supporting requirements for sugarcane.
# 4.7.3
Released 22nd August 2022.
## General
- Added complete translations for Spanish and Vietnamese.
- All continuous integration (static analysis, unit tests, integration tests) are now performed on PHP 8.1 as well as 8.0.
- InventoryTransaction now verifies that stack sizes of items after the transaction don't exceed the maximum stack size of the item type or the containing inventory.
## Fixes
- Fixed Normal generator crash on PHP 8.1.
- Fixed a race condition during async worker shutdown that could lead to tasks executing in the wrong order. This (very rarely) led to a crash in `PopulationTask` due to its preceding `GeneratorRegisterTask` not being executed.
- Fixed `/give` accepting negative amounts or amounts larger than 32767 (vanilla max).
- Fixed placement conditions for vines (no longer able to be placed on the side of cacti).
- Fixed incorrect documentation of `SignText::__construct()`.

View File

@ -1,23 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.21**
### 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.8.0
Released 24th August 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.21.
- Removed support for older versions.
# 4.8.1
Released 26th August 2022.
## General
- Crashdumps now include JIT mode information for use by the Crash Archive.
## Fixes
- Fixed uninitialized offset error in `DyeColorIdMap` when given invalid dye color IDs.

View File

@ -1,36 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.30**
### 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.9.0
Released 20th September 2022.
## General
- Added support for Minecraft: Bedrock Edition 1.19.30.
- Removed support for older versions.
# 4.9.1
Released 11th October 2022.
## Documentation
- Added and improved documentation for many API methods in `Player` and `Block`.
- Added missing `@internal` tag for `TaskHandler->setNextRun()`, `TaskHandler->remove()` and `TaskHandler->run()`.
## Fixes
- Flight state is now locked by the server in spectator mode. This prevents any attempt by the client to toggle flight mode.
- Fixed entity health exceeding its max health after the expiry of Health Boost effect.
- Fixed burp sound not being played when a player eats food.
- Fixed placement conditions for mushrooms - they can now only be placed when the light level at the target is <= 12, or on podzol or mycelium.
- Fixed sign text appearing to change colour and/or glow when using dye on a sign - since this feature is not yet implemented, no change should occur.
- Fixed players drowning when sprint-swimming on the surface of water.
## Internals
- Added more detailed debug logging during the player login sequence.
- Silenced debug spam during `PreSpawnPacketHandler`, considerably reducing debug noise when players join.
- Fixed an edge case in `InventoryManager->removeWindow()`. This bug didn't have any effect on stable versions, but caused a `next-minor` development version to crash.
- `Item`s returned by event getters are now cloned if modifying the result will have no useful side effects.
- Updated `pocketmine/bedrock-data` to [`1.11.1`](https://github.com/pmmp/BedrockData/tree/1.11.1%2Bbedrock-1.19.30), which reduces bandwidth consumption during logins by not sending useless biome generation data.

View File

@ -12,13 +12,9 @@
"ext-ctype": "*",
"ext-curl": "*",
"ext-date": "*",
"ext-gmp": "*",
"ext-hash": "*",
"ext-igbinary": "^3.0.1",
"ext-json": "*",
"ext-leveldb": "^0.2.1 || ^0.3.0",
"ext-mbstring": "*",
"ext-morton": "^0.1.0",
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
@ -33,46 +29,36 @@
"composer-runtime-api": "^2.0",
"adhocore/json-comment": "^1.1",
"fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0",
"pocketmine/bedrock-block-upgrade-schema": "~2.1.0+bedrock-1.19.80",
"pocketmine/bedrock-data": "~2.2.0+bedrock-1.19.80",
"pocketmine/bedrock-item-upgrade-schema": "~1.2.0+bedrock-1.19.80",
"pocketmine/bedrock-protocol": "~21.0.0+bedrock-1.19.80",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/binaryutils": "^0.1.9",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.2.0",
"pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.6.0",
"pocketmine/locale-data": "~2.19.0",
"pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.4.0",
"pocketmine/math": "^0.4.0",
"pocketmine/nbt": "^0.3.2",
"pocketmine/raklib": "^0.14.2",
"pocketmine/raklib-ipc": "^0.1.0",
"pocketmine/snooze": "^0.3.0",
"ramsey/uuid": "^4.1",
"symfony/filesystem": "^5.4",
"webmozart/path-util": "^2.3"
"pocketmine/classloader": "^0.1.0",
"pocketmine/log": "^0.2.0",
"pocketmine/log-pthreads": "^0.1.0",
"pocketmine/math": "^0.2.0",
"pocketmine/nbt": "^0.2.19",
"pocketmine/raklib": "^0.12.7",
"pocketmine/snooze": "^0.1.0",
"pocketmine/spl": "^0.4.0"
},
"require-dev": {
"phpstan/phpstan": "1.10.14",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0",
"phpstan/phpstan": "1.3.3",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.2"
},
"autoload": {
"psr-4": {
"pocketmine\\": "src/"
"": ["src"]
},
"files": [
"src/CoreConstants.php"
"src/pocketmine/CoreConstants.php",
"src/pocketmine/GlobalConstants.php",
"src/pocketmine/VersionInfo.php"
]
},
"autoload-dev": {
"psr-4": {
"pocketmine\\": "tests/phpunit/",
"pocketmine\\phpstan\\rules\\": "tests/phpstan/rules"
"pocketmine\\": "tests/phpunit/"
}
},
"config": {
@ -82,16 +68,10 @@
"sort-packages": true
},
"scripts": {
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make ./ --relative tests/plugins/DevTools --out plugins/DevTools.phar",
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/DevTools/ConsoleScript.php --make tests/plugins/DevTools --out plugins/DevTools.phar",
"make-server": [
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
"@php -dphar.readonly=0 build/server-phar.php"
],
"update-registry-annotations": [
"@php build/generate-registry-annotations.php src"
],
"update-translation-apis": [
"@php build/generate-known-translation-apis.php"
]
}
}

1900
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
# Doxyfile 1.9.3
# Doxyfile 1.8.15
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all generated output in the proper direction.
# Possible values are: None, LTR, RTL and Context.
# The default value is: None.
OUTPUT_TEXT_DIRECTION = None
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
@ -189,16 +197,6 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
# such as
# /***************
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
# Javadoc-style will behave just like regular comments and it will not be
# interpreted by doxygen.
# The default value is: NO.
JAVADOC_BANNER = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
@ -219,14 +217,6 @@ QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
# By default Python docstrings are displayed as preformatted text and doxygen's
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
# doxygen's special commands can be used and the contents of the docstring
# documentation blocks is shown as doxygen documentation.
# The default value is: YES.
PYTHON_DOCSTRING = YES
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
@ -250,19 +240,25 @@ TAB_SIZE = 4
# the documentation. An alias has the form:
# name=value
# For example adding
# "sideeffect=@par Side Effects:^^"
# "sideeffect=@par Side Effects:\n"
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". Note that you cannot put \n's in the value part of an alias
# to insert newlines (in the resulting output). You can put ^^ in the value part
# of an alias to insert a newline as if a physical newline was in the original
# file. When you need a literal { or } or , in the value part of an alias you
# have to escape them by means of a backslash (\), this can lead to conflicts
# with the commands \{ and \} for these it is advised to use the version @{ and
# @} or use a double escape (\\{ and \\})
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines (in the resulting output). You can put ^^ in the value part of an
# alias to insert a newline as if a physical newline was in the original file.
# When you need a literal { or } or , in the value part of an alias you have to
# escape them by means of a backslash (\), this can lead to conflicts with the
# commands \{ and \} for these it is advised to use the version @{ and @} or use
# a double escape (\\{ and \\})
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
@ -303,22 +299,19 @@ OPTIMIZE_OUTPUT_SLICE = NO
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran type files). For instance to make doxygen treat .inc files
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C.
# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
# .inc files as Fortran files (default is PHP), and .f files as C (default is
# Fortran), use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen. When specifying no_extension you should add
# * to the FILE_PATTERNS.
#
# Note see also the list of default file extension mappings.
# the files are not read by doxygen.
EXTENSION_MAPPING =
@ -336,7 +329,7 @@ MARKDOWN_SUPPORT = YES
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
# Minimum value: 0, maximum value: 99, default value: 5.
# Minimum value: 0, maximum value: 99, default value: 0.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 0
@ -452,19 +445,6 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
# speed. At this moment only the input processing can be done using multiple
# threads. Since this is still an experimental feature the default is set to 1,
# which effectively disables parallel processing. Please report any issues you
# encounter. Generating dot graphs in parallel is controlled by the
# DOT_NUM_THREADS setting.
# Minimum value: 0, maximum value: 32, default value: 1.
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@ -485,12 +465,6 @@ EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
# methods of a class will be included in the documentation.
# The default value is: NO.
EXTRACT_PRIV_VIRTUAL = NO
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
@ -528,13 +502,6 @@ EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = YES
# If this flag is set to YES, the name of an unnamed parameter in a declaration
# will be determined by the corresponding definition. By default unnamed
# parameters remain unnamed in the output.
# The default value is: YES.
RESOLVE_UNNAMED_PARAMS = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
@ -552,8 +519,8 @@ HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# declarations. If set to NO, these declarations will be included in the
# documentation.
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
@ -572,18 +539,11 @@ HIDE_IN_BODY_DOCS = YES
INTERNAL_DOCS = NO
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
# able to match the capabilities of the underlying filesystem. In case the
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
# The default value is: system dependent.
CASE_SENSE_NAMES = NO
@ -602,12 +562,6 @@ HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
# will show which file needs to be included to use the class.
# The default value is: YES.
SHOW_HEADERFILE = YES
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
@ -765,8 +719,7 @@ FILE_VERSION_FILTER =
# output files in an output format independent way. To create the layout file
# that represents doxygen's defaults, run doxygen with the -l option. You can
# optionally specify a file name after the option, if omitted DoxygenLayout.xml
# will be used as the name of the layout file. See also section "Changing the
# layout of pages" for information.
# will be used as the name of the layout file.
#
# Note that if you run doxygen from a directory containing a file called
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
@ -812,35 +765,24 @@ WARNINGS = NO
WARN_IF_UNDOCUMENTED = NO
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as documenting some parameters in
# a documented function twice, or documenting parameters that don't exist or
# using markup commands wrongly.
# potential errors in the documentation, such as not documenting some parameters
# in a documented function, or documenting parameters that don't exist or using
# markup commands wrongly.
# The default value is: YES.
WARN_IF_DOC_ERROR = YES
# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
# function parameter documentation. If set to NO, doxygen will accept that some
# parameters have no documentation without warning.
# The default value is: YES.
WARN_IF_INCOMPLETE_DOC = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong parameter
# documentation, but not about the absence of documentation. If EXTRACT_ALL is
# set to YES then this flag will automatically be disabled. See also
# WARN_IF_INCOMPLETE_DOC
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation. If
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
# The default value is: NO.
WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# a warning is encountered.
# The default value is: NO.
WARN_AS_ERROR = NO
@ -857,10 +799,7 @@ WARN_FORMAT = "$file:$line: $text"
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
# error (stderr). In case the file specified cannot be opened for writing the
# warning and error messages are written to standard error. When as file - is
# specified the warning and error messages are written to standard output
# (stdout).
# error (stderr).
WARN_LOGFILE =
@ -881,8 +820,8 @@ INPUT = ../src \
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
@ -895,15 +834,11 @@ INPUT_ENCODING = UTF-8
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
# *.vhdl, *.ucf, *.qsf and *.ice.
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.php
@ -948,7 +883,7 @@ EXCLUDE_PATTERNS = */bin/* \
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# ANamespace::AClass, ANamespace::*Test
# AClass::ANamespace, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
@ -1124,24 +1059,16 @@ USE_HTAGS = NO
VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see:
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# performance. This can be particularly helpful with template rich C++ code for
# which doxygen's built-in parser lacks the necessary type information.
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
# cost of reduced performance. This can be particularly helpful with template
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
# tag is set to YES then doxygen will add the directory of each input to the
# include path.
# The default value is: YES.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
CLANG_ADD_INC_PATHS = YES
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
@ -1151,13 +1078,10 @@ CLANG_ADD_INC_PATHS = YES
CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the directory containing a file called compile_commands.json. This
# file is the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
# options used when the source files were built. This is equivalent to
# specifying the -p option to a clang tool, such as clang-check. These options
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
# will be added as well.
# path to the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
# were built. This is equivalent to specifying the "-p" option to a clang tool,
# such as clang-check. These options will then be passed to the parser.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
@ -1174,6 +1098,13 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
@ -1273,7 +1204,7 @@ HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a color-wheel, see
# this color. Hue is specified as an angle on a colorwheel, see
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
@ -1283,7 +1214,7 @@ HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use gray-scales only. A
# in the HTML output. For a value of 0 the output will use grayscales only. A
# value of 255 will produce the most vivid colors.
# Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
@ -1308,13 +1239,13 @@ HTML_COLORSTYLE_GAMMA = 80
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = NO
HTML_TIMESTAMP = YES
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will
# are dynamically created via Javascript. If disabled, the navigation index will
# consists of multiple levels of tabs that are statically embedded in every HTML
# page. Disable this option to support browsers that do not have JavaScript,
# page. Disable this option to support browsers that do not have Javascript,
# like the Qt help browser.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
@ -1344,11 +1275,10 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see:
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
# create a documentation set, doxygen will generate a Makefile in the HTML
# output directory. Running make will produce the docset in that directory and
# running make install will install the docset in
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information.
@ -1365,13 +1295,6 @@ GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
# This tag determines the URL of the docset feed. A documentation feed provides
# an umbrella under which multiple documentation sets from a single provider
# (such as a company or product suite) can be grouped.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_FEEDURL =
# This tag specifies a string that should uniquely identify the documentation
# set bundle. This should be a reverse domain-name style string, e.g.
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
@ -1397,12 +1320,8 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# on Windows. In the beginning of 2021 Microsoft took the original page, with
# a.o. the download links, offline the HTML help workshop was already many years
# in maintenance mode). You can download the HTML help workshop from the web
# archives at Installation executable (see:
# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@ -1432,7 +1351,7 @@ CHM_FILE =
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the main .chm file (NO).
# (YES) or that it should be included in the master .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@ -1477,8 +1396,7 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@ -1486,8 +1404,8 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
# folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@ -1495,30 +1413,30 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
# The QHG_LOCATION tag can be used to specify the location (absolute path
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
# run qhelpgenerator on the generated .qhp file.
# The QHG_LOCATION tag can be used to specify the location of Qt's
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
# generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
@ -1561,28 +1479,16 @@ DISABLE_INDEX = NO
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
# further fine tune the look of the index (see "Fine-tuning the output"). As an
# example, the default style sheet generated by doxygen has an example that
# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
# Since the tree basically has the same information as the tab index, you could
# consider setting DISABLE_INDEX to YES when enabling this option.
# further fine-tune the look of the index. As an example, the default style
# sheet generated by doxygen has an example that shows how to put an image at
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
# the same information as the tab index, you could consider setting
# DISABLE_INDEX to YES when enabling this option.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = YES
# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
# area (value NO) or if it should extend to the full height of the window (value
# YES). Setting this to YES gives a layout similar to
# https://docs.readthedocs.io with more room for contents, but less room for the
# project logo, title, and description. If either GENERATE_TREEVIEW or
# DISABLE_INDEX is set to NO, this option has no effect.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
FULL_SIDEBAR = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
#
@ -1607,24 +1513,6 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
# addresses.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
OBFUSCATE_EMAILS = YES
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
# the HTML output. These images will generally look nicer at scaled resolutions.
# Possible values are: png (the default) and svg (looks nicer but requires the
# pdf2svg or inkscape tool).
# The default value is: png.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FORMULA_FORMAT = png
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
@ -1645,14 +1533,8 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
FORMULA_MACROFILE =
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# https://www.mathjax.org) which uses client side JavaScript for the rendering
# https://www.mathjax.org) which uses client side Javascript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@ -1662,29 +1544,11 @@ FORMULA_MACROFILE =
USE_MATHJAX = YES
# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
# Note that the different versions of MathJax have different requirements with
# regards to the different settings, so it is possible that also other MathJax
# settings have to be changed when switching between the different MathJax
# versions.
# Possible values are: MathJax_2 and MathJax_3.
# The default value is: MathJax_2.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_VERSION = MathJax_2
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. For more details about the output format see MathJax
# version 2 (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
# (see:
# http://docs.mathjax.org/en/latest/web/components/output.html).
# the MathJax output. See the MathJax site (see:
# http://docs.mathjax.org/en/latest/output.html) for more details.
# Possible values are: HTML-CSS (which is slower, but has the best
# compatibility. This is the name for Mathjax version 2, for MathJax version 3
# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
# is the name for Mathjax version 3, for MathJax version 2 this will be
# translated into HTML-CSS) and SVG.
# compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS.
# This tag requires that the tag USE_MATHJAX is set to YES.
@ -1697,29 +1561,22 @@ MATHJAX_FORMAT = HTML-CSS
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from https://www.mathjax.org before deployment. The default value is:
# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
# MathJax from https://www.mathjax.org before deployment.
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
# for MathJax version 2 (see
# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# For example for MathJax version 3 (see
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
# MATHJAX_EXTENSIONS = ams
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
# (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
@ -1747,7 +1604,7 @@ MATHJAX_CODEFILE =
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using JavaScript. There
# implemented using a web server instead of a web client using Javascript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
@ -1766,8 +1623,7 @@ SERVER_BASED_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see:
# https://xapian.org/).
# Xapian (see: https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@ -1780,9 +1636,8 @@ EXTERNAL_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see:
# https://xapian.org/). See the section "External Indexing and Searching" for
# details.
# Xapian (see: https://xapian.org/). See the section "External Indexing and
# Searching" for details.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
@ -1853,11 +1708,10 @@ LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
# generate index for LaTeX. In case there is no backslash (\) as first character
# it will be automatically added in the LaTeX code.
# generate index for LaTeX.
# Note: This tag is used in the generated output file (.tex).
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
# The default value is: makeindex.
# The default value is: \makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_MAKEINDEX_CMD = \makeindex
@ -1891,31 +1745,29 @@ PAPER_TYPE = a4
EXTRA_PACKAGES =
# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
# the generated LaTeX document. The header should contain everything until the
# first chapter. If it is left blank doxygen will generate a standard header. It
# is highly recommended to start with a default header using
# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
# and then modify the file new_header.tex. See also section "Doxygen usage" for
# information on how to generate the default header that doxygen normally uses.
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
# generated LaTeX document. The header should contain everything until the first
# chapter. If it is left blank doxygen will generate a standard header. See
# section "Doxygen usage" for information on how to let doxygen write the
# default header to a separate file.
#
# Note: Only use a user-defined header if you know what you are doing!
# Note: The header is subject to change so you typically have to regenerate the
# default header when upgrading to a newer version of doxygen. The following
# commands have a special meaning inside the header (and footer): For a
# description of the possible markers and block names see the documentation.
# Note: Only use a user-defined header if you know what you are doing! The
# following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
# string, for the replacement values of the other commands the user is referred
# to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
# the generated LaTeX document. The footer should contain everything after the
# last chapter. If it is left blank doxygen will generate a standard footer. See
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
# generated LaTeX document. The footer should contain everything after the last
# chapter. If it is left blank doxygen will generate a standard footer. See
# LATEX_HEADER for more information on how to generate a default footer and what
# special commands can be used inside the footer. See also section "Doxygen
# usage" for information on how to generate the default footer that doxygen
# normally uses. Note: Only use a user-defined footer if you know what you are
# doing!
# special commands can be used inside the footer.
#
# Note: Only use a user-defined footer if you know what you are doing!
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
@ -1948,11 +1800,9 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
# files. Set this option to YES, to get a higher quality PDF documentation.
#
# See also section LATEX_CMD_NAME for selecting the engine.
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@ -1960,7 +1810,8 @@ USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running
# if errors occur, instead of asking the user for help.
# if errors occur, instead of asking the user for help. This option is also used
# when generating formulas in HTML.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@ -1973,6 +1824,16 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
# code with syntax highlighting in the LaTeX output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
@ -2053,6 +1914,16 @@ RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
# with syntax highlighting in the RTF output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
@ -2149,6 +2020,15 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
# The default value is: NO.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
@ -2323,10 +2203,34 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of 'which perl').
# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
# powerful graphs.
# The default value is: YES.
CLASS_DIAGRAMS = NO
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see:
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@ -2383,14 +2287,11 @@ DOT_FONTSIZE = 10
DOT_FONTPATH =
# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
# graph for each documented class showing the direct and indirect inheritance
# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
# to TEXT the direct and indirect inheritance relations will be shown as texts /
# links.
# Possible values are: NO, YES, TEXT and GRAPH.
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
# each documented class showing the direct and indirect inheritance relations.
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES
@ -2427,31 +2328,9 @@ UML_LOOK = YES
# but if the number exceeds 15, the total amount of fields shown is limited to
# 10.
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag UML_LOOK is set to YES.
UML_LIMIT_NUM_FIELDS = 10
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
# tag is set to YES, doxygen will add type and arguments for attributes and
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
# will not generate fields with class member information in the UML graphs. The
# class diagrams will look similar to the default class diagrams but using UML
# notation for the relationships.
# Possible values are: NO, YES and NONE.
# The default value is: NO.
# This tag requires that the tag UML_LOOK is set to YES.
DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_WRAP_THRESHOLD = 17
UML_LIMIT_NUM_FIELDS = 10
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
@ -2519,13 +2398,6 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
# of child directories generated in directory dependency graphs by dot.
# Minimum value: 1, maximum value: 25, default value: 1.
# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
DIR_GRAPH_MAX_DEPTH = 1
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see:
@ -2579,10 +2451,10 @@ MSCFILE_DIRS =
DIAFILE_DIRS =
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
# path where java can find the plantuml.jar file or to the filename of jar file
# to be used. If left blank, it is assumed PlantUML is not used or called during
# a preprocessing step. Doxygen will generate a warning when it encounters a
# \startuml command in this case and will not generate output for the diagram.
# path where java can find the plantuml.jar file. If left blank, it is assumed
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
PLANTUML_JAR_PATH =
@ -2644,18 +2516,14 @@ DOT_MULTI_TARGETS = YES
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
# explaining the meaning of the various boxes and arrows in the dot generated
# graphs.
# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
# graphical representation for inheritance and collaboration diagrams is used.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# files that are used to generate the various graphs.
#
# Note: This setting is not only used for dot files but also for msc temporary
# files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES

View File

@ -1,20 +1,15 @@
includes:
- tests/phpstan/analyse-for-current-php-version.neon.php
- tests/phpstan/configs/actual-problems.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/impossible-generics.neon
- tests/phpstan/configs/php-bugs.neon
- tests/phpstan/configs/phpstan-bugs.neon
- tests/phpstan/configs/phpunit-wiring-tests.neon
- tests/phpstan/configs/runtime-type-checks.neon
- tests/phpstan/configs/spl-fixed-array-sucks.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
rules:
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
parameters:
level: 9
checkMissingCallableSignature: true
@ -24,25 +19,25 @@ parameters:
scanDirectories:
- build
- tests/plugins/TesterPlugin
- tools
scanFiles:
- src/PocketMine.php
- src/pocketmine/PocketMine.php
paths:
- build
- src
- tests/phpstan/rules
- tests/phpunit
- tests/plugins/TesterPlugin
- tools
excludePaths:
analyseAndScan:
- build/php
- build/preprocessor
analyse:
- src/pocketmine/block/StoneSlab.php #overrides STONE constant
- src/pocketmine/item/Potion.php #overrides WATER constant
dynamicConstantNames:
- pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD
- pocketmine\DEBUG
- pocketmine\IS_DEVELOPMENT_BUILD
stubFiles:
- tests/phpstan/stubs/JsonMapper.stub
- tests/phpstan/stubs/chunkutils.stub
- tests/phpstan/stubs/leveldb.stub
- tests/phpstan/stubs/phpasn1.stub
- tests/phpstan/stubs/pthreads.stub

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +0,0 @@
#This configuration file allows you to control which plugins are loaded on your server.
#List behaviour
# - blacklist: Only plugins which ARE NOT listed will load.
# - whitelist: Only plugins which ARE listed will load.
mode: blacklist
#List names of plugins here.
plugins: []

View File

@ -1,42 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine;
use function define;
use function defined;
use function dirname;
// composer autoload doesn't use require_once and also pthreads can inherit things
if(defined('pocketmine\_CORE_CONSTANTS_INCLUDED')){
return;
}
define('pocketmine\_CORE_CONSTANTS_INCLUDED', true);
define('pocketmine\PATH', dirname(__DIR__) . '/');
define('pocketmine\RESOURCE_PATH', dirname(__DIR__) . '/resources/');
define('pocketmine\BEDROCK_DATA_PATH', dirname(__DIR__) . '/vendor/pocketmine/bedrock-data/');
define('pocketmine\LOCALE_DATA_PATH', dirname(__DIR__) . '/vendor/pocketmine/locale-data/');
define('pocketmine\BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH', dirname(__DIR__) . '/vendor/pocketmine/bedrock-block-upgrade-schema/');
define('pocketmine\BEDROCK_ITEM_UPGRADE_SCHEMA_PATH', dirname(__DIR__) . '/vendor/pocketmine/bedrock-item-upgrade-schema/');
define('pocketmine\COMPOSER_AUTOLOADER_PATH', dirname(__DIR__) . '/vendor/autoload.php');

View File

@ -1,531 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine;
use pocketmine\event\server\LowMemoryEvent;
use pocketmine\network\mcpe\cache\ChunkCache;
use pocketmine\scheduler\DumpWorkerMemoryTask;
use pocketmine\scheduler\GarbageCollectionTask;
use pocketmine\timings\Timings;
use pocketmine\utils\Process;
use pocketmine\utils\Utils;
use Symfony\Component\Filesystem\Path;
use function arsort;
use function count;
use function fclose;
use function file_exists;
use function file_put_contents;
use function fopen;
use function fwrite;
use function gc_collect_cycles;
use function gc_disable;
use function gc_enable;
use function gc_mem_caches;
use function get_class;
use function get_declared_classes;
use function get_defined_functions;
use function ini_get;
use function ini_set;
use function intdiv;
use function is_array;
use function is_float;
use function is_object;
use function is_resource;
use function is_string;
use function json_encode;
use function mb_strtoupper;
use function min;
use function mkdir;
use function preg_match;
use function print_r;
use function round;
use function spl_object_hash;
use function sprintf;
use function strlen;
use function substr;
use const JSON_PRETTY_PRINT;
use const JSON_THROW_ON_ERROR;
use const JSON_UNESCAPED_SLASHES;
use const SORT_NUMERIC;
class MemoryManager{
private const DEFAULT_CHECK_RATE = Server::TARGET_TICKS_PER_SECOND;
private const DEFAULT_CONTINUOUS_TRIGGER_RATE = Server::TARGET_TICKS_PER_SECOND * 2;
private const DEFAULT_TICKS_PER_GC = 30 * 60 * Server::TARGET_TICKS_PER_SECOND;
private int $memoryLimit;
private int $globalMemoryLimit;
private int $checkRate;
private int $checkTicker = 0;
private bool $lowMemory = false;
private bool $continuousTrigger = true;
private int $continuousTriggerRate;
private int $continuousTriggerCount = 0;
private int $continuousTriggerTicker = 0;
private int $garbageCollectionPeriod;
private int $garbageCollectionTicker = 0;
private bool $garbageCollectionTrigger;
private bool $garbageCollectionAsync;
private int $lowMemChunkRadiusOverride;
private bool $lowMemChunkGC;
private bool $lowMemDisableChunkCache;
private bool $lowMemClearWorldCache;
private bool $dumpWorkers = true;
private \Logger $logger;
public function __construct(
private Server $server
){
$this->logger = new \PrefixedLogger($server->getLogger(), "Memory Manager");
$this->init($server->getConfigGroup());
}
private function init(ServerConfigGroup $config) : void{
$this->memoryLimit = $config->getPropertyInt("memory.main-limit", 0) * 1024 * 1024;
$defaultMemory = 1024;
if(preg_match("/([0-9]+)([KMGkmg])/", $config->getConfigString("memory-limit", ""), $matches) > 0){
$m = (int) $matches[1];
if($m <= 0){
$defaultMemory = 0;
}else{
$defaultMemory = match(mb_strtoupper($matches[2])){
"K" => intdiv($m, 1024),
"M" => $m,
"G" => $m * 1024,
default => $m,
};
}
}
$hardLimit = $config->getPropertyInt("memory.main-hard-limit", $defaultMemory);
if($hardLimit <= 0){
ini_set("memory_limit", '-1');
}else{
ini_set("memory_limit", $hardLimit . "M");
}
$this->globalMemoryLimit = $config->getPropertyInt("memory.global-limit", 0) * 1024 * 1024;
$this->checkRate = $config->getPropertyInt("memory.check-rate", self::DEFAULT_CHECK_RATE);
$this->continuousTrigger = $config->getPropertyBool("memory.continuous-trigger", true);
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", self::DEFAULT_TICKS_PER_GC);
$this->garbageCollectionTrigger = $config->getPropertyBool("memory.garbage-collection.low-memory-trigger", true);
$this->garbageCollectionAsync = $config->getPropertyBool("memory.garbage-collection.collect-async-worker", true);
$this->lowMemChunkRadiusOverride = $config->getPropertyInt("memory.max-chunks.chunk-radius", 4);
$this->lowMemChunkGC = $config->getPropertyBool("memory.max-chunks.trigger-chunk-collect", true);
$this->lowMemDisableChunkCache = $config->getPropertyBool("memory.world-caches.disable-chunk-cache", true);
$this->lowMemClearWorldCache = $config->getPropertyBool("memory.world-caches.low-memory-trigger", true);
$this->dumpWorkers = $config->getPropertyBool("memory.memory-dump.dump-async-worker", true);
gc_enable();
}
public function isLowMemory() : bool{
return $this->lowMemory;
}
public function getGlobalMemoryLimit() : int{
return $this->globalMemoryLimit;
}
public function canUseChunkCache() : bool{
return !$this->lowMemory || !$this->lowMemDisableChunkCache;
}
/**
* Returns the allowed chunk radius based on the current memory usage.
*/
public function getViewDistance(int $distance) : int{
return ($this->lowMemory && $this->lowMemChunkRadiusOverride > 0) ? min($this->lowMemChunkRadiusOverride, $distance) : $distance;
}
/**
* Triggers garbage collection and cache cleanup to try and free memory.
*/
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0) : void{
$this->logger->debug(sprintf("%sLow memory triggered, limit %gMB, using %gMB",
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
if($this->lowMemClearWorldCache){
foreach($this->server->getWorldManager()->getWorlds() as $world){
$world->clearCache(true);
}
ChunkCache::pruneCaches();
}
if($this->lowMemChunkGC){
foreach($this->server->getWorldManager()->getWorlds() as $world){
$world->doChunkGarbageCollection();
}
}
$ev = new LowMemoryEvent($memory, $limit, $global, $triggerCount);
$ev->call();
$cycles = 0;
if($this->garbageCollectionTrigger){
$cycles = $this->triggerGarbageCollector();
}
$this->logger->debug(sprintf("Freed %gMB, $cycles cycles", round(($ev->getMemoryFreed() / 1024) / 1024, 2)));
}
/**
* Called every tick to update the memory manager state.
*/
public function check() : void{
Timings::$memoryManager->startTiming();
if(($this->memoryLimit > 0 || $this->globalMemoryLimit > 0) && ++$this->checkTicker >= $this->checkRate){
$this->checkTicker = 0;
$memory = Process::getAdvancedMemoryUsage();
$trigger = false;
if($this->memoryLimit > 0 && $memory[0] > $this->memoryLimit){
$trigger = 0;
}elseif($this->globalMemoryLimit > 0 && $memory[1] > $this->globalMemoryLimit){
$trigger = 1;
}
if($trigger !== false){
if($this->lowMemory && $this->continuousTrigger){
if(++$this->continuousTriggerTicker >= $this->continuousTriggerRate){
$this->continuousTriggerTicker = 0;
$this->trigger($memory[$trigger], $this->memoryLimit, $trigger > 0, ++$this->continuousTriggerCount);
}
}else{
$this->lowMemory = true;
$this->continuousTriggerCount = 0;
$this->trigger($memory[$trigger], $this->memoryLimit, $trigger > 0);
}
}else{
$this->lowMemory = false;
}
}
if($this->garbageCollectionPeriod > 0 && ++$this->garbageCollectionTicker >= $this->garbageCollectionPeriod){
$this->garbageCollectionTicker = 0;
$this->triggerGarbageCollector();
}
Timings::$memoryManager->stopTiming();
}
public function triggerGarbageCollector() : int{
Timings::$garbageCollector->startTiming();
if($this->garbageCollectionAsync){
$pool = $this->server->getAsyncPool();
if(($w = $pool->shutdownUnusedWorkers()) > 0){
$this->logger->debug("Shut down $w idle async pool workers");
}
foreach($pool->getRunningWorkers() as $i){
$pool->submitTaskToWorker(new GarbageCollectionTask(), $i);
}
}
$cycles = gc_collect_cycles();
gc_mem_caches();
Timings::$garbageCollector->stopTiming();
return $cycles;
}
/**
* Dumps the server memory into the specified output folder.
*/
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize) : void{
$logger = new \PrefixedLogger($this->server->getLogger(), "Memory Dump");
$logger->notice("After the memory dump is done, the server might crash");
self::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize, $logger);
if($this->dumpWorkers){
$pool = $this->server->getAsyncPool();
foreach($pool->getRunningWorkers() as $i){
$pool->submitTaskToWorker(new DumpWorkerMemoryTask($outputFolder, $maxNesting, $maxStringSize), $i);
}
}
}
/**
* Static memory dumper accessible from any thread.
*
* @param mixed $startingObject
*/
public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
$hardLimit = Utils::assumeNotFalse(ini_get('memory_limit'), "memory_limit INI directive should always exist");
ini_set('memory_limit', '-1');
gc_disable();
if(!file_exists($outputFolder)){
mkdir($outputFolder, 0777, true);
}
$obData = Utils::assumeNotFalse(fopen(Path::join($outputFolder, "objects.js"), "wb+"));
$objects = [];
$refCounts = [];
$instanceCounts = [];
$staticProperties = [];
$staticCount = 0;
$functionStaticVars = [];
$functionStaticVarsCount = 0;
foreach(get_declared_classes() as $className){
$reflection = new \ReflectionClass($className);
$staticProperties[$className] = [];
foreach($reflection->getProperties() as $property){
if(!$property->isStatic() || $property->getDeclaringClass()->getName() !== $className){
continue;
}
if(!$property->isPublic()){
$property->setAccessible(true);
}
if(!$property->isInitialized()){
continue;
}
$staticCount++;
$staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($staticProperties[$className]) === 0){
unset($staticProperties[$className]);
}
foreach($reflection->getMethods() as $method){
if($method->getDeclaringClass()->getName() !== $reflection->getName()){
continue;
}
$methodStatics = [];
foreach($method->getStaticVariables() as $name => $variable){
$methodStatics[$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($methodStatics) > 0){
$functionStaticVars[$className . "::" . $method->getName()] = $methodStatics;
$functionStaticVarsCount += count($functionStaticVars);
}
}
}
file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Wrote $staticCount static properties");
$globalVariables = [];
$globalCount = 0;
$ignoredGlobals = [
'GLOBALS' => true,
'_SERVER' => true,
'_REQUEST' => true,
'_POST' => true,
'_GET' => true,
'_FILES' => true,
'_ENV' => true,
'_COOKIE' => true,
'_SESSION' => true
];
foreach(Utils::stringifyKeys($GLOBALS) as $varName => $value){
if(isset($ignoredGlobals[$varName])){
continue;
}
$globalCount++;
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Wrote $globalCount global variables");
foreach(get_defined_functions()["user"] as $function){
$reflect = new \ReflectionFunction($function);
$vars = [];
foreach($reflect->getStaticVariables() as $varName => $variable){
$vars[$varName] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($vars) > 0){
$functionStaticVars[$function] = $vars;
$functionStaticVarsCount += count($vars);
}
}
file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Wrote $functionStaticVarsCount function static variables");
$data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
do{
$continue = false;
foreach(Utils::stringifyKeys($objects) as $hash => $object){
if(!is_object($object)){
continue;
}
$continue = true;
$className = get_class($object);
if(!isset($instanceCounts[$className])){
$instanceCounts[$className] = 1;
}else{
$instanceCounts[$className]++;
}
$objects[$hash] = true;
$info = [
"information" => "$hash@$className",
];
if($object instanceof \Closure){
$info["definition"] = Utils::getNiceClosureName($object);
$info["referencedVars"] = [];
$reflect = new \ReflectionFunction($object);
if(($closureThis = $reflect->getClosureThis()) !== null){
$info["this"] = self::continueDump($closureThis, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
foreach($reflect->getStaticVariables() as $name => $variable){
$info["referencedVars"][$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
}else{
$reflection = new \ReflectionObject($object);
$info["properties"] = [];
for($original = $reflection; $reflection !== false; $reflection = $reflection->getParentClass()){
foreach($reflection->getProperties() as $property){
if($property->isStatic()){
continue;
}
$name = $property->getName();
if($reflection !== $original){
if($property->isPrivate()){
$name = $reflection->getName() . ":" . $name;
}else{
continue;
}
}
if(!$property->isPublic()){
$property->setAccessible(true);
}
if(!$property->isInitialized($object)){
continue;
}
$info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
}
}
fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n");
}
}while($continue);
$logger->info("Wrote " . count($objects) . " objects");
fclose($obData);
file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
arsort($instanceCounts, SORT_NUMERIC);
file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Finished!");
ini_set('memory_limit', $hardLimit);
gc_enable();
}
/**
* @param mixed $from
* @param object[] $objects reference parameter
* @param int[] $refCounts reference parameter
*
* @phpstan-param array<string, object> $objects
* @phpstan-param array<string, int> $refCounts
* @phpstan-param-out array<string, object> $objects
* @phpstan-param-out array<string, int> $refCounts
*
* @return mixed
*/
private static function continueDump($from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
if($maxNesting <= 0){
return "(error) NESTING LIMIT REACHED";
}
--$maxNesting;
if(is_object($from)){
if(!isset($objects[$hash = spl_object_hash($from)])){
$objects[$hash] = $from;
$refCounts[$hash] = 0;
}
++$refCounts[$hash];
$data = "(object) $hash";
}elseif(is_array($from)){
if($recursion >= 5){
return "(error) ARRAY RECURSION LIMIT REACHED";
}
$data = [];
$numeric = 0;
foreach($from as $key => $value){
$data[$numeric] = [
"k" => self::continueDump($key, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
"v" => self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
];
$numeric++;
}
}elseif(is_string($from)){
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
}elseif(is_resource($from)){
$data = "(resource) " . print_r($from, true);
}elseif(is_float($from)){
$data = "(float) $from";
}else{
$data = $from;
}
return $data;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,140 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine;
use pocketmine\utils\Config;
use function array_key_exists;
use function getopt;
use function is_bool;
use function is_int;
use function is_string;
use function strtolower;
final class ServerConfigGroup{
/**
* @var mixed[]
* @phpstan-var array<string, mixed>
*/
private array $propertyCache = [];
public function __construct(
private Config $pocketmineYml,
private Config $serverProperties
){}
/**
* @param mixed $defaultValue
*
* @return mixed
*/
public function getProperty(string $variable, $defaultValue = null){
if(!array_key_exists($variable, $this->propertyCache)){
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
$this->propertyCache[$variable] = $v[$variable];
}else{
$this->propertyCache[$variable] = $this->pocketmineYml->getNested($variable);
}
}
return $this->propertyCache[$variable] ?? $defaultValue;
}
public function getPropertyBool(string $variable, bool $defaultValue) : bool{
return (bool) $this->getProperty($variable, $defaultValue);
}
public function getPropertyInt(string $variable, int $defaultValue) : int{
return (int) $this->getProperty($variable, $defaultValue);
}
public function getPropertyString(string $variable, string $defaultValue) : string{
return (string) $this->getProperty($variable, $defaultValue);
}
public function getConfigString(string $variable, string $defaultValue = "") : string{
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
return (string) $v[$variable];
}
return $this->serverProperties->exists($variable) ? (string) $this->serverProperties->get($variable) : $defaultValue;
}
public function setConfigString(string $variable, string $value) : void{
$this->serverProperties->set($variable, $value);
}
public function getConfigInt(string $variable, int $defaultValue = 0) : int{
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
return (int) $v[$variable];
}
return $this->serverProperties->exists($variable) ? (int) $this->serverProperties->get($variable) : $defaultValue;
}
public function setConfigInt(string $variable, int $value) : void{
$this->serverProperties->set($variable, $value);
}
public function getConfigBool(string $variable, bool $defaultValue = false) : bool{
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){
$value = $v[$variable];
}else{
$value = $this->serverProperties->exists($variable) ? $this->serverProperties->get($variable) : $defaultValue;
}
if(is_bool($value)){
return $value;
}
if(is_int($value)){
return $value !== 0;
}
if(is_string($value)){
switch(strtolower($value)){
case "on":
case "true":
case "1":
case "yes":
return true;
}
}
return false;
}
public function setConfigBool(string $variable, bool $value) : void{
$this->serverProperties->set($variable, $value ? "1" : "0");
}
public function save() : void{
if($this->serverProperties->hasChanged()){
$this->serverProperties->save();
}
if($this->pocketmineYml->hasChanged()){
$this->pocketmineYml->save();
}
}
}

View File

@ -1,64 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine;
use pocketmine\snooze\SleeperHandler;
use pocketmine\timings\TimingsHandler;
use function hrtime;
/**
* Custom Snooze sleeper handler which captures notification processing time.
* @internal
*/
final class TimeTrackingSleeperHandler extends SleeperHandler{
private int $notificationProcessingTimeNs = 0;
public function __construct(
private TimingsHandler $timings
){
parent::__construct();
}
/**
* Returns the time in nanoseconds spent processing notifications since the last reset.
*/
public function getNotificationProcessingTime() : int{ return $this->notificationProcessingTimeNs; }
/**
* Resets the notification processing time tracker to zero.
*/
public function resetNotificationProcessingTime() : void{ $this->notificationProcessingTimeNs = 0; }
public function processNotifications() : void{
$startTime = hrtime(true);
$this->timings->startTiming();
try{
parent::processNotifications();
}finally{
$this->notificationProcessingTimeNs += hrtime(true) - $startTime;
$this->timings->stopTiming();
}
}
}

View File

@ -1,89 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine;
use pocketmine\utils\Git;
use pocketmine\utils\VersionString;
use function is_array;
use function is_int;
use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "4.20.3";
public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
private function __construct(){
//NOOP
}
private static ?string $gitHash = null;
public static function GIT_HASH() : string{
if(self::$gitHash === null){
$gitHash = str_repeat("00", 20);
if(\Phar::running(true) === ""){
$gitHash = Git::getRepositoryStatePretty(\pocketmine\PATH);
}else{
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(isset($meta["git"])){
$gitHash = $meta["git"];
}
}
self::$gitHash = $gitHash;
}
return self::$gitHash;
}
private static ?int $buildNumber = null;
public static function BUILD_NUMBER() : int{
if(self::$buildNumber === null){
self::$buildNumber = 0;
if(\Phar::running(true) !== ""){
$phar = new \Phar(\Phar::running(false));
$meta = $phar->getMetadata();
if(is_array($meta) && isset($meta["build"]) && is_int($meta["build"])){
self::$buildNumber = $meta["build"];
}
}
}
return self::$buildNumber;
}
private static ?VersionString $fullVersion = null;
public static function VERSION() : VersionString{
if(self::$fullVersion === null){
self::$fullVersion = new VersionString(self::BASE_VERSION, self::IS_DEVELOPMENT_BUILD, self::BUILD_NUMBER());
}
return self::$fullVersion;
}
}

View File

@ -1,106 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\AnvilInventory;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\Fallable;
use pocketmine\block\utils\FallableTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class Anvil extends Transparent implements Fallable{
use FallableTrait;
use HorizontalFacingTrait;
public const UNDAMAGED = 0;
public const SLIGHTLY_DAMAGED = 1;
public const VERY_DAMAGED = 2;
private int $damage = self::UNDAMAGED;
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) | ($this->damage << 2);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x3);
$this->damage = BlockDataSerializer::readBoundedInt("damage", $stateMeta >> 2, self::UNDAMAGED, self::VERY_DAMAGED);
}
public function getStateBitmask() : int{
return 0b1111;
}
protected function writeStateToItemMeta() : int{
return $this->damage << 2;
}
public function getDamage() : int{ return $this->damage; }
/** @return $this */
public function setDamage(int $damage) : self{
if($damage < self::UNDAMAGED || $damage > self::VERY_DAMAGED){
throw new \InvalidArgumentException("Damage must be in range " . self::UNDAMAGED . " ... " . self::VERY_DAMAGED);
}
$this->damage = $damage;
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->squash(Facing::axis(Facing::rotateY($this->facing, false)), 1 / 8)];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){
$player->setCurrentWindow(new AnvilInventory($this->position));
}
return true;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
$this->facing = Facing::rotateY($player->getHorizontalFacing(), true);
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function tickFalling() : ?Block{
return null;
}
}

View File

@ -1,246 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\StructureGrowEvent;
use pocketmine\item\Bamboo as ItemBamboo;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function count;
use function gmp_add;
use function gmp_and;
use function gmp_intval;
use function gmp_mul;
use function gmp_xor;
use function min;
use function mt_rand;
use const PHP_INT_MAX;
class Bamboo extends Transparent{
public const NO_LEAVES = 0;
public const SMALL_LEAVES = 1;
public const LARGE_LEAVES = 2;
protected bool $thick = false; //age in PC, but this is 0/1
protected bool $ready = false;
protected int $leafSize = self::NO_LEAVES;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->thick = ($stateMeta & BlockLegacyMetadata::BAMBOO_FLAG_THICK) !== 0;
$this->leafSize = BlockDataSerializer::readBoundedInt("leafSize", ($stateMeta >> BlockLegacyMetadata::BAMBOO_LEAF_SIZE_SHIFT) & BlockLegacyMetadata::BAMBOO_LEAF_SIZE_MASK, self::NO_LEAVES, self::LARGE_LEAVES);
$this->ready = ($stateMeta & BlockLegacyMetadata::BAMBOO_FLAG_READY) !== 0;
}
public function writeStateToMeta() : int{
return ($this->thick ? BlockLegacyMetadata::BAMBOO_FLAG_THICK : 0) | ($this->leafSize << BlockLegacyMetadata::BAMBOO_LEAF_SIZE_SHIFT) | ($this->ready ? BlockLegacyMetadata::BAMBOO_FLAG_READY : 0);
}
public function getStateBitmask() : int{
return 0b1111;
}
public function isThick() : bool{ return $this->thick; }
/** @return $this */
public function setThick(bool $thick) : self{
$this->thick = $thick;
return $this;
}
public function isReady() : bool{ return $this->ready; }
/** @return $this */
public function setReady(bool $ready) : self{
$this->ready = $ready;
return $this;
}
public function getLeafSize() : int{ return $this->leafSize; }
/** @return $this */
public function setLeafSize(int $leafSize) : self{
$this->leafSize = $leafSize;
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//this places the BB at the northwest corner, not the center
$inset = 1 - (($this->thick ? 3 : 2) / 16);
return [AxisAlignedBB::one()->trim(Facing::SOUTH, $inset)->trim(Facing::EAST, $inset)];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
private static function getOffsetSeed(int $x, int $y, int $z) : int{
$p1 = gmp_mul($z, 0x6ebfff5);
$p2 = gmp_mul($x, 0x2fc20f);
$p3 = $y;
$xord = gmp_xor(gmp_xor($p1, $p2), $p3);
$fullResult = gmp_mul(gmp_add(gmp_mul($xord, 0x285b825), 0xb), $xord);
return gmp_intval(gmp_and($fullResult, 0xffffffff));
}
private static function getMaxHeight(int $x, int $z) : int{
return 12 + (self::getOffsetSeed($x, 0, $z) % 5);
}
public function getModelPositionOffset() : ?Vector3{
$seed = self::getOffsetSeed($this->position->getFloorX(), 0, $this->position->getFloorZ());
$retX = (($seed % 12) + 1) / 16;
$retZ = ((($seed >> 8) % 12) + 1) / 16;
return new Vector3($retX, 0, $retZ);
}
private function canBeSupportedBy(Block $block) : bool{
//TODO: tags would be better for this
return
$block instanceof Dirt ||
$block instanceof Grass ||
$block instanceof Gravel ||
$block instanceof Sand ||
$block instanceof Mycelium ||
$block instanceof Podzol;
}
private function seekToTop() : Bamboo{
$world = $this->position->getWorld();
$top = $this;
while(($next = $world->getBlock($top->position->up())) instanceof Bamboo && $next->isSameType($this)){
$top = $next;
}
return $top;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer){
$top = $this->seekToTop();
if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2), $player)){
$item->pop();
return true;
}
}elseif($item instanceof ItemBamboo){
if($this->seekToTop()->grow(PHP_INT_MAX, 1, $player)){
$item->pop();
return true;
}
}
return false;
}
public function onNearbyBlockChange() : void{
$world = $this->position->getWorld();
$below = $world->getBlock($this->position->down());
if(!$this->canBeSupportedBy($below) && !$below->isSameType($this)){
$world->useBreakOn($this->position);
}
}
private function grow(int $maxHeight, int $growAmount, ?Player $player) : bool{
$world = $this->position->getWorld();
if(!$world->getBlock($this->position->up())->canBeReplaced()){
return false;
}
$height = 1;
while($world->getBlock($this->position->subtract(0, $height, 0))->isSameType($this)){
if(++$height >= $maxHeight){
return false;
}
}
$newHeight = $height + $growAmount;
$stemBlock = (clone $this)->setReady(false)->setLeafSize(self::NO_LEAVES);
if($newHeight >= 4 && !$stemBlock->isThick()){ //don't change it to false if height is less, because it might have been chopped
$stemBlock = $stemBlock->setThick(true);
}
$smallLeavesBlock = (clone $stemBlock)->setLeafSize(self::SMALL_LEAVES);
$bigLeavesBlock = (clone $stemBlock)->setLeafSize(self::LARGE_LEAVES);
$newBlocks = [];
if($newHeight === 2){
$newBlocks[] = $smallLeavesBlock;
}elseif($newHeight === 3){
$newBlocks[] = $smallLeavesBlock;
$newBlocks[] = $smallLeavesBlock;
}elseif($newHeight === 4){
$newBlocks[] = $bigLeavesBlock;
$newBlocks[] = $smallLeavesBlock;
$newBlocks[] = $stemBlock;
$newBlocks[] = $stemBlock;
}elseif($newHeight > 4){
$newBlocks[] = $bigLeavesBlock;
$newBlocks[] = $bigLeavesBlock;
$newBlocks[] = $smallLeavesBlock;
for($i = 0, $max = min($growAmount, $newHeight - count($newBlocks)); $i < $max; ++$i){
$newBlocks[] = $stemBlock; //to replace the bottom blocks that currently have leaves
}
}
$tx = new BlockTransaction($world);
foreach($newBlocks as $idx => $newBlock){
$tx->addBlock($this->position->subtract(0, $idx - $growAmount, 0), $newBlock);
}
$ev = new StructureGrowEvent($this, $tx, $player);
$ev->call();
if($ev->isCancelled()){
return false;
}
return $tx->apply();
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
$world = $this->position->getWorld();
if($this->ready){
$this->ready = false;
if($world->getFullLight($this->position) < 9 || !$this->grow(self::getMaxHeight($this->position->getFloorX(), $this->position->getFloorZ()), 1, null)){
$world->setBlock($this->position, $this);
}
}elseif($world->getBlock($this->position->up())->canBeReplaced()){
$this->ready = true;
$world->setBlock($this->position, $this);
}
}
}

View File

@ -1,131 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\event\block\StructureGrowEvent;
use pocketmine\item\Bamboo as ItemBamboo;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class BambooSapling extends Flowable{
private bool $ready = false;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->ready = ($stateMeta & BlockLegacyMetadata::BAMBOO_SAPLING_FLAG_READY) !== 0;
}
protected function writeStateToMeta() : int{
return $this->ready ? BlockLegacyMetadata::BAMBOO_SAPLING_FLAG_READY : 0;
}
public function getStateBitmask() : int{ return 0b1; }
public function isReady() : bool{ return $this->ready; }
/** @return $this */
public function setReady(bool $ready) : self{
$this->ready = $ready;
return $this;
}
private function canBeSupportedBy(Block $block) : bool{
//TODO: tags would be better for this
return
$block instanceof Dirt ||
$block instanceof Grass ||
$block instanceof Gravel ||
$block instanceof Sand ||
$block instanceof Mycelium ||
$block instanceof Podzol;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->position->getWorld()->getBlock($blockReplace->position->down()))){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer || $item instanceof ItemBamboo){
if($this->grow($player)){
$item->pop();
return true;
}
}
return false;
}
public function onNearbyBlockChange() : void{
$world = $this->position->getWorld();
if(!$this->canBeSupportedBy($world->getBlock($this->position->down()))){
$world->useBreakOn($this->position);
}
}
private function grow(?Player $player) : bool{
$world = $this->position->getWorld();
if(!$world->getBlock($this->position->up())->canBeReplaced()){
return false;
}
$tx = new BlockTransaction($world);
$bamboo = VanillaBlocks::BAMBOO();
$tx->addBlock($this->position, $bamboo)
->addBlock($this->position->up(), (clone $bamboo)->setLeafSize(Bamboo::SMALL_LEAVES));
$ev = new StructureGrowEvent($this, $tx, $player);
$ev->call();
if($ev->isCancelled()){
return false;
}
return $tx->apply();
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
$world = $this->position->getWorld();
if($this->ready){
$this->ready = false;
if($world->getFullLight($this->position) < 9 || !$this->grow(null)){
$world->setBlock($this->position, $this);
}
}elseif($world->getBlock($this->position->up())->canBeReplaced()){
$this->ready = true;
$world->setBlock($this->position, $this);
}
}
public function asItem() : Item{
return VanillaBlocks::BAMBOO()->asItem();
}
}

View File

@ -1,102 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Barrel as TileBarrel;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function abs;
class Barrel extends Opaque{
use AnyFacingTrait;
protected bool $open = false;
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeFacing($this->facing) | ($this->open ? BlockLegacyMetadata::BARREL_FLAG_OPEN : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readFacing($stateMeta & 0x07);
$this->open = ($stateMeta & BlockLegacyMetadata::BARREL_FLAG_OPEN) === BlockLegacyMetadata::BARREL_FLAG_OPEN;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function isOpen() : bool{
return $this->open;
}
/** @return $this */
public function setOpen(bool $open) : Barrel{
$this->open = $open;
return $this;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
if(abs($player->getPosition()->getX() - $this->position->getX()) < 2 && abs($player->getPosition()->getZ() - $this->position->getZ()) < 2){
$y = $player->getEyePos()->getY();
if($y - $this->position->getY() > 2){
$this->facing = Facing::UP;
}elseif($this->position->getY() - $y > 0){
$this->facing = Facing::DOWN;
}else{
$this->facing = Facing::opposite($player->getHorizontalFacing());
}
}else{
$this->facing = Facing::opposite($player->getHorizontalFacing());
}
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){
$barrel = $this->position->getWorld()->getTile($this->position);
if($barrel instanceof TileBarrel){
if(!$barrel->canOpenWith($item->getCustomName())){
return true;
}
$player->setCurrentWindow($barrel->getInventory());
}
}
return true;
}
public function getFuelTime() : int{
return 300;
}
}

View File

@ -1,159 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Banner as TileBanner;
use pocketmine\block\utils\BannerPatternLayer;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SupportType;
use pocketmine\data\bedrock\DyeColorIdMap;
use pocketmine\item\Banner as ItemBanner;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function array_filter;
use function assert;
use function count;
abstract class BaseBanner extends Transparent{
use ColoredTrait;
/**
* @var BannerPatternLayer[]
* @phpstan-var list<BannerPatternLayer>
*/
protected array $patterns = [];
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::BLACK();
parent::__construct($idInfo, $name, $breakInfo);
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBanner){
$this->color = $tile->getBaseColor();
$this->setPatterns($tile->getPatterns());
}
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileBanner);
$tile->setBaseColor($this->color);
$tile->setPatterns($this->patterns);
}
public function isSolid() : bool{
return false;
}
public function getMaxStackSize() : int{
return 16;
}
/**
* @return BannerPatternLayer[]
* @phpstan-return list<BannerPatternLayer>
*/
public function getPatterns() : array{
return $this->patterns;
}
/**
* @param BannerPatternLayer[] $patterns
*
* @phpstan-param list<BannerPatternLayer> $patterns
* @return $this
*/
public function setPatterns(array $patterns) : self{
$checked = array_filter($patterns, fn($v) => $v instanceof BannerPatternLayer);
if(count($checked) !== count($patterns)){
throw new \TypeError("Deque must only contain " . BannerPatternLayer::class . " objects");
}
$this->patterns = $checked;
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
private function canBeSupportedBy(Block $block) : bool{
return $block->isSolid();
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
return false;
}
if($item instanceof ItemBanner){
$this->color = $item->getColor();
$this->setPatterns($item->getPatterns());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
abstract protected function getSupportingFace() : int;
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){
$this->position->getWorld()->useBreakOn($this->position);
}
}
protected function writeStateToItemMeta() : int{
return DyeColorIdMap::getInstance()->toInvertedId($this->color);
}
public function getDropsForCompatibleTool(Item $item) : array{
$drop = $this->asItem();
if($drop instanceof ItemBanner && count($this->patterns) > 0){
$drop->setPatterns($this->patterns);
}
return [$drop];
}
public function getPickedItem(bool $addUserData = false) : Item{
$result = $this->asItem();
if($addUserData && $result instanceof ItemBanner && count($this->patterns) > 0){
$result->setPatterns($this->patterns);
}
return $result;
}
}

View File

@ -1,78 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\BlockDeathEvent;
use pocketmine\item\Item;
abstract class BaseCoral extends Transparent{
use CoralTypeTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
parent::__construct($idInfo, $name, $breakInfo);
$this->coralType = CoralType::TUBE();
}
public function onNearbyBlockChange() : void{
if(!$this->dead){
$world = $this->position->getWorld();
$hasWater = false;
foreach($this->position->sides() as $vector3){
if($world->getBlock($vector3) instanceof Water){
$hasWater = true;
break;
}
}
//TODO: check water inside the block itself (not supported on the API yet)
if(!$hasWater){
$ev = new BlockDeathEvent($this, $this->setDead(true));
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
}
}
}
}
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function isAffectedBySilkTouch() : bool{
return true;
}
public function isSolid() : bool{ return false; }
protected function recalculateCollisionBoxes() : array{ return []; }
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
}

View File

@ -1,236 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\RailConnectionInfo;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function array_reverse;
use function array_search;
use function array_shift;
use function count;
use function in_array;
abstract class BaseRail extends Flowable{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($blockReplace->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onPostPlace() : void{
$this->tryReconnect();
}
/**
* @param int[] $connections
* @param int[][] $lookup
* @phpstan-param array<int, list<int>> $lookup
*/
protected static function searchState(array $connections, array $lookup) : ?int{
$shape = array_search($connections, $lookup, true);
if($shape === false){
$shape = array_search(array_reverse($connections), $lookup, true);
}
return $shape === false ? null : $shape;
}
/**
* Sets the rail shape according to the given connections, if a shape matches.
*
* @param int[] $connections
*
* @throws \InvalidArgumentException if no shape matches the given connections
*/
abstract protected function setShapeFromConnections(array $connections) : void;
/**
* Returns the connection directions of this rail (depending on the current block state)
*
* @return int[]
*/
abstract protected function getCurrentShapeConnections() : array;
/**
* Returns all the directions this rail is already connected in.
*
* @return int[]
*/
private function getConnectedDirections() : array{
/** @var int[] $connections */
$connections = [];
/** @var int $connection */
foreach($this->getCurrentShapeConnections() as $connection){
$other = $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND);
$otherConnection = Facing::opposite($connection & ~RailConnectionInfo::FLAG_ASCEND);
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0){
$other = $other->getSide(Facing::UP);
}elseif(!($other instanceof BaseRail)){ //check for rail sloping up to meet this one
$other = $other->getSide(Facing::DOWN);
$otherConnection |= RailConnectionInfo::FLAG_ASCEND;
}
if(
$other instanceof BaseRail &&
in_array($otherConnection, $other->getCurrentShapeConnections(), true)
){
$connections[] = $connection;
}
}
return $connections;
}
/**
* @param int[] $constraints
*
* @return true[]
* @phpstan-return array<int, true>
*/
private function getPossibleConnectionDirections(array $constraints) : array{
switch(count($constraints)){
case 0:
//No constraints, can connect in any direction
$possible = [
Facing::NORTH => true,
Facing::SOUTH => true,
Facing::WEST => true,
Facing::EAST => true
];
foreach($possible as $p => $_){
$possible[$p | RailConnectionInfo::FLAG_ASCEND] = true;
}
return $possible;
case 1:
return $this->getPossibleConnectionDirectionsOneConstraint(array_shift($constraints));
case 2:
return [];
default:
throw new \InvalidArgumentException("Expected at most 2 constraints, got " . count($constraints));
}
}
/**
* @return true[]
* @phpstan-return array<int, true>
*/
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
$opposite = Facing::opposite($constraint & ~RailConnectionInfo::FLAG_ASCEND);
$possible = [$opposite => true];
if(($constraint & RailConnectionInfo::FLAG_ASCEND) === 0){
//We can slope the other way if this connection isn't already a slope
$possible[$opposite | RailConnectionInfo::FLAG_ASCEND] = true;
}
return $possible;
}
private function tryReconnect() : void{
$thisConnections = $this->getConnectedDirections();
$changed = false;
$world = $this->position->getWorld();
do{
$possible = $this->getPossibleConnectionDirections($thisConnections);
$continue = false;
foreach($possible as $thisSide => $_){
$otherSide = Facing::opposite($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
$other = $this->getSide($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
if(($thisSide & RailConnectionInfo::FLAG_ASCEND) !== 0){
$other = $other->getSide(Facing::UP);
}elseif(!($other instanceof BaseRail)){ //check if other rails can slope up to meet this one
$other = $other->getSide(Facing::DOWN);
$otherSide |= RailConnectionInfo::FLAG_ASCEND;
}
if(!($other instanceof BaseRail) || count($otherConnections = $other->getConnectedDirections()) >= 2){
//we can only connect to a rail that has less than 2 connections
continue;
}
$otherPossible = $other->getPossibleConnectionDirections($otherConnections);
if(isset($otherPossible[$otherSide])){
$otherConnections[] = $otherSide;
$other->setConnections($otherConnections);
$world->setBlock($other->position, $other);
$changed = true;
$thisConnections[] = $thisSide;
$continue = count($thisConnections) < 2;
break; //force recomputing possible directions, since this connection could invalidate others
}
}
}while($continue);
if($changed){
$this->setConnections($thisConnections);
$world->setBlock($this->position, $this);
}
}
/**
* @param int[] $connections
*/
private function setConnections(array $connections) : void{
if(count($connections) === 1){
$connections[] = Facing::opposite($connections[0] & ~RailConnectionInfo::FLAG_ASCEND);
}elseif(count($connections) !== 2){
throw new \InvalidArgumentException("Expected exactly 2 connections, got " . count($connections));
}
$this->setShapeFromConnections($connections);
}
public function onNearbyBlockChange() : void{
$world = $this->position->getWorld();
if(!$this->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){
$world->useBreakOn($this->position);
}else{
foreach($this->getCurrentShapeConnections() as $connection){
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && !$this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->getSupportType(Facing::UP)->hasEdgeSupport()){
$world->useBreakOn($this->position);
break;
}
}
}
}
}

View File

@ -1,165 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Sign as TileSign;
use pocketmine\block\utils\SignText;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\SignChangeEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
use pocketmine\world\BlockTransaction;
use function array_map;
use function assert;
use function strlen;
abstract class BaseSign extends Transparent{
protected SignText $text;
protected ?int $editorEntityRuntimeId = null;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
parent::__construct($idInfo, $name, $breakInfo);
$this->text = new SignText();
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileSign){
$this->text = $tile->getText();
$this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId();
}
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileSign);
$tile->setText($this->text);
$tile->setEditorEntityRuntimeId($this->editorEntityRuntimeId);
}
public function isSolid() : bool{
return false;
}
public function getMaxStackSize() : int{
return 16;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
abstract protected function getSupportingFace() : int;
public function onNearbyBlockChange() : void{
if($this->getSide($this->getSupportingFace())->getId() === BlockLegacyIds::AIR){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
$this->editorEntityRuntimeId = $player->getId();
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onPostPlace() : void{
$player = $this->editorEntityRuntimeId !== null ?
$this->position->getWorld()->getEntity($this->editorEntityRuntimeId) :
null;
if($player instanceof Player){
$player->openSignEditor($this->position);
}
}
/**
* Returns an object containing information about the sign text.
*/
public function getText() : SignText{
return $this->text;
}
/** @return $this */
public function setText(SignText $text) : self{
$this->text = $text;
return $this;
}
/**
* Sets the runtime entity ID of the player editing this sign. Only this player will be able to edit the sign.
* This is used to prevent multiple players from editing the same sign at the same time, and to prevent players
* from editing signs they didn't place.
*/
public function getEditorEntityRuntimeId() : ?int{ return $this->editorEntityRuntimeId; }
/** @return $this */
public function setEditorEntityRuntimeId(?int $editorEntityRuntimeId) : self{
$this->editorEntityRuntimeId = $editorEntityRuntimeId;
return $this;
}
/**
* Called by the player controller (network session) to update the sign text, firing events as appropriate.
*
* @return bool if the sign update was successful.
* @throws \UnexpectedValueException if the text payload is too large
*/
public function updateText(Player $author, SignText $text) : bool{
$size = 0;
foreach($text->getLines() as $line){
$size += strlen($line);
}
if($size > 1000){
throw new \UnexpectedValueException($author->getName() . " tried to write $size bytes of text onto a sign (bigger than max 1000)");
}
$ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) : string{
return TextFormat::clean($line, false);
}, $text->getLines())));
if($this->editorEntityRuntimeId === null || $this->editorEntityRuntimeId !== $author->getId()){
$ev->cancel();
}
$ev->call();
if(!$ev->isCancelled()){
$this->setText($ev->getNewText());
$this->setEditorEntityRuntimeId(null);
$this->position->getWorld()->setBlock($this->position, $this);
return true;
}
return false;
}
}

View File

@ -1,227 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Bed as TileBed;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\bedrock\DyeColorIdMap;
use pocketmine\entity\Entity;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
use pocketmine\world\BlockTransaction;
use pocketmine\world\World;
class Bed extends Transparent{
use ColoredTrait;
use HorizontalFacingTrait;
protected bool $occupied = false;
protected bool $head = false;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::RED();
parent::__construct($idInfo, $name, $breakInfo);
}
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) |
($this->occupied ? BlockLegacyMetadata::BED_FLAG_OCCUPIED : 0) |
($this->head ? BlockLegacyMetadata::BED_FLAG_HEAD : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
$this->occupied = ($stateMeta & BlockLegacyMetadata::BED_FLAG_OCCUPIED) !== 0;
$this->head = ($stateMeta & BlockLegacyMetadata::BED_FLAG_HEAD) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
//read extra state information from the tile - this is an ugly hack
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBed){
$this->color = $tile->getColor();
}
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
//extra block properties storage hack
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBed){
$tile->setColor($this->color);
}
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 16)];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function isHeadPart() : bool{
return $this->head;
}
/** @return $this */
public function setHead(bool $head) : self{
$this->head = $head;
return $this;
}
public function isOccupied() : bool{
return $this->occupied;
}
/** @return $this */
public function setOccupied(bool $occupied = true) : self{
$this->occupied = $occupied;
return $this;
}
private function getOtherHalfSide() : int{
return $this->head ? Facing::opposite($this->facing) : $this->facing;
}
public function getOtherHalf() : ?Bed{
$other = $this->getSide($this->getOtherHalfSide());
if($other instanceof Bed && $other->head !== $this->head && $other->facing === $this->facing){
return $other;
}
return null;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
$other = $this->getOtherHalf();
$playerPos = $player->getPosition();
if($other === null){
$player->sendMessage(TextFormat::GRAY . "This bed is incomplete");
return true;
}elseif($playerPos->distanceSquared($this->position) > 4 && $playerPos->distanceSquared($other->position) > 4){
$player->sendMessage(KnownTranslationFactory::tile_bed_tooFar()->prefix(TextFormat::GRAY));
return true;
}
$time = $this->position->getWorld()->getTimeOfDay();
$isNight = ($time >= World::TIME_NIGHT && $time < World::TIME_SUNRISE);
if(!$isNight){
$player->sendMessage(KnownTranslationFactory::tile_bed_noSleep()->prefix(TextFormat::GRAY));
return true;
}
$b = ($this->isHeadPart() ? $this : $other);
if($b->isOccupied()){
$player->sendMessage(KnownTranslationFactory::tile_bed_occupied()->prefix(TextFormat::GRAY));
return true;
}
$player->sleepOn($b->position);
}
return true;
}
public function onNearbyBlockChange() : void{
if(!$this->head && ($other = $this->getOtherHalf()) !== null && $other->occupied !== $this->occupied){
$this->occupied = $other->occupied;
$this->position->getWorld()->setBlock($this->position, $this);
}
}
public function onEntityLand(Entity $entity) : ?float{
if($entity instanceof Living && $entity->isSneaking()){
return null;
}
$entity->fallDistance *= 0.5;
return $entity->getMotion()->y * -3 / 4; // 2/3 in Java, according to the wiki
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($this->getSide(Facing::DOWN))){
$this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH;
$next = $this->getSide($this->getOtherHalfSide());
if($next->canBeReplaced() && $this->canBeSupportedBy($next->getSide(Facing::DOWN))){
$nextState = clone $this;
$nextState->head = true;
$tx->addBlock($blockReplace->position, $this)->addBlock($next->position, $nextState);
return true;
}
}
return false;
}
public function getDrops(Item $item) : array{
if($this->head){
return parent::getDrops($item);
}
return [];
}
protected function writeStateToItemMeta() : int{
return DyeColorIdMap::getInstance()->toId($this->color);
}
public function getAffectedBlocks() : array{
if(($other = $this->getOtherHalf()) !== null){
return [$this, $other];
}
return parent::getAffectedBlocks();
}
private function canBeSupportedBy(Block $block) : bool{
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE());
}
}

View File

@ -1,51 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
class Bedrock extends Opaque{
private bool $burnsForever = false;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->burnsForever = ($stateMeta & BlockLegacyMetadata::BEDROCK_FLAG_INFINIBURN) !== 0;
}
protected function writeStateToMeta() : int{
return $this->burnsForever ? BlockLegacyMetadata::BEDROCK_FLAG_INFINIBURN : 0;
}
public function getStateBitmask() : int{
return 0b1;
}
public function burnsForever() : bool{
return $this->burnsForever;
}
/** @return $this */
public function setBurnsForever(bool $burnsForever) : self{
$this->burnsForever = $burnsForever;
return $this;
}
}

View File

@ -1,187 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Bell as TileBell;
use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\BellRingSound;
final class Bell extends Transparent{
use HorizontalFacingTrait;
private BellAttachmentType $attachmentType;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->attachmentType = BellAttachmentType::FLOOR();
parent::__construct($idInfo, $name, $breakInfo);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->setFacing(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03));
$attachmentType = [
BlockLegacyMetadata::BELL_ATTACHMENT_FLOOR => BellAttachmentType::FLOOR(),
BlockLegacyMetadata::BELL_ATTACHMENT_CEILING => BellAttachmentType::CEILING(),
BlockLegacyMetadata::BELL_ATTACHMENT_ONE_WALL => BellAttachmentType::ONE_WALL(),
BlockLegacyMetadata::BELL_ATTACHMENT_TWO_WALLS => BellAttachmentType::TWO_WALLS()
][($stateMeta >> 2) & 0b11] ?? null;
if($attachmentType === null){
throw new InvalidBlockStateException("No such attachment type");
}
$this->setAttachmentType($attachmentType);
}
public function writeStateToMeta() : int{
$attachmentTypeMeta = [
BellAttachmentType::FLOOR()->id() => BlockLegacyMetadata::BELL_ATTACHMENT_FLOOR,
BellAttachmentType::CEILING()->id() => BlockLegacyMetadata::BELL_ATTACHMENT_CEILING,
BellAttachmentType::ONE_WALL()->id() => BlockLegacyMetadata::BELL_ATTACHMENT_ONE_WALL,
BellAttachmentType::TWO_WALLS()->id() => BlockLegacyMetadata::BELL_ATTACHMENT_TWO_WALLS
][$this->getAttachmentType()->id()] ?? null;
if($attachmentTypeMeta === null){
throw new AssumptionFailedError("Mapping should cover all cases");
}
return BlockDataSerializer::writeLegacyHorizontalFacing($this->getFacing()) | ($attachmentTypeMeta << 2);
}
public function getStateBitmask() : int{
return 0b1111;
}
protected function recalculateCollisionBoxes() : array{
if($this->attachmentType->equals(BellAttachmentType::FLOOR())){
return [
AxisAlignedBB::one()->squash(Facing::axis($this->facing), 1 / 4)->trim(Facing::UP, 3 / 16)
];
}
if($this->attachmentType->equals(BellAttachmentType::CEILING())){
return [
AxisAlignedBB::one()->contract(1 / 4, 0, 1 / 4)->trim(Facing::DOWN, 1 / 4)
];
}
$box = AxisAlignedBB::one()
->squash(Facing::axis(Facing::rotateY($this->facing, true)), 1 / 4)
->trim(Facing::UP, 1 / 16)
->trim(Facing::DOWN, 1 / 4);
return [
$this->attachmentType->equals(BellAttachmentType::ONE_WALL()) ? $box->trim($this->facing, 3 / 16) : $box
];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function getAttachmentType() : BellAttachmentType{ return $this->attachmentType; }
/** @return $this */
public function setAttachmentType(BellAttachmentType $attachmentType) : self{
$this->attachmentType = $attachmentType;
return $this;
}
private function canBeSupportedBy(Block $block, int $face) : bool{
return !$block->getSupportType($face)->equals(SupportType::NONE());
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face === Facing::UP){
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->down()), Facing::UP)){
return false;
}
if($player !== null){
$this->setFacing(Facing::opposite($player->getHorizontalFacing()));
}
$this->setAttachmentType(BellAttachmentType::FLOOR());
}elseif($face === Facing::DOWN){
if(!$this->canBeSupportedBy($tx->fetchBlock($this->position->up()), Facing::DOWN)){
return false;
}
$this->setAttachmentType(BellAttachmentType::CEILING());
}else{
$this->setFacing($face);
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide(Facing::opposite($face))), $face)){
$this->setAttachmentType(BellAttachmentType::ONE_WALL());
}else{
return false;
}
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide($face)), Facing::opposite($face))){
$this->setAttachmentType(BellAttachmentType::TWO_WALLS());
}
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if(
($this->attachmentType->equals(BellAttachmentType::CEILING()) && !$this->canBeSupportedBy($this->getSide(Facing::UP), Facing::DOWN)) ||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && !$this->canBeSupportedBy($this->getSide(Facing::DOWN), Facing::UP)) ||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) && !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)) ||
($this->attachmentType->equals(BellAttachmentType::TWO_WALLS()) && (!$this->canBeSupportedBy($this->getSide($this->facing), Facing::opposite($this->facing)) || !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)))
){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
$faceHit = Facing::opposite($player->getHorizontalFacing());
if(
$this->attachmentType->equals(BellAttachmentType::CEILING()) ||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)) ||
(
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
)
){
$this->ring($faceHit);
return true;
}
}
return false;
}
public function ring(int $faceHit) : void{
$world = $this->position->getWorld();
$world->addSound($this->position, new BellRingSound());
$tile = $world->getTile($this->position);
if($tile instanceof TileBell){
$world->broadcastPacketToViewers($this->position, $tile->createFakeUpdatePacket($faceHit));
}
}
}

View File

@ -1,748 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
/**
* All Block classes are in here
*/
namespace pocketmine\block;
use pocketmine\block\tile\Spawnable;
use pocketmine\block\tile\Tile;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\block\utils\SupportType;
use pocketmine\entity\Entity;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\format\Chunk;
use pocketmine\world\Position;
use pocketmine\world\World;
use function assert;
use function count;
use function dechex;
use const PHP_INT_MAX;
class Block{
public const INTERNAL_METADATA_BITS = 4;
public const INTERNAL_METADATA_MASK = ~(~0 << self::INTERNAL_METADATA_BITS);
protected BlockIdentifier $idInfo;
protected string $fallbackName;
protected BlockBreakInfo $breakInfo;
protected Position $position;
/** @var AxisAlignedBB[]|null */
protected ?array $collisionBoxes = null;
/**
* @param string $name English name of the block type (TODO: implement translations)
*/
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
if(($idInfo->getVariant() & $this->getStateBitmask()) !== 0){
throw new \InvalidArgumentException("Variant 0x" . dechex($idInfo->getVariant()) . " collides with state bitmask 0x" . dechex($this->getStateBitmask()));
}
$this->idInfo = $idInfo;
$this->fallbackName = $name;
$this->breakInfo = $breakInfo;
$this->position = new Position(0, 0, 0, null);
}
public function __clone(){
$this->position = clone $this->position;
}
/**
* Returns an object containing information about how to identify and store this block type, such as its legacy
* numeric ID(s), tile type (if any), and legacy variant metadata.
*/
public function getIdInfo() : BlockIdentifier{
return $this->idInfo;
}
/**
* Returns the printable English name of the block.
*/
public function getName() : string{
return $this->fallbackName;
}
/**
* @deprecated
*
* Returns the legacy numeric Minecraft block ID.
*/
public function getId() : int{
return $this->idInfo->getBlockId();
}
/**
* @internal
*
* Returns the full blockstate ID of this block. This is a compact way of representing a blockstate used to store
* blocks in chunks at runtime.
*
* This ID can be used to later obtain a copy of this block using {@link BlockFactory::get()}.
*/
public function getFullId() : int{
return ($this->getId() << self::INTERNAL_METADATA_BITS) | $this->getMeta();
}
/**
* Returns the block as an item.
* State information such as facing, powered/unpowered, open/closed, etc., is discarded.
* Type information such as colour, wood type, etc. is preserved.
*/
public function asItem() : Item{
return ItemFactory::getInstance()->get(
$this->idInfo->getItemId(),
$this->idInfo->getVariant() | $this->writeStateToItemMeta()
);
}
/**
* @deprecated
*
* Returns the legacy Minecraft block meta value. This is a mixed-purpose value, which is used to store different
* things for different blocks.
*/
public function getMeta() : int{
$stateMeta = $this->writeStateToMeta();
assert(($stateMeta & ~$this->getStateBitmask()) === 0);
return $this->idInfo->getVariant() | $stateMeta;
}
protected function writeStateToItemMeta() : int{
return 0;
}
/**
* Returns a bitmask used to extract state bits from block metadata.
* This is used to remove unwanted information from the legacy meta value when getting the block as an item.
*/
public function getStateBitmask() : int{
return 0;
}
protected function writeStateToMeta() : int{
return 0;
}
/**
* @throws InvalidBlockStateException
*/
public function readStateFromData(int $id, int $stateMeta) : void{
//NOOP
}
/**
* Called when this block is created, set, or has a neighbouring block update, to re-detect dynamic properties which
* are not saved on the world.
*
* Clears any cached precomputed objects, such as bounding boxes. Remove any outdated precomputed things such as
* AABBs and force recalculation.
*/
public function readStateFromWorld() : void{
$this->collisionBoxes = null;
}
/**
* Writes information about the block into the world. This writes the blockstate ID into the chunk, and creates
* and/or removes tiles as necessary.
*
* Note: Do not call this directly. Pass the block to {@link World::setBlock()} instead.
*/
public function writeStateToWorld() : void{
$world = $this->position->getWorld();
$world->getOrLoadChunkAtPosition($this->position)->setFullBlock($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getFullId());
$tileType = $this->idInfo->getTileClass();
$oldTile = $world->getTile($this->position);
if($oldTile !== null){
if($tileType === null || !($oldTile instanceof $tileType)){
$oldTile->close();
$oldTile = null;
}elseif($oldTile instanceof Spawnable){
$oldTile->clearSpawnCompoundCache(); //destroy old network cache
}
}
if($oldTile === null && $tileType !== null){
/**
* @var Tile $tile
* @see Tile::__construct()
*/
$tile = new $tileType($world, $this->position->asVector3());
$world->addTile($tile);
}
}
/**
* Returns a type ID that identifies this type of block. This does not include information like facing, open/closed,
* powered/unpowered, etc.
*/
public function getTypeId() : int{
return ($this->idInfo->getBlockId() << Block::INTERNAL_METADATA_BITS) | $this->idInfo->getVariant();
}
/**
* Returns whether the given block has an equivalent type to this one. This compares the type IDs.
*
* Note: This ignores additional IDs used to represent additional states. This means that, for example, a lit
* furnace and unlit furnace are considered the same type.
*/
public function isSameType(Block $other) : bool{
return $this->getTypeId() === $other->getTypeId();
}
/**
* Returns whether the given block has the same type and properties as this block.
*/
public function isSameState(Block $other) : bool{
return $this->getFullId() === $other->getFullId();
}
/**
* AKA: Block->isPlaceable
*/
public function canBePlaced() : bool{
return true;
}
/**
* Returns whether this block can be replaced by another block placed in the same position.
*/
public function canBeReplaced() : bool{
return false;
}
/**
* Returns whether this block can replace the given block in the given placement conditions.
* This is used to allow slabs of the same type to combine into double slabs.
*/
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
return $blockReplace->canBeReplaced();
}
/**
* Generates a block transaction to set all blocks affected by placing this block. Usually this is just the block
* itself, but may be multiple blocks in some cases (such as doors).
*
* @param BlockTransaction $tx Blocks to be set should be added to this transaction (do not modify thr world directly)
* @param Item $item Item used to place the block
* @param Block $blockReplace Block expected to be replaced
* @param Block $blockClicked Block that was clicked using the item
* @param int $face Face of the clicked block which was clicked
* @param Vector3 $clickVector Exact position inside the clicked block where the click occurred, relative to the block's position
* @param Player|null $player Player who placed the block, or null if it was not a player
*
* @return bool whether the placement should go ahead
*/
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$tx->addBlock($blockReplace->position, $this);
return true;
}
/**
* Called immediately after the block has been placed in the world. Since placement uses a block transaction, some
* things may not be possible until after the transaction has been executed.
*/
public function onPostPlace() : void{
}
/**
* Returns an object containing information about the destruction requirements of this block.
*/
public function getBreakInfo() : BlockBreakInfo{
return $this->breakInfo;
}
/**
* Do the actions needed so the block is broken with the Item
*/
public function onBreak(Item $item, ?Player $player = null) : bool{
$world = $this->position->getWorld();
if(($t = $world->getTile($this->position)) !== null){
$t->onBlockDestroyed();
}
$world->setBlock($this->position, VanillaBlocks::AIR());
return true;
}
/**
* Called when this block or a block immediately adjacent to it changes state.
*/
public function onNearbyBlockChange() : void{
}
/**
* Returns whether random block updates will be done on this block.
*/
public function ticksRandomly() : bool{
return false;
}
/**
* Called when this block is randomly updated due to chunk ticking.
* WARNING: This will not be called if {@link Block::ticksRandomly()} does not return true!
*/
public function onRandomTick() : void{
}
/**
* Called when this block is updated by the delayed blockupdate scheduler in the world.
*/
public function onScheduledUpdate() : void{
}
/**
* Do actions when interacted by Item. Returns if it has done anything
*/
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
return false;
}
/**
* Called when this block is attacked (left-clicked) by a player attempting to start breaking it in survival.
*
* @return bool if an action took place, prevents starting to break the block if true.
*/
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
return false;
}
/**
* Returns a multiplier applied to the velocity of entities moving on top of this block. A higher value will make
* the block more slippery (like ice).
*
* @return float 0.0-1.0
*/
public function getFrictionFactor() : float{
return 0.6;
}
/**
* Returns the amount of light emitted by this block.
*
* @return int 0-15
*/
public function getLightLevel() : int{
return 0;
}
/**
* Returns the amount of light this block will filter out when light passes through this block.
* This value is used in light spread calculation.
*
* @return int 0-15
*/
public function getLightFilter() : int{
return $this->isTransparent() ? 0 : 15;
}
/**
* Returns whether this block blocks direct sky light from passing through it. This is independent from the light
* filter value, which is used during propagation.
*
* In most cases, this is the same as isTransparent(); however, some special cases exist such as leaves and cobwebs,
* which don't have any additional effect on light propagation, but don't allow direct sky light to pass through.
*/
public function blocksDirectSkyLight() : bool{
return $this->getLightFilter() > 0;
}
public function isTransparent() : bool{
return false;
}
public function isSolid() : bool{
return true;
}
/**
* AKA: Block->isFlowable
*/
public function canBeFlowedInto() : bool{
return false;
}
/**
* Returns whether entities can climb up this block.
*/
public function canClimb() : bool{
return false;
}
final public function getPosition() : Position{
return $this->position;
}
/**
* @internal
*/
final public function position(World $world, int $x, int $y, int $z) : void{
$this->position = new Position($x, $y, $z, $world);
}
/**
* Returns an array of Item objects to be dropped
*
* @return Item[]
*/
public function getDrops(Item $item) : array{
if($this->breakInfo->isToolCompatible($item)){
if($this->isAffectedBySilkTouch() && $item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){
return $this->getSilkTouchDrops($item);
}
return $this->getDropsForCompatibleTool($item);
}
return $this->getDropsForIncompatibleTool($item);
}
/**
* Returns an array of Items to be dropped when the block is broken using the correct tool type.
*
* @return Item[]
*/
public function getDropsForCompatibleTool(Item $item) : array{
return [$this->asItem()];
}
/**
* Returns the items dropped by this block when broken with an incorrect tool type (or tool with a too-low tier).
*
* @return Item[]
*/
public function getDropsForIncompatibleTool(Item $item) : array{
return [];
}
/**
* Returns an array of Items to be dropped when the block is broken using a compatible Silk Touch-enchanted tool.
*
* @return Item[]
*/
public function getSilkTouchDrops(Item $item) : array{
return [$this->asItem()];
}
/**
* Returns how much XP will be dropped by breaking this block with the given item.
*/
public function getXpDropForTool(Item $item) : int{
if($item->hasEnchantment(VanillaEnchantments::SILK_TOUCH()) || !$this->breakInfo->isToolCompatible($item)){
return 0;
}
return $this->getXpDropAmount();
}
/**
* Returns how much XP this block will drop when broken with an appropriate tool.
*/
protected function getXpDropAmount() : int{
return 0;
}
/**
* Returns whether Silk Touch enchanted tools will cause this block to drop as itself.
*/
public function isAffectedBySilkTouch() : bool{
return false;
}
/**
* Returns the item that players will equip when middle-clicking on this block.
* If addUserData is true, additional data may be added, such as banner patterns, chest contents, etc.
*/
public function getPickedItem(bool $addUserData = false) : Item{
$item = $this->asItem();
if($addUserData){
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof Tile){
$nbt = $tile->getCleanedNBT();
if($nbt instanceof CompoundTag){
$item->setCustomBlockData($nbt);
$item->setLore(["+(DATA)"]);
}
}
}
return $item;
}
/**
* Returns the time in ticks which the block will fuel a furnace for.
*/
public function getFuelTime() : int{
return 0;
}
/**
* Returns the maximum number of this block that can fit into a single item stack.
*/
public function getMaxStackSize() : int{
return 64;
}
/**
* Returns the chance that the block will catch fire from nearby fire sources. Higher values lead to faster catching
* fire.
*/
public function getFlameEncouragement() : int{
return 0;
}
/**
* Returns the base flammability of this block. Higher values lead to the block burning away more quickly.
*/
public function getFlammability() : int{
return 0;
}
/**
* Returns whether fire lit on this block will burn indefinitely.
*/
public function burnsForever() : bool{
return false;
}
/**
* Returns whether this block can catch fire.
*/
public function isFlammable() : bool{
return $this->getFlammability() > 0;
}
/**
* Called when this block is burned away by being on fire.
*/
public function onIncinerate() : void{
}
/**
* Returns the Block on the side $side, works like Vector3::getSide()
*
* @return Block
*/
public function getSide(int $side, int $step = 1){
if($this->position->isValid()){
return $this->position->getWorld()->getBlock($this->position->getSide($side, $step));
}
throw new \LogicException("Block does not have a valid world");
}
/**
* Returns the 4 blocks on the horizontal axes around the block (north, south, east, west)
*
* @return Block[]|\Generator
* @phpstan-return \Generator<int, Block, void, void>
*/
public function getHorizontalSides() : \Generator{
$world = $this->position->getWorld();
foreach($this->position->sidesAroundAxis(Axis::Y) as $vector3){
yield $world->getBlock($vector3);
}
}
/**
* Returns the six blocks around this block.
*
* @return Block[]|\Generator
* @phpstan-return \Generator<int, Block, void, void>
*/
public function getAllSides() : \Generator{
$world = $this->position->getWorld();
foreach($this->position->sides() as $vector3){
yield $world->getBlock($vector3);
}
}
/**
* Returns a list of blocks that this block is part of. In most cases, only contains the block itself, but in cases
* such as double plants, beds and doors, will contain both halves.
*
* @return Block[]
*/
public function getAffectedBlocks() : array{
return [$this];
}
/**
* @return string
*/
public function __toString(){
return "Block[" . $this->getName() . "] (" . $this->getId() . ":" . $this->getMeta() . ")";
}
/**
* Returns whether any of the block's collision boxes intersect with the given AxisAlignedBB.
*/
public function collidesWithBB(AxisAlignedBB $bb) : bool{
foreach($this->getCollisionBoxes() as $bb2){
if($bb->intersectsWith($bb2)){
return true;
}
}
return false;
}
/**
* Returns whether the block has actions to be executed when an entity enters its cell (full cube space).
*
* @see Block::onEntityInside()
*/
public function hasEntityCollision() : bool{
return false;
}
/**
* Called when an entity's bounding box clips inside this block's cell. Note that the entity may not be intersecting
* with the collision box or bounding box.
*
* WARNING: This will not be called if {@link Block::hasEntityCollision()} returns false.
*
* @return bool Whether the block is still the same after the intersection. If it changed (e.g. due to an explosive
* being ignited), this should return false.
*/
public function onEntityInside(Entity $entity) : bool{
return true;
}
/**
* Returns a direction vector describing which way an entity intersecting this block should be pushed.
* This is used by liquids to push entities in liquid currents.
*
* The returned vector is summed with vectors from every other block the entity is intersecting, and normalized to
* produce a final direction vector.
*
* WARNING: This will not be called if {@link Block::hasEntityCollision()} does not return true!
*/
public function addVelocityToEntity(Entity $entity) : ?Vector3{
return null;
}
/**
* Called when an entity lands on this block (usually due to falling).
* @return float|null The new vertical velocity of the entity, or null if unchanged.
*/
public function onEntityLand(Entity $entity) : ?float{
return null;
}
/**
* Returns an array of collision bounding boxes for this block.
* These are used for:
* - entity movement collision checks (to ensure entities can't clip through blocks)
* - projectile flight paths
* - block placement (to ensure the player can't place blocks inside itself or another entity)
* - anti-cheat checks in plugins
*
* @return AxisAlignedBB[]
*/
final public function getCollisionBoxes() : array{
if($this->collisionBoxes === null){
$this->collisionBoxes = $this->recalculateCollisionBoxes();
$extraOffset = $this->getModelPositionOffset();
$offset = $extraOffset !== null ? $this->position->addVector($extraOffset) : $this->position;
foreach($this->collisionBoxes as $bb){
$bb->offset($offset->x, $offset->y, $offset->z);
}
}
return $this->collisionBoxes;
}
/**
* Returns an additional fractional vector to shift the block model's position by based on the current position.
* Used to randomize position of things like bamboo canes and tall grass.
*/
public function getModelPositionOffset() : ?Vector3{
return null;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()];
}
/**
* Returns the type of support that the block can provide on the given face. This is used to determine whether
* blocks placed on the given face can be supported by this block.
*/
public function getSupportType(int $facing) : SupportType{
return SupportType::FULL();
}
public function isFullCube() : bool{
$bb = $this->getCollisionBoxes();
return count($bb) === 1 && $bb[0]->getAverageEdgeLength() >= 1 && $bb[0]->isCube();
}
/**
* Performs a ray trace along the line between the two positions using the block's collision boxes.
* Returns the intersection point closest to pos1, or null if no intersection occurred.
*/
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
$bbs = $this->getCollisionBoxes();
if(count($bbs) === 0){
return null;
}
/** @var RayTraceResult|null $currentHit */
$currentHit = null;
/** @var int|float $currentDistance */
$currentDistance = PHP_INT_MAX;
foreach($bbs as $bb){
$nextHit = $bb->calculateIntercept($pos1, $pos2);
if($nextHit === null){
continue;
}
$nextDistance = $nextHit->hitVector->distanceSquared($pos1);
if($nextDistance < $currentDistance){
$currentHit = $nextHit;
$currentDistance = $nextDistance;
}
}
return $currentHit;
}
}

View File

@ -1,147 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use function get_class;
class BlockBreakInfo{
/**
* If the tool is the correct type and high enough harvest level (tool tier), base break time is hardness multiplied
* by this value.
*/
public const COMPATIBLE_TOOL_MULTIPLIER = 1.5;
/**
* If the tool is an incorrect type or too low harvest level (tool tier), base break time is hardness multiplied by
* this value.
*/
public const INCOMPATIBLE_TOOL_MULTIPLIER = 5.0;
private float $blastResistance;
/**
* @param float|null $blastResistance default 5x hardness
*/
public function __construct(
private float $hardness,
private int $toolType = BlockToolType::NONE,
private int $toolHarvestLevel = 0,
?float $blastResistance = null
){
$this->blastResistance = $blastResistance ?? $hardness * 5;
}
public static function instant(int $toolType = BlockToolType::NONE, int $toolHarvestLevel = 0) : self{
return new self(0.0, $toolType, $toolHarvestLevel, 0.0);
}
public static function indestructible(float $blastResistance = 18000000.0) : self{
return new self(-1.0, BlockToolType::NONE, 0, $blastResistance);
}
/**
* Returns a base value used to compute block break times.
*/
public function getHardness() : float{
return $this->hardness;
}
/**
* Returns whether the block can be broken at all.
*/
public function isBreakable() : bool{
return $this->hardness >= 0;
}
/**
* Returns whether this block can be instantly broken.
*/
public function breaksInstantly() : bool{
return $this->hardness == 0.0;
}
/**
* Returns the block's resistance to explosions. Usually 5x hardness.
*/
public function getBlastResistance() : float{
return $this->blastResistance;
}
public function getToolType() : int{
return $this->toolType;
}
/**
* Returns the level of tool required to harvest the block (for normal blocks). When the tool type matches the
* block's required tool type, the tool must have a harvest level greater than or equal to this value to be able to
* successfully harvest the block.
*
* If the block requires a specific minimum tier of tiered tool, the minimum tier required should be returned.
* Otherwise, 1 should be returned if a tool is required, 0 if not.
*
* @see Item::getBlockToolHarvestLevel()
*/
public function getToolHarvestLevel() : int{
return $this->toolHarvestLevel;
}
/**
* Returns whether the specified item is the proper tool to use for breaking this block. This checks tool type and
* harvest level requirement.
*
* In most cases this is also used to determine whether block drops should be created or not, except in some
* special cases such as vines.
*/
public function isToolCompatible(Item $tool) : bool{
if($this->hardness < 0){
return false;
}
return $this->toolType === BlockToolType::NONE || $this->toolHarvestLevel === 0 || (
($this->toolType & $tool->getBlockToolType()) !== 0 && $tool->getBlockToolHarvestLevel() >= $this->toolHarvestLevel);
}
/**
* Returns the seconds that this block takes to be broken using an specific Item
*
* @throws \InvalidArgumentException if the item efficiency is not a positive number
*/
public function getBreakTime(Item $item) : float{
$base = $this->hardness;
if($this->isToolCompatible($item)){
$base *= self::COMPATIBLE_TOOL_MULTIPLIER;
}else{
$base *= self::INCOMPATIBLE_TOOL_MULTIPLIER;
}
$efficiency = $item->getMiningEfficiency(($this->toolType & $item->getBlockToolType()) !== 0);
if($efficiency <= 0){
throw new \InvalidArgumentException(get_class($item) . " has invalid mining efficiency: expected >= 0, got $efficiency");
}
$base /= $efficiency;
return $base;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,69 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Tile;
use pocketmine\utils\Utils;
class BlockIdentifier{
/**
* @phpstan-param class-string<Tile>|null $tileClass
*/
public function __construct(
private int $blockId,
private int $variant,
private ?int $itemId = null,
private ?string $tileClass = null
){
if($tileClass !== null){
Utils::testValidInstance($tileClass, Tile::class);
}
}
public function getBlockId() : int{
return $this->blockId;
}
/**
* @return int[]
*/
public function getAllBlockIds() : array{
return [$this->blockId];
}
public function getVariant() : int{
return $this->variant;
}
public function getItemId() : int{
return $this->itemId ?? ($this->blockId > 255 ? 255 - $this->blockId : $this->blockId);
}
/**
* @phpstan-return class-string<Tile>|null
*/
public function getTileClass() : ?string{
return $this->tileClass;
}
}

View File

@ -1,59 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use function count;
class BlockIdentifierFlattened extends BlockIdentifier{
/** @var int[] */
private array $additionalIds;
/**
* @param int[] $additionalIds
*/
public function __construct(int $blockId, array $additionalIds, int $variant, ?int $itemId = null, ?string $tileClass = null){
if(count($additionalIds) === 0){
throw new \InvalidArgumentException("Expected at least 1 additional ID");
}
parent::__construct($blockId, $variant, $itemId, $tileClass);
$this->additionalIds = $additionalIds;
}
public function getAdditionalId(int $index) : int{
if(!isset($this->additionalIds[$index])){
throw new \InvalidArgumentException("No such ID at index $index");
}
return $this->additionalIds[$index];
}
public function getSecondId() : int{
return $this->getAdditionalId(0);
}
public function getAllBlockIds() : array{
return [$this->getBlockId(), ...$this->additionalIds];
}
}

View File

@ -1,248 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\BlockIdentifier as BID;
use pocketmine\block\BlockLegacyIds as Ids;
use pocketmine\block\tile\Sign as TileSign;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\TreeType;
use pocketmine\item\ItemIds;
use pocketmine\utils\AssumptionFailedError;
final class BlockLegacyIdHelper{
public static function getWoodenFloorSignIdentifier(TreeType $treeType) : BID{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BID(Ids::SIGN_POST, 0, ItemIds::SIGN, TileSign::class);
case TreeType::SPRUCE()->id():
return new BID(Ids::SPRUCE_STANDING_SIGN, 0, ItemIds::SPRUCE_SIGN, TileSign::class);
case TreeType::BIRCH()->id():
return new BID(Ids::BIRCH_STANDING_SIGN, 0, ItemIds::BIRCH_SIGN, TileSign::class);
case TreeType::JUNGLE()->id():
return new BID(Ids::JUNGLE_STANDING_SIGN, 0, ItemIds::JUNGLE_SIGN, TileSign::class);
case TreeType::ACACIA()->id():
return new BID(Ids::ACACIA_STANDING_SIGN,0, ItemIds::ACACIA_SIGN, TileSign::class);
case TreeType::DARK_OAK()->id():
return new BID(Ids::DARKOAK_STANDING_SIGN, 0, ItemIds::DARKOAK_SIGN, TileSign::class);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getWoodenWallSignIdentifier(TreeType $treeType) : BID{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BID(Ids::WALL_SIGN, 0, ItemIds::SIGN, TileSign::class);
case TreeType::SPRUCE()->id():
return new BID(Ids::SPRUCE_WALL_SIGN, 0, ItemIds::SPRUCE_SIGN, TileSign::class);
case TreeType::BIRCH()->id():
return new BID(Ids::BIRCH_WALL_SIGN, 0, ItemIds::BIRCH_SIGN, TileSign::class);
case TreeType::JUNGLE()->id():
return new BID(Ids::JUNGLE_WALL_SIGN, 0, ItemIds::JUNGLE_SIGN, TileSign::class);
case TreeType::ACACIA()->id():
return new BID(Ids::ACACIA_WALL_SIGN, 0, ItemIds::ACACIA_SIGN, TileSign::class);
case TreeType::DARK_OAK()->id():
return new BID(Ids::DARKOAK_WALL_SIGN, 0, ItemIds::DARKOAK_SIGN, TileSign::class);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getWoodenTrapdoorIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::WOODEN_TRAPDOOR, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_TRAPDOOR, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_TRAPDOOR, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_TRAPDOOR, 0);
case TreeType::ACACIA()->id():
return new BlockIdentifier(Ids::ACACIA_TRAPDOOR, 0);
case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_TRAPDOOR, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getWoodenButtonIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::WOODEN_BUTTON, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_BUTTON, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_BUTTON, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_BUTTON, 0);
case TreeType::ACACIA()->id():
return new BlockIdentifier(Ids::ACACIA_BUTTON, 0);
case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_BUTTON, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getWoodenPressurePlateIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::WOODEN_PRESSURE_PLATE, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_PRESSURE_PLATE, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_PRESSURE_PLATE, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_PRESSURE_PLATE, 0);
case TreeType::ACACIA()->id():
return new BlockIdentifier(Ids::ACACIA_PRESSURE_PLATE, 0);
case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_PRESSURE_PLATE, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getWoodenDoorIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BID(Ids::OAK_DOOR_BLOCK, 0, ItemIds::OAK_DOOR);
case TreeType::SPRUCE()->id():
return new BID(Ids::SPRUCE_DOOR_BLOCK, 0, ItemIds::SPRUCE_DOOR);
case TreeType::BIRCH()->id():
return new BID(Ids::BIRCH_DOOR_BLOCK, 0, ItemIds::BIRCH_DOOR);
case TreeType::JUNGLE()->id():
return new BID(Ids::JUNGLE_DOOR_BLOCK, 0, ItemIds::JUNGLE_DOOR);
case TreeType::ACACIA()->id():
return new BID(Ids::ACACIA_DOOR_BLOCK, 0, ItemIds::ACACIA_DOOR);
case TreeType::DARK_OAK()->id():
return new BID(Ids::DARK_OAK_DOOR_BLOCK, 0, ItemIds::DARK_OAK_DOOR);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getWoodenFenceIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::OAK_FENCE_GATE, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_FENCE_GATE, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_FENCE_GATE, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_FENCE_GATE, 0);
case TreeType::ACACIA()->id():
return new BlockIdentifier(Ids::ACACIA_FENCE_GATE, 0);
case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_FENCE_GATE, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getWoodenStairsIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::OAK_STAIRS, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_STAIRS, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_STAIRS, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_STAIRS, 0);
case TreeType::ACACIA()->id():
return new BlockIdentifier(Ids::ACACIA_STAIRS, 0);
case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_STAIRS, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getStrippedLogIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::STRIPPED_OAK_LOG, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::STRIPPED_SPRUCE_LOG, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::STRIPPED_BIRCH_LOG, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::STRIPPED_JUNGLE_LOG, 0);
case TreeType::ACACIA()->id():
return new BlockIdentifier(Ids::STRIPPED_ACACIA_LOG, 0);
case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::STRIPPED_DARK_OAK_LOG, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getGlazedTerracottaIdentifier(DyeColor $color) : BlockIdentifier{
switch($color->id()){
case DyeColor::WHITE()->id():
return new BlockIdentifier(Ids::WHITE_GLAZED_TERRACOTTA, 0);
case DyeColor::ORANGE()->id():
return new BlockIdentifier(Ids::ORANGE_GLAZED_TERRACOTTA, 0);
case DyeColor::MAGENTA()->id():
return new BlockIdentifier(Ids::MAGENTA_GLAZED_TERRACOTTA, 0);
case DyeColor::LIGHT_BLUE()->id():
return new BlockIdentifier(Ids::LIGHT_BLUE_GLAZED_TERRACOTTA, 0);
case DyeColor::YELLOW()->id():
return new BlockIdentifier(Ids::YELLOW_GLAZED_TERRACOTTA, 0);
case DyeColor::LIME()->id():
return new BlockIdentifier(Ids::LIME_GLAZED_TERRACOTTA, 0);
case DyeColor::PINK()->id():
return new BlockIdentifier(Ids::PINK_GLAZED_TERRACOTTA, 0);
case DyeColor::GRAY()->id():
return new BlockIdentifier(Ids::GRAY_GLAZED_TERRACOTTA, 0);
case DyeColor::LIGHT_GRAY()->id():
return new BlockIdentifier(Ids::SILVER_GLAZED_TERRACOTTA, 0);
case DyeColor::CYAN()->id():
return new BlockIdentifier(Ids::CYAN_GLAZED_TERRACOTTA, 0);
case DyeColor::PURPLE()->id():
return new BlockIdentifier(Ids::PURPLE_GLAZED_TERRACOTTA, 0);
case DyeColor::BLUE()->id():
return new BlockIdentifier(Ids::BLUE_GLAZED_TERRACOTTA, 0);
case DyeColor::BROWN()->id():
return new BlockIdentifier(Ids::BROWN_GLAZED_TERRACOTTA, 0);
case DyeColor::GREEN()->id():
return new BlockIdentifier(Ids::GREEN_GLAZED_TERRACOTTA, 0);
case DyeColor::RED()->id():
return new BlockIdentifier(Ids::RED_GLAZED_TERRACOTTA, 0);
case DyeColor::BLACK()->id():
return new BlockIdentifier(Ids::BLACK_GLAZED_TERRACOTTA, 0);
}
throw new AssumptionFailedError("Switch should cover all colours");
}
public static function getStoneSlabIdentifier(int $stoneSlabId, int $meta) : BlockIdentifierFlattened{
$id = [
1 => [Ids::STONE_SLAB, Ids::DOUBLE_STONE_SLAB],
2 => [Ids::STONE_SLAB2, Ids::DOUBLE_STONE_SLAB2],
3 => [Ids::STONE_SLAB3, Ids::DOUBLE_STONE_SLAB3],
4 => [Ids::STONE_SLAB4, Ids::DOUBLE_STONE_SLAB4]
][$stoneSlabId] ?? null;
if($id === null){
throw new \InvalidArgumentException("Stone slab type should be 1, 2, 3 or 4");
}
return new BlockIdentifierFlattened($id[0], [$id[1]], $meta);
}
}

View File

@ -1,303 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
/**
* Constants for legacy metadata for various blocks.
*/
final class BlockLegacyMetadata{
private function __construct(){
//NOOP
}
public const ANVIL_NORMAL = 0;
public const ANVIL_SLIGHTLY_DAMAGED = 4;
public const ANVIL_VERY_DAMAGED = 8;
public const BAMBOO_FLAG_THICK = 0x01;
public const BAMBOO_FLAG_READY = 0x08;
public const BAMBOO_LEAF_SIZE_SHIFT = 1;
public const BAMBOO_LEAF_SIZE_MASK = 0x03;
public const BAMBOO_SAPLING_FLAG_READY = 0x01;
public const BARREL_FLAG_OPEN = 0x08;
public const BED_FLAG_HEAD = 0x08;
public const BED_FLAG_OCCUPIED = 0x04;
public const BEDROCK_FLAG_INFINIBURN = 0x01;
public const BELL_ATTACHMENT_FLOOR = 0;
public const BELL_ATTACHMENT_CEILING = 1;
public const BELL_ATTACHMENT_ONE_WALL = 2;
public const BELL_ATTACHMENT_TWO_WALLS = 3;
public const BREWING_STAND_FLAG_EAST = 0x01;
public const BREWING_STAND_FLAG_SOUTHWEST = 0x02;
public const BREWING_STAND_FLAG_NORTHWEST = 0x04;
public const BUTTON_FLAG_POWERED = 0x08;
public const CHEMISTRY_COMPOUND_CREATOR = 0;
public const CHEMISTRY_MATERIAL_REDUCER = 4;
public const CHEMISTRY_ELEMENT_CONSTRUCTOR = 8;
public const CHEMISTRY_LAB_TABLE = 12;
public const COLORED_TORCH_BP_BLUE = 0;
public const COLORED_TORCH_BP_PURPLE = 8;
public const COLORED_TORCH_RG_RED = 0;
public const COLORED_TORCH_RG_GREEN = 8;
public const CORAL_BLOCK_FLAG_DEAD = 0x8;
public const CORAL_FAN_EAST_WEST = 0;
public const CORAL_FAN_NORTH_SOUTH = 1;
public const CORAL_FAN_TYPE_MASK = 0x7;
public const CORAL_FAN_HANG_FLAG_DEAD = 0x2;
public const CORAL_FAN_HANG_TUBE = 0;
public const CORAL_FAN_HANG_BRAIN = 1;
public const CORAL_FAN_HANG2_BUBBLE = 0;
public const CORAL_FAN_HANG2_FIRE = 1;
public const CORAL_FAN_HANG3_HORN = 0;
public const CORAL_FAN_HANG_TYPE_MASK = 0x1;
public const CORAL_VARIANT_TUBE = 0;
public const CORAL_VARIANT_BRAIN = 1;
public const CORAL_VARIANT_BUBBLE = 2;
public const CORAL_VARIANT_FIRE = 3;
public const CORAL_VARIANT_HORN = 4;
public const DIRT_FLAG_COARSE = 0x1;
public const DOOR_FLAG_TOP = 0x08;
public const DOOR_BOTTOM_FLAG_OPEN = 0x04;
public const DOOR_TOP_FLAG_RIGHT = 0x01;
public const DOOR_TOP_FLAG_POWERED = 0x02;
public const DOUBLE_PLANT_SUNFLOWER = 0;
public const DOUBLE_PLANT_LILAC = 1;
public const DOUBLE_PLANT_TALLGRASS = 2;
public const DOUBLE_PLANT_LARGE_FERN = 3;
public const DOUBLE_PLANT_ROSE_BUSH = 4;
public const DOUBLE_PLANT_PEONY = 5;
public const DOUBLE_PLANT_FLAG_TOP = 0x08;
public const END_PORTAL_FRAME_FLAG_EYE = 0x04;
public const FENCE_GATE_FLAG_OPEN = 0x04;
public const FENCE_GATE_FLAG_IN_WALL = 0x08;
public const FLOWER_POPPY = 0;
public const FLOWER_BLUE_ORCHID = 1;
public const FLOWER_ALLIUM = 2;
public const FLOWER_AZURE_BLUET = 3;
public const FLOWER_RED_TULIP = 4;
public const FLOWER_ORANGE_TULIP = 5;
public const FLOWER_WHITE_TULIP = 6;
public const FLOWER_PINK_TULIP = 7;
public const FLOWER_OXEYE_DAISY = 8;
public const FLOWER_CORNFLOWER = 9;
public const FLOWER_LILY_OF_THE_VALLEY = 10;
public const FLOWER_POT_FLAG_OCCUPIED = 0x01;
public const HOPPER_FLAG_POWERED = 0x08;
public const INFESTED_STONE = 0;
public const INFESTED_COBBLESTONE = 1;
public const INFESTED_STONE_BRICK = 2;
public const INFESTED_STONE_BRICK_MOSSY = 3;
public const INFESTED_STONE_BRICK_CRACKED = 4;
public const INFESTED_STONE_BRICK_CHISELED = 5;
public const ITEM_FRAME_FLAG_HAS_MAP = 0x04;
public const LANTERN_FLAG_HANGING = 0x01;
public const LEAVES_FLAG_NO_DECAY = 0x04;
public const LEAVES_FLAG_CHECK_DECAY = 0x08;
public const LECTERN_FLAG_POWERED = 0x04;
public const LEVER_FLAG_POWERED = 0x08;
public const LIQUID_FLAG_FALLING = 0x08;
public const MUSHROOM_BLOCK_ALL_PORES = 0;
public const MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER = 1;
public const MUSHROOM_BLOCK_CAP_NORTH_SIDE = 2;
public const MUSHROOM_BLOCK_CAP_NORTHEAST_CORNER = 3;
public const MUSHROOM_BLOCK_CAP_WEST_SIDE = 4;
public const MUSHROOM_BLOCK_CAP_TOP_ONLY = 5;
public const MUSHROOM_BLOCK_CAP_EAST_SIDE = 6;
public const MUSHROOM_BLOCK_CAP_SOUTHWEST_CORNER = 7;
public const MUSHROOM_BLOCK_CAP_SOUTH_SIDE = 8;
public const MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER = 9;
public const MUSHROOM_BLOCK_STEM = 10;
//11, 12 and 13 appear the same as 0
public const MUSHROOM_BLOCK_ALL_CAP = 14;
public const MUSHROOM_BLOCK_ALL_STEM = 15;
public const NETHER_PORTAL_AXIS_X = 1;
public const NETHER_PORTAL_AXIS_Z = 2;
public const NETHER_REACTOR_INACTIVE = 0;
public const NETHER_REACTOR_ACTIVE = 1;
public const NETHER_REACTOR_USED = 2;
public const PRESSURE_PLATE_FLAG_POWERED = 0x01;
public const PRISMARINE_NORMAL = 0;
public const PRISMARINE_DARK = 1;
public const PRISMARINE_BRICKS = 2;
public const PURPUR_NORMAL = 0;
public const PURPUR_PILLAR = 2;
public const QUARTZ_NORMAL = 0;
public const QUARTZ_CHISELED = 1;
public const QUARTZ_PILLAR = 2;
public const QUARTZ_SMOOTH = 3;
public const RAIL_STRAIGHT_NORTH_SOUTH = 0;
public const RAIL_STRAIGHT_EAST_WEST = 1;
public const RAIL_ASCENDING_EAST = 2;
public const RAIL_ASCENDING_WEST = 3;
public const RAIL_ASCENDING_NORTH = 4;
public const RAIL_ASCENDING_SOUTH = 5;
public const RAIL_CURVE_SOUTHEAST = 6;
public const RAIL_CURVE_SOUTHWEST = 7;
public const RAIL_CURVE_NORTHWEST = 8;
public const RAIL_CURVE_NORTHEAST = 9;
public const REDSTONE_COMPARATOR_FLAG_SUBTRACT = 0x04;
public const REDSTONE_COMPARATOR_FLAG_POWERED = 0x08;
public const REDSTONE_RAIL_FLAG_POWERED = 0x08;
public const SANDSTONE_NORMAL = 0;
public const SANDSTONE_CHISELED = 1;
public const SANDSTONE_CUT = 2;
public const SANDSTONE_SMOOTH = 3;
public const SAPLING_FLAG_READY = 0x08;
public const SEA_PICKLE_FLAG_NOT_UNDERWATER = 0x04;
public const SKULL_FLAG_NO_DROPS = 0x08;
public const SLAB_FLAG_UPPER = 0x08;
public const SPONGE_FLAG_WET = 0x01;
public const STAIR_FLAG_UPSIDE_DOWN = 0x04;
public const STONE_NORMAL = 0;
public const STONE_GRANITE = 1;
public const STONE_POLISHED_GRANITE = 2;
public const STONE_DIORITE = 3;
public const STONE_POLISHED_DIORITE = 4;
public const STONE_ANDESITE = 5;
public const STONE_POLISHED_ANDESITE = 6;
public const STONE_BRICK_NORMAL = 0;
public const STONE_BRICK_MOSSY = 1;
public const STONE_BRICK_CRACKED = 2;
public const STONE_BRICK_CHISELED = 3;
public const STONE_SLAB_SMOOTH_STONE = 0;
public const STONE_SLAB_SANDSTONE = 1;
public const STONE_SLAB_FAKE_WOODEN = 2;
public const STONE_SLAB_COBBLESTONE = 3;
public const STONE_SLAB_BRICK = 4;
public const STONE_SLAB_STONE_BRICK = 5;
public const STONE_SLAB_QUARTZ = 6;
public const STONE_SLAB_NETHER_BRICK = 7;
public const STONE_SLAB2_RED_SANDSTONE = 0;
public const STONE_SLAB2_PURPUR = 1;
public const STONE_SLAB2_PRISMARINE = 2;
public const STONE_SLAB2_DARK_PRISMARINE = 3;
public const STONE_SLAB2_PRISMARINE_BRICKS = 4;
public const STONE_SLAB2_MOSSY_COBBLESTONE = 5;
public const STONE_SLAB2_SMOOTH_SANDSTONE = 6;
public const STONE_SLAB2_RED_NETHER_BRICK = 7;
public const STONE_SLAB3_END_STONE_BRICK = 0;
public const STONE_SLAB3_SMOOTH_RED_SANDSTONE = 1;
public const STONE_SLAB3_POLISHED_ANDESITE = 2;
public const STONE_SLAB3_ANDESITE = 3;
public const STONE_SLAB3_DIORITE = 4;
public const STONE_SLAB3_POLISHED_DIORITE = 5;
public const STONE_SLAB3_GRANITE = 6;
public const STONE_SLAB3_POLISHED_GRANITE = 7;
public const STONE_SLAB4_MOSSY_STONE_BRICK = 0;
public const STONE_SLAB4_SMOOTH_QUARTZ = 1;
public const STONE_SLAB4_STONE = 2;
public const STONE_SLAB4_CUT_SANDSTONE = 3;
public const STONE_SLAB4_CUT_RED_SANDSTONE = 4;
public const TALLGRASS_NORMAL = 1;
public const TALLGRASS_FERN = 2;
public const TNT_FLAG_UNSTABLE = 0x01;
public const TNT_FLAG_UNDERWATER = 0x02;
public const TRAPDOOR_FLAG_UPPER = 0x04;
public const TRAPDOOR_FLAG_OPEN = 0x08;
public const TRIPWIRE_FLAG_TRIGGERED = 0x01;
public const TRIPWIRE_FLAG_SUSPENDED = 0x02;
public const TRIPWIRE_FLAG_CONNECTED = 0x04;
public const TRIPWIRE_FLAG_DISARMED = 0x08;
public const TRIPWIRE_HOOK_FLAG_CONNECTED = 0x04;
public const TRIPWIRE_HOOK_FLAG_POWERED = 0x08;
public const VINE_FLAG_SOUTH = 0x01;
public const VINE_FLAG_WEST = 0x02;
public const VINE_FLAG_NORTH = 0x04;
public const VINE_FLAG_EAST = 0x08;
public const WALL_COBBLESTONE = 0;
public const WALL_MOSSY_COBBLESTONE = 1;
public const WALL_GRANITE = 2;
public const WALL_DIORITE = 3;
public const WALL_ANDESITE = 4;
public const WALL_SANDSTONE = 5;
public const WALL_BRICK = 6;
public const WALL_STONE_BRICK = 7;
public const WALL_MOSSY_STONE_BRICK = 8;
public const WALL_NETHER_BRICK = 9;
public const WALL_END_STONE_BRICK = 10;
public const WALL_PRISMARINE = 11;
public const WALL_RED_SANDSTONE = 12;
public const WALL_RED_NETHER_BRICK = 13;
public const WOOD_FLAG_STRIPPED = 0x8;
}

View File

@ -1,154 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\BrewingStand as TileBrewingStand;
use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function array_key_exists;
class BrewingStand extends Transparent{
/**
* @var BrewingStandSlot[]
* @phpstan-var array<int, BrewingStandSlot>
*/
protected array $slots = [];
protected function writeStateToMeta() : int{
$flags = 0;
foreach([
BlockLegacyMetadata::BREWING_STAND_FLAG_EAST => BrewingStandSlot::EAST(),
BlockLegacyMetadata::BREWING_STAND_FLAG_NORTHWEST => BrewingStandSlot::NORTHWEST(),
BlockLegacyMetadata::BREWING_STAND_FLAG_SOUTHWEST => BrewingStandSlot::SOUTHWEST(),
] as $flag => $slot){
$flags |= (array_key_exists($slot->id(), $this->slots) ? $flag : 0);
}
return $flags;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->slots = [];
foreach([
BlockLegacyMetadata::BREWING_STAND_FLAG_EAST => BrewingStandSlot::EAST(),
BlockLegacyMetadata::BREWING_STAND_FLAG_NORTHWEST => BrewingStandSlot::NORTHWEST(),
BlockLegacyMetadata::BREWING_STAND_FLAG_SOUTHWEST => BrewingStandSlot::SOUTHWEST(),
] as $flag => $slot){
if(($stateMeta & $flag) !== 0){
$this->slots[$slot->id()] = $slot;
}
}
}
public function getStateBitmask() : int{
return 0b111;
}
protected function recalculateCollisionBoxes() : array{
return [
//bottom slab part - in PC this is also inset on X/Z by 1/16, but Bedrock sucks
AxisAlignedBB::one()->trim(Facing::UP, 7 / 8),
//center post
AxisAlignedBB::one()
->squash(Axis::X, 7 / 16)
->squash(Axis::Z, 7 / 16)
->trim(Facing::UP, 1 / 8)
];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function hasSlot(BrewingStandSlot $slot) : bool{
return array_key_exists($slot->id(), $this->slots);
}
public function setSlot(BrewingStandSlot $slot, bool $occupied) : self{
if($occupied){
$this->slots[$slot->id()] = $slot;
}else{
unset($this->slots[$slot->id()]);
}
return $this;
}
/**
* @return BrewingStandSlot[]
* @phpstan-return array<int, BrewingStandSlot>
*/
public function getSlots() : array{
return $this->slots;
}
/** @param BrewingStandSlot[] $slots */
public function setSlots(array $slots) : self{
$this->slots = [];
foreach($slots as $slot){
$this->slots[$slot->id()] = $slot;
}
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){
$stand = $this->position->getWorld()->getTile($this->position);
if($stand instanceof TileBrewingStand && $stand->canOpenWith($item->getCustomName())){
$player->setCurrentWindow($stand->getInventory());
}
}
return true;
}
public function onScheduledUpdate() : void{
$world = $this->position->getWorld();
$brewing = $world->getTile($this->position);
if($brewing instanceof TileBrewingStand){
if($brewing->onUpdate()){
$world->scheduleDelayedBlockUpdate($this->position, 1);
}
$changed = false;
foreach(BrewingStandSlot::getAll() as $slot){
$occupied = !$brewing->getInventory()->isSlotEmpty($slot->getSlotNumber());
if($occupied !== $this->hasSlot($slot)){
$this->setSlot($slot, $occupied);
$changed = true;
}
}
if($changed){
$world->setBlock($this->position, $this);
}
}
}
}

View File

@ -1,103 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\RedstonePowerOffSound;
use pocketmine\world\sound\RedstonePowerOnSound;
abstract class Button extends Flowable{
use AnyFacingTrait;
protected bool $pressed = false;
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeFacing($this->facing) | ($this->pressed ? BlockLegacyMetadata::BUTTON_FLAG_POWERED : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
//TODO: in PC it's (6 - facing) for every meta except 0 (down)
$this->facing = BlockDataSerializer::readFacing($stateMeta & 0x07);
$this->pressed = ($stateMeta & BlockLegacyMetadata::BUTTON_FLAG_POWERED) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function isPressed() : bool{ return $this->pressed; }
/** @return $this */
public function setPressed(bool $pressed) : self{
$this->pressed = $pressed;
return $this;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($blockReplace->getSide(Facing::opposite($face)), $face)){
$this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
abstract protected function getActivationTime() : int;
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->pressed){
$this->pressed = true;
$world = $this->position->getWorld();
$world->setBlock($this->position, $this);
$world->scheduleDelayedBlockUpdate($this->position, $this->getActivationTime());
$world->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOnSound());
}
return true;
}
public function onScheduledUpdate() : void{
if($this->pressed){
$this->pressed = false;
$world = $this->position->getWorld();
$world->setBlock($this->position, $this);
$world->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOffSound());
}
}
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)){
$this->position->getWorld()->useBreakOn($this->position);
}
}
private function canBeSupportedBy(Block $support, int $face) : bool{
return $support->getSupportType($face)->hasCenterSupport();
}
}

View File

@ -1,152 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class Cactus extends Transparent{
public const MAX_AGE = 15;
protected int $age = 0;
protected function writeStateToMeta() : int{
return $this->age;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta, 0, self::MAX_AGE);
}
public function getStateBitmask() : int{
return 0b1111;
}
public function getAge() : int{ return $this->age; }
/** @return $this */
public function setAge(int $age) : self{
if($age < 0 || $age > self::MAX_AGE){
throw new \InvalidArgumentException("Age must be in range 0 ... " . self::MAX_AGE);
}
$this->age = $age;
return $this;
}
public function hasEntityCollision() : bool{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$shrinkSize = 1 / 16;
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function onEntityInside(Entity $entity) : bool{
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1);
$entity->attack($ev);
return true;
}
public function onNearbyBlockChange() : void{
$down = $this->getSide(Facing::DOWN);
$world = $this->position->getWorld();
if($down->getId() !== BlockLegacyIds::SAND && !$down->isSameType($this)){
$world->useBreakOn($this->position);
}else{
foreach(Facing::HORIZONTAL as $side){
$b = $this->getSide($side);
if($b->isSolid()){
$world->useBreakOn($this->position);
break;
}
}
}
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
if(!$this->getSide(Facing::DOWN)->isSameType($this)){
$world = $this->position->getWorld();
if($this->age === self::MAX_AGE){
for($y = 1; $y < 3; ++$y){
if(!$world->isInWorld($this->position->x, $this->position->y + $y, $this->position->z)){
break;
}
$b = $world->getBlockAt($this->position->x, $this->position->y + $y, $this->position->z);
if($b->getId() === BlockLegacyIds::AIR){
$ev = new BlockGrowEvent($b, VanillaBlocks::CACTUS());
$ev->call();
if($ev->isCancelled()){
break;
}
$world->setBlock($b->position, $ev->getNewState());
}else{
break;
}
}
$this->age = 0;
$world->setBlock($this->position, $this);
}else{
++$this->age;
$world->setBlock($this->position, $this);
}
}
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $this->getSide(Facing::DOWN);
if($down->getId() === BlockLegacyIds::SAND || $down->isSameType($this)){
foreach(Facing::HORIZONTAL as $side){
if($this->getSide($side)->isSolid()){
return false;
}
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
}

View File

@ -1,143 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\FoodSource;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class Cake extends Transparent implements FoodSource{
public const MAX_BITES = 6;
protected int $bites = 0;
protected function writeStateToMeta() : int{
return $this->bites;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->bites = BlockDataSerializer::readBoundedInt("bites", $stateMeta, 0, self::MAX_BITES);
}
public function getStateBitmask() : int{
return 0b111;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()
->contract(1 / 16, 0, 1 / 16)
->trim(Facing::UP, 0.5)
->trim(Facing::WEST, $this->bites / 8)
];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function getBites() : int{ return $this->bites; }
/** @return $this */
public function setBites(int $bites) : self{
if($bites < 0 || $bites > self::MAX_BITES){
throw new \InvalidArgumentException("Bites must be in range 0 ... " . self::MAX_BITES);
}
$this->bites = $bites;
return $this;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $this->getSide(Facing::DOWN);
if($down->getId() !== BlockLegacyIds::AIR){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getId() === BlockLegacyIds::AIR){ //Replace with common break method
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR());
}
}
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
return $player->consumeObject($this);
}
return false;
}
public function getFoodRestore() : int{
return 2;
}
public function getSaturationRestore() : float{
return 0.4;
}
public function requiresHunger() : bool{
return true;
}
/**
* @return Block
*/
public function getResidue(){
$clone = clone $this;
$clone->bites++;
if($clone->bites > self::MAX_BITES){
$clone = VanillaBlocks::AIR();
}
return $clone;
}
/**
* @return EffectInstance[]
*/
public function getAdditionalEffects() : array{
return [];
}
public function onConsume(Living $consumer) : void{
$this->position->getWorld()->setBlock($this->position, $this->getResidue());
}
}

View File

@ -1,45 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
class CarvedPumpkin extends Opaque{
use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
}
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing);
}
public function getStateBitmask() : int{
return 0b11;
}
}

View File

@ -1,32 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
final class ChemicalHeat extends Transparent{
/*
* TODO: this block causes melting of nearby ice and snow within 2 blocks taxicab distance.
* Since it doesn't emit any light, the mechanics of this block's behaviour are not currently clear.
*/
}

View File

@ -1,54 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
final class ChemistryTable extends Opaque{
use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = Facing::opposite(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x3));
}
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing(Facing::opposite($this->facing));
}
public function getStateBitmask() : int{
return 0b0011;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
//TODO
return false;
}
}

View File

@ -1,100 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Chest as TileChest;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\ChestPairEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
class Chest extends Transparent{
use FacesOppositePlacingPlayerTrait;
use NormalHorizontalFacingInMetadataTrait;
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//these are slightly bigger than in PC
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function onPostPlace() : void{
$world = $this->position->getWorld();
$tile = $world->getTile($this->position);
if($tile instanceof TileChest){
foreach([false, true] as $clockwise){
$side = Facing::rotateY($this->facing, $clockwise);
$c = $this->getSide($side);
if($c instanceof Chest && $c->isSameType($this) && $c->facing === $this->facing){
$pair = $world->getTile($c->position);
if($pair instanceof TileChest && !$pair->isPaired()){
[$left, $right] = $clockwise ? [$c, $this] : [$this, $c];
$ev = new ChestPairEvent($left, $right);
$ev->call();
if(!$ev->isCancelled() && $world->getBlock($this->position)->isSameType($this) && $world->getBlock($c->position)->isSameType($c)){
$pair->pairWith($tile);
$tile->pairWith($pair);
break;
}
}
}
}
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){
$chest = $this->position->getWorld()->getTile($this->position);
if($chest instanceof TileChest){
if(
!$this->getSide(Facing::UP)->isTransparent() ||
(($pair = $chest->getPair()) !== null && !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) ||
!$chest->canOpenWith($item->getCustomName())
){
return true;
}
$player->setCurrentWindow($chest->getInventory());
}
}
return true;
}
public function getFuelTime() : int{
return 300;
}
}

View File

@ -1,153 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\TreeType;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function mt_rand;
class CocoaBlock extends Transparent{
use HorizontalFacingTrait;
public const MAX_AGE = 2;
protected int $age = 0;
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing(Facing::opposite($this->facing)) | ($this->age << 2);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = Facing::opposite(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03));
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta >> 2, 0, self::MAX_AGE);
}
public function getStateBitmask() : int{
return 0b1111;
}
public function getAge() : int{ return $this->age; }
/** @return $this */
public function setAge(int $age) : self{
if($age < 0 || $age > self::MAX_AGE){
throw new \InvalidArgumentException("Age must be in range 0 ... " . self::MAX_AGE);
}
$this->age = $age;
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()
->squash(Facing::axis(Facing::rotateY($this->facing, true)), (6 - $this->age) / 16) //sides
->trim(Facing::DOWN, (7 - $this->age * 2) / 16)
->trim(Facing::UP, 0.25)
->trim(Facing::opposite($this->facing), 1 / 16) //gap between log and pod
->trim($this->facing, (11 - $this->age * 2) / 16) //outward face
];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
private function canAttachTo(Block $block) : bool{
return $block instanceof Wood && $block->getTreeType()->equals(TreeType::JUNGLE());
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(Facing::axis($face) !== Axis::Y && $this->canAttachTo($blockClicked)){
$this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer && $this->grow()){
$item->pop();
return true;
}
return false;
}
public function onNearbyBlockChange() : void{
if(!$this->canAttachTo($this->getSide(Facing::opposite($this->facing)))){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
if(mt_rand(1, 5) === 1){
$this->grow();
}
}
private function grow() : bool{
if($this->age < self::MAX_AGE){
$block = clone $this;
$block->age++;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
return true;
}
}
return false;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaItems::COCOA_BEANS()->setCount($this->age === self::MAX_AGE ? mt_rand(2, 3) : 1)
];
}
public function getPickedItem(bool $addUserData = false) : Item{
return VanillaItems::COCOA_BEANS();
}
}

View File

@ -1,36 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColorInMetadataTrait;
use pocketmine\block\utils\DyeColor;
class Concrete extends Opaque{
use ColorInMetadataTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::WHITE();
parent::__construct($idInfo, $name, $breakInfo);
}
}

View File

@ -1,87 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\data\bedrock\CoralTypeIdMap;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class Coral extends BaseCoral{
public function readStateFromData(int $id, int $stateMeta) : void{
$coralType = CoralTypeIdMap::getInstance()->fromId($stateMeta);
if($coralType === null){
throw new InvalidBlockStateException("No such coral type");
}
$this->coralType = $coralType;
}
public function writeStateToMeta() : int{
return CoralTypeIdMap::getInstance()->toId($this->coralType);
}
protected function writeStateToItemMeta() : int{
return $this->writeStateToMeta();
}
public function getStateBitmask() : int{
return 0b0111;
}
public function readStateFromWorld() : void{
//TODO: this hack ensures correct state of coral plants, because they don't retain their dead flag in metadata
$world = $this->position->getWorld();
$this->dead = true;
foreach($this->position->sides() as $vector3){
if($world->getBlock($vector3) instanceof Water){
$this->dead = false;
break;
}
}
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($tx->fetchBlock($blockReplace->getPosition()->down()))){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
$world = $this->position->getWorld();
if(!$this->canBeSupportedBy($world->getBlock($this->position->down()))){
$world->useBreakOn($this->position);
}else{
parent::onNearbyBlockChange();
}
}
private function canBeSupportedBy(Block $block) : bool{
return $block->getSupportType(Facing::UP)->hasCenterSupport();
}
}

Some files were not shown because too many files have changed in this diff Show More