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
1747 changed files with 82238 additions and 86947 deletions

View File

@ -6,8 +6,3 @@ updates:
interval: daily
time: "10:00"
open-pull-requests-limit: 10
- package-ecosystem: gitsubmodule
directory: "/"
schedule:
interval: daily

View File

@ -1,97 +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@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Clone pmmp/PocketMine-Docker repository
uses: actions/checkout@v2
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 ::set-output name=TAG_NAME::$VERSION
echo ::set-output name=MAJOR::$(echo $VERSION | cut -d. -f1)
echo ::set-output name=MINOR::$(echo $VERSION | cut -d. -f1-2)
- 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 ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json)
- name: Get name of Docker repository name
id: docker-repo-name
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
- name: Build image for tag
uses: docker/build-push-action@v2.10.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@v2.10.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@v2.10.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@v2.10.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

@ -43,7 +43,30 @@ jobs:
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,10 +74,10 @@ jobs:
- name: Get PocketMine-MP release version
id: get-pm-version
run: |
echo ::set-output name=PM_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BASE_VERSION;')
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\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);')
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);')
echo ::set-output name=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 }} > build_info.json
@ -81,3 +104,16 @@ jobs:
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
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,11 +13,11 @@ jobs:
strategy:
matrix:
image: [ubuntu-20.04]
php: [8.0.16]
php: [8.0.11]
steps:
- name: Build and prepare PHP cache
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -31,13 +31,13 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.16]
php: [8.0.11]
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -69,13 +69,13 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.16]
php: [8.0.11]
steps:
- uses: actions/checkout@v2
- name: Setup PHP
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -107,7 +107,7 @@ jobs:
fail-fast: false
matrix:
image: [ubuntu-20.04]
php: [8.0.16]
php: [8.0.11]
steps:
- uses: actions/checkout@v2
@ -115,7 +115,7 @@ jobs:
submodules: true
- name: Setup PHP
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -139,21 +139,23 @@ 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.16]
php: [8.0.11]
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Setup PHP
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
uses: pmmp/setup-php-action@e232f72a4330a07aae8418e8aa56b64efcdda636
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
@ -174,16 +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: 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
@ -201,4 +224,4 @@ jobs:
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

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

@ -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)
@ -43,7 +44,6 @@ return (new PhpCsFixer\Config)
'import_classes' => null,
],
'indentation_type' => true,
'logical_operators' => true,
'native_function_invocation' => [
'scope' => 'namespaced',
'include' => ['@all'],

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

@ -4,13 +4,10 @@
</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
@ -27,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 `next-major` 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

@ -30,14 +30,14 @@ if(count($argv) !== 5){
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]",
], 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 Webmozart\PathUtil\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,119 +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 implode;
use function ksort;
use function mb_strtoupper;
use function preg_match;
use function sprintf;
use function str_replace;
use function substr;
use const SORT_STRING;
if(count($argv) !== 2){
die("Provide a path to process");
}
/**
* @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);
}
require dirname(__DIR__) . '/vendor/autoload.php';
/** @var string $file */
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $file){
if(substr($file, -4) !== ".php"){
continue;
}
$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){
continue;
}
$shortClassName = basename($file, ".php");
$className = $matches[1] . "\\" . $shortClassName;
if(!class_exists($className)){
continue;
}
$reflect = new \ReflectionClass($className);
$docComment = $reflect->getDocComment();
if($docComment === false || preg_match("/(*ANYCRLF)^\s*\*\s*@generate-registry-docblock$/m", $docComment) !== 1){
continue;
}
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";
}
}

View File

@ -23,9 +23,7 @@ declare(strict_types=1);
namespace pocketmine\build\make_release;
use pocketmine\utils\Utils;
use pocketmine\utils\VersionString;
use pocketmine\VersionInfo;
use function array_keys;
use function array_map;
use function dirname;
@ -42,6 +40,8 @@ use function sprintf;
use function str_pad;
use function strlen;
use function system;
use const pocketmine\BASE_VERSION;
use const pocketmine\BUILD_CHANNEL;
use const STDERR;
use const STDIN;
use const STDOUT;
@ -50,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 = Utils::assumeNotFalse(file_get_contents($versionInfoPath), $versionInfoPath . " should always exist");
$versionInfo = file_get_contents($versionInfoPath);
$versionInfo = preg_replace(
$pattern = '/^([\t ]*public )?const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m',
'$1const BASE_VERSION = "' . $newVersion . '";',
@ -75,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");
@ -105,7 +97,7 @@ function main() : void{
if(isset($filteredOpts["current"])){
$currentVer = new VersionString($filteredOpts["current"]);
}else{
$currentVer = new VersionString(VersionInfo::BASE_VERSION);
$currentVer = new VersionString(BASE_VERSION);
}
if(isset($filteredOpts["next"])){
$nextVer = new VersionString($filteredOpts["next"]);
@ -117,29 +109,28 @@ function main() : void{
$currentVer->getPatch() + 1
));
}
$channel = $filteredOpts["channel"] ?? VersionInfo::BUILD_CHANNEL;
$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);
systemWrapper('git push origin HEAD ' . $currentVer->getBaseVersion(), "failed to push changes to remote");
system('git push origin HEAD ' . $currentVer->getBaseVersion());
}
main();

1
build/preprocessor Submodule

Submodule build/preprocessor added at 1b9304de61

View File

@ -150,7 +150,6 @@ function main() : void{
$opts["out"] ?? getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar",
dirname(__DIR__) . DIRECTORY_SEPARATOR,
[
'resources',
'src',
'vendor'
],
@ -169,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,81 +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.

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,43 +29,36 @@
"composer-runtime-api": "^2.0",
"adhocore/json-comment": "^1.1",
"fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0",
"pocketmine/bedrock-data": "~1.6.0+bedrock-1.18.10",
"pocketmine/bedrock-protocol": "~8.0.0+bedrock-1.18.10",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/binaryutils": "^0.1.9",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.2.0",
"pocketmine/color": "^0.2.0",
"pocketmine/errorhandler": "^0.6.0",
"pocketmine/locale-data": "~2.4.2",
"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",
"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.4.10",
"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": {
@ -79,16 +68,10 @@
"sort-packages": true
},
"scripts": {
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make 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"
]
}
}

1293
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/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

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,529 +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 Webmozart\PathUtil\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_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 Server $server;
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(Server $server){
$this->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{
switch(mb_strtoupper($matches[2])){
case "K":
$defaultMemory = intdiv($m, 1024);
break;
case "M":
$defaultMemory = $m;
break;
case "G":
$defaultMemory = $m * 1024;
break;
default:
$defaultMemory = $m;
break;
}
}
}
$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", 20);
$this->continuousTrigger = $config->getPropertyBool("memory.continuous-trigger", true);
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", 30);
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", 36000);
$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($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
*
* @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);
}else{
$data = $from;
}
return $data;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,146 +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 Config */
private $pocketmineYml;
/** @var Config */
private $serverProperties;
/**
* @var mixed[]
* @phpstan-var array<string, mixed>
*/
private $propertyCache = [];
public function __construct(Config $pocketmineYml, Config $serverProperties){
$this->pocketmineYml = $pocketmineYml;
$this->serverProperties = $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,91 +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.2.5";
public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "stable";
private function __construct(){
//NOOP
}
/** @var string|null */
private static $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;
}
/** @var VersionString|null */
private static $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,97 +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\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;
private int $damage = 0;
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, 0, 2);
}
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 < 0 || $damage > 2){
throw new \InvalidArgumentException("Damage must be in range 0-2");
}
$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 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,240 +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\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)];
}
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{
$below = $this->position->getWorld()->getBlock($this->position->down());
if(!$this->canBeSupportedBy($below) && !$below->isSameType($this)){
$this->position->getWorld()->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($this->position->getWorld());
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,130 +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{
if(!$this->canBeSupportedBy($this->position->getWorld()->getBlock($this->position->down()))){
$this->position->getWorld()->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,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\block\tile\Banner as TileBanner;
use pocketmine\block\utils\BannerPatternLayer;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
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 place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
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->getSide($this->getSupportingFace())->getId() === BlockLegacyIds::AIR){
$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,68 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\CoralTypeTrait;
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){
$world->setBlock($this->position, $this->setDead(true));
}
}
}
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function isAffectedBySilkTouch() : bool{
return true;
}
public function isSolid() : bool{ return false; }
protected function recalculateCollisionBoxes() : array{ return []; }
}

View File

@ -1,234 +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)->isTransparent()){
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;
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);
$this->position->getWorld()->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);
$this->position->getWorld()->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{
if($this->getSide(Facing::DOWN)->isTransparent()){
$this->position->getWorld()->useBreakOn($this->position);
}else{
foreach($this->getCurrentShapeConnections() as $connection){
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->isTransparent()){
$this->position->getWorld()->useBreakOn($this->position);
break;
}
}
}
}
}

View File

@ -1,137 +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\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 [];
}
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);
}
/**
* 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;
}
/**
* 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->position->getWorld()->setBlock($this->position, $this);
return true;
}
return false;
}
}

View File

@ -1,219 +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\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 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{
$down = $this->getSide(Facing::DOWN);
if(!$down->isTransparent()){
$this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH;
$next = $this->getSide($this->getOtherHalfSide());
if($next->canBeReplaced() && !$next->getSide(Facing::DOWN)->isTransparent()){
$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();
}
}

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,183 +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\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 getAttachmentType() : BellAttachmentType{ return $this->attachmentType; }
/** @return $this */
public function setAttachmentType(BellAttachmentType $attachmentType) : self{
$this->attachmentType = $attachmentType;
return $this;
}
private function canBeSupportedBy(Block $block) : bool{
//TODO: this isn't the actual logic, but it's the closest approximation we can support for now
return $block->isSolid();
}
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()))){
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()))){
return false;
}
$this->setAttachmentType(BellAttachmentType::CEILING());
}else{
$this->setFacing($face);
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide(Facing::opposite($face))))){
$this->setAttachmentType(BellAttachmentType::ONE_WALL());
}else{
return false;
}
if($this->canBeSupportedBy($tx->fetchBlock($this->position->getSide($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))) ||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && !$this->canBeSupportedBy($this->getSide(Facing::DOWN))) ||
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) && !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)))) ||
($this->attachmentType->equals(BellAttachmentType::TWO_WALLS()) && (!$this->canBeSupportedBy($this->getSide($this->facing)) || !$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)))))
){
$this->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->ring($faceHit);
}
if($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)){
$this->ring($faceHit);
}
if(
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
){
$this->ring($faceHit);
}
}
return true;
}
public function ring(int $faceHit) : void{
$this->position->getWorld()->addSound($this->position, new BellRingSound());
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBell){
$this->position->getWorld()->broadcastPacketToViewers($this->position, $tile->createFakeUpdatePacket($faceHit));
}
}
}

View File

@ -1,645 +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\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;
}
public function getIdInfo() : BlockIdentifier{
return $this->idInfo;
}
public function getName() : string{
return $this->fallbackName;
}
public function getId() : int{
return $this->idInfo->getBlockId();
}
/**
* @internal
*/
public function getFullId() : int{
return ($this->getId() << self::INTERNAL_METADATA_BITS) | $this->getMeta();
}
public function asItem() : Item{
return ItemFactory::getInstance()->get(
$this->idInfo->getItemId(),
$this->idInfo->getVariant() | $this->writeStateToItemMeta()
);
}
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.
*/
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;
}
public function writeStateToWorld() : void{
$this->position->getWorld()->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 = $this->position->getWorld()->getTile($this->position);
if($oldTile !== null){
if($tileType === null || !($oldTile instanceof $tileType)){
$oldTile->close();
$oldTile = null;
}elseif($oldTile instanceof Spawnable){
$oldTile->setDirty(); //destroy old network cache
}
}
if($oldTile === null && $tileType !== null){
/**
* @var Tile $tile
* @see Tile::__construct()
*/
$tile = new $tileType($this->position->getWorld(), $this->position->asVector3());
$this->position->getWorld()->addTile($tile);
}
}
/**
* Returns a type ID that identifies this type of block. This does not include information like facing, colour,
* 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;
}
public function canBeReplaced() : bool{
return false;
}
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
return $blockReplace->canBeReplaced();
}
/**
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
*/
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;
}
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{
if(($t = $this->position->getWorld()->getTile($this->position)) !== null){
$t->onBlockDestroyed();
}
$this->position->getWorld()->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 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). This is called when a player left-clicks the block to try and
* start to break it in survival mode.
*
* @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;
}
public function getFrictionFactor() : float{
return 0.6;
}
/**
* @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;
}
public function hasEntityCollision() : bool{
return false;
}
/**
* Returns whether entities can climb up this block.
*/
public function canClimb() : bool{
return false;
}
public function addVelocityToEntity(Entity $entity) : ?Vector3{
return null;
}
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.
*/
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() . ")";
}
/**
* Checks for collision against an AxisAlignedBB
*/
public function collidesWithBB(AxisAlignedBB $bb) : bool{
foreach($this->getCollisionBoxes() as $bb2){
if($bb->intersectsWith($bb2)){
return true;
}
}
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.
*
* @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;
}
/**
* 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;
}
/**
* @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()];
}
public function isFullCube() : bool{
$bb = $this->getCollisionBoxes();
return count($bb) === 1 && $bb[0]->getAverageEdgeLength() >= 1 && $bb[0]->isCube();
}
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,148 +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 $hardness;
private float $blastResistance;
private int $toolType;
private int $toolHarvestLevel;
/**
* @param float|null $blastResistance default 5x hardness
*/
public function __construct(float $hardness, int $toolType = BlockToolType::NONE, int $toolHarvestLevel = 0, ?float $blastResistance = null){
$this->hardness = $hardness;
$this->toolType = $toolType;
$this->toolHarvestLevel = $toolHarvestLevel;
$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,76 +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{
private int $blockId;
private int $variant;
private ?int $itemId;
/** @phpstan-var class-string<Tile>|null */
private ?string $tileClass;
/**
* @phpstan-param class-string<Tile>|null $tileClass
*/
public function __construct(int $blockId, int $variant, ?int $itemId = null, ?string $tileClass = null){
$this->blockId = $blockId;
$this->variant = $variant;
$this->itemId = $itemId;
if($tileClass !== null){
Utils::testValidInstance($tileClass, Tile::class);
}
$this->tileClass = $tileClass;
}
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,148 +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\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 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{
$brewing = $this->position->getWorld()->getTile($this->position);
if($brewing instanceof TileBrewingStand){
if($brewing->onUpdate()){
$this->position->getWorld()->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){
$this->position->getWorld()->setBlock($this->position, $this);
}
}
}
}

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\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{
//TODO: check valid target block
$this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
abstract protected function getActivationTime() : int;
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->pressed){
$this->pressed = true;
$this->position->getWorld()->setBlock($this->position, $this);
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, $this->getActivationTime());
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOnSound());
}
return true;
}
public function onScheduledUpdate() : void{
if($this->pressed){
$this->pressed = false;
$this->position->getWorld()->setBlock($this->position, $this);
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOffSound());
}
}
}

View File

@ -1,144 +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\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{
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, 15);
}
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 > 15){
throw new \InvalidArgumentException("Age must be in range 0-15");
}
$this->age = $age;
return $this;
}
public function hasEntityCollision() : bool{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
static $shrinkSize = 1 / 16;
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];
}
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);
if($down->getId() !== BlockLegacyIds::SAND && !$down->isSameType($this)){
$this->position->getWorld()->useBreakOn($this->position);
}else{
foreach(Facing::HORIZONTAL as $side){
$b = $this->getSide($side);
if($b->isSolid()){
$this->position->getWorld()->useBreakOn($this->position);
break;
}
}
}
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
if(!$this->getSide(Facing::DOWN)->isSameType($this)){
if($this->age === 15){
for($y = 1; $y < 3; ++$y){
if(!$this->position->getWorld()->isInWorld($this->position->x, $this->position->y + $y, $this->position->z)){
break;
}
$b = $this->position->getWorld()->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;
}
$this->position->getWorld()->setBlock($b->position, $ev->getNewState());
}else{
break;
}
}
$this->age = 0;
$this->position->getWorld()->setBlock($this->position, $this);
}else{
++$this->age;
$this->position->getWorld()->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,137 +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\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{
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, 6);
}
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 getBites() : int{ return $this->bites; }
/** @return $this */
public function setBites(int $bites) : self{
if($bites < 0 || $bites > 6){
throw new \InvalidArgumentException("Bites must be in range 0-6");
}
$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 > 6){
$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,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,95 +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\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 onPostPlace() : void{
$tile = $this->position->getWorld()->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){
$world = $this->position->getWorld();
$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,146 +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\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;
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, 2);
}
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 > 2){
throw new \InvalidArgumentException("Age must be in range 0-2");
}
$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
];
}
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 < 2){
$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 === 2 ? 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,82 +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\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(!$tx->fetchBlock($blockReplace->getPosition()->down())->isSolid()){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
$world = $this->position->getWorld();
if(!$world->getBlock($this->position->down())->isSolid()){
$world->useBreakOn($this->position);
}else{
parent::onNearbyBlockChange();
}
}
}

View File

@ -1,92 +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\InvalidBlockStateException;
use pocketmine\data\bedrock\CoralTypeIdMap;
use pocketmine\item\Item;
use function mt_rand;
final class CoralBlock extends Opaque{
use CoralTypeTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->coralType = CoralType::TUBE();
parent::__construct($idInfo, $name, $breakInfo);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$coralType = CoralTypeIdMap::getInstance()->fromId($stateMeta & 0x7);
if($coralType === null){
throw new InvalidBlockStateException("No such coral type");
}
$this->coralType = $coralType;
$this->dead = ($stateMeta & BlockLegacyMetadata::CORAL_BLOCK_FLAG_DEAD) !== 0;
}
protected function writeStateToMeta() : int{
return ($this->dead ? BlockLegacyMetadata::CORAL_BLOCK_FLAG_DEAD : 0) | CoralTypeIdMap::getInstance()->toId($this->coralType);
}
protected function writeStateToItemMeta() : int{
return $this->writeStateToMeta();
}
public function getStateBitmask() : int{
return 0b1111;
}
public function onNearbyBlockChange() : void{
if(!$this->dead){
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(40, 200));
}
}
public function onScheduledUpdate() : 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;
}
}
if(!$hasWater){
$world->setBlock($this->position, $this->setDead(true));
}
}
}
public function getDropsForCompatibleTool(Item $item) : array{
return [$this->setDead(true)->asItem()];
}
public function isAffectedBySilkTouch() : bool{
return true;
}
}

View File

@ -1,113 +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\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function mt_rand;
abstract class Crops extends Flowable{
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, 7);
}
public function getStateBitmask() : int{
return 0b111;
}
public function getAge() : int{ return $this->age; }
/** @return $this */
public function setAge(int $age) : self{
if($age < 0 || $age > 7){
throw new \InvalidArgumentException("Age must be in range 0-7");
}
$this->age = $age;
return $this;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($blockReplace->getSide(Facing::DOWN)->getId() === BlockLegacyIds::FARMLAND){
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($this->age < 7 && $item instanceof Fertilizer){
$block = clone $this;
$block->age += mt_rand(2, 5);
if($block->age > 7){
$block->age = 7;
}
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
$item->pop();
}
return true;
}
return false;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getId() !== BlockLegacyIds::FARMLAND){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
if($this->age < 7 && mt_rand(0, 2) === 1){
$block = clone $this;
++$block->age;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
}
}
}
}

View File

@ -1,117 +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\AnalogRedstoneSignalEmitterTrait;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function cos;
use function max;
use function round;
use const M_PI;
class DaylightSensor extends Transparent{
use AnalogRedstoneSignalEmitterTrait;
protected BlockIdentifierFlattened $idInfoFlattened;
protected bool $inverted = false;
public function __construct(BlockIdentifierFlattened $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->idInfoFlattened = $idInfo;
parent::__construct($idInfo, $name, $breakInfo);
}
public function getId() : int{
return $this->inverted ? $this->idInfoFlattened->getSecondId() : parent::getId();
}
protected function writeStateToMeta() : int{
return $this->signalStrength;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->signalStrength = BlockDataSerializer::readBoundedInt("signalStrength", $stateMeta, 0, 15);
$this->inverted = $id === $this->idInfoFlattened->getSecondId();
}
public function getStateBitmask() : int{
return 0b1111;
}
public function isInverted() : bool{
return $this->inverted;
}
/**
* @return $this
*/
public function setInverted(bool $inverted = true) : self{
$this->inverted = $inverted;
return $this;
}
public function getFuelTime() : int{
return 300;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 10 / 16)];
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->inverted = !$this->inverted;
$this->signalStrength = $this->recalculateSignalStrength();
$this->position->getWorld()->setBlock($this->position, $this);
return true;
}
public function onScheduledUpdate() : void{
$signalStrength = $this->recalculateSignalStrength();
if($this->signalStrength !== $signalStrength){
$this->signalStrength = $signalStrength;
$this->position->getWorld()->setBlock($this->position, $this);
}
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 20);
}
private function recalculateSignalStrength() : int{
$lightLevel = $this->position->getWorld()->getRealBlockSkyLightAt($this->position->x, $this->position->y, $this->position->z);
if($this->inverted){
return 15 - $lightLevel;
}
$sunAngle = $this->position->getWorld()->getSunAnglePercentage();
return max(0, (int) round($lightLevel * cos(($sunAngle + ((($sunAngle < 0.5 ? 0 : 1) - $sunAngle) / 5)) * 2 * M_PI)));
}
//TODO
}

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 DetectorRail extends StraightOnlyRail{
protected bool $activated = false;
public function isActivated() : bool{ return $this->activated; }
/** @return $this */
public function setActivated(bool $activated) : self{
$this->activated = $activated;
return $this;
}
public function readStateFromData(int $id, int $stateMeta) : void{
parent::readStateFromData($id, $stateMeta & ~BlockLegacyMetadata::REDSTONE_RAIL_FLAG_POWERED);
$this->activated = ($stateMeta & BlockLegacyMetadata::REDSTONE_RAIL_FLAG_POWERED) !== 0;
}
protected function writeStateToMeta() : int{
return parent::writeStateToMeta() | ($this->activated ? BlockLegacyMetadata::REDSTONE_RAIL_FLAG_POWERED : 0);
}
public function getStateBitmask() : int{
return 0b1111;
}
//TODO
}

View File

@ -1,74 +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\Hoe;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\ItemUseOnBlockSound;
class Dirt extends Opaque{
protected bool $coarse = false;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->coarse = ($stateMeta & BlockLegacyMetadata::DIRT_FLAG_COARSE) !== 0;
}
protected function writeStateToMeta() : int{
return $this->coarse ? BlockLegacyMetadata::DIRT_FLAG_COARSE : 0;
}
protected function writeStateToItemMeta() : int{
return $this->writeStateToMeta();
}
public function getStateBitmask() : int{
return 0b1;
}
public function isCoarse() : bool{ return $this->coarse; }
/** @return $this */
public function setCoarse(bool $coarse) : self{
$this->coarse = $coarse;
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face === Facing::UP && $item instanceof Hoe){
$item->applyDamage(1);
$newBlock = $this->coarse ? VanillaBlocks::DIRT() : VanillaBlocks::FARMLAND();
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
$this->position->getWorld()->setBlock($this->position, $newBlock);
return true;
}
return false;
}
}

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\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\PoweredByRedstoneTrait;
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 pocketmine\world\sound\DoorSound;
class Door extends Transparent{
use HorizontalFacingTrait;
use PoweredByRedstoneTrait;
protected bool $top = false;
protected bool $hingeRight = false;
protected bool $open = false;
protected function writeStateToMeta() : int{
if($this->top){
return BlockLegacyMetadata::DOOR_FLAG_TOP |
($this->hingeRight ? BlockLegacyMetadata::DOOR_TOP_FLAG_RIGHT : 0) |
($this->powered ? BlockLegacyMetadata::DOOR_TOP_FLAG_POWERED : 0);
}
return BlockDataSerializer::writeLegacyHorizontalFacing(Facing::rotateY($this->facing, true)) | ($this->open ? BlockLegacyMetadata::DOOR_BOTTOM_FLAG_OPEN : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->top = ($stateMeta & BlockLegacyMetadata::DOOR_FLAG_TOP) !== 0;
if($this->top){
$this->hingeRight = ($stateMeta & BlockLegacyMetadata::DOOR_TOP_FLAG_RIGHT) !== 0;
$this->powered = ($stateMeta & BlockLegacyMetadata::DOOR_TOP_FLAG_POWERED) !== 0;
}else{
$this->facing = Facing::rotateY(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03), false);
$this->open = ($stateMeta & BlockLegacyMetadata::DOOR_BOTTOM_FLAG_OPEN) !== 0;
}
}
public function getStateBitmask() : int{
return 0b1111;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
//copy door properties from other half
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
if($other instanceof Door && $other->isSameType($this)){
if($this->top){
$this->facing = $other->facing;
$this->open = $other->open;
}else{
$this->hingeRight = $other->hingeRight;
$this->powered = $other->powered;
}
}
}
public function isTop() : bool{ return $this->top; }
/** @return $this */
public function setTop(bool $top) : self{
$this->top = $top;
return $this;
}
public function isHingeRight() : bool{ return $this->hingeRight; }
/** @return $this */
public function setHingeRight(bool $hingeRight) : self{
$this->hingeRight = $hingeRight;
return $this;
}
public function isOpen() : bool{ return $this->open; }
/** @return $this */
public function setOpen(bool $open) : self{
$this->open = $open;
return $this;
}
public function isSolid() : bool{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//TODO: doors are 0.1825 blocks thick, instead of 0.1875 like JE (https://bugs.mojang.com/browse/MCPE-19214)
return [AxisAlignedBB::one()->trim($this->open ? Facing::rotateY($this->facing, !$this->hingeRight) : $this->facing, 327 / 400)];
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getId() === BlockLegacyIds::AIR){ //Replace with common break method
$this->position->getWorld()->useBreakOn($this->position); //this will delete both halves if they exist
}
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face === Facing::UP){
$blockUp = $this->getSide(Facing::UP);
$blockDown = $this->getSide(Facing::DOWN);
if(!$blockUp->canBeReplaced() || $blockDown->isTransparent()){
return false;
}
if($player !== null){
$this->facing = $player->getHorizontalFacing();
}
$next = $this->getSide(Facing::rotateY($this->facing, false));
$next2 = $this->getSide(Facing::rotateY($this->facing, true));
if($next->isSameType($this) || (!$next2->isTransparent() && $next->isTransparent())){ //Door hinge
$this->hingeRight = true;
}
$topHalf = clone $this;
$topHalf->top = true;
$tx->addBlock($blockReplace->position, $this)->addBlock($blockUp->position, $topHalf);
return true;
}
return false;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->open = !$this->open;
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
if($other instanceof Door && $other->isSameType($this)){
$other->open = $this->open;
$this->position->getWorld()->setBlock($other->position, $other);
}
$this->position->getWorld()->setBlock($this->position, $this);
$this->position->getWorld()->addSound($this->position, new DoorSound());
return true;
}
public function getDrops(Item $item) : array{
if(!$this->top){
return parent::getDrops($item);
}
return [];
}
public function getAffectedBlocks() : array{
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
if($other->isSameType($this)){
return [$this, $other];
}
return parent::getAffectedBlocks();
}
}

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\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class DoublePlant extends Flowable{
protected bool $top = false;
protected function writeStateToMeta() : int{
return ($this->top ? BlockLegacyMetadata::DOUBLE_PLANT_FLAG_TOP : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->top = ($stateMeta & BlockLegacyMetadata::DOUBLE_PLANT_FLAG_TOP) !== 0;
}
public function getStateBitmask() : int{
return 0b1000;
}
public function isTop() : bool{ return $this->top; }
/** @return $this */
public function setTop(bool $top) : self{
$this->top = $top;
return $this;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$id = $blockReplace->getSide(Facing::DOWN)->getId();
if(($id === BlockLegacyIds::GRASS || $id === BlockLegacyIds::DIRT) && $blockReplace->getSide(Facing::UP)->canBeReplaced()){
$top = clone $this;
$top->top = true;
$tx->addBlock($blockReplace->position, $this)->addBlock($blockReplace->position->getSide(Facing::UP), $top);
return true;
}
return false;
}
/**
* Returns whether this double-plant has a corresponding other half.
*/
public function isValidHalfPlant() : bool{
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
return (
$other instanceof DoublePlant &&
$other->isSameType($this) &&
$other->top !== $this->top
);
}
public function onNearbyBlockChange() : void{
if(!$this->isValidHalfPlant() || (!$this->top && $this->getSide(Facing::DOWN)->isTransparent())){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function getDrops(Item $item) : array{
return $this->top ? parent::getDrops($item) : [];
}
public function getAffectedBlocks() : array{
if($this->isValidHalfPlant()){
return [$this, $this->getSide($this->top ? Facing::DOWN : Facing::UP)];
}
return parent::getAffectedBlocks();
}
public function getFlameEncouragement() : int{
return 60;
}
public function getFlammability() : int{
return 100;
}
}

View File

@ -1,85 +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\Fallable;
use pocketmine\block\utils\FallableTrait;
use pocketmine\event\block\BlockTeleportEvent;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\player\GameMode;
use pocketmine\player\Player;
use pocketmine\world\particle\DragonEggTeleportParticle;
use pocketmine\world\World;
use function max;
use function min;
use function mt_rand;
class DragonEgg extends Transparent implements Fallable{
use FallableTrait;
public function getLightLevel() : int{
return 1;
}
public function tickFalling() : ?Block{
return null;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->teleport();
return true;
}
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
if($player !== null && !$player->getGamemode()->equals(GameMode::CREATIVE())){
$this->teleport();
return true;
}
return false;
}
public function teleport() : void{
for($tries = 0; $tries < 16; ++$tries){
$block = $this->position->getWorld()->getBlockAt(
$this->position->x + mt_rand(-16, 16),
max(World::Y_MIN, min(World::Y_MAX - 1, $this->position->y + mt_rand(-8, 8))),
$this->position->z + mt_rand(-16, 16)
);
if($block instanceof Air){
$ev = new BlockTeleportEvent($this, $block->position);
$ev->call();
if($ev->isCancelled()){
break;
}
$blockPos = $ev->getTo();
$this->position->getWorld()->addParticle($this->position, new DragonEggTeleportParticle($this->position->x - $blockPos->x, $this->position->y - $blockPos->y, $this->position->z - $blockPos->z));
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR());
$this->position->getWorld()->setBlock($blockPos, $this);
break;
}
}
}
}

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;
final class DyedShulkerBox extends ShulkerBox{
use ColorInMetadataTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::WHITE();
parent::__construct($idInfo, $name, $breakInfo);
}
}

View File

@ -1,50 +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 Element extends Opaque{
private int $atomicWeight;
private int $group;
private string $symbol;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo, string $symbol, int $atomicWeight, int $group){
parent::__construct($idInfo, $name, $breakInfo);
$this->atomicWeight = $atomicWeight;
$this->group = $group;
$this->symbol = $symbol;
}
public function getAtomicWeight() : int{
return $this->atomicWeight;
}
public function getGroup() : int{
return $this->group;
}
public function getSymbol() : string{
return $this->symbol;
}
}

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\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
class EndPortalFrame extends Opaque{
use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait;
protected bool $eye = false;
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) | ($this->eye ? BlockLegacyMetadata::END_PORTAL_FRAME_FLAG_EYE : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
$this->eye = ($stateMeta & BlockLegacyMetadata::END_PORTAL_FRAME_FLAG_EYE) !== 0;
}
public function getStateBitmask() : int{
return 0b111;
}
public function hasEye() : bool{ return $this->eye; }
/** @return $this */
public function setEye(bool $eye) : self{
$this->eye = $eye;
return $this;
}
public function getLightLevel() : int{
return 1;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 3 / 16)];
}
}

View File

@ -1,92 +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\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class EndRod extends Flowable{
use AnyFacingTrait;
protected function writeStateToMeta() : int{
$result = BlockDataSerializer::writeFacing($this->facing);
if(Facing::axis($this->facing) !== Axis::Y){
$result ^= 1; //TODO: in PC this is always the same as facing, just PE is stupid
}
return $result;
}
public function readStateFromData(int $id, int $stateMeta) : void{
if($stateMeta !== 0 && $stateMeta !== 1){
$stateMeta ^= 1;
}
$this->facing = BlockDataSerializer::readFacing($stateMeta);
}
public function getStateBitmask() : int{
return 0b111;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->facing = $face;
if($blockClicked instanceof EndRod && $blockClicked->facing === $this->facing){
$this->facing = Facing::opposite($face);
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function isSolid() : bool{
return true;
}
public function getLightLevel() : int{
return 14;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$myAxis = Facing::axis($this->facing);
$bb = AxisAlignedBB::one();
foreach([Axis::Y, Axis::Z, Axis::X] as $axis){
if($axis === $myAxis){
continue;
}
$bb->squash($axis, 6 / 16);
}
return [$bb];
}
}

View File

@ -1,73 +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\EnderChestInventory;
use pocketmine\block\tile\EnderChest as TileEnderChest;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
class EnderChest extends Transparent{
use FacesOppositePlacingPlayerTrait;
use NormalHorizontalFacingInMetadataTrait;
public function getLightLevel() : int{
return 7;
}
/**
* @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 onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){
$enderChest = $this->position->getWorld()->getTile($this->position);
if($enderChest instanceof TileEnderChest && $this->getSide(Facing::UP)->isTransparent()){
$enderChest->setViewerCount($enderChest->getViewerCount() + 1);
$player->setCurrentWindow(new EnderChestInventory($this->position, $player->getEnderInventory()));
}
}
return true;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaBlocks::OBSIDIAN()->asItem()->setCount(8)
];
}
public function isAffectedBySilkTouch() : bool{
return true;
}
}

View File

@ -1,130 +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\entity\Entity;
use pocketmine\entity\Living;
use pocketmine\event\entity\EntityTrampleFarmlandEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use function lcg_value;
class Farmland extends Transparent{
protected int $wetness = 0; //"moisture" blockstate property in PC
protected function writeStateToMeta() : int{
return $this->wetness;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->wetness = BlockDataSerializer::readBoundedInt("wetness", $stateMeta, 0, 7);
}
public function getStateBitmask() : int{
return 0b111;
}
public function getWetness() : int{ return $this->wetness; }
/** @return $this */
public function setWetness(int $wetness) : self{
if($wetness < 0 || $wetness > 7){
throw new \InvalidArgumentException("Wetness must be in range 0-7");
}
$this->wetness = $wetness;
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()]; //TODO: this should be trimmed at the top by 1/16, but MCPE currently treats them as a full block (https://bugs.mojang.com/browse/MCPE-12109)
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::UP)->isSolid()){
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::DIRT());
}
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
if(!$this->canHydrate()){
if($this->wetness > 0){
$this->wetness--;
$this->position->getWorld()->setBlock($this->position, $this, false);
}else{
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::DIRT());
}
}elseif($this->wetness < 7){
$this->wetness = 7;
$this->position->getWorld()->setBlock($this->position, $this, false);
}
}
public function onEntityLand(Entity $entity) : ?float{
if($entity instanceof Living && lcg_value() < $entity->getFallDistance() - 0.5){
$ev = new EntityTrampleFarmlandEvent($entity, $this);
$ev->call();
if(!$ev->isCancelled()){
$this->getPosition()->getWorld()->setBlock($this->getPosition(), VanillaBlocks::DIRT());
}
}
return null;
}
protected function canHydrate() : bool{
//TODO: check rain
$start = $this->position->add(-4, 0, -4);
$end = $this->position->add(4, 1, 4);
for($y = $start->y; $y <= $end->y; ++$y){
for($z = $start->z; $z <= $end->z; ++$z){
for($x = $start->x; $x <= $end->x; ++$x){
if($this->position->getWorld()->getBlockAt($x, $y, $z) instanceof Water){
return true;
}
}
}
}
return false;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaBlocks::DIRT()->asItem()
];
}
public function getPickedItem(bool $addUserData = false) : Item{
return VanillaBlocks::DIRT()->asItem();
}
}

View File

@ -1,96 +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\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use function count;
class Fence extends Transparent{
/** @var bool[] facing => dummy */
protected array $connections = [];
public function getThickness() : float{
return 0.25;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
foreach(Facing::HORIZONTAL as $facing){
$block = $this->getSide($facing);
if($block instanceof static || $block instanceof FenceGate || ($block->isSolid() && !$block->isTransparent())){
$this->connections[$facing] = true;
}else{
unset($this->connections[$facing]);
}
}
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$inset = 0.5 - $this->getThickness() / 2;
/** @var AxisAlignedBB[] $bbs */
$bbs = [];
$connectWest = isset($this->connections[Facing::WEST]);
$connectEast = isset($this->connections[Facing::EAST]);
if($connectWest || $connectEast){
//X axis (west/east)
$bbs[] = AxisAlignedBB::one()
->squash(Axis::Z, $inset)
->extend(Facing::UP, 0.5)
->trim(Facing::WEST, $connectWest ? 0 : $inset)
->trim(Facing::EAST, $connectEast ? 0 : $inset);
}
$connectNorth = isset($this->connections[Facing::NORTH]);
$connectSouth = isset($this->connections[Facing::SOUTH]);
if($connectNorth || $connectSouth){
//Z axis (north/south)
$bbs[] = AxisAlignedBB::one()
->squash(Axis::X, $inset)
->extend(Facing::UP, 0.5)
->trim(Facing::NORTH, $connectNorth ? 0 : $inset)
->trim(Facing::SOUTH, $connectSouth ? 0 : $inset);
}
if(count($bbs) === 0){
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
return [
AxisAlignedBB::one()
->extend(Facing::UP, 0.5)
->contract($inset, 0, $inset)
];
}
return $bbs;
}
}

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\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait;
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 pocketmine\world\sound\DoorSound;
class FenceGate extends Transparent{
use HorizontalFacingTrait;
protected bool $open = false;
protected bool $inWall = false;
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) |
($this->open ? BlockLegacyMetadata::FENCE_GATE_FLAG_OPEN : 0) |
($this->inWall ? BlockLegacyMetadata::FENCE_GATE_FLAG_IN_WALL : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
$this->open = ($stateMeta & BlockLegacyMetadata::FENCE_GATE_FLAG_OPEN) !== 0;
$this->inWall = ($stateMeta & BlockLegacyMetadata::FENCE_GATE_FLAG_IN_WALL) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function isOpen() : bool{ return $this->open; }
/** @return $this */
public function setOpen(bool $open) : self{
$this->open = $open;
return $this;
}
public function isInWall() : bool{ return $this->inWall; }
/** @return $this */
public function setInWall(bool $inWall) : self{
$this->inWall = $inWall;
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return $this->open ? [] : [AxisAlignedBB::one()->extend(Facing::UP, 0.5)->squash(Facing::axis($this->facing), 6 / 16)];
}
private function checkInWall() : bool{
return (
$this->getSide(Facing::rotateY($this->facing, false)) instanceof Wall ||
$this->getSide(Facing::rotateY($this->facing, true)) instanceof Wall
);
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
$this->facing = $player->getHorizontalFacing();
}
$this->inWall = $this->checkInWall();
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
$inWall = $this->checkInWall();
if($inWall !== $this->inWall){
$this->inWall = $inWall;
$this->position->getWorld()->setBlock($this->position, $this);
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->open = !$this->open;
if($this->open && $player !== null){
$playerFacing = $player->getHorizontalFacing();
if($playerFacing === Facing::opposite($this->facing)){
$this->facing = $playerFacing;
}
}
$this->position->getWorld()->setBlock($this->position, $this);
$this->position->getWorld()->addSound($this->position, new DoorSound());
return true;
}
public function getFuelTime() : int{
return 300;
}
public function getFlameEncouragement() : int{
return 5;
}
public function getFlammability() : int{
return 20;
}
}

View File

@ -1,266 +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\entity\Entity;
use pocketmine\entity\projectile\Arrow;
use pocketmine\event\block\BlockBurnEvent;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\event\entity\EntityCombustByBlockEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\world\format\Chunk;
use pocketmine\world\World;
use function intdiv;
use function max;
use function min;
use function mt_rand;
class Fire extends Flowable{
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, 15);
}
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 > 15){
throw new \InvalidArgumentException("Age must be in range 0-15");
}
$this->age = $age;
return $this;
}
public function hasEntityCollision() : bool{
return true;
}
public function getLightLevel() : int{
return 15;
}
public function canBeReplaced() : bool{
return true;
}
public function onEntityInside(Entity $entity) : bool{
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
$entity->attack($ev);
$ev = new EntityCombustByBlockEvent($this, $entity, 8);
if($entity instanceof Arrow){
$ev->cancel();
}
$ev->call();
if(!$ev->isCancelled()){
$entity->setOnFire($ev->getDuration());
}
return true;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->isTransparent() && !$this->hasAdjacentFlammableBlocks()){
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR());
}else{
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(30, 40));
}
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
$down = $this->getSide(Facing::DOWN);
$result = null;
if($this->age < 15 && mt_rand(0, 2) === 0){
$this->age++;
$result = $this;
}
$canSpread = true;
if(!$down->burnsForever()){
//TODO: check rain
if($this->age === 15){
if(!$down->isFlammable() && mt_rand(0, 3) === 3){ //1/4 chance to extinguish
$canSpread = false;
$result = VanillaBlocks::AIR();
}
}elseif(!$this->hasAdjacentFlammableBlocks()){
$canSpread = false;
if($down->isTransparent() || $this->age > 3){
$result = VanillaBlocks::AIR();
}
}
}
if($result !== null){
$this->position->getWorld()->setBlock($this->position, $result);
}
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(30, 40));
if($canSpread){
$this->burnBlocksAround();
$this->spreadFire();
}
}
public function onScheduledUpdate() : void{
$this->onRandomTick();
}
private function hasAdjacentFlammableBlocks() : bool{
foreach(Facing::ALL as $face){
if($this->getSide($face)->isFlammable()){
return true;
}
}
return false;
}
private function burnBlocksAround() : void{
//TODO: raise upper bound for chance in humid biomes
foreach($this->getHorizontalSides() as $side){
$this->burnBlock($side, 300);
}
//vanilla uses a 250 upper bound here, but I don't think they intended to increase the chance of incineration
$this->burnBlock($this->getSide(Facing::UP), 350);
$this->burnBlock($this->getSide(Facing::DOWN), 350);
}
private function burnBlock(Block $block, int $chanceBound) : void{
if(mt_rand(0, $chanceBound) < $block->getFlammability()){
$ev = new BlockBurnEvent($block, $this);
$ev->call();
if(!$ev->isCancelled()){
$block->onIncinerate();
if($this->position->getWorld()->getBlock($block->getPosition())->isSameState($block)){
$spreadedFire = false;
if(mt_rand(0, $this->age + 9) < 5){ //TODO: check rain
$fire = clone $this;
$fire->age = min(15, $fire->age + (mt_rand(0, 4) >> 2));
$spreadedFire = $this->spreadBlock($block, $fire);
}
if(!$spreadedFire){
$this->position->getWorld()->setBlock($block->position, VanillaBlocks::AIR());
}
}
}
}
}
private function spreadFire() : void{
$world = $this->position->getWorld();
$difficultyChanceIncrease = $world->getDifficulty() * 7;
$ageDivisor = $this->age + 30;
for($y = -1; $y <= 4; ++$y){
$targetY = $y + (int) $this->position->y;
if($targetY < World::Y_MIN || $targetY >= World::Y_MAX){
continue;
}
//Higher blocks have a lower chance of catching fire
$randomBound = 100 + ($y > 1 ? ($y - 1) * 100 : 0);
for($z = -1; $z <= 1; ++$z){
$targetZ = $z + (int) $this->position->z;
for($x = -1; $x <= 1; ++$x){
if($x === 0 && $y === 0 && $z === 0){
continue;
}
$targetX = $x + (int) $this->position->x;
if(!$world->isInWorld($targetX, $targetY, $targetZ)){
continue;
}
if(!$world->isChunkLoaded($targetX >> Chunk::COORD_BIT_SIZE, $targetZ >> Chunk::COORD_BIT_SIZE)){
continue;
}
$block = $world->getBlockAt($targetX, $targetY, $targetZ);
if($block->getId() !== BlockLegacyIds::AIR){
continue;
}
//TODO: fire can't spread if it's raining in any horizontally adjacent block, or the current one
$encouragement = 0;
foreach($block->position->sides() as $vector3){
if($world->isInWorld($vector3->x, $vector3->y, $vector3->z)){
$encouragement = max($encouragement, $world->getBlockAt($vector3->x, $vector3->y, $vector3->z)->getFlameEncouragement());
}
}
if($encouragement <= 0){
continue;
}
$maxChance = intdiv($encouragement + 40 + $difficultyChanceIncrease, $ageDivisor);
//TODO: max chance is lowered by half in humid biomes
if($maxChance > 0 && mt_rand(0, $randomBound - 1) <= $maxChance){
$new = clone $this;
$new->age = min(15, $this->age + (mt_rand(0, 4) >> 2));
$this->spreadBlock($block, $new);
}
}
}
}
}
private function spreadBlock(Block $block, Block $newState) : bool{
$ev = new BlockSpreadEvent($block, $this, $newState);
$ev->call();
if(!$ev->isCancelled()){
$block->position->getWorld()->setBlock($block->position, $ev->getNewState());
return true;
}
return false;
}
}

View File

@ -1,30 +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 FletchingTable extends Opaque{
public function getFuelTime() : int{
return 300;
}
}

View File

@ -1,62 +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\SignLikeRotationTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class FloorBanner extends BaseBanner{
use SignLikeRotationTrait;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->rotation = $stateMeta;
}
protected function writeStateToMeta() : int{
return $this->rotation;
}
public function getStateBitmask() : int{
return 0b1111;
}
protected function getSupportingFace() : int{
return Facing::DOWN;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::UP){
return false;
}
if($player !== null){
$this->rotation = self::getRotationFromYaw($player->getLocation()->getYaw());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -1,122 +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\item\ItemFactory;
use pocketmine\item\ItemIds;
use pocketmine\math\Axis;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function atan2;
use function rad2deg;
final class FloorCoralFan extends BaseCoral{
protected BlockIdentifierFlattened $idInfoFlattened;
private int $axis = Axis::X;
public function __construct(BlockIdentifierFlattened $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->idInfoFlattened = $idInfo;
parent::__construct($idInfo, $name, $breakInfo);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->dead = $id === $this->idInfoFlattened->getSecondId();
$this->axis = ($stateMeta >> 3) === BlockLegacyMetadata::CORAL_FAN_EAST_WEST ? Axis::X : Axis::Z;
$coralType = CoralTypeIdMap::getInstance()->fromId($stateMeta & BlockLegacyMetadata::CORAL_FAN_TYPE_MASK);
if($coralType === null){
throw new InvalidBlockStateException("No such coral type");
}
$this->coralType = $coralType;
}
public function getId() : int{
return $this->dead ? $this->idInfoFlattened->getSecondId() : parent::getId();
}
public function asItem() : Item{
//TODO: HACK! workaround dead flag being lost when broken / blockpicked (original impl only uses first ID)
return ItemFactory::getInstance()->get(
$this->dead ? ItemIds::CORAL_FAN_DEAD : ItemIds::CORAL_FAN,
$this->writeStateToItemMeta()
);
}
protected function writeStateToMeta() : int{
return (($this->axis === Axis::X ? BlockLegacyMetadata::CORAL_FAN_EAST_WEST : BlockLegacyMetadata::CORAL_FAN_NORTH_SOUTH) << 3) |
CoralTypeIdMap::getInstance()->toId($this->coralType);
}
protected function writeStateToItemMeta() : int{
return CoralTypeIdMap::getInstance()->toId($this->coralType);
}
public function getStateBitmask() : int{
return 0b1111;
}
public function getAxis() : int{ return $this->axis; }
/** @return $this */
public function setAxis(int $axis) : self{
if($axis !== Axis::X && $axis !== Axis::Z){
throw new \InvalidArgumentException("Axis must be X or Z only");
}
$this->axis = $axis;
return $this;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$tx->fetchBlock($blockReplace->getPosition()->down())->isSolid()){
return false;
}
if($player !== null){
$playerBlockPos = $player->getPosition()->floor();
$directionVector = $blockReplace->getPosition()->subtractVector($playerBlockPos)->normalize();
$angle = rad2deg(atan2($directionVector->getZ(), $directionVector->getX()));
if($angle <= 45 || 315 <= $angle || (135 <= $angle && $angle <= 225)){
//TODO: This produces Z axis 75% of the time, because any negative angle will produce Z axis.
//This is a bug in vanilla. https://bugs.mojang.com/browse/MCPE-125311
$this->axis = Axis::Z;
}
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
$world = $this->position->getWorld();
if(!$world->getBlock($this->position->down())->isSolid()){
$world->useBreakOn($this->position);
}else{
parent::onNearbyBlockChange();
}
}
}

View File

@ -1,62 +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\SignLikeRotationTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class FloorSign extends BaseSign{
use SignLikeRotationTrait;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->rotation = $stateMeta;
}
protected function writeStateToMeta() : int{
return $this->rotation;
}
public function getStateBitmask() : int{
return 0b1111;
}
protected function getSupportingFace() : int{
return Facing::DOWN;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::UP){
return false;
}
if($player !== null){
$this->rotation = self::getRotationFromYaw($player->getLocation()->getYaw());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -1,141 +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\FlowerPot as TileFlowerPot;
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 assert;
class FlowerPot extends Flowable{
protected ?Block $plant = null;
protected function writeStateToMeta() : int{
//TODO: HACK! this is just to make the client actually render the plant - we purposely don't read the flag back
return $this->plant !== null ? BlockLegacyMetadata::FLOWER_POT_FLAG_OCCUPIED : 0;
}
public function getStateBitmask() : int{
return 0b1;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileFlowerPot){
$this->setPlant($tile->getPlant());
}else{
$this->setPlant(null);
}
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileFlowerPot);
$tile->setPlant($this->plant);
}
public function getPlant() : ?Block{
return $this->plant;
}
/** @return $this */
public function setPlant(?Block $plant) : self{
if($plant === null || $plant instanceof Air){
$this->plant = null;
}else{
$this->plant = clone $plant;
}
return $this;
}
public function canAddPlant(Block $block) : bool{
if($this->plant !== null){
return false;
}
return
$block instanceof Cactus ||
$block instanceof DeadBush ||
$block instanceof Flower ||
$block instanceof RedMushroom ||
$block instanceof Sapling ||
($block instanceof TallGrass && $block->getIdInfo()->getVariant() === BlockLegacyMetadata::TALLGRASS_FERN); //TODO: clean up
//TODO: bamboo
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->contract(3 / 16, 0, 3 / 16)->trim(Facing::UP, 5 / 8)];
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->getSide(Facing::DOWN)->isTransparent()){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->isTransparent()){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$plant = $item->getBlock();
if(!$this->canAddPlant($plant)){
return false;
}
$this->setPlant($plant);
$item->pop();
$this->position->getWorld()->setBlock($this->position, $this);
return true;
}
public function getDropsForCompatibleTool(Item $item) : array{
$items = parent::getDropsForCompatibleTool($item);
if($this->plant !== null){
$items[] = $this->plant->asItem();
}
return $items;
}
public function getPickedItem(bool $addUserData = false) : Item{
return $this->plant !== null ? $this->plant->asItem() : parent::getPickedItem($addUserData);
}
}

View File

@ -1,122 +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\event\block\BlockMeltEvent;
use function mt_rand;
class FrostedIce extends Ice{
protected int $age = 0;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta, 0, 3);
}
protected function writeStateToMeta() : int{
return $this->age;
}
public function getStateBitmask() : int{
return 0b11;
}
public function getAge() : int{ return $this->age; }
/** @return $this */
public function setAge(int $age) : self{
if($age < 0 || $age > 3){
throw new \InvalidArgumentException("Age must be in range 0-3");
}
$this->age = $age;
return $this;
}
public function onNearbyBlockChange() : void{
if(!$this->checkAdjacentBlocks(2)){
$this->position->getWorld()->useBreakOn($this->position);
}else{
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(20, 40));
}
}
public function onRandomTick() : void{
if((!$this->checkAdjacentBlocks(4) || mt_rand(0, 2) === 0) &&
$this->position->getWorld()->getHighestAdjacentFullLightAt($this->position->x, $this->position->y, $this->position->z) >= 12 - $this->age){
if($this->tryMelt()){
foreach($this->getAllSides() as $block){
if($block instanceof FrostedIce){
$block->tryMelt();
}
}
}
}else{
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(20, 40));
}
}
public function onScheduledUpdate() : void{
$this->onRandomTick();
}
private function checkAdjacentBlocks(int $requirement) : bool{
$found = 0;
for($x = -1; $x <= 1; ++$x){
for($z = -1; $z <= 1; ++$z){
if($x === 0 && $z === 0){
continue;
}
if(
$this->position->getWorld()->getBlockAt($this->position->x + $x, $this->position->y, $this->position->z + $z) instanceof FrostedIce &&
++$found >= $requirement
){
return true;
}
}
}
return false;
}
/**
* Updates the age of the ice, destroying it if appropriate.
*
* @return bool Whether the ice was destroyed.
*/
private function tryMelt() : bool{
if($this->age >= 3){
$ev = new BlockMeltEvent($this, VanillaBlocks::WATER());
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
}
return true;
}
$this->age++;
$this->position->getWorld()->setBlock($this->position, $this);
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(20, 40));
return false;
}
}

View File

@ -1,94 +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\Furnace as TileFurnace;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function mt_rand;
class Furnace extends Opaque{
use FacesOppositePlacingPlayerTrait;
use NormalHorizontalFacingInMetadataTrait {
readStateFromData as readFacingStateFromData;
}
protected BlockIdentifierFlattened $idInfoFlattened;
protected bool $lit = false; //this is set based on the blockID
public function __construct(BlockIdentifierFlattened $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->idInfoFlattened = $idInfo;
parent::__construct($idInfo, $name, $breakInfo);
}
public function getId() : int{
return $this->lit ? $this->idInfoFlattened->getSecondId() : parent::getId();
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->readFacingStateFromData($id, $stateMeta);
$this->lit = $id === $this->idInfoFlattened->getSecondId();
}
public function getLightLevel() : int{
return $this->lit ? 13 : 0;
}
public function isLit() : bool{
return $this->lit;
}
/**
* @return $this
*/
public function setLit(bool $lit = true) : self{
$this->lit = $lit;
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){
$furnace = $this->position->getWorld()->getTile($this->position);
if($furnace instanceof TileFurnace && $furnace->canOpenWith($item->getCustomName())){
$player->setCurrentWindow($furnace->getInventory());
}
}
return true;
}
public function onScheduledUpdate() : void{
$furnace = $this->position->getWorld()->getTile($this->position);
if($furnace instanceof TileFurnace && $furnace->onUpdate()){
if(mt_rand(1, 60) === 1){ //in vanilla this is between 1 and 5 seconds; try to average about 3
$this->position->getWorld()->addSound($this->position, $furnace->getFurnaceType()->getCookSound());
}
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); //TODO: check this
}
}
}

View File

@ -1,117 +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\BlockSpreadEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Hoe;
use pocketmine\item\Item;
use pocketmine\item\Shovel;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\Random;
use pocketmine\world\generator\object\TallGrass as TallGrassObject;
use pocketmine\world\sound\ItemUseOnBlockSound;
use function mt_rand;
class Grass extends Opaque{
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaBlocks::DIRT()->asItem()
];
}
public function isAffectedBySilkTouch() : bool{
return true;
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
$lightAbove = $this->position->getWorld()->getFullLightAt($this->position->x, $this->position->y + 1, $this->position->z);
if($lightAbove < 4 && $this->position->getWorld()->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z)->getLightFilter() >= 2){
//grass dies
$ev = new BlockSpreadEvent($this, $this, VanillaBlocks::DIRT());
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState(), false);
}
}elseif($lightAbove >= 9){
//try grass spread
for($i = 0; $i < 4; ++$i){
$x = mt_rand($this->position->x - 1, $this->position->x + 1);
$y = mt_rand($this->position->y - 3, $this->position->y + 1);
$z = mt_rand($this->position->z - 1, $this->position->z + 1);
$b = $this->position->getWorld()->getBlockAt($x, $y, $z);
if(
!($b instanceof Dirt) ||
$b->isCoarse() ||
$this->position->getWorld()->getFullLightAt($x, $y + 1, $z) < 4 ||
$this->position->getWorld()->getBlockAt($x, $y + 1, $z)->getLightFilter() >= 2
){
continue;
}
$ev = new BlockSpreadEvent($b, $this, VanillaBlocks::GRASS());
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($b->position, $ev->getNewState(), false);
}
}
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::UP){
return false;
}
if($item instanceof Fertilizer){
$item->pop();
TallGrassObject::growGrass($this->position->getWorld(), $this->position, new Random(mt_rand()), 8, 2);
return true;
}elseif($item instanceof Hoe){
$item->applyDamage(1);
$newBlock = VanillaBlocks::FARMLAND();
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
$this->position->getWorld()->setBlock($this->position, $newBlock);
return true;
}elseif($item instanceof Shovel && $this->getSide(Facing::UP)->getId() === BlockLegacyIds::AIR){
$item->applyDamage(1);
$newBlock = VanillaBlocks::GRASS_PATH();
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
$this->position->getWorld()->setBlock($this->position, $newBlock);
return true;
}
return false;
}
}

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\tile\Hopper as TileHopper;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\block\utils\PoweredByRedstoneTrait;
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 Hopper extends Transparent{
use PoweredByRedstoneTrait;
private int $facing = Facing::DOWN;
public function readStateFromData(int $id, int $stateMeta) : void{
$facing = BlockDataSerializer::readFacing($stateMeta & 0x07);
if($facing === Facing::UP){
throw new InvalidBlockStateException("Hopper may not face upward");
}
$this->facing = $facing;
$this->powered = ($stateMeta & BlockLegacyMetadata::HOPPER_FLAG_POWERED) !== 0;
}
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeFacing($this->facing) | ($this->powered ? BlockLegacyMetadata::HOPPER_FLAG_POWERED : 0);
}
public function getStateBitmask() : int{
return 0b1111;
}
public function getFacing() : int{ return $this->facing; }
/** @return $this */
public function setFacing(int $facing) : self{
if($facing === Facing::UP){
throw new \InvalidArgumentException("Hopper may not face upward");
}
$this->facing = $facing;
return $this;
}
protected function recalculateCollisionBoxes() : array{
$result = [
AxisAlignedBB::one()->trim(Facing::UP, 6 / 16) //the empty area around the bottom is currently considered solid
];
foreach(Facing::HORIZONTAL as $f){ //add the frame parts around the bowl
$result[] = AxisAlignedBB::one()->trim($f, 14 / 16);
}
return $result;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->facing = $face === Facing::DOWN ? Facing::DOWN : Facing::opposite($face);
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 !== null){
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileHopper){ //TODO: find a way to have inventories open on click without this boilerplate in every block
$player->setCurrentWindow($tile->getInventory());
}
return true;
}
return false;
}
public function onScheduledUpdate() : void{
//TODO
}
//TODO: redstone logic, sucking logic
}

View File

@ -1,190 +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\ItemFrame as TileItemFrame;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function is_infinite;
use function is_nan;
use function lcg_value;
class ItemFrame extends Flowable{
use HorizontalFacingTrait;
public const ROTATIONS = 8;
protected bool $hasMap = false; //makes frame appear large if set
protected ?Item $framedItem = null;
protected int $itemRotation = 0;
protected float $itemDropChance = 1.0;
protected function writeStateToMeta() : int{
return BlockDataSerializer::write5MinusHorizontalFacing($this->facing) | ($this->hasMap ? BlockLegacyMetadata::ITEM_FRAME_FLAG_HAS_MAP : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::read5MinusHorizontalFacing($stateMeta);
$this->hasMap = ($stateMeta & BlockLegacyMetadata::ITEM_FRAME_FLAG_HAS_MAP) !== 0;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileItemFrame){
$this->framedItem = $tile->getItem();
if($this->framedItem->isNull()){
$this->framedItem = null;
}
$this->itemRotation = $tile->getItemRotation() % self::ROTATIONS;
$this->itemDropChance = $tile->getItemDropChance();
}
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileItemFrame){
$tile->setItem($this->framedItem);
$tile->setItemRotation($this->itemRotation);
$tile->setItemDropChance($this->itemDropChance);
}
}
public function getStateBitmask() : int{
return 0b111;
}
public function getFramedItem() : ?Item{
return $this->framedItem !== null ? clone $this->framedItem : null;
}
/** @return $this */
public function setFramedItem(?Item $item) : self{
if($item === null || $item->isNull()){
$this->framedItem = null;
$this->itemRotation = 0;
}else{
$this->framedItem = clone $item;
}
return $this;
}
public function getItemRotation() : int{
return $this->itemRotation;
}
/** @return $this */
public function setItemRotation(int $itemRotation) : self{
$this->itemRotation = $itemRotation;
return $this;
}
public function getItemDropChance() : float{
return $this->itemDropChance;
}
/** @return $this */
public function setItemDropChance(float $itemDropChance) : self{
if($itemDropChance < 0.0 || $itemDropChance > 1.0 || is_nan($itemDropChance) || is_infinite($itemDropChance)){
throw new \InvalidArgumentException("Drop chance must be in range 0-1");
}
$this->itemDropChance = $itemDropChance;
return $this;
}
public function hasMap() : bool{ return $this->hasMap; }
/**
* This can be set irrespective of whether the frame actually contains a map or not. When set, the frame stretches
* to the edges of the block without leaving space around the edges.
*
* @return $this
*/
public function setHasMap(bool $hasMap) : self{
$this->hasMap = $hasMap;
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->framedItem !== null){
$this->itemRotation = ($this->itemRotation + 1) % self::ROTATIONS;
}elseif(!$item->isNull()){
$this->framedItem = $item->pop();
}else{
return true;
}
$this->position->getWorld()->setBlock($this->position, $this);
return true;
}
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
if($this->framedItem === null){
return false;
}
if(lcg_value() <= $this->itemDropChance){
$this->position->getWorld()->dropItem($this->position->add(0.5, 0.5, 0.5), clone $this->framedItem);
}
$this->setFramedItem(null);
$this->position->getWorld()->setBlock($this->position, $this);
return true;
}
public function onNearbyBlockChange() : void{
if(!$this->getSide(Facing::opposite($this->facing))->isSolid()){
$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($face === Facing::DOWN || $face === Facing::UP || !$blockClicked->isSolid()){
return false;
}
$this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function getDropsForCompatibleTool(Item $item) : array{
$drops = parent::getDropsForCompatibleTool($item);
if($this->framedItem !== null && lcg_value() <= $this->itemDropChance){
$drops[] = clone $this->framedItem;
}
return $drops;
}
public function getPickedItem(bool $addUserData = false) : Item{
return $this->framedItem !== null ? clone $this->framedItem : parent::getPickedItem($addUserData);
}
}

View File

@ -1,116 +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\Jukebox as JukeboxTile;
use pocketmine\item\Item;
use pocketmine\item\Record;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\RecordSound;
use pocketmine\world\sound\RecordStopSound;
class Jukebox extends Opaque{
private ?Record $record = null;
public function getFuelTime() : int{
return 300;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){
if($this->record !== null){
$this->ejectRecord();
}elseif($item instanceof Record){
$player->sendJukeboxPopup("record.nowPlaying", [$player->getLanguage()->translate($item->getRecordType()->getTranslatableName())]);
$this->insertRecord($item->pop());
}
}
$this->position->getWorld()->setBlock($this->position, $this);
return true;
}
public function getRecord() : ?Record{
return $this->record;
}
public function ejectRecord() : void{
if($this->record !== null){
$this->getPosition()->getWorld()->dropItem($this->getPosition()->add(0.5, 1, 0.5), $this->record);
$this->record = null;
$this->stopSound();
}
}
public function insertRecord(Record $record) : void{
if($this->record === null){
$this->record = $record;
$this->startSound();
}
}
public function startSound() : void{
if($this->record !== null){
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordSound($this->record->getRecordType()));
}
}
public function stopSound() : void{
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordStopSound());
}
public function onBreak(Item $item, ?Player $player = null) : bool{
$this->stopSound();
return parent::onBreak($item, $player);
}
public function getDropsForCompatibleTool(Item $item) : array{
$drops = parent::getDropsForCompatibleTool($item);
if($this->record !== null){
$drops[] = $this->record;
}
return $drops;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$jukebox = $this->position->getWorld()->getTile($this->position);
if($jukebox instanceof JukeboxTile){
$this->record = $jukebox->getRecord();
}
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$jukebox = $this->position->getWorld()->getTile($this->position);
if($jukebox instanceof JukeboxTile){
$jukebox->setRecord($this->record);
}
}
//TODO: Jukebox has redstone effects, they are not implemented.
}

View File

@ -1,81 +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\NormalHorizontalFacingInMetadataTrait;
use pocketmine\entity\Entity;
use pocketmine\entity\Living;
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 pocketmine\world\BlockTransaction;
class Ladder extends Transparent{
use NormalHorizontalFacingInMetadataTrait;
public function hasEntityCollision() : bool{
return true;
}
public function isSolid() : bool{
return false;
}
public function canClimb() : bool{
return true;
}
public function onEntityInside(Entity $entity) : bool{
if($entity instanceof Living && $entity->getPosition()->floor()->distanceSquared($this->position) < 1){ //entity coordinates must be inside block
$entity->resetFallDistance();
$entity->onGround = true;
}
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim($this->facing, 13 / 16)];
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$blockClicked->isTransparent() && Facing::axis($face) !== Axis::Y){
$this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onNearbyBlockChange() : void{
if(!$this->getSide(Facing::opposite($this->facing))->isSolid()){ //Replace with common break method
$this->position->getWorld()->useBreakOn($this->position);
}
}
}

View File

@ -1,93 +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 pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class Lantern extends Transparent{
protected bool $hanging = false;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->hanging = ($stateMeta & BlockLegacyMetadata::LANTERN_FLAG_HANGING) !== 0;
}
protected function writeStateToMeta() : int{
return $this->hanging ? BlockLegacyMetadata::LANTERN_FLAG_HANGING : 0;
}
public function getStateBitmask() : int{
return 0b1;
}
public function isHanging() : bool{ return $this->hanging; }
/** @return $this */
public function setHanging(bool $hanging) : self{
$this->hanging = $hanging;
return $this;
}
public function getLightLevel() : int{
return 15;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()
->trim(Facing::UP, $this->hanging ? 6 / 16 : 8 / 16)
->trim(Facing::DOWN, $this->hanging ? 2 / 16 : 0)
->squash(Axis::X, 5 / 16)
->squash(Axis::Z, 5 / 16)
];
}
protected function canAttachTo(Block $b) : bool{
return !$b->isTransparent();
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->up())) && !$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->down()))){
return false;
}
$this->hanging = ($face === Facing::DOWN || !$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->down())));
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if(!$this->canAttachTo($this->position->getWorld()->getBlock($this->hanging ? $this->position->up() : $this->position->down()))){
$this->position->getWorld()->useBreakOn($this->position);
}
}
}

View File

@ -1,166 +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\TreeType;
use pocketmine\event\block\LeavesDecayEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemFactory;
use pocketmine\item\ItemIds;
use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\World;
use function mt_rand;
class Leaves extends Transparent{
protected TreeType $treeType;
protected bool $noDecay = false;
protected bool $checkDecay = false;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo, TreeType $treeType){
parent::__construct($idInfo, $name, $breakInfo);
$this->treeType = $treeType;
}
protected function writeStateToMeta() : int{
return ($this->noDecay ? BlockLegacyMetadata::LEAVES_FLAG_NO_DECAY : 0) | ($this->checkDecay ? BlockLegacyMetadata::LEAVES_FLAG_CHECK_DECAY : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->noDecay = ($stateMeta & BlockLegacyMetadata::LEAVES_FLAG_NO_DECAY) !== 0;
$this->checkDecay = ($stateMeta & BlockLegacyMetadata::LEAVES_FLAG_CHECK_DECAY) !== 0;
}
public function getStateBitmask() : int{
return 0b1100;
}
public function isNoDecay() : bool{ return $this->noDecay; }
/** @return $this */
public function setNoDecay(bool $noDecay) : self{
$this->noDecay = $noDecay;
return $this;
}
public function isCheckDecay() : bool{ return $this->checkDecay; }
/** @return $this */
public function setCheckDecay(bool $checkDecay) : self{
$this->checkDecay = $checkDecay;
return $this;
}
public function blocksDirectSkyLight() : bool{
return true;
}
/**
* @param true[] $visited reference parameter
* @phpstan-param array<int, true> $visited
*/
protected function findLog(Vector3 $pos, array &$visited = [], int $distance = 0) : bool{
$index = World::blockHash($pos->x, $pos->y, $pos->z);
if(isset($visited[$index])){
return false;
}
$visited[$index] = true;
$block = $this->position->getWorld()->getBlock($pos);
if($block instanceof Wood){ //type doesn't matter
return true;
}
if($block->getId() === $this->getId() && $distance <= 4){
foreach(Facing::ALL as $side){
if($this->findLog($pos->getSide($side), $visited, $distance + 1)){
return true;
}
}
}
return false;
}
public function onNearbyBlockChange() : void{
if(!$this->noDecay && !$this->checkDecay){
$this->checkDecay = true;
$this->position->getWorld()->setBlock($this->position, $this, false);
}
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
if(!$this->noDecay && $this->checkDecay){
$ev = new LeavesDecayEvent($this);
$ev->call();
if($ev->isCancelled() || $this->findLog($this->position)){
$this->checkDecay = false;
$this->position->getWorld()->setBlock($this->position, $this, false);
}else{
$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{
$this->noDecay = true; //artificial leaves don't decay
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function getDropsForCompatibleTool(Item $item) : array{
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0){
return parent::getDropsForCompatibleTool($item);
}
$drops = [];
if(mt_rand(1, 20) === 1){ //Saplings
$drops[] = ItemFactory::getInstance()->get(ItemIds::SAPLING, $this->treeType->getMagicNumber());
}
if(($this->treeType->equals(TreeType::OAK()) || $this->treeType->equals(TreeType::DARK_OAK())) && mt_rand(1, 200) === 1){ //Apples
$drops[] = VanillaItems::APPLE();
}
return $drops;
}
public function isAffectedBySilkTouch() : bool{
return true;
}
public function getFlameEncouragement() : int{
return 30;
}
public function getFlammability() : int{
return 60;
}
}

View File

@ -1,166 +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\Lectern as TileLectern;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\item\WritableBookBase;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\LecternPlaceBookSound;
use function count;
class Lectern extends Transparent{
use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait;
protected int $viewedPage = 0;
protected ?WritableBookBase $book = null;
protected bool $producingSignal = false;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
$this->producingSignal = ($stateMeta & BlockLegacyMetadata::LECTERN_FLAG_POWERED) !== 0;
}
public function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) | ($this->producingSignal ? BlockLegacyMetadata::LECTERN_FLAG_POWERED : 0);
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileLectern){
$this->viewedPage = $tile->getViewedPage();
$this->book = $tile->getBook();
}
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileLectern){
$tile->setViewedPage($this->viewedPage);
$tile->setBook($this->book);
}
}
public function getStateBitmask() : int{
return 0b111;
}
public function getFlammability() : int{
return 30;
}
public function getDrops(Item $item) : array{
$drops = parent::getDrops($item);
if($this->book !== null){
$drops[] = clone $this->book;
}
return $drops;
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 0.1)];
}
public function isProducingSignal() : bool{ return $this->producingSignal; }
/** @return $this */
public function setProducingSignal(bool $producingSignal) : self{
$this->producingSignal = $producingSignal;
return $this;
}
public function getViewedPage() : int{
return $this->viewedPage;
}
/** @return $this */
public function setViewedPage(int $viewedPage) : self{
$this->viewedPage = $viewedPage;
return $this;
}
public function getBook() : ?WritableBookBase{
return $this->book !== null ? clone $this->book : null;
}
/** @return $this */
public function setBook(?WritableBookBase $book) : self{
$this->book = $book !== null && !$book->isNull() ? (clone $book)->setCount(1) : null;
$this->viewedPage = 0;
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->book === null && $item instanceof WritableBookBase){
$this->position->getWorld()->setBlock($this->position, $this->setBook($item));
$this->position->getWorld()->addSound($this->position, new LecternPlaceBookSound());
$item->pop();
}
return true;
}
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
if($this->book !== null){
$this->position->getWorld()->dropItem($this->position->up(), $this->book);
$this->position->getWorld()->setBlock($this->position, $this->setBook(null));
}
return false;
}
public function onPageTurn(int $newPage) : bool{
if($newPage === $this->viewedPage){
return true;
}
if($this->book === null || $newPage >= count($this->book->getPages()) || $newPage < 0){
return false;
}
$this->viewedPage = $newPage;
if(!$this->producingSignal){
$this->producingSignal = true;
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1);
}
$this->position->getWorld()->setBlock($this->position, $this);
return true;
}
public function onScheduledUpdate() : void{
if($this->producingSignal){
$this->producingSignal = false;
$this->position->getWorld()->setBlock($this->position, $this);
}
}
}

View File

@ -1,139 +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\LeverFacing;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\RedstonePowerOffSound;
use pocketmine\world\sound\RedstonePowerOnSound;
class Lever extends Flowable{
protected LeverFacing $facing;
protected bool $activated = false;
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->facing = LeverFacing::UP_AXIS_X();
parent::__construct($idInfo, $name, $breakInfo);
}
protected function writeStateToMeta() : int{
$rotationMeta = match($this->facing->id()){
LeverFacing::DOWN_AXIS_X()->id() => 0,
LeverFacing::EAST()->id() => 1,
LeverFacing::WEST()->id() => 2,
LeverFacing::SOUTH()->id() => 3,
LeverFacing::NORTH()->id() => 4,
LeverFacing::UP_AXIS_Z()->id() => 5,
LeverFacing::UP_AXIS_X()->id() => 6,
LeverFacing::DOWN_AXIS_Z()->id() => 7,
default => throw new AssumptionFailedError(),
};
return $rotationMeta | ($this->activated ? BlockLegacyMetadata::LEVER_FLAG_POWERED : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$rotationMeta = $stateMeta & 0x07;
$this->facing = match($rotationMeta){
0 => LeverFacing::DOWN_AXIS_X(),
1 => LeverFacing::EAST(),
2 => LeverFacing::WEST(),
3 => LeverFacing::SOUTH(),
4 => LeverFacing::NORTH(),
5 => LeverFacing::UP_AXIS_Z(),
6 => LeverFacing::UP_AXIS_X(),
7 => LeverFacing::DOWN_AXIS_Z(),
default => throw new AssumptionFailedError("0x07 mask should make this impossible"), //phpstan doesn't understand :(
};
$this->activated = ($stateMeta & BlockLegacyMetadata::LEVER_FLAG_POWERED) !== 0;
}
public function getFacing() : LeverFacing{ return $this->facing; }
/** @return $this */
public function setFacing(LeverFacing $facing) : self{
$this->facing = $facing;
return $this;
}
public function isActivated() : bool{ return $this->activated; }
/** @return $this */
public function setActivated(bool $activated) : self{
$this->activated = $activated;
return $this;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$blockClicked->isSolid()){
return false;
}
$selectUpDownPos = function(LeverFacing $x, LeverFacing $z) use ($player) : LeverFacing{
if($player !== null){
return Facing::axis($player->getHorizontalFacing()) === Axis::X ? $x : $z;
}
return $x;
};
$this->facing = match($face){
Facing::DOWN => $selectUpDownPos(LeverFacing::DOWN_AXIS_X(), LeverFacing::DOWN_AXIS_Z()),
Facing::UP => $selectUpDownPos(LeverFacing::UP_AXIS_X(), LeverFacing::UP_AXIS_Z()),
Facing::NORTH => LeverFacing::NORTH(),
Facing::SOUTH => LeverFacing::SOUTH(),
Facing::WEST => LeverFacing::WEST(),
Facing::EAST => LeverFacing::EAST(),
default => throw new AssumptionFailedError("Bad facing value"),
};
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if(!$this->getSide(Facing::opposite($this->facing->getFacing()))->isSolid()){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->activated = !$this->activated;
$this->position->getWorld()->setBlock($this->position, $this);
$this->position->getWorld()->addSound(
$this->position->add(0.5, 0.5, 0.5),
$this->activated ? new RedstonePowerOnSound() : new RedstonePowerOffSound()
);
return true;
}
//TODO
}

View File

@ -1,391 +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\MinimumCostFlowCalculator;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockFormEvent;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\world\sound\FizzSound;
use pocketmine\world\sound\Sound;
use function lcg_value;
abstract class Liquid extends Transparent{
protected BlockIdentifierFlattened $idInfoFlattened;
public int $adjacentSources = 0;
protected ?Vector3 $flowVector = null;
protected bool $falling = false;
protected int $decay = 0; //PC "level" property
protected bool $still = false;
public function __construct(BlockIdentifierFlattened $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->idInfoFlattened = $idInfo;
parent::__construct($idInfo, $name, $breakInfo);
}
public function getId() : int{
return $this->still ? $this->idInfoFlattened->getSecondId() : parent::getId();
}
protected function writeStateToMeta() : int{
return $this->decay | ($this->falling ? BlockLegacyMetadata::LIQUID_FLAG_FALLING : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->decay = BlockDataSerializer::readBoundedInt("decay", $stateMeta & 0x07, 0, 7);
$this->falling = ($stateMeta & BlockLegacyMetadata::LIQUID_FLAG_FALLING) !== 0;
$this->still = $id === $this->idInfoFlattened->getSecondId();
}
public function getStateBitmask() : int{
return 0b1111;
}
public function isFalling() : bool{ return $this->falling; }
/** @return $this */
public function setFalling(bool $falling) : self{
$this->falling = $falling;
return $this;
}
public function getDecay() : int{ return $this->decay; }
/** @return $this */
public function setDecay(int $decay) : self{
if($decay < 0 || $decay > 7){
throw new \InvalidArgumentException("Decay must be in range 0-7");
}
$this->decay = $decay;
return $this;
}
public function hasEntityCollision() : bool{
return true;
}
public function canBeReplaced() : bool{
return true;
}
public function canBeFlowedInto() : bool{
return true;
}
public function isSolid() : bool{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function getStillForm() : Block{
$b = clone $this;
$b->still = true;
return $b;
}
public function getFlowingForm() : Block{
$b = clone $this;
$b->still = false;
return $b;
}
abstract public function getBucketFillSound() : Sound;
abstract public function getBucketEmptySound() : Sound;
public function isSource() : bool{
return !$this->falling && $this->decay === 0;
}
/**
* @return float
*/
public function getFluidHeightPercent(){
return (($this->falling ? 0 : $this->decay) + 1) / 9;
}
public function isStill() : bool{
return $this->still;
}
/**
* @return $this
*/
public function setStill(bool $still = true) : self{
$this->still = $still;
return $this;
}
protected function getEffectiveFlowDecay(Block $block) : int{
if(!($block instanceof Liquid) || !$block->isSameType($this)){
return -1;
}
return $block->falling ? 0 : $block->decay;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$this->flowVector = null;
}
public function getFlowVector() : Vector3{
if($this->flowVector !== null){
return $this->flowVector;
}
$vX = $vY = $vZ = 0;
$decay = $this->getEffectiveFlowDecay($this);
$world = $this->position->getWorld();
foreach(Facing::HORIZONTAL as $j){
$x = $this->position->x;
$y = $this->position->y;
$z = $this->position->z;
match($j){
Facing::WEST => --$x,
Facing::EAST => ++$x,
Facing::NORTH => --$z,
Facing::SOUTH => ++$z
};
$sideBlock = $world->getBlockAt($x, $y, $z);
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
if($blockDecay < 0){
if(!$sideBlock->canBeFlowedInto()){
continue;
}
$blockDecay = $this->getEffectiveFlowDecay($world->getBlockAt($x, $y - 1, $z));
if($blockDecay >= 0){
$realDecay = $blockDecay - ($decay - 8);
$vX += ($x - $this->position->x) * $realDecay;
$vY += ($y - $this->position->y) * $realDecay;
$vZ += ($z - $this->position->z) * $realDecay;
}
continue;
}else{
$realDecay = $blockDecay - $decay;
$vX += ($x - $this->position->x) * $realDecay;
$vY += ($y - $this->position->y) * $realDecay;
$vZ += ($z - $this->position->z) * $realDecay;
}
}
$vector = new Vector3($vX, $vY, $vZ);
if($this->falling){
foreach(Facing::HORIZONTAL as $facing){
$pos = $this->position->getSide($facing);
if(
!$this->canFlowInto($world->getBlockAt($pos->x, $pos->y, $pos->z)) ||
!$this->canFlowInto($world->getBlockAt($pos->x, $pos->y + 1, $pos->z))
){
$vector = $vector->normalize()->add(0, -6, 0);
break;
}
}
}
return $this->flowVector = $vector->normalize();
}
public function addVelocityToEntity(Entity $entity) : ?Vector3{
if($entity->canBeMovedByCurrents()){
return $this->getFlowVector();
}
return null;
}
abstract public function tickRate() : int;
/**
* Returns how many liquid levels are lost per block flowed horizontally. Affects how far the liquid can flow.
*/
public function getFlowDecayPerBlock() : int{
return 1;
}
/**
* Returns the number of source blocks of this liquid that must be horizontally adjacent to this block in order for
* this block to become a source block itself, or null if the liquid does not exhibit source-forming behaviour.
*/
public function getMinAdjacentSourcesToFormSource() : ?int{
return null;
}
public function onNearbyBlockChange() : void{
if(!$this->checkForHarden()){
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, $this->tickRate());
}
}
public function onScheduledUpdate() : void{
$multiplier = $this->getFlowDecayPerBlock();
$world = $this->position->getWorld();
if(!$this->isSource()){
$smallestFlowDecay = -100;
$this->adjacentSources = 0;
$smallestFlowDecay = $this->getSmallestFlowDecay($world->getBlockAt($this->position->x, $this->position->y, $this->position->z - 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($world->getBlockAt($this->position->x, $this->position->y, $this->position->z + 1), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($world->getBlockAt($this->position->x - 1, $this->position->y, $this->position->z), $smallestFlowDecay);
$smallestFlowDecay = $this->getSmallestFlowDecay($world->getBlockAt($this->position->x + 1, $this->position->y, $this->position->z), $smallestFlowDecay);
$newDecay = $smallestFlowDecay + $multiplier;
$falling = false;
if($newDecay >= 8 || $smallestFlowDecay < 0){
$newDecay = -1;
}
if($this->getEffectiveFlowDecay($world->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z)) >= 0){
$falling = true;
}
$minAdjacentSources = $this->getMinAdjacentSourcesToFormSource();
if($minAdjacentSources !== null && $this->adjacentSources >= $minAdjacentSources){
$bottomBlock = $world->getBlockAt($this->position->x, $this->position->y - 1, $this->position->z);
if($bottomBlock->isSolid() || ($bottomBlock instanceof Liquid && $bottomBlock->isSameType($this) && $bottomBlock->isSource())){
$newDecay = 0;
$falling = false;
}
}
if($falling !== $this->falling || (!$falling && $newDecay !== $this->decay)){
if(!$falling && $newDecay < 0){
$world->setBlock($this->position, VanillaBlocks::AIR());
return;
}
$this->falling = $falling;
$this->decay = $falling ? 0 : $newDecay;
$world->setBlock($this->position, $this); //local block update will cause an update to be scheduled
}
}
$bottomBlock = $world->getBlockAt($this->position->x, $this->position->y - 1, $this->position->z);
$this->flowIntoBlock($bottomBlock, 0, true);
if($this->isSource() || !$bottomBlock->canBeFlowedInto()){
if($this->falling){
$adjacentDecay = 1; //falling liquid behaves like source block
}else{
$adjacentDecay = $this->decay + $multiplier;
}
if($adjacentDecay < 8){
$calculator = new MinimumCostFlowCalculator($this->position->getWorld(), $this->getFlowDecayPerBlock(), \Closure::fromCallable([$this, 'canFlowInto']));
foreach($calculator->getOptimalFlowDirections($this->position->getFloorX(), $this->position->getFloorY(), $this->position->getFloorZ()) as $facing){
$this->flowIntoBlock($world->getBlock($this->position->getSide($facing)), $adjacentDecay, false);
}
}
}
$this->checkForHarden();
}
protected function flowIntoBlock(Block $block, int $newFlowDecay, bool $falling) : void{
if($this->canFlowInto($block) && !($block instanceof Liquid)){
$new = clone $this;
$new->falling = $falling;
$new->decay = $falling ? 0 : $newFlowDecay;
$ev = new BlockSpreadEvent($block, $this, $new);
$ev->call();
if(!$ev->isCancelled()){
if($block->getId() !== BlockLegacyIds::AIR){
$this->position->getWorld()->useBreakOn($block->position);
}
$this->position->getWorld()->setBlock($block->position, $ev->getNewState());
}
}
}
/** @phpstan-impure */
private function getSmallestFlowDecay(Block $block, int $decay) : int{
if(!($block instanceof Liquid) || !$block->isSameType($this)){
return $decay;
}
$blockDecay = $block->decay;
if($block->isSource()){
++$this->adjacentSources;
}elseif($block->falling){
$blockDecay = 0;
}
return ($decay >= 0 && $blockDecay >= $decay) ? $decay : $blockDecay;
}
protected function checkForHarden() : bool{
return false;
}
protected function liquidCollide(Block $cause, Block $result) : bool{
$ev = new BlockFormEvent($this, $result);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new FizzSound(2.6 + (lcg_value() - lcg_value()) * 0.8));
}
return true;
}
protected function canFlowInto(Block $block) : bool{
return
$this->position->getWorld()->isInWorld($block->position->x, $block->position->y, $block->position->z) &&
$block->canBeFlowedInto() &&
!($block instanceof Liquid && $block->isSource()); //TODO: I think this should only be liquids of the same type
}
}

View File

@ -1,57 +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\LoomInventory;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
final class Loom extends Opaque{
use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x3);
}
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing);
}
public function getStateBitmask() : int{
return 0b11;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
$player->setCurrentWindow(new LoomInventory($this->position));
return true;
}
return false;
}
}

View File

@ -1,33 +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;
final class MushroomStem extends Opaque{
public function getDropsForCompatibleTool(Item $item) : array{ return []; }
public function isAffectedBySilkTouch() : bool{ return true; }
}

View File

@ -1,86 +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\entity\Entity;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
class NetherPortal extends Transparent{
protected int $axis = Axis::X;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->axis = $stateMeta === BlockLegacyMetadata::NETHER_PORTAL_AXIS_Z ? Axis::Z : Axis::X; //mojang u dumb
}
protected function writeStateToMeta() : int{
return $this->axis === Axis::Z ? BlockLegacyMetadata::NETHER_PORTAL_AXIS_Z : BlockLegacyMetadata::NETHER_PORTAL_AXIS_X;
}
public function getStateBitmask() : int{
return 0b11;
}
public function getAxis() : int{
return $this->axis;
}
/**
* @throws \InvalidArgumentException
* @return $this
*/
public function setAxis(int $axis) : self{
if($axis !== Axis::X && $axis !== Axis::Z){
throw new \InvalidArgumentException("Invalid axis");
}
$this->axis = $axis;
return $this;
}
public function getLightLevel() : int{
return 11;
}
public function isSolid() : bool{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}
public function getDrops(Item $item) : array{
return [];
}
public function onEntityInside(Entity $entity) : bool{
//TODO
return true;
}
}

View File

@ -1,98 +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\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function mt_rand;
class NetherWartPlant extends Flowable{
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, 3);
}
public function getStateBitmask() : int{
return 0b11;
}
public function getAge() : int{ return $this->age; }
/** @return $this */
public function setAge(int $age) : self{
if($age < 0 || $age > 3){
throw new \InvalidArgumentException("Age must be in range 0-3");
}
$this->age = $age;
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::SOUL_SAND){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getId() !== BlockLegacyIds::SOUL_SAND){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function ticksRandomly() : bool{
return true;
}
public function onRandomTick() : void{
if($this->age < 3 && mt_rand(0, 10) === 0){ //Still growing
$block = clone $this;
$block->age++;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
}
}
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
$this->asItem()->setCount($this->age === 3 ? mt_rand(2, 4) : 1)
];
}
}

View File

@ -1,70 +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\Note as TileNote;
use function assert;
class Note extends Opaque{
public const MIN_PITCH = 0;
public const MAX_PITCH = 24;
private int $pitch = self::MIN_PITCH;
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileNote){
$this->pitch = $tile->getPitch();
}else{
$this->pitch = self::MIN_PITCH;
}
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileNote);
$tile->setPitch($this->pitch);
}
public function getFuelTime() : int{
return 300;
}
public function getPitch() : int{
return $this->pitch;
}
/** @return $this */
public function setPitch(int $pitch) : self{
if($pitch < self::MIN_PITCH || $pitch > self::MAX_PITCH){
throw new \InvalidArgumentException("Pitch must be in range " . self::MIN_PITCH . " - " . self::MAX_PITCH);
}
$this->pitch = $pitch;
return $this;
}
//TODO
}

View File

@ -1,31 +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 PumpkinStem extends Stem{
protected function getPlant() : Block{
return VanillaBlocks::PUMPKIN();
}
}

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