mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-11 12:08:05 +00:00
Compare commits
221 Commits
4.4.0-BETA
...
4.9.1
Author | SHA1 | Date | |
---|---|---|---|
15645759e9 | |||
7df2719fce | |||
10b8dcfdd1 | |||
c1fbac412e | |||
cd4bb91676 | |||
2be527060f | |||
6f68c6d8a0 | |||
ac16378410 | |||
1f9dfa77bf | |||
fc56c041f3 | |||
22486dd75e | |||
37ec1193ea | |||
def2f8c145 | |||
ed7c95549d | |||
4650a3bb22 | |||
5e5661de75 | |||
e2f1b10165 | |||
455f9fa92e | |||
dec188d4ad | |||
2db3498891 | |||
f448b2e685 | |||
6a0c54f850 | |||
77a18d0aea | |||
140a809c40 | |||
cb7c136035 | |||
3f7d8a3777 | |||
3c55db531d | |||
93d4475111 | |||
7804172846 | |||
481bda8cd5 | |||
d1c75da14b | |||
66e70e5b0e | |||
785dc71256 | |||
d459afaa54 | |||
db586233da | |||
23e98a30f5 | |||
5bc7ca6569 | |||
f39d2a9be3 | |||
47d98af6ac | |||
82ba7903c8 | |||
112974758e | |||
313850eec4 | |||
a82923acb4 | |||
67887afd6b | |||
3d03bb1301 | |||
c063198b89 | |||
f3ca6de1eb | |||
88eafdd614 | |||
6dd5fec4ea | |||
6866c86d39 | |||
a735a69870 | |||
a0ea74c08f | |||
ca4b8a5827 | |||
f88c4d9a8c | |||
66cd156d80 | |||
222049927a | |||
d72e947d15 | |||
770cca2efa | |||
033dac3d16 | |||
1ee02d7e02 | |||
85678aa356 | |||
1d253bc8c2 | |||
973a56ab28 | |||
9e0b4621be | |||
b7a15b6e01 | |||
456439566b | |||
fb25e05416 | |||
78b5be8dd0 | |||
0a92e91a30 | |||
b3a13a2f21 | |||
08b9495bce | |||
5779622235 | |||
7f175b47e6 | |||
0e73ffe555 | |||
1ffd38b37b | |||
bd13f39156 | |||
0c446c276c | |||
0284e65f60 | |||
b0d787b3d3 | |||
65e3ed43d5 | |||
75eba9c9ed | |||
b5a049d1fe | |||
bd9fcffe62 | |||
feffbc2c5b | |||
53b51c99b4 | |||
5cb77c8365 | |||
bf8befc40b | |||
f75ca312cc | |||
d144832928 | |||
709a869045 | |||
ac056044ce | |||
fc8434308b | |||
5426b41447 | |||
af2babec23 | |||
717ab1989a | |||
83db186b6a | |||
6a4e5aba8b | |||
c13170a00b | |||
98778052bb | |||
e86e8254a8 | |||
1b852ac290 | |||
10b799fadb | |||
bc5008334a | |||
575dd47db7 | |||
e4a5defabb | |||
c9626c610b | |||
8fb7fff6b9 | |||
5c8d8ff61f | |||
99b55f7427 | |||
dce8bd6d21 | |||
8fa81242d6 | |||
2f4a9469b6 | |||
c5b2488fc1 | |||
d62df585f2 | |||
19d7c2b552 | |||
036e06e889 | |||
9343a0b800 | |||
14b4644b03 | |||
464b65b25c | |||
15586ed80e | |||
0f8ad8ecf7 | |||
82b9afef77 | |||
2fc84f6c67 | |||
566f5935a3 | |||
44e4dabf6e | |||
8acc535218 | |||
e9a1cb7ce5 | |||
a21419d120 | |||
c2b599166c | |||
df7a1fcba6 | |||
d77a95e4af | |||
5c72807b16 | |||
5c6927e16c | |||
9abbb85a93 | |||
554182b2cb | |||
d669a6f0c7 | |||
5d9f783037 | |||
01ca14c314 | |||
608c6ed6db | |||
c26631d06d | |||
b75bc61a64 | |||
3724479be3 | |||
eb916fe43d | |||
5e3b3a0700 | |||
e10a624444 | |||
b20e04539d | |||
4852f8029a | |||
c4f85e526b | |||
6cee428287 | |||
bcba064d69 | |||
86647683bc | |||
64f0e58e60 | |||
62f21516d1 | |||
c553f7cf06 | |||
fec89b7803 | |||
2b61c025c2 | |||
c7133bc2e6 | |||
baf75089f5 | |||
705df7d508 | |||
75d7adfb2d | |||
9d535e2917 | |||
3ccd288afd | |||
06655bee78 | |||
0ad2985247 | |||
269b6ed16a | |||
f031c3c602 | |||
f3e09dd7d5 | |||
68e704bf97 | |||
9898577135 | |||
784d602600 | |||
15c99cfe77 | |||
d5fa0a2fc5 | |||
0da9260994 | |||
df2d1fd4f9 | |||
9f65fb5f90 | |||
caa4b78a3f | |||
14352a05bc | |||
bb5b52d998 | |||
5e22b70b6d | |||
02513818a9 | |||
d641812c52 | |||
a851496293 | |||
01a8bce2dd | |||
becbd562d6 | |||
82edb20e0c | |||
64a8c462f9 | |||
4ec97d0f7a | |||
016a80bb70 | |||
ce66a400a7 | |||
50776875bb | |||
bcb0e2ff1f | |||
1584768c80 | |||
5fd685e07d | |||
6ecfbd1bde | |||
b661097c51 | |||
0771295899 | |||
702816458c | |||
e040c2b281 | |||
e12e4e8fb8 | |||
d15a90899e | |||
237c2866e0 | |||
38d6284671 | |||
7355798e77 | |||
4b662d65b3 | |||
c87a3b054c | |||
8b86e43d51 | |||
eade2d2af0 | |||
f2299a562f | |||
3fcf6372e0 | |||
533cb77c50 | |||
681a9bb0e1 | |||
6c080dae55 | |||
670fb4de74 | |||
6d7318af43 | |||
97c0d72e28 | |||
4ccae2d1de | |||
b36c6ea13b | |||
39b8daeeec | |||
c492352d50 | |||
8f1452acd1 | |||
227f28a6d2 |
8
.github/workflows/build-docker-image.yml
vendored
8
.github/workflows/build-docker-image.yml
vendored
@ -46,7 +46,7 @@ jobs:
|
||||
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v3.0.0
|
||||
uses: docker/build-push-action@v3.1.1
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.0.0
|
||||
uses: docker/build-push-action@v3.1.1
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -72,7 +72,7 @@ jobs:
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.0.0
|
||||
uses: docker/build-push-action@v3.1.1
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -85,7 +85,7 @@ jobs:
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v3.0.0
|
||||
uses: docker/build-push-action@v3.1.1
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
100
.github/workflows/discord-release-embed.php
vendored
Normal file
100
.github/workflows/discord-release-embed.php
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\utils\Internet;
|
||||
use function dirname;
|
||||
use function fwrite;
|
||||
use function is_array;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const STDERR;
|
||||
|
||||
require dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* @phpstan-return array<string, mixed>
|
||||
*/
|
||||
function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl) : array{
|
||||
return [
|
||||
"embeds" => [
|
||||
[
|
||||
"title" => "New PocketMine-MP release: $version ($channel)",
|
||||
"description" => <<<DESCRIPTION
|
||||
$description
|
||||
|
||||
[Details]($detailsUrl) | [Source Code]($sourceUrl) | [Build Log]($buildLogUrl) | [Download]($pharDownloadUrl)
|
||||
DESCRIPTION,
|
||||
"url" => $detailsUrl,
|
||||
"color" => $channel === "stable" ? 0x57ab5a : 0xc69026
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
if(count($argv) !== 5){
|
||||
fwrite(STDERR, "Required arguments: github repo, version, API token\n");
|
||||
exit(1);
|
||||
}
|
||||
[, $repo, $tagName, $token, $hookURL] = $argv;
|
||||
|
||||
$result = Internet::getURL('https://api.github.com/repos/' . $repo . '/releases/tags/' . $tagName, extraHeaders: [
|
||||
'Authorization: token ' . $token
|
||||
]);
|
||||
if($result === null){
|
||||
fwrite(STDERR, "failed to access GitHub API\n");
|
||||
return;
|
||||
}
|
||||
if($result->getCode() !== 200){
|
||||
fwrite(STDERR, "Error accessing GitHub API: " . $result->getCode() . "\n");
|
||||
fwrite(STDERR, $result->getBody() . "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$releaseInfoJson = json_decode($result->getBody(), true, JSON_THROW_ON_ERROR);
|
||||
if(!is_array($releaseInfoJson)){
|
||||
fwrite(STDERR, "Invalid release JSON returned from GitHub API\n");
|
||||
exit(1);
|
||||
}
|
||||
$buildInfoPath = 'https://github.com/' . $repo . '/releases/download/' . $tagName . '/build_info.json';
|
||||
|
||||
$buildInfoResult = Internet::getURL($buildInfoPath, extraHeaders: [
|
||||
'Authorization: token ' . $token
|
||||
]);
|
||||
if($buildInfoResult === null){
|
||||
fwrite(STDERR, "missing build_info.json\n");
|
||||
exit(1);
|
||||
}
|
||||
if($buildInfoResult->getCode() !== 200){
|
||||
fwrite(STDERR, "error accessing build_info.json: " . $buildInfoResult->getCode() . "\n");
|
||||
fwrite(STDERR, $buildInfoResult->getBody() . "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$buildInfoJson = json_decode($buildInfoResult->getBody(), true, JSON_THROW_ON_ERROR);
|
||||
if(!is_array($buildInfoJson)){
|
||||
fwrite(STDERR, "invalid build_info.json\n");
|
||||
exit(1);
|
||||
}
|
||||
$detailsUrl = $buildInfoJson["details_url"];
|
||||
$sourceUrl = $buildInfoJson["source_url"];
|
||||
$pharDownloadUrl = $buildInfoJson["download_url"];
|
||||
$buildLogUrl = $buildInfoJson["build_log_url"];
|
||||
|
||||
$description = $releaseInfoJson["body"];
|
||||
|
||||
$discordPayload = generateDiscordEmbed($buildInfoJson["base_version"], $buildInfoJson["channel"], $description, $detailsUrl, $sourceUrl, $pharDownloadUrl, $buildLogUrl);
|
||||
|
||||
$response = Internet::postURL(
|
||||
$hookURL,
|
||||
json_encode($discordPayload, JSON_THROW_ON_ERROR),
|
||||
extraHeaders: ['Content-Type: application/json']
|
||||
);
|
||||
if($response?->getCode() !== 204){
|
||||
fwrite(STDERR, "failed to send Discord webhook\n");
|
||||
fwrite(STDERR, $response?->getBody() ?? "no response body\n");
|
||||
exit(1);
|
||||
}
|
38
.github/workflows/discord-release-notify.yml
vendored
Normal file
38
.github/workflows/discord-release-notify.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: Notify Discord webhook of release
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.21.2
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
|
||||
|
||||
- name: Get actual tag name
|
||||
id: tag-name
|
||||
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
|
||||
|
||||
- name: Run webhook post script
|
||||
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }}
|
6
.github/workflows/draft-release.yml
vendored
6
.github/workflows/draft-release.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.18.1
|
||||
uses: shivammathur/setup-php@2.21.2
|
||||
with:
|
||||
php-version: 8.0
|
||||
|
||||
@ -57,7 +57,7 @@ jobs:
|
||||
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::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
|
||||
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} ${{ github.run_id }} > build_info.json
|
||||
|
||||
- name: Upload release artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
@ -80,4 +80,4 @@ jobs:
|
||||
body: |
|
||||
**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.
|
||||
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
|
||||
|
24
.github/workflows/main.yml
vendored
24
.github/workflows/main.yml
vendored
@ -13,11 +13,11 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.18]
|
||||
php: [8.0.23, 8.1.10]
|
||||
|
||||
steps:
|
||||
- name: Build and prepare PHP cache
|
||||
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
|
||||
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
@ -31,13 +31,13 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.18]
|
||||
php: [8.0.23, 8.1.10]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
|
||||
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
@ -69,13 +69,13 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.18]
|
||||
php: [8.0.23, 8.1.10]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
|
||||
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
@ -107,7 +107,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.18]
|
||||
php: [8.0.23, 8.1.10]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -115,7 +115,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
|
||||
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
@ -147,13 +147,13 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: [8.0.18]
|
||||
php: [8.0.23, 8.1.10]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@aa636a4fe0c1c035fd9a3f05e360eadd86e06440
|
||||
uses: pmmp/setup-php-action@82a44d659bf5046612c69f036af3e14dc32e3fa8
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
@ -195,10 +195,10 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.18.1
|
||||
uses: shivammathur/setup-php@2.21.2
|
||||
with:
|
||||
php-version: 8.0
|
||||
tools: php-cs-fixer:3.2
|
||||
tools: php-cs-fixer:3.11
|
||||
|
||||
- name: Run PHP-CS-Fixer
|
||||
run: php-cs-fixer fix --dry-run --diff --ansi
|
||||
|
9
.github/workflows/support.yml
vendored
9
.github/workflows/support.yml
vendored
@ -13,7 +13,14 @@ jobs:
|
||||
github-token: ${{ github.token }}
|
||||
support-label: "Support request"
|
||||
issue-comment: >
|
||||
Thanks, but this issue tracker is not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue).
|
||||
Hi, we only accept **bug reports** on this issue tracker, but this issue looks like a support request.
|
||||
|
||||
|
||||
Instead of creating an issue, try the following:
|
||||
|
||||
- Check our [Documentation](https://doc.pmmp.io) to see if you can find answers there
|
||||
|
||||
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG) or our [Forums](https://forums.pmmp.io)
|
||||
|
||||
|
||||
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
|
||||
|
3
.github/workflows/update-php-versions.php
vendored
3
.github/workflows/update-php-versions.php
vendored
@ -22,7 +22,8 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
const VERSIONS = [
|
||||
"8.0"
|
||||
"8.0",
|
||||
"8.1"
|
||||
];
|
||||
|
||||
$workflowFile = file_get_contents(__DIR__ . '/main.yml');
|
||||
|
@ -42,12 +42,38 @@ return (new PhpCsFixer\Config)
|
||||
'import_functions' => true,
|
||||
'import_classes' => null,
|
||||
],
|
||||
'header_comment' => [
|
||||
'comment_type' => 'comment',
|
||||
'header' => <<<BODY
|
||||
|
||||
____ _ _ __ __ _ __ __ ____
|
||||
| _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
| |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
| __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
|_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
@author PocketMine Team
|
||||
@link http://www.pocketmine.net/
|
||||
|
||||
|
||||
BODY,
|
||||
'location' => 'after_open'
|
||||
],
|
||||
'indentation_type' => true,
|
||||
'logical_operators' => true,
|
||||
'native_function_invocation' => [
|
||||
'scope' => 'namespaced',
|
||||
'include' => ['@all'],
|
||||
],
|
||||
'new_with_braces' => [
|
||||
'named_class' => true,
|
||||
'anonymous_class' => false,
|
||||
],
|
||||
'no_closing_tag' => true,
|
||||
'no_empty_phpdoc' => true,
|
||||
'no_extra_blank_lines' => true,
|
||||
|
@ -18,6 +18,32 @@ Larger contributions like feature additions should be preceded by a [Change Prop
|
||||
## Other things you'll need
|
||||
- [git](https://git-scm.com/)
|
||||
|
||||
## Choosing a target branch
|
||||
PocketMine-MP has three primary branches of development.
|
||||
|
||||
| Type of change | `stable` | `next-minor` | `next-major` |
|
||||
|:---------------|:--------:|:------------:|:------------:|
|
||||
| Bug fixes | ✔️ | ✔️ | ✔️ |
|
||||
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
|
||||
| Cleaning up code | ❌ | ✔️ | ✔️ |
|
||||
| Changing code formatting or style | ❌ | ✔️ | ✔️ |
|
||||
| Addition of new core features | ❌ | 🟡 Only if non-disruptive | ✔️ |
|
||||
| Changing core behaviour (e.g. making something use threads) | ❌ | ✔️ | ✔️ |
|
||||
| Addition of new configuration options | ❌ | 🟡 Only if optional | ✔️ |
|
||||
| Addition of new API classes, methods or constants | ❌ | ✔️ | ✔️ |
|
||||
| Deprecating API classes, methods or constants | ❌ | ✔️ | ✔️ |
|
||||
| Adding optional parameters to an API method | ❌ | ✔️ | ✔️ |
|
||||
| Changing API behaviour | ❌ | 🟡 Only if backwards-compatible | ✔️ |
|
||||
| Removal of API | ❌ | ❌ | ✔️ |
|
||||
| Backwards-incompatible API change (e.g. renaming a method) | ❌ | ❌ | ✔️ |
|
||||
|
||||
### Notes
|
||||
- **Non-disruptive** means that usage should not be significantly altered by the change.
|
||||
- Examples of **non-disruptive** changes include adding new commands, or gameplay features like blocks and items.
|
||||
- Examples of **disruptive** changes include changing the way the server is run, world format changes (since those require downtime for the user to convert their world).
|
||||
- **API** includes all public and protected classes, functions and constants (unless marked as `@internal`).
|
||||
- Private members are not part of the API, **unless in a trait**.
|
||||
|
||||
## Making a pull request
|
||||
The basic procedure to create a pull request is:
|
||||
1. [Fork the repository on GitHub](https://github.com/pmmp/PocketMine-MP/fork). This gives you your own copy of the repository to make changes to.
|
||||
|
@ -7,10 +7,11 @@ GitHub is public and anyone can see the issues you post on the issue tracker, in
|
||||
|
||||
**WARNING: You may put live servers at risk by reporting a vulnerability on the GitHub issue tracker.**
|
||||
|
||||
**Contact us** by sending an email to [**team@pmmp.io**](mailto:team@pmmp.io?subject=Security%20Vulnerability%20in%20PocketMine-MP). Include the following information:
|
||||
**Contact us** by sending an email to [**security@pmmp.io**](mailto:security@pmmp.io). Include the following information:
|
||||
|
||||
- Version of PocketMine-MP
|
||||
- Detailed description of the vulnerability (e.g. how to exploit it, what the effects are)
|
||||
- Your GitHub username, if you wish to be credited for reporting the problem in the security advisory
|
||||
|
||||
Please note that we can't guarantee a reply to every email.
|
||||
|
||||
|
@ -23,8 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if(count($argv) !== 5){
|
||||
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number>");
|
||||
if(count($argv) !== 6){
|
||||
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number> <github actions run ID>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -40,4 +40,5 @@ echo json_encode([
|
||||
"details_url" => "https://github.com/$argv[3]/releases/tag/$argv[2]",
|
||||
"download_url" => "https://github.com/$argv[3]/releases/download/$argv[2]/PocketMine-MP.phar",
|
||||
"source_url" => "https://github.com/$argv[3]/tree/$argv[2]",
|
||||
"build_log_url" => "https://github.com/$argv[3]/actions/runs/$argv[5]",
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n";
|
||||
|
@ -29,7 +29,9 @@ use function count;
|
||||
use function dirname;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function fwrite;
|
||||
use function implode;
|
||||
use function is_dir;
|
||||
use function ksort;
|
||||
use function mb_strtoupper;
|
||||
use function preg_match;
|
||||
@ -39,7 +41,8 @@ use function substr;
|
||||
use const SORT_STRING;
|
||||
|
||||
if(count($argv) !== 2){
|
||||
die("Provide a path to process");
|
||||
fwrite(STDERR, "Provide a path to process\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,30 +83,24 @@ function generateMethodAnnotations(string $namespaceName, array $members) : stri
|
||||
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;
|
||||
}
|
||||
function processFile(string $file) : void{
|
||||
$contents = file_get_contents($file);
|
||||
if($contents === false){
|
||||
throw new \RuntimeException("Failed to get contents of $file");
|
||||
}
|
||||
|
||||
if(preg_match("/(*ANYCRLF)^namespace (.+);$/m", $contents, $matches) !== 1 || preg_match('/(*ANYCRLF)^((final|abstract)\s+)?class /m', $contents) !== 1){
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
$shortClassName = basename($file, ".php");
|
||||
$className = $matches[1] . "\\" . $shortClassName;
|
||||
if(!class_exists($className)){
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
$reflect = new \ReflectionClass($className);
|
||||
$docComment = $reflect->getDocComment();
|
||||
if($docComment === false || preg_match("/(*ANYCRLF)^\s*\*\s*@generate-registry-docblock$/m", $docComment) !== 1){
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
echo "Found registry in $file\n";
|
||||
|
||||
@ -117,3 +114,18 @@ foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1],
|
||||
echo "No changes made to file $file\n";
|
||||
}
|
||||
}
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if(is_dir($argv[1])){
|
||||
/** @var string $file */
|
||||
foreach(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($argv[1], \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $file){
|
||||
if(substr($file, -4) !== ".php"){
|
||||
continue;
|
||||
}
|
||||
|
||||
processFile($file);
|
||||
}
|
||||
}else{
|
||||
processFile($argv[1]);
|
||||
}
|
||||
|
Submodule build/php updated: 8138c6a4a4...50062b5861
@ -19,7 +19,7 @@ Released 25th May 2022.
|
||||
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to generate (e.g. due to invalid generator settings)
|
||||
- Enabling the server whitelist while the server is running (e.g. using `/whitelist on`) will now kick any non-whitelisted players currently on the server (**PR [#4774](https://github.com/pmmp/PocketMine-MP/pull/4774)**).
|
||||
- Help for commands (`/help <name of command>`) now displays a list of aliases of that command.
|
||||
- A CRITICIAL log message is now generated if a plugin disables itself when enabling, in case the plugin doesn't emit any error of its own.
|
||||
- A CRITICAL log message is now generated if a plugin disables itself when enabling, in case the plugin doesn't emit any error of its own.
|
||||
- The `/give` command now shows the alias used to find the given item in the success message, instead of the item ID/meta.
|
||||
|
||||
## Fixes
|
||||
|
97
changelogs/4.4.md
Normal file
97
changelogs/4.4.md
Normal file
@ -0,0 +1,97 @@
|
||||
**For Minecraft: Bedrock Edition 1.18.30**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.4.0
|
||||
Released 1st June 2022.
|
||||
|
||||
## General
|
||||
- The server will now shut itself down if any of the following errors occur during startup:
|
||||
- Any plugin fails to load or enable (plugins loaded by other plugins post-startup are **not** affected by this change) (**PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)**)
|
||||
- The motivation for this change is to prevent situations where plugins failing to load could result in adverse outcomes, such as a world protection plugin leaving a lobby unprotected from griefing.
|
||||
- If you encounter this problem, remove the offending plugin(s) or prevent it from loading using `plugin_list.yml`.
|
||||
- See **PR [#4951](https://github.com/pmmp/PocketMine-MP/pull/4951)** for more detail on this change.
|
||||
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to load (worlds loaded by plugins are **not** affected by this change)
|
||||
- Any world mentioned in `server.properties` or `pocketmine.yml` fails to generate (e.g. due to invalid generator settings)
|
||||
- Enabling the server whitelist while the server is running (e.g. using `/whitelist on`) will now kick any non-whitelisted players currently on the server (**PR [#4774](https://github.com/pmmp/PocketMine-MP/pull/4774)**).
|
||||
- Help for commands (`/help <name of command>`) now displays a list of aliases of that command.
|
||||
- A CRITICAL log message is now generated if a plugin disables itself when enabling, in case the plugin doesn't emit any error of its own.
|
||||
- The `/give` command now shows the alias used to find the given item in the success message, instead of the item ID/meta.
|
||||
|
||||
## Fixes
|
||||
- Block placement has been fixed in many places where it previously didn't work correctly (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**):
|
||||
- torches on top of slabs, upside-down stairs
|
||||
- torches on the back face of stairs
|
||||
- flower pots on top of fences
|
||||
- the list goes on and on ...
|
||||
- Fixed backslash escapes not getting properly removed from commands in some cases.
|
||||
- Fixed aliases defined in the `aliases` section of `pocketmine.yml` not being treated as quote-aware.
|
||||
|
||||
## Gameplay
|
||||
- Plants in flower pots can now be removed by right-clicking on the flower pot.
|
||||
- Leaves now have a 2% chance of dropping sticks when destroyed by hand (**PR [#5019](https://github.com/pmmp/PocketMine-MP/pull/5019)**).
|
||||
- Food exhaustion now matches Bedrock 1.18.30 (**PR [#5034](https://github.com/pmmp/PocketMine-MP/pull/5034)**).
|
||||
- Implemented Stonecutter block (**PR [#4732](https://github.com/pmmp/PocketMine-MP/pull/4732)**).
|
||||
|
||||
## API
|
||||
### Block
|
||||
- Added `Block->getSupportType(Facing) : SupportType` (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
|
||||
- This is used to determine the kind of support a block face can provide to a block (e.g. a torch) placed on it.
|
||||
- Added `utils\SupportType` enum (**PR [#4886](https://github.com/pmmp/PocketMine-MP/pull/4886)**).
|
||||
- `tile\Spawnable->isDirty()` and `tile\Spawnable->setDirty()` are now `@deprecated`.
|
||||
|
||||
### Command
|
||||
- Added `CommandStringHelper::parseQuoteAware()`. This static method contains the code used by `SimpleCommandMap` used to parse quoted command arguments.
|
||||
|
||||
### Entity
|
||||
- Added `Human::emote()` (**PR [#4610](https://github.com/pmmp/PocketMine-MP/pull/4610)**)
|
||||
|
||||
### Event
|
||||
- `PlayerCommandPreprocessEvent` is now `@deprecated`, since its functionality is entirely replaced by other, general-purpose events.
|
||||
- Use `CommandEvent` to intercept commands.
|
||||
- Use `PlayerChatEvent` to intercept chat messages.
|
||||
- To convert a chat message into a command, pass it directly to `Server->dispatchCommand()` with the player as sender.
|
||||
- Added `PlayerPostChunkSendEvent` (**PR [#4937](https://github.com/pmmp/PocketMine-MP/pull/4937)**).
|
||||
- Added `PlayerDeathEvent->setKeepXp()` (**PR [#4015](https://github.com/pmmp/PocketMine-MP/pull/4015)**).
|
||||
- `InventoryCloseEvent` is now called **after** the target window has been removed. This fixes various feedback loops caused by trying to open new windows to a player while there was one still active.
|
||||
- As a side effect, this now means that `Player->getCurrentWindow()` will return `null` during `InventoryCloseEvent`. Use `InventoryCloseEvent->getInventory()` instead.
|
||||
|
||||
### Item
|
||||
- `StringToItemParser` now recognizes `cod`, `raw_cod` and `cooked_cod` aliases.
|
||||
|
||||
### Plugin
|
||||
- `DisablePluginException` may now be thrown from `Plugin::onEnable()` to make the server gracefully disable the plugin (without crashing) (**PR [#4780](https://github.com/pmmp/PocketMine-MP/pull/4780)**).
|
||||
- `PluginManager->registerEvent()` now returns the `RegisteredListener` created for the handler, to permit unregistering it later.
|
||||
|
||||
## Internals
|
||||
- Private property declarations now use typed properties (PHP 7.4) and promoted constructor properties (PHP 8.0) wherever possible.
|
||||
- Protected and public properties remain unchanged, since they can't be changed without breaking subclasses.
|
||||
- Promoted constructor properties are only used when it's consistently possible to promote most or all properties in a class.
|
||||
- Simplified and improved legibility of `FormattedCommandAlias`.
|
||||
- Added unit tests for the quote-aware command parser used by `SimpleCommandMap`.
|
||||
- Various hardcoded values in `block` package classes have been moved to private constants to improve readability.
|
||||
- Added various constants used in the `LevelDB` world provider.
|
||||
|
||||
# 4.4.1
|
||||
Released 5th June 2022.
|
||||
|
||||
## General
|
||||
- The server process will now exit with an error code if plugins, worlds or network interfaces failed to start.
|
||||
|
||||
## Fixes
|
||||
- Fixed graylisted plugins preventing the server from starting.
|
||||
- Fixed `composer make-devtools` command.
|
||||
- Fixed the `Maximum memory (manager)` units being incorrectly displayed in `/status`.
|
||||
- Fixed `Player->removeCurrentWindow()` breaking inventory windows.
|
||||
|
||||
# 4.4.2
|
||||
Released 7th June 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed a crash when arbitrary item IDs appeared in network items in some cases.
|
||||
- Fixed saved paintings being deleted when loaded from disk (regression from 4.3.4).
|
||||
- Fixed max stack size of fishing rods.
|
28
changelogs/4.5.md
Normal file
28
changelogs/4.5.md
Normal file
@ -0,0 +1,28 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.0**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.5.0
|
||||
Released 7th June 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.0.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.5.1
|
||||
Released 8th June 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed commands defined in `pocketmine.yml` `aliases` not passing the correct arguments.
|
||||
- Updated BedrockProtocol to fix command argument types displayed on client-side command suggestions.
|
||||
|
||||
# 4.5.2
|
||||
Released 29th June 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed terrain getting redrawn when flying in spectator mode (or when using `Player->setHasBlockCollision(false)`).
|
||||
- Fixed skulls with the `noDrops` flag set being treated as unknown blocks.
|
42
changelogs/4.6.md
Normal file
42
changelogs/4.6.md
Normal file
@ -0,0 +1,42 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.10**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.6.0
|
||||
Released 13th July 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.10.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.6.1
|
||||
Released 22nd July 2022.
|
||||
|
||||
## Tools
|
||||
- `build/generate-registry-annotations.php` now supports processing single files (useful for PhpStorm file watchers).
|
||||
|
||||
## API
|
||||
- Updated documentation for `AsyncTask`.
|
||||
|
||||
## Fixes
|
||||
- Fixed incorrect items being displayed in item frames.
|
||||
- Fixed books not showing in lecterns.
|
||||
- Fixed incorrect damage interval of Wither status effect.
|
||||
- Fixed incorrect fire ticks when being set on fire by lava (8 seconds in Bedrock instead of 15).
|
||||
- `Entity->attack()` now cancels damage from `FIRE` and `FIRE_TICK` damage causes if the entity is fireproof.
|
||||
- Fixed inventory windows getting force-closed when the client attempts to use an enchanting table or anvil.
|
||||
|
||||
# 4.6.2
|
||||
Released 6th August 2022.
|
||||
|
||||
## Core
|
||||
- Improved server-side performance of `PlayerAuthInputPacket` handler.
|
||||
- Improved client-side performance of `FloatingTextParticle` by using an invisible falling block entity. This offered a roughly 5x performance improvement over using tiny invisible players in local testing.
|
||||
|
||||
## Fixes
|
||||
- Fixed assert failures and debug spam on debug Minecraft clients related to abilities in `AddPlayerPacket`.
|
||||
- Fixed crash in `ReversePriorityQueue` on PHP 8.1 by adding `#[ReturnTypeWillChange]` attribute.
|
46
changelogs/4.7.md
Normal file
46
changelogs/4.7.md
Normal file
@ -0,0 +1,46 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.20**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.7.0
|
||||
Released 9th August 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.20.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.7.1
|
||||
Released 14th August 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed server crash when loading items from disk which have negative meta values.
|
||||
- Fixed Turtle Master potions not giving any effects.
|
||||
- Unimplemented items are no longer craftable.
|
||||
- Fixed incorrect items appearing in item frames (due to an obsolete workaround for 1.19.10).
|
||||
|
||||
# 4.7.2
|
||||
Released 16th August 2022.
|
||||
|
||||
## Fixes
|
||||
- Fixed crash when processing player skins with invalid geometry data.
|
||||
- Fixed spectator players being able to pick blocks using mousewheel click.
|
||||
- Improved supporting requirements for sugarcane.
|
||||
|
||||
# 4.7.3
|
||||
Released 22nd August 2022.
|
||||
|
||||
## General
|
||||
- Added complete translations for Spanish and Vietnamese.
|
||||
- All continuous integration (static analysis, unit tests, integration tests) are now performed on PHP 8.1 as well as 8.0.
|
||||
- InventoryTransaction now verifies that stack sizes of items after the transaction don't exceed the maximum stack size of the item type or the containing inventory.
|
||||
|
||||
## Fixes
|
||||
- Fixed Normal generator crash on PHP 8.1.
|
||||
- Fixed a race condition during async worker shutdown that could lead to tasks executing in the wrong order. This (very rarely) led to a crash in `PopulationTask` due to its preceding `GeneratorRegisterTask` not being executed.
|
||||
- Fixed `/give` accepting negative amounts or amounts larger than 32767 (vanilla max).
|
||||
- Fixed placement conditions for vines (no longer able to be placed on the side of cacti).
|
||||
- Fixed incorrect documentation of `SignText::__construct()`.
|
23
changelogs/4.8.md
Normal file
23
changelogs/4.8.md
Normal file
@ -0,0 +1,23 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.21**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.8.0
|
||||
Released 24th August 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.21.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.8.1
|
||||
Released 26th August 2022.
|
||||
|
||||
## General
|
||||
- Crashdumps now include JIT mode information for use by the Crash Archive.
|
||||
|
||||
## Fixes
|
||||
- Fixed uninitialized offset error in `DyeColorIdMap` when given invalid dye color IDs.
|
36
changelogs/4.9.md
Normal file
36
changelogs/4.9.md
Normal file
@ -0,0 +1,36 @@
|
||||
**For Minecraft: Bedrock Edition 1.19.30**
|
||||
|
||||
### Note about API versions
|
||||
Plugins which don't touch the protocol and compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
|
||||
Plugin developers should **only** update their required API to this version if you need the changes in this build.
|
||||
|
||||
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
|
||||
|
||||
# 4.9.0
|
||||
Released 20th September 2022.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.19.30.
|
||||
- Removed support for older versions.
|
||||
|
||||
# 4.9.1
|
||||
Released 11th October 2022.
|
||||
|
||||
## Documentation
|
||||
- Added and improved documentation for many API methods in `Player` and `Block`.
|
||||
- Added missing `@internal` tag for `TaskHandler->setNextRun()`, `TaskHandler->remove()` and `TaskHandler->run()`.
|
||||
|
||||
## Fixes
|
||||
- Flight state is now locked by the server in spectator mode. This prevents any attempt by the client to toggle flight mode.
|
||||
- Fixed entity health exceeding its max health after the expiry of Health Boost effect.
|
||||
- Fixed burp sound not being played when a player eats food.
|
||||
- Fixed placement conditions for mushrooms - they can now only be placed when the light level at the target is <= 12, or on podzol or mycelium.
|
||||
- Fixed sign text appearing to change colour and/or glow when using dye on a sign - since this feature is not yet implemented, no change should occur.
|
||||
- Fixed players drowning when sprint-swimming on the surface of water.
|
||||
|
||||
## Internals
|
||||
- Added more detailed debug logging during the player login sequence.
|
||||
- Silenced debug spam during `PreSpawnPacketHandler`, considerably reducing debug noise when players join.
|
||||
- Fixed an edge case in `InventoryManager->removeWindow()`. This bug didn't have any effect on stable versions, but caused a `next-minor` development version to crash.
|
||||
- `Item`s returned by event getters are now cloned if modifying the result will have no useful side effects.
|
||||
- Updated `pocketmine/bedrock-data` to [`1.11.1`](https://github.com/pmmp/BedrockData/tree/1.11.1%2Bbedrock-1.19.30), which reduces bandwidth consumption during logins by not sending useless biome generation data.
|
@ -34,14 +34,14 @@
|
||||
"adhocore/json-comment": "^1.1",
|
||||
"fgrosse/phpasn1": "^2.3",
|
||||
"netresearch/jsonmapper": "^4.0",
|
||||
"pocketmine/bedrock-data": "~1.7.0+bedrock-1.18.30",
|
||||
"pocketmine/bedrock-protocol": "~9.0.0+bedrock-1.18.30",
|
||||
"pocketmine/bedrock-data": "~1.11.0+bedrock-1.19.30",
|
||||
"pocketmine/bedrock-protocol": "~13.0.0+bedrock-1.19.30",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"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.8.0",
|
||||
"pocketmine/locale-data": "~2.8.0 <2.8.9",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/log-pthreads": "^0.4.0",
|
||||
"pocketmine/math": "^0.4.0",
|
||||
@ -53,7 +53,7 @@
|
||||
"webmozart/path-util": "^2.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.7.1",
|
||||
"phpstan/phpstan": "1.8.8",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^9.2"
|
||||
@ -79,7 +79,7 @@
|
||||
"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/ConsoleScript.php --make ./ --relative 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"
|
||||
|
610
composer.lock
generated
610
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
||||
includes:
|
||||
- tests/phpstan/analyse-for-current-php-version.neon.php
|
||||
- tests/phpstan/configs/actual-problems.neon
|
||||
- tests/phpstan/configs/gc-hacks.neon
|
||||
- tests/phpstan/configs/impossible-generics.neon
|
||||
|
@ -37,6 +37,7 @@ namespace pocketmine {
|
||||
use Webmozart\PathUtil\Path;
|
||||
use function defined;
|
||||
use function extension_loaded;
|
||||
use function function_exists;
|
||||
use function getcwd;
|
||||
use function phpversion;
|
||||
use function preg_match;
|
||||
@ -160,7 +161,7 @@ namespace pocketmine {
|
||||
if(PHP_DEBUG !== 0){
|
||||
$logger->warning("This PHP binary was compiled in debug mode. This has a major impact on performance.");
|
||||
}
|
||||
if(extension_loaded("xdebug")){
|
||||
if(extension_loaded("xdebug") && (!function_exists('xdebug_info') || count(xdebug_info('mode')) !== 0)){
|
||||
$logger->warning("Xdebug extension is enabled. This has a major impact on performance.");
|
||||
}
|
||||
if(((int) ini_get('zend.assertions')) !== -1){
|
||||
@ -176,10 +177,10 @@ namespace pocketmine {
|
||||
|
||||
|
||||
--------------------------------------- ! WARNING ! ---------------------------------------
|
||||
You're using PHP 8.0 with JIT enabled. This provides significant performance improvements.
|
||||
You're using PHP with JIT enabled. This provides significant performance improvements.
|
||||
HOWEVER, it is EXPERIMENTAL, and has already been seen to cause weird and unexpected bugs.
|
||||
Proceed with caution.
|
||||
If you want to report any bugs, make sure to mention that you are using PHP 8.0 with JIT.
|
||||
If you want to report any bugs, make sure to mention that you have enabled PHP JIT.
|
||||
To turn off JIT, change `opcache.jit` to `0` in your php.ini file.
|
||||
-------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -132,6 +132,7 @@ use function get_class;
|
||||
use function ini_set;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
use function is_int;
|
||||
use function is_object;
|
||||
use function is_resource;
|
||||
use function is_string;
|
||||
@ -570,6 +571,7 @@ class Server{
|
||||
$playerPos = null;
|
||||
$spawn = $world->getSpawnLocation();
|
||||
}
|
||||
/** @phpstan-var PromiseResolver<Player> $playerPromiseResolver */
|
||||
$playerPromiseResolver = new PromiseResolver();
|
||||
$world->requestChunkPopulation($spawn->getFloorX() >> Chunk::COORD_BIT_SIZE, $spawn->getFloorZ() >> Chunk::COORD_BIT_SIZE, null)->onCompletion(
|
||||
function() use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $world, $playerPos, $spawn, $offlinePlayerData) : void{
|
||||
@ -861,7 +863,7 @@ class Server{
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error3()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4("settings.enable-dev-builds")));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error5("https://github.com/pmmp/PocketMine-MP/releases")));
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -976,7 +978,7 @@ class Server{
|
||||
$pluginGraylist = PluginGraylist::fromArray(yaml_parse(file_get_contents($graylistFile)));
|
||||
}catch(\InvalidArgumentException $e){
|
||||
$this->logger->emergency("Failed to load $graylistFile: " . $e->getMessage());
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool("plugins.legacy-data-dir", true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
|
||||
@ -1007,28 +1009,28 @@ class Server{
|
||||
$this->pluginManager->loadPlugins($this->pluginPath, $loadErrorCount);
|
||||
if($loadErrorCount > 0){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_plugin_someLoadErrors()));
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
if(!$this->enablePlugins(PluginEnableOrder::STARTUP())){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_plugin_someEnableErrors()));
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$this->startupPrepareWorlds()){
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$this->enablePlugins(PluginEnableOrder::POSTWORLD())){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_plugin_someEnableErrors()));
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!$this->startupPrepareNetworkInterfaces()){
|
||||
$this->forceShutdown();
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1456,6 +1458,11 @@ class Server{
|
||||
}
|
||||
}
|
||||
|
||||
private function forceShutdownExit() : void{
|
||||
$this->forceShutdown();
|
||||
Process::kill(Process::pid(), true);
|
||||
}
|
||||
|
||||
public function forceShutdown() : void{
|
||||
if($this->hasStopped){
|
||||
return;
|
||||
@ -1645,12 +1652,14 @@ class Server{
|
||||
], 10, [], $postUrlError);
|
||||
|
||||
if($reply !== null && is_object($data = json_decode($reply->getBody()))){
|
||||
if(isset($data->crashId) && isset($data->crashUrl)){
|
||||
if(isset($data->crashId) && is_int($data->crashId) && isset($data->crashUrl) && is_string($data->crashUrl)){
|
||||
$reportId = $data->crashId;
|
||||
$reportUrl = $data->crashUrl;
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
|
||||
}elseif(isset($data->error)){
|
||||
}elseif(isset($data->error) && is_string($data->error)){
|
||||
$this->logger->emergency("Automatic crash report submission failed: $data->error");
|
||||
}else{
|
||||
$this->logger->emergency("Invalid JSON response received from crash archive: " . $reply->getBody());
|
||||
}
|
||||
}else{
|
||||
$this->logger->emergency("Failed to communicate with crash archive: $postUrlError");
|
||||
|
@ -31,9 +31,9 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "4.4.0-BETA1";
|
||||
public const BASE_VERSION = "4.9.1";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "beta";
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
|
@ -78,25 +78,47 @@ class Block{
|
||||
$this->position = clone $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object containing information about how to identify and store this block type, such as its legacy
|
||||
* numeric ID(s), tile type (if any), and legacy variant metadata.
|
||||
*/
|
||||
public function getIdInfo() : BlockIdentifier{
|
||||
return $this->idInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the printable English name of the block.
|
||||
*/
|
||||
public function getName() : string{
|
||||
return $this->fallbackName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* Returns the legacy numeric Minecraft block ID.
|
||||
*/
|
||||
public function getId() : int{
|
||||
return $this->idInfo->getBlockId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Returns the full blockstate ID of this block. This is a compact way of representing a blockstate used to store
|
||||
* blocks in chunks at runtime.
|
||||
*
|
||||
* This ID can be used to later obtain a copy of this block using {@link BlockFactory::get()}.
|
||||
*/
|
||||
public function getFullId() : int{
|
||||
return ($this->getId() << self::INTERNAL_METADATA_BITS) | $this->getMeta();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block as an item.
|
||||
* State information such as facing, powered/unpowered, open/closed, etc., is discarded.
|
||||
* Type information such as colour, wood type, etc. is preserved.
|
||||
*/
|
||||
public function asItem() : Item{
|
||||
return ItemFactory::getInstance()->get(
|
||||
$this->idInfo->getItemId(),
|
||||
@ -104,6 +126,12 @@ class Block{
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* Returns the legacy Minecraft block meta value. This is a mixed-purpose value, which is used to store different
|
||||
* things for different blocks.
|
||||
*/
|
||||
public function getMeta() : int{
|
||||
$stateMeta = $this->writeStateToMeta();
|
||||
assert(($stateMeta & ~$this->getStateBitmask()) === 0);
|
||||
@ -116,6 +144,7 @@ class Block{
|
||||
|
||||
/**
|
||||
* Returns a bitmask used to extract state bits from block metadata.
|
||||
* This is used to remove unwanted information from the legacy meta value when getting the block as an item.
|
||||
*/
|
||||
public function getStateBitmask() : int{
|
||||
return 0;
|
||||
@ -143,6 +172,12 @@ class Block{
|
||||
$this->collisionBoxes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes information about the block into the world. This writes the blockstate ID into the chunk, and creates
|
||||
* and/or removes tiles as necessary.
|
||||
*
|
||||
* Note: Do not call this directly. Pass the block to {@link World::setBlock()} instead.
|
||||
*/
|
||||
public function writeStateToWorld() : void{
|
||||
$this->position->getWorld()->getOrLoadChunkAtPosition($this->position)->setFullBlock($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getFullId());
|
||||
|
||||
@ -167,7 +202,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type ID that identifies this type of block. This does not include information like facing, colour,
|
||||
* Returns a type ID that identifies this type of block. This does not include information like facing, open/closed,
|
||||
* powered/unpowered, etc.
|
||||
*/
|
||||
public function getTypeId() : int{
|
||||
@ -198,22 +233,36 @@ class Block{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this block can be replaced by another block placed in the same position.
|
||||
*/
|
||||
public function canBeReplaced() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this block can replace the given block in the given placement conditions.
|
||||
* This is used to allow slabs of the same type to combine into double slabs.
|
||||
*/
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return $blockReplace->canBeReplaced();
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the Block, using block space and block target, and side. Returns if the block has been placed.
|
||||
* Generates a block transaction to set all blocks affected by placing this block. Usually this is just the block
|
||||
* itself, but may be multiple blocks in some cases (such as doors).
|
||||
*
|
||||
* @return bool whether the placement should go ahead
|
||||
*/
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$tx->addBlock($blockReplace->position, $this);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called immediately after the block has been placed in the world. Since placement uses a block transaction, some
|
||||
* things may not be possible until after the transaction has been executed.
|
||||
*/
|
||||
public function onPostPlace() : void{
|
||||
|
||||
}
|
||||
@ -252,7 +301,7 @@ class Block{
|
||||
|
||||
/**
|
||||
* Called when this block is randomly updated due to chunk ticking.
|
||||
* WARNING: This will not be called if ticksRandomly() does not return true!
|
||||
* WARNING: This will not be called if {@link Block::ticksRandomly()} does not return true!
|
||||
*/
|
||||
public function onRandomTick() : void{
|
||||
|
||||
@ -273,8 +322,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Called when this block is attacked (left-clicked) by a player attempting to start breaking it in survival.
|
||||
*
|
||||
* @return bool if an action took place, prevents starting to break the block if true.
|
||||
*/
|
||||
@ -282,11 +330,19 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a multiplier applied to the velocity of entities moving on top of this block. A higher value will make
|
||||
* the block more slippery (like ice).
|
||||
*
|
||||
* @return float 0.0-1.0
|
||||
*/
|
||||
public function getFrictionFactor() : float{
|
||||
return 0.6;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of light emitted by this block.
|
||||
*
|
||||
* @return int 0-15
|
||||
*/
|
||||
public function getLightLevel() : int{
|
||||
@ -329,10 +385,6 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasEntityCollision() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether entities can climb up this block.
|
||||
*/
|
||||
@ -340,10 +392,6 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addVelocityToEntity(Entity $entity) : ?Vector3{
|
||||
return null;
|
||||
}
|
||||
|
||||
final public function getPosition() : Position{
|
||||
return $this->position;
|
||||
}
|
||||
@ -426,6 +474,7 @@ class Block{
|
||||
|
||||
/**
|
||||
* Returns the item that players will equip when middle-clicking on this block.
|
||||
* If addUserData is true, additional data may be added, such as banner patterns, chest contents, etc.
|
||||
*/
|
||||
public function getPickedItem(bool $addUserData = false) : Item{
|
||||
$item = $this->asItem();
|
||||
@ -549,7 +598,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for collision against an AxisAlignedBB
|
||||
* Returns whether any of the block's collision boxes intersect with the given AxisAlignedBB.
|
||||
*/
|
||||
public function collidesWithBB(AxisAlignedBB $bb) : bool{
|
||||
foreach($this->getCollisionBoxes() as $bb2){
|
||||
@ -561,10 +610,21 @@ class Block{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the block has actions to be executed when an entity enters its cell (full cube space).
|
||||
*
|
||||
* @see Block::onEntityInside()
|
||||
*/
|
||||
public function hasEntityCollision() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an entity's bounding box clips inside this block's cell. Note that the entity may not be intersecting
|
||||
* with the collision box or bounding box.
|
||||
*
|
||||
* WARNING: This will not be called if {@link Block::hasEntityCollision()} returns false.
|
||||
*
|
||||
* @return bool Whether the block is still the same after the intersection. If it changed (e.g. due to an explosive
|
||||
* being ignited), this should return false.
|
||||
*/
|
||||
@ -572,6 +632,19 @@ class Block{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a direction vector describing which way an entity intersecting this block should be pushed.
|
||||
* This is used by liquids to push entities in liquid currents.
|
||||
*
|
||||
* The returned vector is summed with vectors from every other block the entity is intersecting, and normalized to
|
||||
* produce a final direction vector.
|
||||
*
|
||||
* WARNING: This will not be called if {@link Block::hasEntityCollision()} does not return true!
|
||||
*/
|
||||
public function addVelocityToEntity(Entity $entity) : ?Vector3{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an entity lands on this block (usually due to falling).
|
||||
* @return float|null The new vertical velocity of the entity, or null if unchanged.
|
||||
@ -581,6 +654,13 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of collision bounding boxes for this block.
|
||||
* These are used for:
|
||||
* - entity movement collision checks (to ensure entities can't clip through blocks)
|
||||
* - projectile flight paths
|
||||
* - block placement (to ensure the player can't place blocks inside itself or another entity)
|
||||
* - anti-cheat checks in plugins
|
||||
*
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
final public function getCollisionBoxes() : array{
|
||||
@ -611,6 +691,10 @@ class Block{
|
||||
return [AxisAlignedBB::one()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of support that the block can provide on the given face. This is used to determine whether
|
||||
* blocks placed on the given face can be supported by this block.
|
||||
*/
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::FULL();
|
||||
}
|
||||
@ -621,6 +705,10 @@ class Block{
|
||||
return count($bb) === 1 && $bb[0]->getAverageEdgeLength() >= 1 && $bb[0]->isCube();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a ray trace along the line between the two positions using the block's collision boxes.
|
||||
* Returns the intersection point closest to pos1, or null if no intersection occurred.
|
||||
*/
|
||||
public function calculateIntercept(Vector3 $pos1, Vector3 $pos2) : ?RayTraceResult{
|
||||
$bbs = $this->getCollisionBoxes();
|
||||
if(count($bbs) === 0){
|
||||
|
@ -23,10 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\BlockBreakInfo as BreakInfo;
|
||||
use pocketmine\block\BlockIdentifier as BID;
|
||||
use pocketmine\block\BlockIdentifierFlattened as BIDFlattened;
|
||||
use pocketmine\block\BlockLegacyIds as Ids;
|
||||
use pocketmine\block\BlockLegacyMetadata as Meta;
|
||||
use pocketmine\block\BlockToolType as ToolType;
|
||||
use pocketmine\block\tile\Banner as TileBanner;
|
||||
use pocketmine\block\tile\Barrel as TileBarrel;
|
||||
use pocketmine\block\tile\Beacon as TileBeacon;
|
||||
@ -112,184 +114,184 @@ class BlockFactory{
|
||||
$this->blocksDirectSkyLight = \SplFixedArray::fromArray(array_fill(0, 1024 << Block::INTERNAL_METADATA_BITS, false));
|
||||
$this->blastResistance = \SplFixedArray::fromArray(array_fill(0, 1024 << Block::INTERNAL_METADATA_BITS, 0.0));
|
||||
|
||||
$railBreakInfo = new BlockBreakInfo(0.7);
|
||||
$railBreakInfo = new BreakInfo(0.7);
|
||||
$this->registerAllMeta(new ActivatorRail(new BID(Ids::ACTIVATOR_RAIL, 0), "Activator Rail", $railBreakInfo));
|
||||
$this->registerAllMeta(new Air(new BID(Ids::AIR, 0), "Air", BlockBreakInfo::indestructible(-1.0)));
|
||||
$this->registerAllMeta(new Anvil(new BID(Ids::ANVIL, 0), "Anvil", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new class(2.0 /* 1.0 in PC */, BlockToolType::AXE) extends BlockBreakInfo{
|
||||
$this->registerAllMeta(new Air(new BID(Ids::AIR, 0), "Air", BreakInfo::indestructible(-1.0)));
|
||||
$this->registerAllMeta(new Anvil(new BID(Ids::ANVIL, 0), "Anvil", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new Bamboo(new BID(Ids::BAMBOO, 0), "Bamboo", new class(2.0 /* 1.0 in PC */, ToolType::AXE) extends BreakInfo{
|
||||
public function getBreakTime(Item $item) : float{
|
||||
if($item->getBlockToolType() === BlockToolType::SWORD){
|
||||
if($item->getBlockToolType() === ToolType::SWORD){
|
||||
return 0.0;
|
||||
}
|
||||
return parent::getBreakTime($item);
|
||||
}
|
||||
}));
|
||||
$this->registerAllMeta(new BambooSapling(new BID(Ids::BAMBOO_SAPLING, 0), "Bamboo Sapling", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new BambooSapling(new BID(Ids::BAMBOO_SAPLING, 0), "Bamboo Sapling", BreakInfo::instant()));
|
||||
|
||||
$bannerBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE);
|
||||
$bannerBreakInfo = new BreakInfo(1.0, ToolType::AXE);
|
||||
$this->registerAllMeta(new FloorBanner(new BID(Ids::STANDING_BANNER, 0, ItemIds::BANNER, TileBanner::class), "Banner", $bannerBreakInfo));
|
||||
$this->registerAllMeta(new WallBanner(new BID(Ids::WALL_BANNER, 0, ItemIds::BANNER, TileBanner::class), "Wall Banner", $bannerBreakInfo));
|
||||
$this->registerAllMeta(new Barrel(new BID(Ids::BARREL, 0, null, TileBarrel::class), "Barrel", new BlockBreakInfo(2.5, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Transparent(new BID(Ids::BARRIER, 0), "Barrier", BlockBreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new Beacon(new BID(Ids::BEACON, 0, null, TileBeacon::class), "Beacon", new BlockBreakInfo(3.0)));
|
||||
$this->registerAllMeta(new Bed(new BID(Ids::BED_BLOCK, 0, ItemIds::BED, TileBed::class), "Bed Block", new BlockBreakInfo(0.2)));
|
||||
$this->registerAllMeta(new Bedrock(new BID(Ids::BEDROCK, 0), "Bedrock", BlockBreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new Barrel(new BID(Ids::BARREL, 0, null, TileBarrel::class), "Barrel", new BreakInfo(2.5, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Transparent(new BID(Ids::BARRIER, 0), "Barrier", BreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new Beacon(new BID(Ids::BEACON, 0, null, TileBeacon::class), "Beacon", new BreakInfo(3.0)));
|
||||
$this->registerAllMeta(new Bed(new BID(Ids::BED_BLOCK, 0, ItemIds::BED, TileBed::class), "Bed Block", new BreakInfo(0.2)));
|
||||
$this->registerAllMeta(new Bedrock(new BID(Ids::BEDROCK, 0), "Bedrock", BreakInfo::indestructible()));
|
||||
|
||||
$this->registerAllMeta(new Beetroot(new BID(Ids::BEETROOT_BLOCK, 0), "Beetroot Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Bell(new BID(Ids::BELL, 0, null, TileBell::class), "Bell", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new BlueIce(new BID(Ids::BLUE_ICE, 0), "Blue Ice", new BlockBreakInfo(2.8, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new BoneBlock(new BID(Ids::BONE_BLOCK, 0), "Bone Block", new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Bookshelf(new BID(Ids::BOOKSHELF, 0), "Bookshelf", new BlockBreakInfo(1.5, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new BrewingStand(new BID(Ids::BREWING_STAND_BLOCK, 0, ItemIds::BREWING_STAND, TileBrewingStand::class), "Brewing Stand", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Beetroot(new BID(Ids::BEETROOT_BLOCK, 0), "Beetroot Block", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Bell(new BID(Ids::BELL, 0, null, TileBell::class), "Bell", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new BlueIce(new BID(Ids::BLUE_ICE, 0), "Blue Ice", new BreakInfo(2.8, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new BoneBlock(new BID(Ids::BONE_BLOCK, 0), "Bone Block", new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Bookshelf(new BID(Ids::BOOKSHELF, 0), "Bookshelf", new BreakInfo(1.5, ToolType::AXE)));
|
||||
$this->registerAllMeta(new BrewingStand(new BID(Ids::BREWING_STAND_BLOCK, 0, ItemIds::BREWING_STAND, TileBrewingStand::class), "Brewing Stand", new BreakInfo(0.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
|
||||
$bricksBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$bricksBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::BRICK_STAIRS, 0), "Brick Stairs", $bricksBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::BRICK_BLOCK, 0), "Bricks", $bricksBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new BrownMushroom(new BID(Ids::BROWN_MUSHROOM, 0), "Brown Mushroom", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Cactus(new BID(Ids::CACTUS, 0), "Cactus", new BlockBreakInfo(0.4)));
|
||||
$this->registerAllMeta(new Cake(new BID(Ids::CAKE_BLOCK, 0, ItemIds::CAKE), "Cake", new BlockBreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Carrot(new BID(Ids::CARROTS, 0), "Carrot Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new BrownMushroom(new BID(Ids::BROWN_MUSHROOM, 0), "Brown Mushroom", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Cactus(new BID(Ids::CACTUS, 0), "Cactus", new BreakInfo(0.4)));
|
||||
$this->registerAllMeta(new Cake(new BID(Ids::CAKE_BLOCK, 0, ItemIds::CAKE), "Cake", new BreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Carrot(new BID(Ids::CARROTS, 0), "Carrot Block", BreakInfo::instant()));
|
||||
|
||||
$chestBreakInfo = new BlockBreakInfo(2.5, BlockToolType::AXE);
|
||||
$chestBreakInfo = new BreakInfo(2.5, ToolType::AXE);
|
||||
$this->registerAllMeta(new Chest(new BID(Ids::CHEST, 0, null, TileChest::class), "Chest", $chestBreakInfo));
|
||||
$this->registerAllMeta(new Clay(new BID(Ids::CLAY_BLOCK, 0), "Clay Block", new BlockBreakInfo(0.6, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Coal(new BID(Ids::COAL_BLOCK, 0), "Coal Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new CoalOre(new BID(Ids::COAL_ORE, 0), "Coal Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Clay(new BID(Ids::CLAY_BLOCK, 0), "Clay Block", new BreakInfo(0.6, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Coal(new BID(Ids::COAL_BLOCK, 0), "Coal Block", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new CoalOre(new BID(Ids::COAL_ORE, 0), "Coal Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
|
||||
$cobblestoneBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$cobblestoneBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta($cobblestone = new Opaque(new BID(Ids::COBBLESTONE, 0), "Cobblestone", $cobblestoneBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::MOSSY_COBBLESTONE, 0), "Mossy Cobblestone", $cobblestoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::COBBLESTONE_STAIRS, 0), "Cobblestone Stairs", $cobblestoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::MOSSY_COBBLESTONE_STAIRS, 0), "Mossy Cobblestone Stairs", $cobblestoneBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new Cobweb(new BID(Ids::COBWEB, 0), "Cobweb", new BlockBreakInfo(4.0, BlockToolType::SWORD | BlockToolType::SHEARS, 1)));
|
||||
$this->registerAllMeta(new CocoaBlock(new BID(Ids::COCOA, 0), "Cocoa Block", new BlockBreakInfo(0.2, BlockToolType::AXE, 0, 15.0)));
|
||||
$this->registerAllMeta(new CoralBlock(new BID(Ids::CORAL_BLOCK, 0), "Coral Block", new BlockBreakInfo(7.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new CraftingTable(new BID(Ids::CRAFTING_TABLE, 0), "Crafting Table", new BlockBreakInfo(2.5, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new DaylightSensor(new BIDFlattened(Ids::DAYLIGHT_DETECTOR, [Ids::DAYLIGHT_DETECTOR_INVERTED], 0, null, TileDaylightSensor::class), "Daylight Sensor", new BlockBreakInfo(0.2, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new DeadBush(new BID(Ids::DEADBUSH, 0), "Dead Bush", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)));
|
||||
$this->registerAllMeta(new Cobweb(new BID(Ids::COBWEB, 0), "Cobweb", new BreakInfo(4.0, ToolType::SWORD | ToolType::SHEARS, 1)));
|
||||
$this->registerAllMeta(new CocoaBlock(new BID(Ids::COCOA, 0), "Cocoa Block", new BreakInfo(0.2, ToolType::AXE, 0, 15.0)));
|
||||
$this->registerAllMeta(new CoralBlock(new BID(Ids::CORAL_BLOCK, 0), "Coral Block", new BreakInfo(7.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new CraftingTable(new BID(Ids::CRAFTING_TABLE, 0), "Crafting Table", new BreakInfo(2.5, ToolType::AXE)));
|
||||
$this->registerAllMeta(new DaylightSensor(new BIDFlattened(Ids::DAYLIGHT_DETECTOR, [Ids::DAYLIGHT_DETECTOR_INVERTED], 0, null, TileDaylightSensor::class), "Daylight Sensor", new BreakInfo(0.2, ToolType::AXE)));
|
||||
$this->registerAllMeta(new DeadBush(new BID(Ids::DEADBUSH, 0), "Dead Bush", BreakInfo::instant(ToolType::SHEARS, 1)));
|
||||
$this->registerAllMeta(new DetectorRail(new BID(Ids::DETECTOR_RAIL, 0), "Detector Rail", $railBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::DIAMOND_BLOCK, 0), "Diamond Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new DiamondOre(new BID(Ids::DIAMOND_ORE, 0), "Diamond Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Dirt(new BID(Ids::DIRT, 0), "Dirt", new BlockBreakInfo(0.5, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::DIAMOND_BLOCK, 0), "Diamond Block", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new DiamondOre(new BID(Ids::DIAMOND_ORE, 0), "Diamond Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Dirt(new BID(Ids::DIRT, 0), "Dirt", new BreakInfo(0.5, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_SUNFLOWER), "Sunflower", BlockBreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LILAC), "Lilac", BlockBreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_ROSE_BUSH), "Rose Bush", BlockBreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_PEONY), "Peony", BlockBreakInfo::instant()),
|
||||
new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_TALLGRASS), "Double Tallgrass", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)),
|
||||
new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LARGE_FERN), "Large Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_SUNFLOWER), "Sunflower", BreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LILAC), "Lilac", BreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_ROSE_BUSH), "Rose Bush", BreakInfo::instant()),
|
||||
new DoublePlant(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_PEONY), "Peony", BreakInfo::instant()),
|
||||
new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_TALLGRASS), "Double Tallgrass", BreakInfo::instant(ToolType::SHEARS, 1)),
|
||||
new DoubleTallGrass(new BID(Ids::DOUBLE_PLANT, Meta::DOUBLE_PLANT_LARGE_FERN), "Large Fern", BreakInfo::instant(ToolType::SHEARS, 1)),
|
||||
);
|
||||
$this->registerAllMeta(new DragonEgg(new BID(Ids::DRAGON_EGG, 0), "Dragon Egg", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new DriedKelp(new BID(Ids::DRIED_KELP_BLOCK, 0), "Dried Kelp Block", new BlockBreakInfo(0.5, BlockToolType::NONE, 0, 12.5)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::EMERALD_BLOCK, 0), "Emerald Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new EmeraldOre(new BID(Ids::EMERALD_ORE, 0), "Emerald Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new EnchantingTable(new BID(Ids::ENCHANTING_TABLE, 0, null, TileEnchantingTable::class), "Enchanting Table", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new EndPortalFrame(new BID(Ids::END_PORTAL_FRAME, 0), "End Portal Frame", BlockBreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new EndRod(new BID(Ids::END_ROD, 0), "End Rod", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::END_STONE, 0), "End Stone", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 45.0)));
|
||||
$this->registerAllMeta(new DragonEgg(new BID(Ids::DRAGON_EGG, 0), "Dragon Egg", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new DriedKelp(new BID(Ids::DRIED_KELP_BLOCK, 0), "Dried Kelp Block", new BreakInfo(0.5, ToolType::NONE, 0, 12.5)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::EMERALD_BLOCK, 0), "Emerald Block", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new EmeraldOre(new BID(Ids::EMERALD_ORE, 0), "Emerald Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new EnchantingTable(new BID(Ids::ENCHANTING_TABLE, 0, null, TileEnchantingTable::class), "Enchanting Table", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new EndPortalFrame(new BID(Ids::END_PORTAL_FRAME, 0), "End Portal Frame", BreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new EndRod(new BID(Ids::END_ROD, 0), "End Rod", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::END_STONE, 0), "End Stone", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 45.0)));
|
||||
|
||||
$endBrickBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 4.0);
|
||||
$endBrickBreakInfo = new BreakInfo(0.8, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 4.0);
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::END_BRICKS, 0), "End Stone Bricks", $endBrickBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::END_BRICK_STAIRS, 0), "End Stone Brick Stairs", $endBrickBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new EnderChest(new BID(Ids::ENDER_CHEST, 0, null, TileEnderChest::class), "Ender Chest", new BlockBreakInfo(22.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 3000.0)));
|
||||
$this->registerAllMeta(new Farmland(new BID(Ids::FARMLAND, 0), "Farmland", new BlockBreakInfo(0.6, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Fire(new BID(Ids::FIRE, 0), "Fire Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new FletchingTable(new BID(Ids::FLETCHING_TABLE, 0), "Fletching Table", new BlockBreakInfo(2.5, BlockToolType::AXE, 0, 2.5)));
|
||||
$this->registerAllMeta(new Flower(new BID(Ids::DANDELION, 0), "Dandelion", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new EnderChest(new BID(Ids::ENDER_CHEST, 0, null, TileEnderChest::class), "Ender Chest", new BreakInfo(22.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 3000.0)));
|
||||
$this->registerAllMeta(new Farmland(new BID(Ids::FARMLAND, 0), "Farmland", new BreakInfo(0.6, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Fire(new BID(Ids::FIRE, 0), "Fire Block", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new FletchingTable(new BID(Ids::FLETCHING_TABLE, 0), "Fletching Table", new BreakInfo(2.5, ToolType::AXE, 0, 2.5)));
|
||||
$this->registerAllMeta(new Flower(new BID(Ids::DANDELION, 0), "Dandelion", BreakInfo::instant()));
|
||||
$this->registerAllMeta(
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_POPPY), "Poppy", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ALLIUM), "Allium", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_AZURE_BLUET), "Azure Bluet", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_BLUE_ORCHID), "Blue Orchid", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_CORNFLOWER), "Cornflower", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_LILY_OF_THE_VALLEY), "Lily of the Valley", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ORANGE_TULIP), "Orange Tulip", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_OXEYE_DAISY), "Oxeye Daisy", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_PINK_TULIP), "Pink Tulip", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_RED_TULIP), "Red Tulip", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_WHITE_TULIP), "White Tulip", BlockBreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_POPPY), "Poppy", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ALLIUM), "Allium", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_AZURE_BLUET), "Azure Bluet", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_BLUE_ORCHID), "Blue Orchid", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_CORNFLOWER), "Cornflower", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_LILY_OF_THE_VALLEY), "Lily of the Valley", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_ORANGE_TULIP), "Orange Tulip", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_OXEYE_DAISY), "Oxeye Daisy", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_PINK_TULIP), "Pink Tulip", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_RED_TULIP), "Red Tulip", BreakInfo::instant()),
|
||||
new Flower(new BID(Ids::RED_FLOWER, Meta::FLOWER_WHITE_TULIP), "White Tulip", BreakInfo::instant()),
|
||||
);
|
||||
$this->registerAllMeta(new FlowerPot(new BID(Ids::FLOWER_POT_BLOCK, 0, ItemIds::FLOWER_POT, TileFlowerPot::class), "Flower Pot", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new FrostedIce(new BID(Ids::FROSTED_ICE, 0), "Frosted Ice", new BlockBreakInfo(2.5, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::FURNACE, [Ids::LIT_FURNACE], 0, null, TileNormalFurnace::class), "Furnace", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::BLAST_FURNACE, [Ids::LIT_BLAST_FURNACE], 0, null, TileBlastFurnace::class), "Blast Furnace", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::SMOKER, [Ids::LIT_SMOKER], 0, null, TileSmoker::class), "Smoker", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new FlowerPot(new BID(Ids::FLOWER_POT_BLOCK, 0, ItemIds::FLOWER_POT, TileFlowerPot::class), "Flower Pot", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new FrostedIce(new BID(Ids::FROSTED_ICE, 0), "Frosted Ice", new BreakInfo(2.5, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::FURNACE, [Ids::LIT_FURNACE], 0, null, TileNormalFurnace::class), "Furnace", new BreakInfo(3.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::BLAST_FURNACE, [Ids::LIT_BLAST_FURNACE], 0, null, TileBlastFurnace::class), "Blast Furnace", new BreakInfo(3.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Furnace(new BIDFlattened(Ids::SMOKER, [Ids::LIT_SMOKER], 0, null, TileSmoker::class), "Smoker", new BreakInfo(3.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
|
||||
$glassBreakInfo = new BlockBreakInfo(0.3);
|
||||
$glassBreakInfo = new BreakInfo(0.3);
|
||||
$this->registerAllMeta(new Glass(new BID(Ids::GLASS, 0), "Glass", $glassBreakInfo));
|
||||
$this->registerAllMeta(new GlassPane(new BID(Ids::GLASS_PANE, 0), "Glass Pane", $glassBreakInfo));
|
||||
$this->registerAllMeta(new GlowingObsidian(new BID(Ids::GLOWINGOBSIDIAN, 0), "Glowing Obsidian", new BlockBreakInfo(10.0, BlockToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 50.0)));
|
||||
$this->registerAllMeta(new Glowstone(new BID(Ids::GLOWSTONE, 0), "Glowstone", new BlockBreakInfo(0.3, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::GOLD_BLOCK, 0), "Gold Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::GOLD_ORE, 0), "Gold Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new GlowingObsidian(new BID(Ids::GLOWINGOBSIDIAN, 0), "Glowing Obsidian", new BreakInfo(10.0, ToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 50.0)));
|
||||
$this->registerAllMeta(new Glowstone(new BID(Ids::GLOWSTONE, 0), "Glowstone", new BreakInfo(0.3, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::GOLD_BLOCK, 0), "Gold Block", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::GOLD_ORE, 0), "Gold Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
|
||||
$grassBreakInfo = new BlockBreakInfo(0.6, BlockToolType::SHOVEL);
|
||||
$grassBreakInfo = new BreakInfo(0.6, ToolType::SHOVEL);
|
||||
$this->registerAllMeta(new Grass(new BID(Ids::GRASS, 0), "Grass", $grassBreakInfo));
|
||||
$this->registerAllMeta(new GrassPath(new BID(Ids::GRASS_PATH, 0), "Grass Path", $grassBreakInfo));
|
||||
$this->registerAllMeta(new Gravel(new BID(Ids::GRAVEL, 0), "Gravel", new BlockBreakInfo(0.6, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Gravel(new BID(Ids::GRAVEL, 0), "Gravel", new BreakInfo(0.6, ToolType::SHOVEL)));
|
||||
|
||||
$hardenedClayBreakInfo = new BlockBreakInfo(1.25, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 21.0);
|
||||
$hardenedClayBreakInfo = new BreakInfo(1.25, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 21.0);
|
||||
$this->registerAllMeta(new HardenedClay(new BID(Ids::HARDENED_CLAY, 0), "Hardened Clay", $hardenedClayBreakInfo));
|
||||
|
||||
$hardenedGlassBreakInfo = new BlockBreakInfo(10.0);
|
||||
$hardenedGlassBreakInfo = new BreakInfo(10.0);
|
||||
$this->registerAllMeta(new HardenedGlass(new BID(Ids::HARD_GLASS, 0), "Hardened Glass", $hardenedGlassBreakInfo));
|
||||
$this->registerAllMeta(new HardenedGlassPane(new BID(Ids::HARD_GLASS_PANE, 0), "Hardened Glass Pane", $hardenedGlassBreakInfo));
|
||||
$this->registerAllMeta(new HayBale(new BID(Ids::HAY_BALE, 0), "Hay Bale", new BlockBreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Hopper(new BID(Ids::HOPPER_BLOCK, 0, ItemIds::HOPPER, TileHopper::class), "Hopper", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 15.0)));
|
||||
$this->registerAllMeta(new Ice(new BID(Ids::ICE, 0), "Ice", new BlockBreakInfo(0.5, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new HayBale(new BID(Ids::HAY_BALE, 0), "Hay Bale", new BreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Hopper(new BID(Ids::HOPPER_BLOCK, 0, ItemIds::HOPPER, TileHopper::class), "Hopper", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 15.0)));
|
||||
$this->registerAllMeta(new Ice(new BID(Ids::ICE, 0), "Ice", new BreakInfo(0.5, ToolType::PICKAXE)));
|
||||
|
||||
$updateBlockBreakInfo = new BlockBreakInfo(1.0);
|
||||
$updateBlockBreakInfo = new BreakInfo(1.0);
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::INFO_UPDATE, 0), "update!", $updateBlockBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::INFO_UPDATE2, 0), "ate!upd", $updateBlockBreakInfo));
|
||||
$this->registerAllMeta(new Transparent(new BID(Ids::INVISIBLEBEDROCK, 0), "Invisible Bedrock", BlockBreakInfo::indestructible()));
|
||||
$this->registerAllMeta(new Transparent(new BID(Ids::INVISIBLEBEDROCK, 0), "Invisible Bedrock", BreakInfo::indestructible()));
|
||||
|
||||
$ironBreakInfo = new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel(), 30.0);
|
||||
$ironBreakInfo = new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::IRON_BLOCK, 0), "Iron Block", $ironBreakInfo));
|
||||
$this->registerAllMeta(new Thin(new BID(Ids::IRON_BARS, 0), "Iron Bars", $ironBreakInfo));
|
||||
$ironDoorBreakInfo = new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 25.0);
|
||||
$ironDoorBreakInfo = new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 25.0);
|
||||
$this->registerAllMeta(new Door(new BID(Ids::IRON_DOOR_BLOCK, 0, ItemIds::IRON_DOOR), "Iron Door", $ironDoorBreakInfo));
|
||||
$this->registerAllMeta(new Trapdoor(new BID(Ids::IRON_TRAPDOOR, 0), "Iron Trapdoor", $ironDoorBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::IRON_ORE, 0), "Iron Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new ItemFrame(new BID(Ids::FRAME_BLOCK, 0, ItemIds::FRAME, TileItemFrame::class), "Item Frame", new BlockBreakInfo(0.25)));
|
||||
$this->registerAllMeta(new Jukebox(new BID(Ids::JUKEBOX, 0, ItemIds::JUKEBOX, TileJukebox::class), "Jukebox", new BlockBreakInfo(0.8, BlockToolType::AXE))); //TODO: in PC the hardness is 2.0, not 0.8, unsure if this is a MCPE bug or not
|
||||
$this->registerAllMeta(new Ladder(new BID(Ids::LADDER, 0), "Ladder", new BlockBreakInfo(0.4, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Lantern(new BID(Ids::LANTERN, 0), "Lantern", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::LAPIS_BLOCK, 0), "Lapis Lazuli Block", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new LapisOre(new BID(Ids::LAPIS_ORE, 0), "Lapis Lazuli Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Lava(new BIDFlattened(Ids::FLOWING_LAVA, [Ids::STILL_LAVA], 0), "Lava", BlockBreakInfo::indestructible(500.0)));
|
||||
$this->registerAllMeta(new Lectern(new BID(Ids::LECTERN, 0, ItemIds::LECTERN, TileLectern::class), "Lectern", new BlockBreakInfo(2.0, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Lever(new BID(Ids::LEVER, 0), "Lever", new BlockBreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Loom(new BID(Ids::LOOM, 0), "Loom", new BlockBreakInfo(2.5, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Magma(new BID(Ids::MAGMA, 0), "Magma Block", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Melon(new BID(Ids::MELON_BLOCK, 0), "Melon Block", new BlockBreakInfo(1.0, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new MelonStem(new BID(Ids::MELON_STEM, 0, ItemIds::MELON_SEEDS), "Melon Stem", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new MonsterSpawner(new BID(Ids::MOB_SPAWNER, 0, null, TileMonsterSpawner::class), "Monster Spawner", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Mycelium(new BID(Ids::MYCELIUM, 0), "Mycelium", new BlockBreakInfo(0.6, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::IRON_ORE, 0), "Iron Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new ItemFrame(new BID(Ids::FRAME_BLOCK, 0, ItemIds::FRAME, TileItemFrame::class), "Item Frame", new BreakInfo(0.25)));
|
||||
$this->registerAllMeta(new Jukebox(new BID(Ids::JUKEBOX, 0, ItemIds::JUKEBOX, TileJukebox::class), "Jukebox", new BreakInfo(0.8, ToolType::AXE))); //TODO: in PC the hardness is 2.0, not 0.8, unsure if this is a MCPE bug or not
|
||||
$this->registerAllMeta(new Ladder(new BID(Ids::LADDER, 0), "Ladder", new BreakInfo(0.4, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Lantern(new BID(Ids::LANTERN, 0), "Lantern", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::LAPIS_BLOCK, 0), "Lapis Lazuli Block", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new LapisOre(new BID(Ids::LAPIS_ORE, 0), "Lapis Lazuli Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::STONE()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Lava(new BIDFlattened(Ids::FLOWING_LAVA, [Ids::STILL_LAVA], 0), "Lava", BreakInfo::indestructible(500.0)));
|
||||
$this->registerAllMeta(new Lectern(new BID(Ids::LECTERN, 0, ItemIds::LECTERN, TileLectern::class), "Lectern", new BreakInfo(2.0, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Lever(new BID(Ids::LEVER, 0), "Lever", new BreakInfo(0.5)));
|
||||
$this->registerAllMeta(new Loom(new BID(Ids::LOOM, 0), "Loom", new BreakInfo(2.5, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Magma(new BID(Ids::MAGMA, 0), "Magma Block", new BreakInfo(0.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Melon(new BID(Ids::MELON_BLOCK, 0), "Melon Block", new BreakInfo(1.0, ToolType::AXE)));
|
||||
$this->registerAllMeta(new MelonStem(new BID(Ids::MELON_STEM, 0, ItemIds::MELON_SEEDS), "Melon Stem", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new MonsterSpawner(new BID(Ids::MOB_SPAWNER, 0, null, TileMonsterSpawner::class), "Monster Spawner", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Mycelium(new BID(Ids::MYCELIUM, 0), "Mycelium", new BreakInfo(0.6, ToolType::SHOVEL)));
|
||||
|
||||
$netherBrickBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$netherBrickBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::NETHER_BRICK_BLOCK, 0), "Nether Bricks", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::RED_NETHER_BRICK, 0), "Red Nether Bricks", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new Fence(new BID(Ids::NETHER_BRICK_FENCE, 0), "Nether Brick Fence", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::NETHER_BRICK_STAIRS, 0), "Nether Brick Stairs", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::RED_NETHER_BRICK_STAIRS, 0), "Red Nether Brick Stairs", $netherBrickBreakInfo));
|
||||
$this->registerAllMeta(new NetherPortal(new BID(Ids::PORTAL, 0), "Nether Portal", BlockBreakInfo::indestructible(0.0)));
|
||||
$this->registerAllMeta(new NetherQuartzOre(new BID(Ids::NETHER_QUARTZ_ORE, 0), "Nether Quartz Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new NetherReactor(new BID(Ids::NETHERREACTOR, 0), "Nether Reactor Core", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BlockBreakInfo(1.0, BlockToolType::HOE)));
|
||||
$this->registerAllMeta(new NetherWartPlant(new BID(Ids::NETHER_WART_PLANT, 0, ItemIds::NETHER_WART), "Nether Wart", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Netherrack(new BID(Ids::NETHERRACK, 0), "Netherrack", new BlockBreakInfo(0.4, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Note(new BID(Ids::NOTEBLOCK, 0, null, TileNote::class), "Note Block", new BlockBreakInfo(0.8, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::OBSIDIAN, 0), "Obsidian", new BlockBreakInfo(35.0 /* 50 in PC */, BlockToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new PackedIce(new BID(Ids::PACKED_ICE, 0), "Packed Ice", new BlockBreakInfo(0.5, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Podzol(new BID(Ids::PODZOL, 0), "Podzol", new BlockBreakInfo(0.5, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Potato(new BID(Ids::POTATOES, 0), "Potato Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new NetherPortal(new BID(Ids::PORTAL, 0), "Nether Portal", BreakInfo::indestructible(0.0)));
|
||||
$this->registerAllMeta(new NetherQuartzOre(new BID(Ids::NETHER_QUARTZ_ORE, 0), "Nether Quartz Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new NetherReactor(new BID(Ids::NETHERREACTOR, 0), "Nether Reactor Core", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::NETHER_WART_BLOCK, 0), "Nether Wart Block", new BreakInfo(1.0, ToolType::HOE)));
|
||||
$this->registerAllMeta(new NetherWartPlant(new BID(Ids::NETHER_WART_PLANT, 0, ItemIds::NETHER_WART), "Nether Wart", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Netherrack(new BID(Ids::NETHERRACK, 0), "Netherrack", new BreakInfo(0.4, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Note(new BID(Ids::NOTEBLOCK, 0, null, TileNote::class), "Note Block", new BreakInfo(0.8, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::OBSIDIAN, 0), "Obsidian", new BreakInfo(35.0 /* 50 in PC */, ToolType::PICKAXE, ToolTier::DIAMOND()->getHarvestLevel(), 6000.0)));
|
||||
$this->registerAllMeta(new PackedIce(new BID(Ids::PACKED_ICE, 0), "Packed Ice", new BreakInfo(0.5, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Podzol(new BID(Ids::PODZOL, 0), "Podzol", new BreakInfo(0.5, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Potato(new BID(Ids::POTATOES, 0), "Potato Block", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new PoweredRail(new BID(Ids::GOLDEN_RAIL, 0), "Powered Rail", $railBreakInfo));
|
||||
|
||||
$prismarineBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$prismarineBreakInfo = new BreakInfo(1.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(
|
||||
new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_NORMAL), "Prismarine", $prismarineBreakInfo),
|
||||
new Opaque(new BID(Ids::PRISMARINE, Meta::PRISMARINE_DARK), "Dark Prismarine", $prismarineBreakInfo),
|
||||
@ -299,21 +301,21 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::DARK_PRISMARINE_STAIRS, 0), "Dark Prismarine Stairs", $prismarineBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::PRISMARINE_STAIRS, 0), "Prismarine Stairs", $prismarineBreakInfo));
|
||||
|
||||
$pumpkinBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE);
|
||||
$pumpkinBreakInfo = new BreakInfo(1.0, ToolType::AXE);
|
||||
$this->registerAllMeta(new Pumpkin(new BID(Ids::PUMPKIN, 0), "Pumpkin", $pumpkinBreakInfo));
|
||||
$this->registerAllMeta(new CarvedPumpkin(new BID(Ids::CARVED_PUMPKIN, 0), "Carved Pumpkin", $pumpkinBreakInfo));
|
||||
$this->registerAllMeta(new LitPumpkin(new BID(Ids::JACK_O_LANTERN, 0), "Jack o'Lantern", $pumpkinBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new PumpkinStem(new BID(Ids::PUMPKIN_STEM, 0, ItemIds::PUMPKIN_SEEDS), "Pumpkin Stem", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new PumpkinStem(new BID(Ids::PUMPKIN_STEM, 0, ItemIds::PUMPKIN_SEEDS), "Pumpkin Stem", BreakInfo::instant()));
|
||||
|
||||
$purpurBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$purpurBreakInfo = new BreakInfo(1.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(
|
||||
new Opaque(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_NORMAL), "Purpur Block", $purpurBreakInfo),
|
||||
new SimplePillar(new BID(Ids::PURPUR_BLOCK, Meta::PURPUR_PILLAR), "Purpur Pillar", $purpurBreakInfo)
|
||||
);
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::PURPUR_STAIRS, 0), "Purpur Stairs", $purpurBreakInfo));
|
||||
|
||||
$quartzBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$quartzBreakInfo = new BreakInfo(0.8, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$this->registerAllMeta(
|
||||
new Opaque(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_NORMAL), "Quartz Block", $quartzBreakInfo),
|
||||
new SimplePillar(new BID(Ids::QUARTZ_BLOCK, Meta::QUARTZ_CHISELED), "Chiseled Quartz Block", $quartzBreakInfo),
|
||||
@ -324,33 +326,33 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_QUARTZ_STAIRS, 0), "Smooth Quartz Stairs", $quartzBreakInfo));
|
||||
|
||||
$this->registerAllMeta(new Rail(new BID(Ids::RAIL, 0), "Rail", $railBreakInfo));
|
||||
$this->registerAllMeta(new RedMushroom(new BID(Ids::RED_MUSHROOM, 0), "Red Mushroom", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Redstone(new BID(Ids::REDSTONE_BLOCK, 0), "Redstone Block", new BlockBreakInfo(5.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new RedstoneComparator(new BIDFlattened(Ids::UNPOWERED_COMPARATOR, [Ids::POWERED_COMPARATOR], 0, ItemIds::COMPARATOR, TileComparator::class), "Redstone Comparator", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneLamp(new BIDFlattened(Ids::REDSTONE_LAMP, [Ids::LIT_REDSTONE_LAMP], 0), "Redstone Lamp", new BlockBreakInfo(0.3)));
|
||||
$this->registerAllMeta(new RedstoneOre(new BIDFlattened(Ids::REDSTONE_ORE, [Ids::LIT_REDSTONE_ORE], 0), "Redstone Ore", new BlockBreakInfo(3.0, BlockToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new RedstoneRepeater(new BIDFlattened(Ids::UNPOWERED_REPEATER, [Ids::POWERED_REPEATER], 0, ItemIds::REPEATER), "Redstone Repeater", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneTorch(new BIDFlattened(Ids::REDSTONE_TORCH, [Ids::UNLIT_REDSTONE_TORCH], 0), "Redstone Torch", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneWire(new BID(Ids::REDSTONE_WIRE, 0, ItemIds::REDSTONE), "Redstone", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Reserved6(new BID(Ids::RESERVED6, 0), "reserved6", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedMushroom(new BID(Ids::RED_MUSHROOM, 0), "Red Mushroom", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Redstone(new BID(Ids::REDSTONE_BLOCK, 0), "Redstone Block", new BreakInfo(5.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0)));
|
||||
$this->registerAllMeta(new RedstoneComparator(new BIDFlattened(Ids::UNPOWERED_COMPARATOR, [Ids::POWERED_COMPARATOR], 0, ItemIds::COMPARATOR, TileComparator::class), "Redstone Comparator", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneLamp(new BIDFlattened(Ids::REDSTONE_LAMP, [Ids::LIT_REDSTONE_LAMP], 0), "Redstone Lamp", new BreakInfo(0.3)));
|
||||
$this->registerAllMeta(new RedstoneOre(new BIDFlattened(Ids::REDSTONE_ORE, [Ids::LIT_REDSTONE_ORE], 0), "Redstone Ore", new BreakInfo(3.0, ToolType::PICKAXE, ToolTier::IRON()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new RedstoneRepeater(new BIDFlattened(Ids::UNPOWERED_REPEATER, [Ids::POWERED_REPEATER], 0, ItemIds::REPEATER), "Redstone Repeater", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneTorch(new BIDFlattened(Ids::REDSTONE_TORCH, [Ids::UNLIT_REDSTONE_TORCH], 0), "Redstone Torch", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new RedstoneWire(new BID(Ids::REDSTONE_WIRE, 0, ItemIds::REDSTONE), "Redstone", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Reserved6(new BID(Ids::RESERVED6, 0), "reserved6", BreakInfo::instant()));
|
||||
|
||||
$sandBreakInfo = new BlockBreakInfo(0.5, BlockToolType::SHOVEL);
|
||||
$sandBreakInfo = new BreakInfo(0.5, ToolType::SHOVEL);
|
||||
$this->registerAllMeta(
|
||||
new Sand(new BID(Ids::SAND, 0), "Sand", $sandBreakInfo),
|
||||
new Sand(new BID(Ids::SAND, 1), "Red Sand", $sandBreakInfo)
|
||||
);
|
||||
$this->registerAllMeta(new SeaLantern(new BID(Ids::SEALANTERN, 0), "Sea Lantern", new BlockBreakInfo(0.3)));
|
||||
$this->registerAllMeta(new SeaPickle(new BID(Ids::SEA_PICKLE, 0), "Sea Pickle", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Skull(new BID(Ids::MOB_HEAD_BLOCK, 0, ItemIds::SKULL, TileSkull::class), "Mob Head", new BlockBreakInfo(1.0)));
|
||||
$this->registerAllMeta(new Slime(new BID(Ids::SLIME, 0), "Slime Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Snow(new BID(Ids::SNOW, 0), "Snow Block", new BlockBreakInfo(0.2, BlockToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new SnowLayer(new BID(Ids::SNOW_LAYER, 0), "Snow Layer", new BlockBreakInfo(0.1, BlockToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new SoulSand(new BID(Ids::SOUL_SAND, 0), "Soul Sand", new BlockBreakInfo(0.5, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Sponge(new BID(Ids::SPONGE, 0), "Sponge", new BlockBreakInfo(0.6, BlockToolType::HOE)));
|
||||
$shulkerBoxBreakInfo = new BlockBreakInfo(2, BlockToolType::PICKAXE);
|
||||
$this->registerAllMeta(new SeaLantern(new BID(Ids::SEALANTERN, 0), "Sea Lantern", new BreakInfo(0.3)));
|
||||
$this->registerAllMeta(new SeaPickle(new BID(Ids::SEA_PICKLE, 0), "Sea Pickle", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Skull(new BID(Ids::MOB_HEAD_BLOCK, 0, ItemIds::SKULL, TileSkull::class), "Mob Head", new BreakInfo(1.0)));
|
||||
$this->registerAllMeta(new Slime(new BID(Ids::SLIME, 0), "Slime Block", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Snow(new BID(Ids::SNOW, 0), "Snow Block", new BreakInfo(0.2, ToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new SnowLayer(new BID(Ids::SNOW_LAYER, 0), "Snow Layer", new BreakInfo(0.1, ToolType::SHOVEL, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new SoulSand(new BID(Ids::SOUL_SAND, 0), "Soul Sand", new BreakInfo(0.5, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Sponge(new BID(Ids::SPONGE, 0), "Sponge", new BreakInfo(0.6, ToolType::HOE)));
|
||||
$shulkerBoxBreakInfo = new BreakInfo(2, ToolType::PICKAXE);
|
||||
$this->registerAllMeta(new ShulkerBox(new BID(Ids::UNDYED_SHULKER_BOX, 0, null, TileShulkerBox::class), "Shulker Box", $shulkerBoxBreakInfo));
|
||||
|
||||
$stoneBreakInfo = new BlockBreakInfo(1.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$stoneBreakInfo = new BreakInfo(1.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(
|
||||
$stone = new class(new BID(Ids::STONE, Meta::STONE_NORMAL), "Stone", $stoneBreakInfo) extends Opaque{
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
@ -374,7 +376,7 @@ class BlockFactory{
|
||||
$crackedStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CRACKED), "Cracked Stone Bricks", $stoneBreakInfo),
|
||||
$chiseledStoneBrick = new Opaque(new BID(Ids::STONEBRICK, Meta::STONE_BRICK_CHISELED), "Chiseled Stone Bricks", $stoneBreakInfo)
|
||||
);
|
||||
$infestedStoneBreakInfo = new BlockBreakInfo(0.75, BlockToolType::PICKAXE);
|
||||
$infestedStoneBreakInfo = new BreakInfo(0.75, ToolType::PICKAXE);
|
||||
$this->registerAllMeta(
|
||||
new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE), "Infested Stone", $infestedStoneBreakInfo, $stone),
|
||||
new InfestedStone(new BID(Ids::MONSTER_EGG, Meta::INFESTED_STONE_BRICK), "Infested Stone Brick", $infestedStoneBreakInfo, $stoneBrick),
|
||||
@ -393,12 +395,12 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::POLISHED_GRANITE_STAIRS, 0), "Polished Granite Stairs", $stoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::STONE_BRICK_STAIRS, 0), "Stone Brick Stairs", $stoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::MOSSY_STONE_BRICK_STAIRS, 0), "Mossy Stone Brick Stairs", $stoneBreakInfo));
|
||||
$this->registerAllMeta(new StoneButton(new BID(Ids::STONE_BUTTON, 0), "Stone Button", new BlockBreakInfo(0.5, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Stonecutter(new BID(Ids::STONECUTTER_BLOCK, 0, ItemIds::STONECUTTER_BLOCK), "Stonecutter", new BlockBreakInfo(3.5, BlockToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new StonePressurePlate(new BID(Ids::STONE_PRESSURE_PLATE, 0), "Stone Pressure Plate", new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new StoneButton(new BID(Ids::STONE_BUTTON, 0), "Stone Button", new BreakInfo(0.5, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new Stonecutter(new BID(Ids::STONECUTTER_BLOCK, 0, ItemIds::STONECUTTER_BLOCK), "Stonecutter", new BreakInfo(3.5, ToolType::PICKAXE)));
|
||||
$this->registerAllMeta(new StonePressurePlate(new BID(Ids::STONE_PRESSURE_PLATE, 0), "Stone Pressure Plate", new BreakInfo(0.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
|
||||
//TODO: in the future this won't be the same for all the types
|
||||
$stoneSlabBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$stoneSlabBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
|
||||
$getStoneSlabId = static fn(int $stoneSlabId, int $meta) => BlockLegacyIdHelper::getStoneSlabIdentifier($stoneSlabId, $meta);
|
||||
foreach([
|
||||
@ -435,50 +437,50 @@ class BlockFactory{
|
||||
$this->registerSlabWithDoubleHighBitsRemapping($slabType);
|
||||
}
|
||||
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::STONECUTTER, 0), "Legacy Stonecutter", new BlockBreakInfo(3.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new TNT(new BID(Ids::TNT, 0), "TNT", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::STONECUTTER, 0), "Legacy Stonecutter", new BreakInfo(3.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new Sugarcane(new BID(Ids::REEDS_BLOCK, 0, ItemIds::REEDS), "Sugarcane", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new SweetBerryBush(new BID(Ids::SWEET_BERRY_BUSH, 0, ItemIds::SWEET_BERRIES), "Sweet Berry Bush", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new TNT(new BID(Ids::TNT, 0), "TNT", BreakInfo::instant()));
|
||||
$this->registerAllMeta(
|
||||
new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_FERN), "Fern", BlockBreakInfo::instant(BlockToolType::SHEARS, 1)),
|
||||
new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_NORMAL), "Tall Grass", BlockBreakInfo::instant(BlockToolType::SHEARS, 1))
|
||||
new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_FERN), "Fern", BreakInfo::instant(ToolType::SHEARS, 1)),
|
||||
new TallGrass(new BID(Ids::TALLGRASS, Meta::TALLGRASS_NORMAL), "Tall Grass", BreakInfo::instant(ToolType::SHEARS, 1))
|
||||
);
|
||||
$this->registerAllMeta(
|
||||
new Torch(new BID(Ids::COLORED_TORCH_BP, 0), "Blue Torch", BlockBreakInfo::instant()),
|
||||
new Torch(new BID(Ids::COLORED_TORCH_BP, 8), "Purple Torch", BlockBreakInfo::instant())
|
||||
new Torch(new BID(Ids::COLORED_TORCH_BP, 0), "Blue Torch", BreakInfo::instant()),
|
||||
new Torch(new BID(Ids::COLORED_TORCH_BP, 8), "Purple Torch", BreakInfo::instant())
|
||||
);
|
||||
$this->registerAllMeta(
|
||||
new Torch(new BID(Ids::COLORED_TORCH_RG, 0), "Red Torch", BlockBreakInfo::instant()),
|
||||
new Torch(new BID(Ids::COLORED_TORCH_RG, 8), "Green Torch", BlockBreakInfo::instant())
|
||||
new Torch(new BID(Ids::COLORED_TORCH_RG, 0), "Red Torch", BreakInfo::instant()),
|
||||
new Torch(new BID(Ids::COLORED_TORCH_RG, 8), "Green Torch", BreakInfo::instant())
|
||||
);
|
||||
$this->registerAllMeta(new Torch(new BID(Ids::TORCH, 0), "Torch", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Torch(new BID(Ids::TORCH, 0), "Torch", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new TrappedChest(new BID(Ids::TRAPPED_CHEST, 0, null, TileChest::class), "Trapped Chest", $chestBreakInfo));
|
||||
$this->registerAllMeta(new Tripwire(new BID(Ids::TRIPWIRE, 0, ItemIds::STRING), "Tripwire", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new TripwireHook(new BID(Ids::TRIPWIRE_HOOK, 0), "Tripwire Hook", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new UnderwaterTorch(new BID(Ids::UNDERWATER_TORCH, 0), "Underwater Torch", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Vine(new BID(Ids::VINE, 0), "Vines", new BlockBreakInfo(0.2, BlockToolType::AXE)));
|
||||
$this->registerAllMeta(new Water(new BIDFlattened(Ids::FLOWING_WATER, [Ids::STILL_WATER], 0), "Water", BlockBreakInfo::indestructible(500.0)));
|
||||
$this->registerAllMeta(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Tripwire(new BID(Ids::TRIPWIRE, 0, ItemIds::STRING), "Tripwire", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new TripwireHook(new BID(Ids::TRIPWIRE_HOOK, 0), "Tripwire Hook", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new UnderwaterTorch(new BID(Ids::UNDERWATER_TORCH, 0), "Underwater Torch", BreakInfo::instant()));
|
||||
$this->registerAllMeta(new Vine(new BID(Ids::VINE, 0), "Vines", new BreakInfo(0.2, ToolType::AXE)));
|
||||
$this->registerAllMeta(new Water(new BIDFlattened(Ids::FLOWING_WATER, [Ids::STILL_WATER], 0), "Water", BreakInfo::indestructible(500.0)));
|
||||
$this->registerAllMeta(new WaterLily(new BID(Ids::LILY_PAD, 0), "Lily Pad", BreakInfo::instant()));
|
||||
|
||||
$weightedPressurePlateBreakInfo = new BlockBreakInfo(0.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$weightedPressurePlateBreakInfo = new BreakInfo(0.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$this->registerAllMeta(new WeightedPressurePlateHeavy(new BID(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Heavy", $weightedPressurePlateBreakInfo));
|
||||
$this->registerAllMeta(new WeightedPressurePlateLight(new BID(Ids::LIGHT_WEIGHTED_PRESSURE_PLATE, 0), "Weighted Pressure Plate Light", $weightedPressurePlateBreakInfo));
|
||||
$this->registerAllMeta(new Wheat(new BID(Ids::WHEAT_BLOCK, 0), "Wheat Block", BlockBreakInfo::instant()));
|
||||
$this->registerAllMeta(new Wheat(new BID(Ids::WHEAT_BLOCK, 0), "Wheat Block", BreakInfo::instant()));
|
||||
|
||||
$planksBreakInfo = new BlockBreakInfo(2.0, BlockToolType::AXE, 0, 15.0);
|
||||
$leavesBreakInfo = new class(0.2, BlockToolType::HOE) extends BlockBreakInfo{
|
||||
$planksBreakInfo = new BreakInfo(2.0, ToolType::AXE, 0, 15.0);
|
||||
$leavesBreakInfo = new class(0.2, ToolType::HOE) extends BreakInfo{
|
||||
public function getBreakTime(Item $item) : float{
|
||||
if($item->getBlockToolType() === BlockToolType::SHEARS){
|
||||
if($item->getBlockToolType() === ToolType::SHEARS){
|
||||
return 0.0;
|
||||
}
|
||||
return parent::getBreakTime($item);
|
||||
}
|
||||
};
|
||||
$signBreakInfo = new BlockBreakInfo(1.0, BlockToolType::AXE);
|
||||
$logBreakInfo = new BlockBreakInfo(2.0, BlockToolType::AXE);
|
||||
$woodenDoorBreakInfo = new BlockBreakInfo(3.0, BlockToolType::AXE, 0, 15.0);
|
||||
$woodenButtonBreakInfo = new BlockBreakInfo(0.5, BlockToolType::AXE);
|
||||
$woodenPressurePlateBreakInfo = new BlockBreakInfo(0.5, BlockToolType::AXE);
|
||||
$signBreakInfo = new BreakInfo(1.0, ToolType::AXE);
|
||||
$logBreakInfo = new BreakInfo(2.0, ToolType::AXE);
|
||||
$woodenDoorBreakInfo = new BreakInfo(3.0, ToolType::AXE, 0, 15.0);
|
||||
$woodenButtonBreakInfo = new BreakInfo(0.5, ToolType::AXE);
|
||||
$woodenPressurePlateBreakInfo = new BreakInfo(0.5, ToolType::AXE);
|
||||
|
||||
$planks = [];
|
||||
$saplings = [];
|
||||
@ -489,7 +491,7 @@ class BlockFactory{
|
||||
$magicNumber = $treeType->getMagicNumber();
|
||||
$name = $treeType->getDisplayName();
|
||||
$planks[] = new Planks(new BID(Ids::PLANKS, $magicNumber), $name . " Planks", $planksBreakInfo);
|
||||
$saplings[] = new Sapling(new BID(Ids::SAPLING, $magicNumber), $name . " Sapling", BlockBreakInfo::instant(), $treeType);
|
||||
$saplings[] = new Sapling(new BID(Ids::SAPLING, $magicNumber), $name . " Sapling", BreakInfo::instant(), $treeType);
|
||||
$fences[] = new WoodenFence(new BID(Ids::FENCE, $magicNumber), $name . " Fence", $planksBreakInfo);
|
||||
$this->registerSlabWithDoubleHighBitsRemapping(new WoodenSlab(new BIDFlattened(Ids::WOODEN_SLAB, [Ids::DOUBLE_WOODEN_SLAB], $magicNumber), $name, $planksBreakInfo));
|
||||
|
||||
@ -521,27 +523,26 @@ class BlockFactory{
|
||||
$this->registerAllMeta(...$leaves);
|
||||
$this->registerAllMeta(...$allSidedLogs);
|
||||
|
||||
static $sandstoneTypes = [
|
||||
Meta::SANDSTONE_NORMAL => "",
|
||||
Meta::SANDSTONE_CHISELED => "Chiseled ",
|
||||
Meta::SANDSTONE_CUT => "Cut ",
|
||||
Meta::SANDSTONE_SMOOTH => "Smooth "
|
||||
];
|
||||
$sandstoneBreakInfo = new BlockBreakInfo(0.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$sandstoneBreakInfo = new BreakInfo(0.8, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::RED_SANDSTONE_STAIRS, 0), "Red Sandstone Stairs", $sandstoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_RED_SANDSTONE_STAIRS, 0), "Smooth Red Sandstone Stairs", $sandstoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::SANDSTONE_STAIRS, 0), "Sandstone Stairs", $sandstoneBreakInfo));
|
||||
$this->registerAllMeta(new Stair(new BID(Ids::SMOOTH_SANDSTONE_STAIRS, 0), "Smooth Sandstone Stairs", $sandstoneBreakInfo));
|
||||
$sandstones = [];
|
||||
$redSandstones = [];
|
||||
foreach($sandstoneTypes as $variant => $prefix){
|
||||
foreach([
|
||||
Meta::SANDSTONE_NORMAL => "",
|
||||
Meta::SANDSTONE_CHISELED => "Chiseled ",
|
||||
Meta::SANDSTONE_CUT => "Cut ",
|
||||
Meta::SANDSTONE_SMOOTH => "Smooth "
|
||||
] as $variant => $prefix){
|
||||
$sandstones[] = new Opaque(new BID(Ids::SANDSTONE, $variant), $prefix . "Sandstone", $sandstoneBreakInfo);
|
||||
$redSandstones[] = new Opaque(new BID(Ids::RED_SANDSTONE, $variant), $prefix . "Red Sandstone", $sandstoneBreakInfo);
|
||||
}
|
||||
$this->registerAllMeta(...$sandstones);
|
||||
$this->registerAllMeta(...$redSandstones);
|
||||
|
||||
$glazedTerracottaBreakInfo = new BlockBreakInfo(1.4, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$glazedTerracottaBreakInfo = new BreakInfo(1.4, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
foreach(DyeColor::getAll() as $color){
|
||||
$coloredName = function(string $name) use($color) : string{
|
||||
return $color->getDisplayName() . " " . $name;
|
||||
@ -554,13 +555,13 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new StainedHardenedClay(new BID(Ids::STAINED_CLAY, 0), "Stained Clay", $hardenedClayBreakInfo));
|
||||
$this->registerAllMeta(new StainedHardenedGlass(new BID(Ids::HARD_STAINED_GLASS, 0), "Stained Hardened Glass", $hardenedGlassBreakInfo));
|
||||
$this->registerAllMeta(new StainedHardenedGlassPane(new BID(Ids::HARD_STAINED_GLASS_PANE, 0), "Stained Hardened Glass Pane", $hardenedGlassBreakInfo));
|
||||
$this->registerAllMeta(new Carpet(new BID(Ids::CARPET, 0), "Carpet", new BlockBreakInfo(0.1)));
|
||||
$this->registerAllMeta(new Concrete(new BID(Ids::CONCRETE, 0), "Concrete", new BlockBreakInfo(1.8, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new ConcretePowder(new BID(Ids::CONCRETE_POWDER, 0), "Concrete Powder", new BlockBreakInfo(0.5, BlockToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Wool(new BID(Ids::WOOL, 0), "Wool", new class(0.8, BlockToolType::SHEARS) extends BlockBreakInfo{
|
||||
$this->registerAllMeta(new Carpet(new BID(Ids::CARPET, 0), "Carpet", new BreakInfo(0.1)));
|
||||
$this->registerAllMeta(new Concrete(new BID(Ids::CONCRETE, 0), "Concrete", new BreakInfo(1.8, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel())));
|
||||
$this->registerAllMeta(new ConcretePowder(new BID(Ids::CONCRETE_POWDER, 0), "Concrete Powder", new BreakInfo(0.5, ToolType::SHOVEL)));
|
||||
$this->registerAllMeta(new Wool(new BID(Ids::WOOL, 0), "Wool", new class(0.8, ToolType::SHEARS) extends BreakInfo{
|
||||
public function getBreakTime(Item $item) : float{
|
||||
$time = parent::getBreakTime($item);
|
||||
if($item->getBlockToolType() === BlockToolType::SHEARS){
|
||||
if($item->getBlockToolType() === ToolType::SHEARS){
|
||||
$time *= 3; //shears break compatible blocks 15x faster, but wool 5x
|
||||
}
|
||||
|
||||
@ -569,7 +570,7 @@ class BlockFactory{
|
||||
}));
|
||||
|
||||
//TODO: in the future these won't all have the same hardness; they only do now because of the old metadata crap
|
||||
$wallBreakInfo = new BlockBreakInfo(2.0, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$wallBreakInfo = new BreakInfo(2.0, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel(), 30.0);
|
||||
$this->registerAllMeta(
|
||||
new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_COBBLESTONE), "Cobblestone Wall", $wallBreakInfo),
|
||||
new Wall(new BID(Ids::COBBLESTONE_WALL, Meta::WALL_ANDESITE), "Andesite Wall", $wallBreakInfo),
|
||||
@ -589,7 +590,7 @@ class BlockFactory{
|
||||
|
||||
$this->registerElements();
|
||||
|
||||
$chemistryTableBreakInfo = new BlockBreakInfo(2.5, BlockToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$chemistryTableBreakInfo = new BreakInfo(2.5, ToolType::PICKAXE, ToolTier::WOOD()->getHarvestLevel());
|
||||
$this->registerAllMeta(
|
||||
new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_COMPOUND_CREATOR), "Compound Creator", $chemistryTableBreakInfo),
|
||||
new ChemistryTable(new BID(Ids::CHEMISTRY_TABLE, Meta::CHEMISTRY_ELEMENT_CONSTRUCTOR), "Element Constructor", $chemistryTableBreakInfo),
|
||||
@ -604,17 +605,17 @@ class BlockFactory{
|
||||
$this->registerAllMeta(new Coral(
|
||||
new BID(Ids::CORAL, 0),
|
||||
"Coral",
|
||||
BlockBreakInfo::instant(),
|
||||
BreakInfo::instant(),
|
||||
));
|
||||
$this->registerAllMeta(new FloorCoralFan(
|
||||
new BlockIdentifierFlattened(Ids::CORAL_FAN, [Ids::CORAL_FAN_DEAD], 0, ItemIds::CORAL_FAN),
|
||||
"Coral Fan",
|
||||
BlockBreakInfo::instant(),
|
||||
BreakInfo::instant(),
|
||||
));
|
||||
$this->registerAllMeta(new WallCoralFan(
|
||||
new BlockIdentifierFlattened(Ids::CORAL_FAN_HANG, [Ids::CORAL_FAN_HANG2, Ids::CORAL_FAN_HANG3], 0, ItemIds::CORAL_FAN),
|
||||
"Wall Coral Fan",
|
||||
BlockBreakInfo::instant(),
|
||||
BreakInfo::instant(),
|
||||
));
|
||||
|
||||
//region --- auto-generated TODOs for bedrock-1.11.0 ---
|
||||
@ -756,7 +757,7 @@ class BlockFactory{
|
||||
//shrooms have to be handled one by one because some metas are variants and others aren't, and they can't be
|
||||
//separated by a bitmask
|
||||
|
||||
$mushroomBlockBreakInfo = new BlockBreakInfo(0.2, BlockToolType::AXE);
|
||||
$mushroomBlockBreakInfo = new BreakInfo(0.2, ToolType::AXE);
|
||||
|
||||
$mushroomBlocks = [
|
||||
new BrownMushroomBlock(new BID(Ids::BROWN_MUSHROOM_BLOCK, 0), "Brown Mushroom Block", $mushroomBlockBreakInfo),
|
||||
@ -800,7 +801,7 @@ class BlockFactory{
|
||||
}
|
||||
|
||||
private function registerElements() : void{
|
||||
$instaBreak = BlockBreakInfo::instant();
|
||||
$instaBreak = BreakInfo::instant();
|
||||
$this->registerAllMeta(new Opaque(new BID(Ids::ELEMENT_0, 0), "???", $instaBreak));
|
||||
|
||||
$this->registerAllMeta(new Element(new BID(Ids::ELEMENT_1, 0), "Hydrogen", $instaBreak, "h", 1, 5));
|
||||
@ -1054,7 +1055,7 @@ class BlockFactory{
|
||||
if($this->fullList[$index] !== null){
|
||||
$block = clone $this->fullList[$index];
|
||||
}else{
|
||||
$block = new UnknownBlock(new BID($id, $meta), BlockBreakInfo::instant());
|
||||
$block = new UnknownBlock(new BID($id, $meta), BreakInfo::instant());
|
||||
}
|
||||
|
||||
return $block;
|
||||
|
@ -72,7 +72,7 @@ class Cactus extends Transparent{
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
static $shrinkSize = 1 / 16;
|
||||
$shrinkSize = 1 / 16;
|
||||
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,10 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
/**
|
||||
* "Flowable" blocks are destroyed if water flows into the same space as the block. These blocks usually don't have any
|
||||
* collision boxes, and can't provide support for other blocks.
|
||||
*/
|
||||
abstract class Flowable extends Transparent{
|
||||
|
||||
public function canBeFlowedInto() : bool{
|
||||
|
@ -94,7 +94,8 @@ class Lava extends Liquid{
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_LAVA, 4);
|
||||
$entity->attack($ev);
|
||||
|
||||
$ev = new EntityCombustByBlockEvent($this, $entity, 15);
|
||||
//in java burns entities for 15 seconds - seems to be a parity issue in bedrock
|
||||
$ev = new EntityCombustByBlockEvent($this, $entity, 8);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$entity->setOnFire($ev->getDuration());
|
||||
|
@ -69,7 +69,6 @@ class Lever extends Flowable{
|
||||
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;
|
||||
|
@ -348,7 +348,7 @@ abstract class Liquid extends Transparent{
|
||||
$ev = new BlockSpreadEvent($block, $this, $new);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
if($block->getId() > 0){
|
||||
if($block->getId() !== BlockLegacyIds::AIR){
|
||||
$this->position->getWorld()->useBreakOn($block->position);
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
|
||||
class Melon extends Transparent{
|
||||
class Melon extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
|
@ -23,6 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
/**
|
||||
* Opaque blocks do not allow light to pass through. They are usually collidable full-cube blocks.
|
||||
* Most blocks in Minecraft fall into this category.
|
||||
*/
|
||||
class Opaque extends Block{
|
||||
|
||||
public function isSolid() : bool{
|
||||
|
@ -43,7 +43,11 @@ class RedMushroom extends Flowable{
|
||||
|
||||
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()){
|
||||
$position = $this->getPosition();
|
||||
$lightLevel = $position->getWorld()->getFullLightAt($position->x, $position->y, $position->z);
|
||||
$downId = $down->getId();
|
||||
//TODO: nylium support
|
||||
if(($lightLevel <= 12 && !$down->isTransparent()) || $downId === BlockLegacyIds::MYCELIUM || $downId === BlockLegacyIds::PODZOL){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,8 @@ class Skull extends Flowable{
|
||||
}
|
||||
|
||||
public function readStateFromData(int $id, int $stateMeta) : void{
|
||||
$this->facing = $stateMeta === 1 ? Facing::UP : BlockDataSerializer::readHorizontalFacing($stateMeta);
|
||||
$facingMeta = $stateMeta & 0x7;
|
||||
$this->facing = $facingMeta === 1 ? Facing::UP : BlockDataSerializer::readHorizontalFacing($facingMeta);
|
||||
$this->noDrops = ($stateMeta & BlockLegacyMetadata::SKULL_FLAG_NO_DROPS) !== 0;
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ class Sugarcane extends Flowable{
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
if($down->isTransparent() && !$down->isSameType($this)){
|
||||
if(!$this->isValidSupport($down)){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
@ -122,9 +122,10 @@ class Sugarcane extends Flowable{
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
if($down->isSameType($this)){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}elseif($down->getId() === BlockLegacyIds::GRASS || $down->getId() === BlockLegacyIds::DIRT || $down->getId() === BlockLegacyIds::SAND || $down->getId() === BlockLegacyIds::PODZOL){
|
||||
}elseif($this->isValidSupport($down)){
|
||||
foreach(Facing::HORIZONTAL as $side){
|
||||
if($down->getSide($side) instanceof Water){
|
||||
$sideBlock = $down->getSide($side);
|
||||
if($sideBlock instanceof Water || $sideBlock instanceof FrostedIce){
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
}
|
||||
@ -132,4 +133,15 @@ class Sugarcane extends Flowable{
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isValidSupport(Block $block) : bool{
|
||||
$id = $block->getId();
|
||||
//TODO: rooted dirt, moss block
|
||||
return $block->isSameType($this)
|
||||
|| $id === BlockLegacyIds::GRASS
|
||||
|| $id === BlockLegacyIds::DIRT
|
||||
|| $id === BlockLegacyIds::PODZOL
|
||||
|| $id === BlockLegacyIds::MYCELIUM
|
||||
|| $id === BlockLegacyIds::SAND;
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,9 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use function count;
|
||||
|
||||
/**
|
||||
* Thin blocks behave like glass panes. They connect to full-cube blocks horizontally adjacent to them if possible.
|
||||
*/
|
||||
class Thin extends Transparent{
|
||||
/** @var bool[] facing => dummy */
|
||||
protected array $connections = [];
|
||||
|
@ -23,6 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
/**
|
||||
* Transparent blocks do not block any light from propagating through them.
|
||||
*
|
||||
* Note: This does **not** imply that the block is **visually** transparent. For example, chests allow light to pass
|
||||
* through, but the player cannot see through them except at the edges.
|
||||
*/
|
||||
class Transparent extends Block{
|
||||
|
||||
public function isTransparent() : bool{
|
||||
|
@ -25,6 +25,9 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
/**
|
||||
* Represents a block which is unrecognized or not implemented.
|
||||
*/
|
||||
class UnknownBlock extends Transparent{
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, BlockBreakInfo $breakInfo){
|
||||
|
@ -585,6 +585,7 @@ final class VanillaBlocks{
|
||||
|
||||
/**
|
||||
* @return Block[]
|
||||
* @phpstan-return array<string, Block>
|
||||
*/
|
||||
public static function getAll() : array{
|
||||
//phpstan doesn't support generic traits yet :(
|
||||
|
@ -116,7 +116,7 @@ class Vine extends Flowable{
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if(!$blockClicked->isSolid() || Facing::axis($face) === Axis::Y){
|
||||
if(!$blockClicked->isFullCube() || Facing::axis($face) === Axis::Y){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\block\utils\SignText;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\world\World;
|
||||
use function array_pad;
|
||||
use function array_slice;
|
||||
@ -42,6 +43,13 @@ use function sprintf;
|
||||
class Sign extends Spawnable{
|
||||
public const TAG_TEXT_BLOB = "Text";
|
||||
public const TAG_TEXT_LINE = "Text%d"; //sprintf()able
|
||||
public const TAG_TEXT_COLOR = "SignTextColor";
|
||||
public const TAG_GLOWING_TEXT = "IgnoreLighting";
|
||||
/**
|
||||
* This tag is set to indicate that MCPE-117835 has been addressed in whatever version this sign was created.
|
||||
* @see https://bugs.mojang.com/browse/MCPE-117835
|
||||
*/
|
||||
public const TAG_LEGACY_BUG_RESOLVE = "TextIgnoreLegacyBugResolved";
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
@ -111,5 +119,11 @@ class Sign extends Spawnable{
|
||||
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
$nbt->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text->getLines()));
|
||||
|
||||
//the following are not yet used by the server, but needed to roll back any changes to glowing state or colour
|
||||
//if the client uses dye on the sign
|
||||
$nbt->setInt(self::TAG_TEXT_COLOR, Binary::signInt(0xff_00_00_00));
|
||||
$nbt->setByte(self::TAG_GLOWING_TEXT, 0);
|
||||
$nbt->setByte(self::TAG_LEGACY_BUG_RESOLVE, 1);
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,6 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\BlockLegacyIds;
|
||||
use pocketmine\block\Fire;
|
||||
use pocketmine\block\Liquid;
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\entity\object\FallingBlock;
|
||||
@ -50,7 +47,7 @@ trait FallableTrait{
|
||||
public function onNearbyBlockChange() : void{
|
||||
$pos = $this->getPosition();
|
||||
$down = $pos->getWorld()->getBlock($pos->getSide(Facing::DOWN));
|
||||
if($down->getId() === BlockLegacyIds::AIR || $down instanceof Liquid || $down instanceof Fire){
|
||||
if($down->canBeReplaced()){
|
||||
$pos->getWorld()->setBlock($pos, VanillaBlocks::AIR());
|
||||
|
||||
$block = $this;
|
||||
|
@ -39,7 +39,7 @@ class SignText{
|
||||
private array $lines;
|
||||
|
||||
/**
|
||||
* @param string[]|null $lines index-sensitive; omitting an index will leave it unchanged
|
||||
* @param string[]|null $lines index-sensitive; keys 0-3 will be used, regardless of array order
|
||||
*
|
||||
* @throws \InvalidArgumentException if the array size is greater than 4
|
||||
* @throws \InvalidArgumentException if invalid keys (out of bounds or string) are found in the array
|
||||
|
@ -85,7 +85,7 @@ class FormattedCommandAlias extends Command{
|
||||
$target->timings->startTiming();
|
||||
|
||||
try{
|
||||
$target->execute($sender, $commandLabel, $args);
|
||||
$target->execute($sender, $commandLabel, $commandArgs);
|
||||
}catch(InvalidCommandSyntaxException $e){
|
||||
$sender->sendMessage($sender->getLanguage()->translate(KnownTranslationFactory::commands_generic_usage($target->getUsage())));
|
||||
}finally{
|
||||
|
@ -75,7 +75,11 @@ class GiveCommand extends VanillaCommand{
|
||||
if(!isset($args[2])){
|
||||
$item->setCount($item->getMaxStackSize());
|
||||
}else{
|
||||
$item->setCount((int) $args[2]);
|
||||
$count = $this->getBoundedInt($sender, $args[2], 1, 32767);
|
||||
if($count === null){
|
||||
return true;
|
||||
}
|
||||
$item->setCount($count);
|
||||
}
|
||||
|
||||
if(isset($args[3])){
|
||||
|
@ -103,7 +103,7 @@ class StatusCommand extends VanillaCommand{
|
||||
|
||||
$globalLimit = $server->getMemoryManager()->getGlobalMemoryLimit();
|
||||
if($globalLimit > 0){
|
||||
$sender->sendMessage(TextFormat::GOLD . "Maximum memory (manager): " . TextFormat::RED . number_format(round($globalLimit, 2), 2) . " MB.");
|
||||
$sender->sendMessage(TextFormat::GOLD . "Maximum memory (manager): " . TextFormat::RED . number_format(round(($globalLimit / 1024) / 1024, 2), 2) . " MB.");
|
||||
}
|
||||
|
||||
foreach($server->getWorldManager()->getWorlds() as $world){
|
||||
|
@ -32,9 +32,7 @@ use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\VersionInfo;
|
||||
use function count;
|
||||
use function function_exists;
|
||||
use function implode;
|
||||
use function opcache_get_status;
|
||||
use function sprintf;
|
||||
use function stripos;
|
||||
use function strtolower;
|
||||
@ -71,16 +69,10 @@ class VersionCommand extends VanillaCommand{
|
||||
));
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_version_phpVersion(PHP_VERSION));
|
||||
|
||||
if(
|
||||
function_exists('opcache_get_status') &&
|
||||
($opcacheStatus = opcache_get_status(false)) !== false &&
|
||||
isset($opcacheStatus["jit"]["on"])
|
||||
){
|
||||
$jit = $opcacheStatus["jit"];
|
||||
if($jit["on"] === true){
|
||||
$jitStatus = KnownTranslationFactory::pocketmine_command_version_phpJitEnabled(
|
||||
sprintf("CRTO: %s%s%s%s", $jit["opt_flags"] >> 2, $jit["opt_flags"] & 0x03, $jit["kind"], $jit["opt_level"])
|
||||
);
|
||||
$jitMode = Utils::getOpcacheJitMode();
|
||||
if($jitMode !== null){
|
||||
if($jitMode !== 0){
|
||||
$jitStatus = KnownTranslationFactory::pocketmine_command_version_phpJitEnabled(sprintf("CRTO: %d", $jitMode));
|
||||
}else{
|
||||
$jitStatus = KnownTranslationFactory::pocketmine_command_version_phpJitDisabled();
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_map;
|
||||
@ -33,6 +34,23 @@ use function json_decode;
|
||||
|
||||
final class CraftingManagerFromDataHelper{
|
||||
|
||||
/**
|
||||
* @param Item[] $items
|
||||
*/
|
||||
private static function containsUnknownOutputs(array $items) : bool{
|
||||
$factory = ItemFactory::getInstance();
|
||||
foreach($items as $item){
|
||||
if($item->hasAnyDamageValue()){
|
||||
throw new \InvalidArgumentException("Recipe outputs must not have wildcard meta values");
|
||||
}
|
||||
if(!$factory->isRegistered($item->getId(), $item->getMeta())){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function make(string $filePath) : CraftingManager{
|
||||
$recipes = json_decode(Utils::assumeNotFalse(file_get_contents($filePath), "Missing required resource file"), true);
|
||||
if(!is_array($recipes)){
|
||||
@ -52,9 +70,13 @@ final class CraftingManagerFromDataHelper{
|
||||
if($recipeType === null){
|
||||
continue;
|
||||
}
|
||||
$output = array_map($itemDeserializerFunc, $recipe["output"]);
|
||||
if(self::containsUnknownOutputs($output)){
|
||||
continue;
|
||||
}
|
||||
$result->registerShapelessRecipe(new ShapelessRecipe(
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"]),
|
||||
$output,
|
||||
$recipeType
|
||||
));
|
||||
}
|
||||
@ -62,10 +84,14 @@ final class CraftingManagerFromDataHelper{
|
||||
if($recipe["block"] !== "crafting_table"){ //TODO: filter others out for now to avoid breaking economics
|
||||
continue;
|
||||
}
|
||||
$output = array_map($itemDeserializerFunc, $recipe["output"]);
|
||||
if(self::containsUnknownOutputs($output)){
|
||||
continue;
|
||||
}
|
||||
$result->registerShapedRecipe(new ShapedRecipe(
|
||||
$recipe["shape"],
|
||||
array_map($itemDeserializerFunc, $recipe["input"]),
|
||||
array_map($itemDeserializerFunc, $recipe["output"])
|
||||
$output
|
||||
));
|
||||
}
|
||||
foreach($recipes["smelting"] as $recipe){
|
||||
@ -79,19 +105,30 @@ final class CraftingManagerFromDataHelper{
|
||||
if($furnaceType === null){
|
||||
continue;
|
||||
}
|
||||
$output = Item::jsonDeserialize($recipe["output"]);
|
||||
if(self::containsUnknownOutputs([$output])){
|
||||
continue;
|
||||
}
|
||||
$result->getFurnaceRecipeManager($furnaceType)->register(new FurnaceRecipe(
|
||||
Item::jsonDeserialize($recipe["output"]),
|
||||
$output,
|
||||
Item::jsonDeserialize($recipe["input"]))
|
||||
);
|
||||
}
|
||||
foreach($recipes["potion_type"] as $recipe){
|
||||
$output = Item::jsonDeserialize($recipe["output"]);
|
||||
if(self::containsUnknownOutputs([$output])){
|
||||
continue;
|
||||
}
|
||||
$result->registerPotionTypeRecipe(new PotionTypeRecipe(
|
||||
Item::jsonDeserialize($recipe["input"]),
|
||||
Item::jsonDeserialize($recipe["ingredient"]),
|
||||
Item::jsonDeserialize($recipe["output"])
|
||||
$output
|
||||
));
|
||||
}
|
||||
foreach($recipes["potion_container_change"] as $recipe){
|
||||
if(!ItemFactory::getInstance()->isRegistered($recipe["output_item_id"])){
|
||||
continue;
|
||||
}
|
||||
$result->registerPotionContainerChangeRecipe(new PotionContainerChangeRecipe(
|
||||
$recipe["input_item_id"],
|
||||
Item::jsonDeserialize($recipe["ingredient"]),
|
||||
|
@ -164,6 +164,8 @@ class CrashDump{
|
||||
}
|
||||
$this->data->extensions = $extensions;
|
||||
|
||||
$this->data->jit_mode = Utils::getOpcacheJitMode();
|
||||
|
||||
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-phpinfo", true)){
|
||||
ob_start();
|
||||
phpinfo();
|
||||
|
@ -66,6 +66,8 @@ final class CrashDumpData implements \JsonSerializable{
|
||||
*/
|
||||
public array $extensions = [];
|
||||
|
||||
public ?int $jit_mode = null;
|
||||
|
||||
public string $phpinfo = "";
|
||||
|
||||
public CrashDumpDataGeneral $general;
|
||||
|
@ -74,7 +74,7 @@ final class DyeColorIdMap{
|
||||
}
|
||||
|
||||
public function fromId(int $id) : ?DyeColor{
|
||||
return $this->idToEnum[$id];
|
||||
return $this->idToEnum[$id] ?? null;
|
||||
}
|
||||
|
||||
public function fromInvertedId(int $id) : ?DyeColor{
|
||||
|
@ -522,6 +522,9 @@ abstract class Entity{
|
||||
}
|
||||
|
||||
public function attack(EntityDamageEvent $source) : void{
|
||||
if($this->isFireProof() && ($source->getCause() === EntityDamageEvent::CAUSE_FIRE || $source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK)){
|
||||
$source->cancel();
|
||||
}
|
||||
$source->call();
|
||||
if($source->isCancelled()){
|
||||
return;
|
||||
@ -1461,8 +1464,9 @@ abstract class Entity{
|
||||
$this->location->pitch,
|
||||
$this->location->yaw,
|
||||
$this->location->yaw, //TODO: head yaw
|
||||
$this->location->yaw, //TODO: body yaw (wtf mojang?)
|
||||
array_map(function(Attribute $attr) : NetworkAttribute{
|
||||
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue());
|
||||
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []);
|
||||
}, $this->attributeMap->getAll()),
|
||||
$this->getAllNetworkData(),
|
||||
[] //TODO: entity links
|
||||
|
@ -227,7 +227,7 @@ final class EntityFactory{
|
||||
*/
|
||||
public function createFromData(World $world, CompoundTag $nbt) : ?Entity{
|
||||
try{
|
||||
$saveId = $nbt->getTag("id") ?? $nbt->getTag("identifier");
|
||||
$saveId = $nbt->getTag("identifier") ?? $nbt->getTag("id");
|
||||
$func = null;
|
||||
if($saveId instanceof StringTag){
|
||||
$func = $this->creationFuncs[$saveId->getValue()] ?? null;
|
||||
@ -248,7 +248,7 @@ final class EntityFactory{
|
||||
|
||||
public function injectSaveId(string $class, CompoundTag $saveData) : void{
|
||||
if(isset($this->saveNames[$class])){
|
||||
$saveData->setTag("id", new StringTag($this->saveNames[$class]));
|
||||
$saveData->setTag("identifier", new StringTag($this->saveNames[$class]));
|
||||
}else{
|
||||
throw new \InvalidArgumentException("Entity $class is not registered");
|
||||
}
|
||||
|
@ -237,11 +237,10 @@ class ExperienceManager{
|
||||
}
|
||||
|
||||
public function onPickupXp(int $xpValue) : void{
|
||||
static $mainHandIndex = -1;
|
||||
static $offHandIndex = -2;
|
||||
$mainHandIndex = -1;
|
||||
$offHandIndex = -2;
|
||||
|
||||
//TODO: replace this with a more generic equipment getting/setting interface
|
||||
/** @var Durable[] $equipment */
|
||||
$equipment = [];
|
||||
|
||||
if(($item = $this->entity->getInventory()->getItemInHand()) instanceof Durable && $item->hasEnchantment(VanillaEnchantments::MENDING())){
|
||||
|
@ -48,9 +48,9 @@ use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\convert\SkinAdapterSingleton;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerListPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\DeviceOS;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||
@ -58,11 +58,15 @@ use pocketmine\network\mcpe\protocol\types\entity\StringMetadataProperty;
|
||||
use pocketmine\network\mcpe\protocol\types\GameMode;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\UpdateAbilitiesPacketLayer;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Limits;
|
||||
use pocketmine\world\sound\TotemUseSound;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
use function array_fill;
|
||||
use function array_filter;
|
||||
use function array_key_exists;
|
||||
use function array_merge;
|
||||
@ -471,7 +475,6 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
$player->getNetworkSession()->sendDataPacket(AddPlayerPacket::create(
|
||||
$this->getUniqueId(),
|
||||
$this->getName(),
|
||||
$this->getId(), //TODO: actor unique ID
|
||||
$this->getId(),
|
||||
"",
|
||||
$this->location->asVector3(),
|
||||
@ -482,7 +485,14 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
|
||||
ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($this->getInventory()->getItemInHand())),
|
||||
GameMode::SURVIVAL,
|
||||
$this->getAllNetworkData(),
|
||||
AdventureSettingsPacket::create(0, 0, 0, 0, 0, $this->getId()), //TODO
|
||||
UpdateAbilitiesPacket::create(CommandPermissions::NORMAL, PlayerPermissions::VISITOR, $this->getId() /* TODO: this should be unique ID */, [
|
||||
new UpdateAbilitiesPacketLayer(
|
||||
UpdateAbilitiesPacketLayer::LAYER_BASE,
|
||||
array_fill(0, UpdateAbilitiesPacketLayer::NUMBER_OF_ABILITIES, false),
|
||||
0.0,
|
||||
0.0
|
||||
)
|
||||
]),
|
||||
[], //TODO: entity links
|
||||
"", //device ID (we intentionally don't send this - secvuln)
|
||||
DeviceOS::UNKNOWN //we intentionally don't send this (secvuln)
|
||||
|
@ -56,6 +56,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\Binary;
|
||||
use pocketmine\world\sound\BurpSound;
|
||||
use pocketmine\world\sound\EntityLandSound;
|
||||
use pocketmine\world\sound\EntityLongFallSound;
|
||||
use pocketmine\world\sound\EntityShortFallSound;
|
||||
@ -255,8 +256,7 @@ abstract class Living extends Entity{
|
||||
$size = $this->getInitialSizeInfo();
|
||||
if($this->isSwimming() || $this->isGliding()){
|
||||
$width = $size->getWidth();
|
||||
//we don't actually know an appropriate eye height for a swimming mob, but 2/3 should be good enough.
|
||||
$this->setSize((new EntitySizeInfo($width, $width, $width * 2 / 3))->scale($this->getScale()));
|
||||
$this->setSize((new EntitySizeInfo($width, $width, $width * 0.9))->scale($this->getScale()));
|
||||
}else{
|
||||
$this->setSize($size->scale($this->getScale()));
|
||||
}
|
||||
@ -320,6 +320,9 @@ abstract class Living extends Entity{
|
||||
foreach($consumable->getAdditionalEffects() as $effect){
|
||||
$this->effectManager->add($effect);
|
||||
}
|
||||
if($consumable instanceof FoodSource){
|
||||
$this->broadcastSound(new BurpSound());
|
||||
}
|
||||
|
||||
$consumable->onConsume($this);
|
||||
}
|
||||
@ -775,7 +778,7 @@ abstract class Living extends Entity{
|
||||
$id = $block->getId();
|
||||
|
||||
if($transparent === null){
|
||||
if($id !== 0){
|
||||
if($id !== BlockLegacyIds::AIR){
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
|
@ -28,7 +28,6 @@ use pocketmine\utils\Limits;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function json_encode;
|
||||
use function json_last_error_msg;
|
||||
use function strlen;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
|
||||
@ -68,9 +67,10 @@ final class Skin{
|
||||
}
|
||||
|
||||
if($geometryData !== ""){
|
||||
try{
|
||||
$decodedGeometry = (new CommentedJsonDecoder())->decode($geometryData);
|
||||
if($decodedGeometry === false){
|
||||
throw new InvalidSkinException("Invalid geometry data (" . json_last_error_msg() . ")");
|
||||
}catch(\RuntimeException $e){
|
||||
throw new InvalidSkinException("Invalid geometry data: " . $e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -38,7 +38,6 @@ class Effect{
|
||||
* @param Translatable|string $name Translation key used for effect name
|
||||
* @param Color $color Color of bubbles given by this effect
|
||||
* @param bool $bad Whether the effect is harmful
|
||||
* @param int $defaultDuration
|
||||
* @param bool $hasBubbles Whether the effect has potion bubbles. Some do not (e.g. Instant Damage has its own particles instead of bubbles)
|
||||
*/
|
||||
public function __construct(
|
||||
|
@ -85,15 +85,12 @@ class EffectManager{
|
||||
$index = spl_object_id($effectType);
|
||||
if(isset($this->effects[$index])){
|
||||
$effect = $this->effects[$index];
|
||||
$hasExpired = $effect->hasExpired();
|
||||
$ev = new EntityEffectRemoveEvent($this->entity, $effect);
|
||||
$ev->call();
|
||||
if($ev->isCancelled()){
|
||||
if($hasExpired && !$ev->getEffect()->hasExpired()){ //altered duration of an expired effect to make it not get removed
|
||||
foreach($this->effectAddHooks as $hook){
|
||||
$hook($ev->getEffect(), true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -33,5 +33,8 @@ class HealthBoostEffect extends Effect{
|
||||
|
||||
public function remove(Living $entity, EffectInstance $instance) : void{
|
||||
$entity->setMaxHealth($entity->getMaxHealth() - 4 * $instance->getEffectLevel());
|
||||
if($entity->getHealth() > $entity->getMaxHealth()){
|
||||
$entity->setHealth($entity->getMaxHealth());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ final class StringToEffectParser extends StringToTParser{
|
||||
use SingletonTrait;
|
||||
|
||||
private static function make() : self{
|
||||
$result = new self;
|
||||
$result = new self();
|
||||
|
||||
$result->register("absorption", fn() => VanillaEffects::ABSORPTION());
|
||||
$result->register("blindness", fn() => VanillaEffects::BLINDNESS());
|
||||
|
@ -101,6 +101,7 @@ final class VanillaEffects{
|
||||
|
||||
/**
|
||||
* @return Effect[]
|
||||
* @phpstan-return array<string, Effect>
|
||||
*/
|
||||
public static function getAll() : array{
|
||||
//phpstan doesn't support generic traits yet :(
|
||||
|
@ -30,7 +30,7 @@ use pocketmine\event\entity\EntityDamageEvent;
|
||||
class WitherEffect extends Effect{
|
||||
|
||||
public function canTick(EffectInstance $instance) : bool{
|
||||
if(($interval = (50 >> $instance->getAmplifier())) > 0){
|
||||
if(($interval = (40 >> $instance->getAmplifier())) > 0){
|
||||
return ($instance->getDuration() % $interval) === 0;
|
||||
}
|
||||
return true;
|
||||
|
@ -186,6 +186,10 @@ class ItemEntity extends Entity{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canSaveWithChunk() : bool{
|
||||
return !$this->item->isNull() && parent::canSaveWithChunk();
|
||||
}
|
||||
|
||||
public function saveNBT() : CompoundTag{
|
||||
$nbt = parent::saveNBT();
|
||||
$nbt->setTag("Item", $this->item->nbtSerialize());
|
||||
|
@ -30,6 +30,7 @@ class PaintingMotive{
|
||||
protected static $motives = [];
|
||||
|
||||
public static function init() : void{
|
||||
self::$initialized = true;
|
||||
foreach([
|
||||
new PaintingMotive(1, 1, "Alban"),
|
||||
new PaintingMotive(1, 1, "Aztec"),
|
||||
@ -67,10 +68,16 @@ class PaintingMotive{
|
||||
}
|
||||
|
||||
public static function registerMotive(PaintingMotive $motive) : void{
|
||||
if(!self::$initialized){
|
||||
self::init();
|
||||
}
|
||||
self::$motives[$motive->getName()] = $motive;
|
||||
}
|
||||
|
||||
public static function getMotiveByName(string $name) : ?PaintingMotive{
|
||||
if(!self::$initialized){
|
||||
self::init();
|
||||
}
|
||||
return self::$motives[$name] ?? null;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ class HandlerListManager{
|
||||
private static ?self $globalInstance = null;
|
||||
|
||||
public static function global() : self{
|
||||
return self::$globalInstance ?? (self::$globalInstance = new self);
|
||||
return self::$globalInstance ?? (self::$globalInstance = new self());
|
||||
}
|
||||
|
||||
/** @var HandlerList[] classname => HandlerList */
|
||||
|
@ -72,7 +72,7 @@ class BlockBreakEvent extends BlockEvent implements Cancellable{
|
||||
* Returns the item used to destroy the block.
|
||||
*/
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,24 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event\block;
|
||||
|
@ -65,7 +65,7 @@ class BlockPlaceEvent extends BlockEvent implements Cancellable{
|
||||
* Gets the item in hand
|
||||
*/
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
|
||||
public function getBlockReplaced() : Block{
|
||||
|
@ -1,5 +1,24 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\event\block;
|
||||
|
@ -69,7 +69,7 @@ class PlayerInteractEvent extends PlayerEvent implements Cancellable{
|
||||
}
|
||||
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
|
||||
public function getBlock() : Block{
|
||||
|
@ -60,6 +60,6 @@ class PlayerItemHeldEvent extends PlayerEvent implements Cancellable{
|
||||
* Returns the item in the slot that the player is trying to equip.
|
||||
*/
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ class PlayerItemUseEvent extends PlayerEvent implements Cancellable{
|
||||
* Returns the item used.
|
||||
*/
|
||||
public function getItem() : Item{
|
||||
return $this->item;
|
||||
return clone $this->item;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,11 +76,13 @@ abstract class BaseInventory implements Inventory{
|
||||
|
||||
/**
|
||||
* @param Item[] $items
|
||||
* @phpstan-param array<int, Item> $items
|
||||
*/
|
||||
abstract protected function internalSetContents(array $items) : void;
|
||||
|
||||
/**
|
||||
* @param Item[] $items
|
||||
* @phpstan-param array<int, Item> $items
|
||||
*/
|
||||
public function setContents(array $items) : void{
|
||||
if(count($items) > $this->getSize()){
|
||||
@ -132,6 +134,7 @@ abstract class BaseInventory implements Inventory{
|
||||
|
||||
return $slots;
|
||||
}
|
||||
|
||||
public function first(Item $item, bool $exact = false) : int{
|
||||
$count = $exact ? $item->getCount() : max(1, $item->getCount());
|
||||
$checkDamage = $exact || !$item->hasAnyDamageValue();
|
||||
|
@ -47,12 +47,20 @@ interface Inventory{
|
||||
public function setItem(int $index, Item $item) : void;
|
||||
|
||||
/**
|
||||
* Returns an array of all the itemstacks in the inventory, indexed by their slot number.
|
||||
* Empty slots are not included unless includeEmpty is true.
|
||||
*
|
||||
* @return Item[]
|
||||
* @phpstan-return array<int, Item>
|
||||
*/
|
||||
public function getContents(bool $includeEmpty = false) : array;
|
||||
|
||||
/**
|
||||
* Sets the contents of the inventory. Non-numeric offsets or offsets larger than the size of the inventory are
|
||||
* ignored.
|
||||
*
|
||||
* @param Item[] $items
|
||||
* @phpstan-param array<int, Item> $items
|
||||
*/
|
||||
public function setContents(array $items) : void;
|
||||
|
||||
@ -85,8 +93,10 @@ interface Inventory{
|
||||
/**
|
||||
* Will return all the Items that has the same id and metadata (if not null).
|
||||
* Won't check amount
|
||||
* The returned array is indexed by slot number.
|
||||
*
|
||||
* @return Item[]
|
||||
* @phpstan-return array<int, Item>
|
||||
*/
|
||||
public function all(Item $item) : array;
|
||||
|
||||
|
@ -58,6 +58,7 @@ class SimpleInventory extends BaseInventory{
|
||||
|
||||
/**
|
||||
* @return Item[]
|
||||
* @phpstan-return array<int, Item>
|
||||
*/
|
||||
public function getContents(bool $includeEmpty = false) : array{
|
||||
$contents = [];
|
||||
|
@ -42,6 +42,9 @@ class DropItemAction extends InventoryAction{
|
||||
if($this->targetItem->isNull()){
|
||||
throw new TransactionValidationException("Cannot drop an empty itemstack");
|
||||
}
|
||||
if($this->targetItem->getCount() > $this->targetItem->getMaxStackSize()){
|
||||
throw new TransactionValidationException("Target item exceeds item type max stack size");
|
||||
}
|
||||
}
|
||||
|
||||
public function onPreExecute(Player $source) : bool{
|
||||
|
@ -70,6 +70,12 @@ class SlotChangeAction extends InventoryAction{
|
||||
if(!$this->inventory->getItem($this->inventorySlot)->equalsExact($this->sourceItem)){
|
||||
throw new TransactionValidationException("Slot does not contain expected original item");
|
||||
}
|
||||
if($this->targetItem->getCount() > $this->targetItem->getMaxStackSize()){
|
||||
throw new TransactionValidationException("Target item exceeds item type max stack size");
|
||||
}
|
||||
if($this->targetItem->getCount() > $this->inventory->getMaxStackSize()){
|
||||
throw new TransactionValidationException("Target item exceeds inventory max stack size");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,7 +23,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
class FishingRod extends Item{
|
||||
class FishingRod extends Durable{
|
||||
|
||||
public function getMaxStackSize() : int{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getMaxDurability() : int{
|
||||
return 384;
|
||||
}
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
@ -100,8 +100,9 @@ class Item implements \JsonSerializable{
|
||||
* Constructs a new Item type. This constructor should ONLY be used when constructing a new item TYPE to register
|
||||
* into the index.
|
||||
*
|
||||
* NOTE: This should NOT BE USED for creating items to set into an inventory. Use {@link ItemFactory#get} for that
|
||||
* NOTE: This should NOT BE USED for creating items to set into an inventory. Use VanillaItems for that
|
||||
* purpose.
|
||||
* @see VanillaItems
|
||||
*/
|
||||
public function __construct(ItemIdentifier $identifier, string $name = "Unknown"){
|
||||
$this->identifier = $identifier;
|
||||
@ -677,7 +678,7 @@ class Item implements \JsonSerializable{
|
||||
*/
|
||||
public static function nbtDeserialize(CompoundTag $tag) : Item{
|
||||
if($tag->getTag("id") === null || $tag->getTag("Count") === null){
|
||||
return ItemFactory::getInstance()->get(0);
|
||||
return VanillaItems::AIR();
|
||||
}
|
||||
|
||||
$count = Binary::unsignByte($tag->getByte("Count"));
|
||||
|
@ -30,7 +30,7 @@ use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\RecordType;
|
||||
use pocketmine\block\utils\SkullType;
|
||||
use pocketmine\block\utils\TreeType;
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
use pocketmine\block\VanillaBlocks as Blocks;
|
||||
use pocketmine\data\bedrock\CompoundTypeIds;
|
||||
use pocketmine\data\bedrock\DyeColorIdMap;
|
||||
use pocketmine\data\bedrock\EntityLegacyIds;
|
||||
@ -41,6 +41,8 @@ use pocketmine\entity\Squid;
|
||||
use pocketmine\entity\Villager;
|
||||
use pocketmine\entity\Zombie;
|
||||
use pocketmine\inventory\ArmorInventory;
|
||||
use pocketmine\item\ItemIdentifier as IID;
|
||||
use pocketmine\item\ItemIds as Ids;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\NbtException;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
@ -62,25 +64,25 @@ class ItemFactory{
|
||||
$this->registerSpawnEggs();
|
||||
$this->registerTierToolItems();
|
||||
|
||||
$this->register(new Apple(new ItemIdentifier(ItemIds::APPLE, 0), "Apple"));
|
||||
$this->register(new Arrow(new ItemIdentifier(ItemIds::ARROW, 0), "Arrow"));
|
||||
$this->register(new Apple(new IID(Ids::APPLE, 0), "Apple"));
|
||||
$this->register(new Arrow(new IID(Ids::ARROW, 0), "Arrow"));
|
||||
|
||||
$this->register(new BakedPotato(new ItemIdentifier(ItemIds::BAKED_POTATO, 0), "Baked Potato"));
|
||||
$this->register(new Bamboo(new ItemIdentifier(ItemIds::BAMBOO, 0), "Bamboo"), true);
|
||||
$this->register(new Beetroot(new ItemIdentifier(ItemIds::BEETROOT, 0), "Beetroot"));
|
||||
$this->register(new BeetrootSeeds(new ItemIdentifier(ItemIds::BEETROOT_SEEDS, 0), "Beetroot Seeds"));
|
||||
$this->register(new BeetrootSoup(new ItemIdentifier(ItemIds::BEETROOT_SOUP, 0), "Beetroot Soup"));
|
||||
$this->register(new BlazeRod(new ItemIdentifier(ItemIds::BLAZE_ROD, 0), "Blaze Rod"));
|
||||
$this->register(new Book(new ItemIdentifier(ItemIds::BOOK, 0), "Book"));
|
||||
$this->register(new Bow(new ItemIdentifier(ItemIds::BOW, 0), "Bow"));
|
||||
$this->register(new Bowl(new ItemIdentifier(ItemIds::BOWL, 0), "Bowl"));
|
||||
$this->register(new Bread(new ItemIdentifier(ItemIds::BREAD, 0), "Bread"));
|
||||
$this->register(new Bucket(new ItemIdentifier(ItemIds::BUCKET, 0), "Bucket"));
|
||||
$this->register(new Carrot(new ItemIdentifier(ItemIds::CARROT, 0), "Carrot"));
|
||||
$this->register(new ChorusFruit(new ItemIdentifier(ItemIds::CHORUS_FRUIT, 0), "Chorus Fruit"));
|
||||
$this->register(new Clock(new ItemIdentifier(ItemIds::CLOCK, 0), "Clock"));
|
||||
$this->register(new Clownfish(new ItemIdentifier(ItemIds::CLOWNFISH, 0), "Clownfish"));
|
||||
$this->register(new Coal(new ItemIdentifier(ItemIds::COAL, 0), "Coal"));
|
||||
$this->register(new BakedPotato(new IID(Ids::BAKED_POTATO, 0), "Baked Potato"));
|
||||
$this->register(new Bamboo(new IID(Ids::BAMBOO, 0), "Bamboo"), true);
|
||||
$this->register(new Beetroot(new IID(Ids::BEETROOT, 0), "Beetroot"));
|
||||
$this->register(new BeetrootSeeds(new IID(Ids::BEETROOT_SEEDS, 0), "Beetroot Seeds"));
|
||||
$this->register(new BeetrootSoup(new IID(Ids::BEETROOT_SOUP, 0), "Beetroot Soup"));
|
||||
$this->register(new BlazeRod(new IID(Ids::BLAZE_ROD, 0), "Blaze Rod"));
|
||||
$this->register(new Book(new IID(Ids::BOOK, 0), "Book"));
|
||||
$this->register(new Bow(new IID(Ids::BOW, 0), "Bow"));
|
||||
$this->register(new Bowl(new IID(Ids::BOWL, 0), "Bowl"));
|
||||
$this->register(new Bread(new IID(Ids::BREAD, 0), "Bread"));
|
||||
$this->register(new Bucket(new IID(Ids::BUCKET, 0), "Bucket"));
|
||||
$this->register(new Carrot(new IID(Ids::CARROT, 0), "Carrot"));
|
||||
$this->register(new ChorusFruit(new IID(Ids::CHORUS_FRUIT, 0), "Chorus Fruit"));
|
||||
$this->register(new Clock(new IID(Ids::CLOCK, 0), "Clock"));
|
||||
$this->register(new Clownfish(new IID(Ids::CLOWNFISH, 0), "Clownfish"));
|
||||
$this->register(new Coal(new IID(Ids::COAL, 0), "Coal"));
|
||||
|
||||
foreach([
|
||||
0 => CoralType::TUBE(),
|
||||
@ -90,192 +92,192 @@ class ItemFactory{
|
||||
4 => CoralType::HORN()
|
||||
] as $meta => $coralType){
|
||||
$this->register(new ItemBlockWallOrFloor(
|
||||
new ItemIdentifier(ItemIds::CORAL_FAN, $meta),
|
||||
VanillaBlocks::CORAL_FAN()->setCoralType($coralType)->setDead(false),
|
||||
VanillaBlocks::WALL_CORAL_FAN()->setCoralType($coralType)->setDead(false)
|
||||
new IID(Ids::CORAL_FAN, $meta),
|
||||
Blocks::CORAL_FAN()->setCoralType($coralType)->setDead(false),
|
||||
Blocks::WALL_CORAL_FAN()->setCoralType($coralType)->setDead(false)
|
||||
), true);
|
||||
$this->register(new ItemBlockWallOrFloor(
|
||||
new ItemIdentifier(ItemIds::CORAL_FAN_DEAD, $meta),
|
||||
VanillaBlocks::CORAL_FAN()->setCoralType($coralType)->setDead(true),
|
||||
VanillaBlocks::WALL_CORAL_FAN()->setCoralType($coralType)->setDead(true)
|
||||
new IID(Ids::CORAL_FAN_DEAD, $meta),
|
||||
Blocks::CORAL_FAN()->setCoralType($coralType)->setDead(true),
|
||||
Blocks::WALL_CORAL_FAN()->setCoralType($coralType)->setDead(true)
|
||||
), true);
|
||||
}
|
||||
|
||||
$this->register(new Coal(new ItemIdentifier(ItemIds::COAL, 1), "Charcoal"));
|
||||
$this->register(new CocoaBeans(new ItemIdentifier(ItemIds::DYE, 3), "Cocoa Beans"));
|
||||
$this->register(new Compass(new ItemIdentifier(ItemIds::COMPASS, 0), "Compass"));
|
||||
$this->register(new CookedChicken(new ItemIdentifier(ItemIds::COOKED_CHICKEN, 0), "Cooked Chicken"));
|
||||
$this->register(new CookedFish(new ItemIdentifier(ItemIds::COOKED_FISH, 0), "Cooked Fish"));
|
||||
$this->register(new CookedMutton(new ItemIdentifier(ItemIds::COOKED_MUTTON, 0), "Cooked Mutton"));
|
||||
$this->register(new CookedPorkchop(new ItemIdentifier(ItemIds::COOKED_PORKCHOP, 0), "Cooked Porkchop"));
|
||||
$this->register(new CookedRabbit(new ItemIdentifier(ItemIds::COOKED_RABBIT, 0), "Cooked Rabbit"));
|
||||
$this->register(new CookedSalmon(new ItemIdentifier(ItemIds::COOKED_SALMON, 0), "Cooked Salmon"));
|
||||
$this->register(new Cookie(new ItemIdentifier(ItemIds::COOKIE, 0), "Cookie"));
|
||||
$this->register(new DriedKelp(new ItemIdentifier(ItemIds::DRIED_KELP, 0), "Dried Kelp"));
|
||||
$this->register(new Egg(new ItemIdentifier(ItemIds::EGG, 0), "Egg"));
|
||||
$this->register(new EnderPearl(new ItemIdentifier(ItemIds::ENDER_PEARL, 0), "Ender Pearl"));
|
||||
$this->register(new ExperienceBottle(new ItemIdentifier(ItemIds::EXPERIENCE_BOTTLE, 0), "Bottle o' Enchanting"));
|
||||
$this->register(new Fertilizer(new ItemIdentifier(ItemIds::DYE, 15), "Bone Meal"));
|
||||
$this->register(new FishingRod(new ItemIdentifier(ItemIds::FISHING_ROD, 0), "Fishing Rod"));
|
||||
$this->register(new FlintSteel(new ItemIdentifier(ItemIds::FLINT_STEEL, 0), "Flint and Steel"));
|
||||
$this->register(new GlassBottle(new ItemIdentifier(ItemIds::GLASS_BOTTLE, 0), "Glass Bottle"));
|
||||
$this->register(new GoldenApple(new ItemIdentifier(ItemIds::GOLDEN_APPLE, 0), "Golden Apple"));
|
||||
$this->register(new GoldenAppleEnchanted(new ItemIdentifier(ItemIds::ENCHANTED_GOLDEN_APPLE, 0), "Enchanted Golden Apple"));
|
||||
$this->register(new GoldenCarrot(new ItemIdentifier(ItemIds::GOLDEN_CARROT, 0), "Golden Carrot"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::BLAZE_POWDER, 0), "Blaze Powder"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::BLEACH, 0), "Bleach")); //EDU
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::BONE, 0), "Bone"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::BRICK, 0), "Brick"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::CHORUS_FRUIT_POPPED, 0), "Popped Chorus Fruit"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::CLAY_BALL, 0), "Clay"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SALT), "Salt"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SODIUM_OXIDE), "Sodium Oxide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SODIUM_HYDROXIDE), "Sodium Hydroxide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::MAGNESIUM_NITRATE), "Magnesium Nitrate"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::IRON_SULPHIDE), "Iron Sulphide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::LITHIUM_HYDRIDE), "Lithium Hydride"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SODIUM_HYDRIDE), "Sodium Hydride"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::CALCIUM_BROMIDE), "Calcium Bromide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::MAGNESIUM_OXIDE), "Magnesium Oxide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SODIUM_ACETATE), "Sodium Acetate"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::LUMINOL), "Luminol"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::CHARCOAL), "Charcoal")); //??? maybe bug
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SUGAR), "Sugar")); //??? maybe bug
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::ALUMINIUM_OXIDE), "Aluminium Oxide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::BORON_TRIOXIDE), "Boron Trioxide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SOAP), "Soap"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::POLYETHYLENE), "Polyethylene"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::RUBBISH), "Rubbish"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::MAGNESIUM_SALTS), "Magnesium Salts"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SULPHATE), "Sulphate"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::BARIUM_SULPHATE), "Barium Sulphate"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::POTASSIUM_CHLORIDE), "Potassium Chloride"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::MERCURIC_CHLORIDE), "Mercuric Chloride"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::CERIUM_CHLORIDE), "Cerium Chloride"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::TUNGSTEN_CHLORIDE), "Tungsten Chloride"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::CALCIUM_CHLORIDE), "Calcium Chloride"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::WATER), "Water")); //???
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::GLUE), "Glue"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::HYPOCHLORITE), "Hypochlorite"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::CRUDE_OIL), "Crude Oil"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::LATEX), "Latex"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::POTASSIUM_IODIDE), "Potassium Iodide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SODIUM_FLUORIDE), "Sodium Fluoride"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::BENZENE), "Benzene"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::INK), "Ink"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::HYDROGEN_PEROXIDE), "Hydrogen Peroxide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::AMMONIA), "Ammonia"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::COMPOUND, CompoundTypeIds::SODIUM_HYPOCHLORITE), "Sodium Hypochlorite"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::DIAMOND, 0), "Diamond"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::DRAGON_BREATH, 0), "Dragon's Breath"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::DYE, 0), "Ink Sac"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::DYE, 4), "Lapis Lazuli"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::EMERALD, 0), "Emerald"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::FEATHER, 0), "Feather"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::FERMENTED_SPIDER_EYE, 0), "Fermented Spider Eye"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::FLINT, 0), "Flint"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::GHAST_TEAR, 0), "Ghast Tear"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::GLISTERING_MELON, 0), "Glistering Melon"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::GLOWSTONE_DUST, 0), "Glowstone Dust"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::GOLD_INGOT, 0), "Gold Ingot"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::GOLD_NUGGET, 0), "Gold Nugget"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::GUNPOWDER, 0), "Gunpowder"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::HEART_OF_THE_SEA, 0), "Heart of the Sea"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::IRON_INGOT, 0), "Iron Ingot"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::IRON_NUGGET, 0), "Iron Nugget"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::LEATHER, 0), "Leather"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::MAGMA_CREAM, 0), "Magma Cream"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::NAUTILUS_SHELL, 0), "Nautilus Shell"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::NETHER_BRICK, 0), "Nether Brick"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::NETHER_QUARTZ, 0), "Nether Quartz"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::NETHER_STAR, 0), "Nether Star"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::PAPER, 0), "Paper"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::PRISMARINE_CRYSTALS, 0), "Prismarine Crystals"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::PRISMARINE_SHARD, 0), "Prismarine Shard"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::RABBIT_FOOT, 0), "Rabbit's Foot"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::RABBIT_HIDE, 0), "Rabbit Hide"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::SHULKER_SHELL, 0), "Shulker Shell"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::SLIME_BALL, 0), "Slimeball"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::SUGAR, 0), "Sugar"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::TURTLE_SHELL_PIECE, 0), "Scute"));
|
||||
$this->register(new Item(new ItemIdentifier(ItemIds::WHEAT, 0), "Wheat"));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::ACACIA_DOOR, 0), VanillaBlocks::ACACIA_DOOR()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::BIRCH_DOOR, 0), VanillaBlocks::BIRCH_DOOR()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::BREWING_STAND, 0), VanillaBlocks::BREWING_STAND()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::CAKE, 0), VanillaBlocks::CAKE()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::COMPARATOR, 0), VanillaBlocks::REDSTONE_COMPARATOR()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::DARK_OAK_DOOR, 0), VanillaBlocks::DARK_OAK_DOOR()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::FLOWER_POT, 0), VanillaBlocks::FLOWER_POT()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::HOPPER, 0), VanillaBlocks::HOPPER()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::IRON_DOOR, 0), VanillaBlocks::IRON_DOOR()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::ITEM_FRAME, 0), VanillaBlocks::ITEM_FRAME()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::JUNGLE_DOOR, 0), VanillaBlocks::JUNGLE_DOOR()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::NETHER_WART, 0), VanillaBlocks::NETHER_WART()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::OAK_DOOR, 0), VanillaBlocks::OAK_DOOR()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::REPEATER, 0), VanillaBlocks::REDSTONE_REPEATER()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::SPRUCE_DOOR, 0), VanillaBlocks::SPRUCE_DOOR()));
|
||||
$this->register(new ItemBlock(new ItemIdentifier(ItemIds::SUGARCANE, 0), VanillaBlocks::SUGARCANE()));
|
||||
$this->register(new Coal(new IID(Ids::COAL, 1), "Charcoal"));
|
||||
$this->register(new CocoaBeans(new IID(Ids::DYE, 3), "Cocoa Beans"));
|
||||
$this->register(new Compass(new IID(Ids::COMPASS, 0), "Compass"));
|
||||
$this->register(new CookedChicken(new IID(Ids::COOKED_CHICKEN, 0), "Cooked Chicken"));
|
||||
$this->register(new CookedFish(new IID(Ids::COOKED_FISH, 0), "Cooked Fish"));
|
||||
$this->register(new CookedMutton(new IID(Ids::COOKED_MUTTON, 0), "Cooked Mutton"));
|
||||
$this->register(new CookedPorkchop(new IID(Ids::COOKED_PORKCHOP, 0), "Cooked Porkchop"));
|
||||
$this->register(new CookedRabbit(new IID(Ids::COOKED_RABBIT, 0), "Cooked Rabbit"));
|
||||
$this->register(new CookedSalmon(new IID(Ids::COOKED_SALMON, 0), "Cooked Salmon"));
|
||||
$this->register(new Cookie(new IID(Ids::COOKIE, 0), "Cookie"));
|
||||
$this->register(new DriedKelp(new IID(Ids::DRIED_KELP, 0), "Dried Kelp"));
|
||||
$this->register(new Egg(new IID(Ids::EGG, 0), "Egg"));
|
||||
$this->register(new EnderPearl(new IID(Ids::ENDER_PEARL, 0), "Ender Pearl"));
|
||||
$this->register(new ExperienceBottle(new IID(Ids::EXPERIENCE_BOTTLE, 0), "Bottle o' Enchanting"));
|
||||
$this->register(new Fertilizer(new IID(Ids::DYE, 15), "Bone Meal"));
|
||||
$this->register(new FishingRod(new IID(Ids::FISHING_ROD, 0), "Fishing Rod"));
|
||||
$this->register(new FlintSteel(new IID(Ids::FLINT_STEEL, 0), "Flint and Steel"));
|
||||
$this->register(new GlassBottle(new IID(Ids::GLASS_BOTTLE, 0), "Glass Bottle"));
|
||||
$this->register(new GoldenApple(new IID(Ids::GOLDEN_APPLE, 0), "Golden Apple"));
|
||||
$this->register(new GoldenAppleEnchanted(new IID(Ids::ENCHANTED_GOLDEN_APPLE, 0), "Enchanted Golden Apple"));
|
||||
$this->register(new GoldenCarrot(new IID(Ids::GOLDEN_CARROT, 0), "Golden Carrot"));
|
||||
$this->register(new Item(new IID(Ids::BLAZE_POWDER, 0), "Blaze Powder"));
|
||||
$this->register(new Item(new IID(Ids::BLEACH, 0), "Bleach")); //EDU
|
||||
$this->register(new Item(new IID(Ids::BONE, 0), "Bone"));
|
||||
$this->register(new Item(new IID(Ids::BRICK, 0), "Brick"));
|
||||
$this->register(new Item(new IID(Ids::CHORUS_FRUIT_POPPED, 0), "Popped Chorus Fruit"));
|
||||
$this->register(new Item(new IID(Ids::CLAY_BALL, 0), "Clay"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SALT), "Salt"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SODIUM_OXIDE), "Sodium Oxide"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SODIUM_HYDROXIDE), "Sodium Hydroxide"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::MAGNESIUM_NITRATE), "Magnesium Nitrate"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::IRON_SULPHIDE), "Iron Sulphide"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::LITHIUM_HYDRIDE), "Lithium Hydride"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SODIUM_HYDRIDE), "Sodium Hydride"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::CALCIUM_BROMIDE), "Calcium Bromide"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::MAGNESIUM_OXIDE), "Magnesium Oxide"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SODIUM_ACETATE), "Sodium Acetate"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::LUMINOL), "Luminol"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::CHARCOAL), "Charcoal")); //??? maybe bug
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SUGAR), "Sugar")); //??? maybe bug
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::ALUMINIUM_OXIDE), "Aluminium Oxide"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::BORON_TRIOXIDE), "Boron Trioxide"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SOAP), "Soap"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::POLYETHYLENE), "Polyethylene"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::RUBBISH), "Rubbish"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::MAGNESIUM_SALTS), "Magnesium Salts"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SULPHATE), "Sulphate"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::BARIUM_SULPHATE), "Barium Sulphate"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::POTASSIUM_CHLORIDE), "Potassium Chloride"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::MERCURIC_CHLORIDE), "Mercuric Chloride"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::CERIUM_CHLORIDE), "Cerium Chloride"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::TUNGSTEN_CHLORIDE), "Tungsten Chloride"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::CALCIUM_CHLORIDE), "Calcium Chloride"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::WATER), "Water")); //???
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::GLUE), "Glue"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::HYPOCHLORITE), "Hypochlorite"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::CRUDE_OIL), "Crude Oil"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::LATEX), "Latex"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::POTASSIUM_IODIDE), "Potassium Iodide"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SODIUM_FLUORIDE), "Sodium Fluoride"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::BENZENE), "Benzene"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::INK), "Ink"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::HYDROGEN_PEROXIDE), "Hydrogen Peroxide"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::AMMONIA), "Ammonia"));
|
||||
$this->register(new Item(new IID(Ids::COMPOUND, CompoundTypeIds::SODIUM_HYPOCHLORITE), "Sodium Hypochlorite"));
|
||||
$this->register(new Item(new IID(Ids::DIAMOND, 0), "Diamond"));
|
||||
$this->register(new Item(new IID(Ids::DRAGON_BREATH, 0), "Dragon's Breath"));
|
||||
$this->register(new Item(new IID(Ids::DYE, 0), "Ink Sac"));
|
||||
$this->register(new Item(new IID(Ids::DYE, 4), "Lapis Lazuli"));
|
||||
$this->register(new Item(new IID(Ids::EMERALD, 0), "Emerald"));
|
||||
$this->register(new Item(new IID(Ids::FEATHER, 0), "Feather"));
|
||||
$this->register(new Item(new IID(Ids::FERMENTED_SPIDER_EYE, 0), "Fermented Spider Eye"));
|
||||
$this->register(new Item(new IID(Ids::FLINT, 0), "Flint"));
|
||||
$this->register(new Item(new IID(Ids::GHAST_TEAR, 0), "Ghast Tear"));
|
||||
$this->register(new Item(new IID(Ids::GLISTERING_MELON, 0), "Glistering Melon"));
|
||||
$this->register(new Item(new IID(Ids::GLOWSTONE_DUST, 0), "Glowstone Dust"));
|
||||
$this->register(new Item(new IID(Ids::GOLD_INGOT, 0), "Gold Ingot"));
|
||||
$this->register(new Item(new IID(Ids::GOLD_NUGGET, 0), "Gold Nugget"));
|
||||
$this->register(new Item(new IID(Ids::GUNPOWDER, 0), "Gunpowder"));
|
||||
$this->register(new Item(new IID(Ids::HEART_OF_THE_SEA, 0), "Heart of the Sea"));
|
||||
$this->register(new Item(new IID(Ids::IRON_INGOT, 0), "Iron Ingot"));
|
||||
$this->register(new Item(new IID(Ids::IRON_NUGGET, 0), "Iron Nugget"));
|
||||
$this->register(new Item(new IID(Ids::LEATHER, 0), "Leather"));
|
||||
$this->register(new Item(new IID(Ids::MAGMA_CREAM, 0), "Magma Cream"));
|
||||
$this->register(new Item(new IID(Ids::NAUTILUS_SHELL, 0), "Nautilus Shell"));
|
||||
$this->register(new Item(new IID(Ids::NETHER_BRICK, 0), "Nether Brick"));
|
||||
$this->register(new Item(new IID(Ids::NETHER_QUARTZ, 0), "Nether Quartz"));
|
||||
$this->register(new Item(new IID(Ids::NETHER_STAR, 0), "Nether Star"));
|
||||
$this->register(new Item(new IID(Ids::PAPER, 0), "Paper"));
|
||||
$this->register(new Item(new IID(Ids::PRISMARINE_CRYSTALS, 0), "Prismarine Crystals"));
|
||||
$this->register(new Item(new IID(Ids::PRISMARINE_SHARD, 0), "Prismarine Shard"));
|
||||
$this->register(new Item(new IID(Ids::RABBIT_FOOT, 0), "Rabbit's Foot"));
|
||||
$this->register(new Item(new IID(Ids::RABBIT_HIDE, 0), "Rabbit Hide"));
|
||||
$this->register(new Item(new IID(Ids::SHULKER_SHELL, 0), "Shulker Shell"));
|
||||
$this->register(new Item(new IID(Ids::SLIME_BALL, 0), "Slimeball"));
|
||||
$this->register(new Item(new IID(Ids::SUGAR, 0), "Sugar"));
|
||||
$this->register(new Item(new IID(Ids::TURTLE_SHELL_PIECE, 0), "Scute"));
|
||||
$this->register(new Item(new IID(Ids::WHEAT, 0), "Wheat"));
|
||||
$this->register(new ItemBlock(new IID(Ids::ACACIA_DOOR, 0), Blocks::ACACIA_DOOR()));
|
||||
$this->register(new ItemBlock(new IID(Ids::BIRCH_DOOR, 0), Blocks::BIRCH_DOOR()));
|
||||
$this->register(new ItemBlock(new IID(Ids::BREWING_STAND, 0), Blocks::BREWING_STAND()));
|
||||
$this->register(new ItemBlock(new IID(Ids::CAKE, 0), Blocks::CAKE()));
|
||||
$this->register(new ItemBlock(new IID(Ids::COMPARATOR, 0), Blocks::REDSTONE_COMPARATOR()));
|
||||
$this->register(new ItemBlock(new IID(Ids::DARK_OAK_DOOR, 0), Blocks::DARK_OAK_DOOR()));
|
||||
$this->register(new ItemBlock(new IID(Ids::FLOWER_POT, 0), Blocks::FLOWER_POT()));
|
||||
$this->register(new ItemBlock(new IID(Ids::HOPPER, 0), Blocks::HOPPER()));
|
||||
$this->register(new ItemBlock(new IID(Ids::IRON_DOOR, 0), Blocks::IRON_DOOR()));
|
||||
$this->register(new ItemBlock(new IID(Ids::ITEM_FRAME, 0), Blocks::ITEM_FRAME()));
|
||||
$this->register(new ItemBlock(new IID(Ids::JUNGLE_DOOR, 0), Blocks::JUNGLE_DOOR()));
|
||||
$this->register(new ItemBlock(new IID(Ids::NETHER_WART, 0), Blocks::NETHER_WART()));
|
||||
$this->register(new ItemBlock(new IID(Ids::OAK_DOOR, 0), Blocks::OAK_DOOR()));
|
||||
$this->register(new ItemBlock(new IID(Ids::REPEATER, 0), Blocks::REDSTONE_REPEATER()));
|
||||
$this->register(new ItemBlock(new IID(Ids::SPRUCE_DOOR, 0), Blocks::SPRUCE_DOOR()));
|
||||
$this->register(new ItemBlock(new IID(Ids::SUGARCANE, 0), Blocks::SUGARCANE()));
|
||||
|
||||
//the meta values for buckets are intentionally hardcoded because block IDs will change in the future
|
||||
$waterBucket = new LiquidBucket(new ItemIdentifier(ItemIds::BUCKET, 8), "Water Bucket", VanillaBlocks::WATER());
|
||||
$waterBucket = new LiquidBucket(new IID(Ids::BUCKET, 8), "Water Bucket", Blocks::WATER());
|
||||
$this->register($waterBucket);
|
||||
$this->remap(new ItemIdentifier(ItemIds::BUCKET, 9), $waterBucket);
|
||||
$lavaBucket = new LiquidBucket(new ItemIdentifier(ItemIds::BUCKET, 10), "Lava Bucket", VanillaBlocks::LAVA());
|
||||
$this->remap(new IID(Ids::BUCKET, 9), $waterBucket);
|
||||
$lavaBucket = new LiquidBucket(new IID(Ids::BUCKET, 10), "Lava Bucket", Blocks::LAVA());
|
||||
$this->register($lavaBucket);
|
||||
$this->remap(new ItemIdentifier(ItemIds::BUCKET, 11), $lavaBucket);
|
||||
$this->register(new Melon(new ItemIdentifier(ItemIds::MELON, 0), "Melon"));
|
||||
$this->register(new MelonSeeds(new ItemIdentifier(ItemIds::MELON_SEEDS, 0), "Melon Seeds"));
|
||||
$this->register(new MilkBucket(new ItemIdentifier(ItemIds::BUCKET, 1), "Milk Bucket"));
|
||||
$this->register(new Minecart(new ItemIdentifier(ItemIds::MINECART, 0), "Minecart"));
|
||||
$this->register(new MushroomStew(new ItemIdentifier(ItemIds::MUSHROOM_STEW, 0), "Mushroom Stew"));
|
||||
$this->register(new PaintingItem(new ItemIdentifier(ItemIds::PAINTING, 0), "Painting"));
|
||||
$this->register(new PoisonousPotato(new ItemIdentifier(ItemIds::POISONOUS_POTATO, 0), "Poisonous Potato"));
|
||||
$this->register(new Potato(new ItemIdentifier(ItemIds::POTATO, 0), "Potato"));
|
||||
$this->register(new Pufferfish(new ItemIdentifier(ItemIds::PUFFERFISH, 0), "Pufferfish"));
|
||||
$this->register(new PumpkinPie(new ItemIdentifier(ItemIds::PUMPKIN_PIE, 0), "Pumpkin Pie"));
|
||||
$this->register(new PumpkinSeeds(new ItemIdentifier(ItemIds::PUMPKIN_SEEDS, 0), "Pumpkin Seeds"));
|
||||
$this->register(new RabbitStew(new ItemIdentifier(ItemIds::RABBIT_STEW, 0), "Rabbit Stew"));
|
||||
$this->register(new RawBeef(new ItemIdentifier(ItemIds::RAW_BEEF, 0), "Raw Beef"));
|
||||
$this->register(new RawChicken(new ItemIdentifier(ItemIds::RAW_CHICKEN, 0), "Raw Chicken"));
|
||||
$this->register(new RawFish(new ItemIdentifier(ItemIds::RAW_FISH, 0), "Raw Fish"));
|
||||
$this->register(new RawMutton(new ItemIdentifier(ItemIds::RAW_MUTTON, 0), "Raw Mutton"));
|
||||
$this->register(new RawPorkchop(new ItemIdentifier(ItemIds::RAW_PORKCHOP, 0), "Raw Porkchop"));
|
||||
$this->register(new RawRabbit(new ItemIdentifier(ItemIds::RAW_RABBIT, 0), "Raw Rabbit"));
|
||||
$this->register(new RawSalmon(new ItemIdentifier(ItemIds::RAW_SALMON, 0), "Raw Salmon"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_13, 0), RecordType::DISK_13(), "Record 13"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_CAT, 0), RecordType::DISK_CAT(), "Record Cat"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_BLOCKS, 0), RecordType::DISK_BLOCKS(), "Record Blocks"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_CHIRP, 0), RecordType::DISK_CHIRP(), "Record Chirp"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_FAR, 0), RecordType::DISK_FAR(), "Record Far"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_MALL, 0), RecordType::DISK_MALL(), "Record Mall"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_MELLOHI, 0), RecordType::DISK_MELLOHI(), "Record Mellohi"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_STAL, 0), RecordType::DISK_STAL(), "Record Stal"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_STRAD, 0), RecordType::DISK_STRAD(), "Record Strad"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_WARD, 0), RecordType::DISK_WARD(), "Record Ward"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_11, 0), RecordType::DISK_11(), "Record 11"));
|
||||
$this->register(new Record(new ItemIdentifier(ItemIds::RECORD_WAIT, 0), RecordType::DISK_WAIT(), "Record Wait"));
|
||||
$this->register(new Redstone(new ItemIdentifier(ItemIds::REDSTONE, 0), "Redstone"));
|
||||
$this->register(new RottenFlesh(new ItemIdentifier(ItemIds::ROTTEN_FLESH, 0), "Rotten Flesh"));
|
||||
$this->register(new Shears(new ItemIdentifier(ItemIds::SHEARS, 0), "Shears"));
|
||||
$this->register(new ItemBlockWallOrFloor(new ItemIdentifier(ItemIds::SIGN, 0), VanillaBlocks::OAK_SIGN(), VanillaBlocks::OAK_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new ItemIdentifier(ItemIds::SPRUCE_SIGN, 0), VanillaBlocks::SPRUCE_SIGN(), VanillaBlocks::SPRUCE_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new ItemIdentifier(ItemIds::BIRCH_SIGN, 0), VanillaBlocks::BIRCH_SIGN(), VanillaBlocks::BIRCH_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new ItemIdentifier(ItemIds::JUNGLE_SIGN, 0), VanillaBlocks::JUNGLE_SIGN(), VanillaBlocks::JUNGLE_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new ItemIdentifier(ItemIds::ACACIA_SIGN, 0), VanillaBlocks::ACACIA_SIGN(), VanillaBlocks::ACACIA_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new ItemIdentifier(ItemIds::DARKOAK_SIGN, 0), VanillaBlocks::DARK_OAK_SIGN(), VanillaBlocks::DARK_OAK_WALL_SIGN()));
|
||||
$this->register(new Snowball(new ItemIdentifier(ItemIds::SNOWBALL, 0), "Snowball"));
|
||||
$this->register(new SpiderEye(new ItemIdentifier(ItemIds::SPIDER_EYE, 0), "Spider Eye"));
|
||||
$this->register(new Steak(new ItemIdentifier(ItemIds::STEAK, 0), "Steak"));
|
||||
$this->register(new Stick(new ItemIdentifier(ItemIds::STICK, 0), "Stick"));
|
||||
$this->register(new StringItem(new ItemIdentifier(ItemIds::STRING, 0), "String"));
|
||||
$this->register(new SweetBerries(new ItemIdentifier(ItemIds::SWEET_BERRIES, 0), "Sweet Berries"));
|
||||
$this->register(new Totem(new ItemIdentifier(ItemIds::TOTEM, 0), "Totem of Undying"));
|
||||
$this->register(new WheatSeeds(new ItemIdentifier(ItemIds::WHEAT_SEEDS, 0), "Wheat Seeds"));
|
||||
$this->register(new WritableBook(new ItemIdentifier(ItemIds::WRITABLE_BOOK, 0), "Book & Quill"));
|
||||
$this->register(new WrittenBook(new ItemIdentifier(ItemIds::WRITTEN_BOOK, 0), "Written Book"));
|
||||
$this->remap(new IID(Ids::BUCKET, 11), $lavaBucket);
|
||||
$this->register(new Melon(new IID(Ids::MELON, 0), "Melon"));
|
||||
$this->register(new MelonSeeds(new IID(Ids::MELON_SEEDS, 0), "Melon Seeds"));
|
||||
$this->register(new MilkBucket(new IID(Ids::BUCKET, 1), "Milk Bucket"));
|
||||
$this->register(new Minecart(new IID(Ids::MINECART, 0), "Minecart"));
|
||||
$this->register(new MushroomStew(new IID(Ids::MUSHROOM_STEW, 0), "Mushroom Stew"));
|
||||
$this->register(new PaintingItem(new IID(Ids::PAINTING, 0), "Painting"));
|
||||
$this->register(new PoisonousPotato(new IID(Ids::POISONOUS_POTATO, 0), "Poisonous Potato"));
|
||||
$this->register(new Potato(new IID(Ids::POTATO, 0), "Potato"));
|
||||
$this->register(new Pufferfish(new IID(Ids::PUFFERFISH, 0), "Pufferfish"));
|
||||
$this->register(new PumpkinPie(new IID(Ids::PUMPKIN_PIE, 0), "Pumpkin Pie"));
|
||||
$this->register(new PumpkinSeeds(new IID(Ids::PUMPKIN_SEEDS, 0), "Pumpkin Seeds"));
|
||||
$this->register(new RabbitStew(new IID(Ids::RABBIT_STEW, 0), "Rabbit Stew"));
|
||||
$this->register(new RawBeef(new IID(Ids::RAW_BEEF, 0), "Raw Beef"));
|
||||
$this->register(new RawChicken(new IID(Ids::RAW_CHICKEN, 0), "Raw Chicken"));
|
||||
$this->register(new RawFish(new IID(Ids::RAW_FISH, 0), "Raw Fish"));
|
||||
$this->register(new RawMutton(new IID(Ids::RAW_MUTTON, 0), "Raw Mutton"));
|
||||
$this->register(new RawPorkchop(new IID(Ids::RAW_PORKCHOP, 0), "Raw Porkchop"));
|
||||
$this->register(new RawRabbit(new IID(Ids::RAW_RABBIT, 0), "Raw Rabbit"));
|
||||
$this->register(new RawSalmon(new IID(Ids::RAW_SALMON, 0), "Raw Salmon"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_13, 0), RecordType::DISK_13(), "Record 13"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_CAT, 0), RecordType::DISK_CAT(), "Record Cat"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_BLOCKS, 0), RecordType::DISK_BLOCKS(), "Record Blocks"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_CHIRP, 0), RecordType::DISK_CHIRP(), "Record Chirp"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_FAR, 0), RecordType::DISK_FAR(), "Record Far"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_MALL, 0), RecordType::DISK_MALL(), "Record Mall"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_MELLOHI, 0), RecordType::DISK_MELLOHI(), "Record Mellohi"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_STAL, 0), RecordType::DISK_STAL(), "Record Stal"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_STRAD, 0), RecordType::DISK_STRAD(), "Record Strad"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_WARD, 0), RecordType::DISK_WARD(), "Record Ward"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_11, 0), RecordType::DISK_11(), "Record 11"));
|
||||
$this->register(new Record(new IID(Ids::RECORD_WAIT, 0), RecordType::DISK_WAIT(), "Record Wait"));
|
||||
$this->register(new Redstone(new IID(Ids::REDSTONE, 0), "Redstone"));
|
||||
$this->register(new RottenFlesh(new IID(Ids::ROTTEN_FLESH, 0), "Rotten Flesh"));
|
||||
$this->register(new Shears(new IID(Ids::SHEARS, 0), "Shears"));
|
||||
$this->register(new ItemBlockWallOrFloor(new IID(Ids::SIGN, 0), Blocks::OAK_SIGN(), Blocks::OAK_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new IID(Ids::SPRUCE_SIGN, 0), Blocks::SPRUCE_SIGN(), Blocks::SPRUCE_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new IID(Ids::BIRCH_SIGN, 0), Blocks::BIRCH_SIGN(), Blocks::BIRCH_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new IID(Ids::JUNGLE_SIGN, 0), Blocks::JUNGLE_SIGN(), Blocks::JUNGLE_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new IID(Ids::ACACIA_SIGN, 0), Blocks::ACACIA_SIGN(), Blocks::ACACIA_WALL_SIGN()));
|
||||
$this->register(new ItemBlockWallOrFloor(new IID(Ids::DARKOAK_SIGN, 0), Blocks::DARK_OAK_SIGN(), Blocks::DARK_OAK_WALL_SIGN()));
|
||||
$this->register(new Snowball(new IID(Ids::SNOWBALL, 0), "Snowball"));
|
||||
$this->register(new SpiderEye(new IID(Ids::SPIDER_EYE, 0), "Spider Eye"));
|
||||
$this->register(new Steak(new IID(Ids::STEAK, 0), "Steak"));
|
||||
$this->register(new Stick(new IID(Ids::STICK, 0), "Stick"));
|
||||
$this->register(new StringItem(new IID(Ids::STRING, 0), "String"));
|
||||
$this->register(new SweetBerries(new IID(Ids::SWEET_BERRIES, 0), "Sweet Berries"));
|
||||
$this->register(new Totem(new IID(Ids::TOTEM, 0), "Totem of Undying"));
|
||||
$this->register(new WheatSeeds(new IID(Ids::WHEAT_SEEDS, 0), "Wheat Seeds"));
|
||||
$this->register(new WritableBook(new IID(Ids::WRITABLE_BOOK, 0), "Book & Quill"));
|
||||
$this->register(new WrittenBook(new IID(Ids::WRITTEN_BOOK, 0), "Written Book"));
|
||||
|
||||
foreach(SkullType::getAll() as $skullType){
|
||||
$this->register(new Skull(new ItemIdentifier(ItemIds::SKULL, $skullType->getMagicNumber()), $skullType->getDisplayName(), $skullType));
|
||||
$this->register(new Skull(new IID(Ids::SKULL, $skullType->getMagicNumber()), $skullType->getDisplayName(), $skullType));
|
||||
}
|
||||
|
||||
$dyeMap = [
|
||||
@ -288,23 +290,23 @@ class ItemFactory{
|
||||
foreach(DyeColor::getAll() as $color){
|
||||
//TODO: use colour object directly
|
||||
//TODO: add interface to dye-colour objects
|
||||
$this->register(new Dye(new ItemIdentifier(ItemIds::DYE, $dyeMap[$color->id()] ?? $colorIdMap->toInvertedId($color)), $color->getDisplayName() . " Dye", $color));
|
||||
$this->register(new Bed(new ItemIdentifier(ItemIds::BED, $colorIdMap->toId($color)), $color->getDisplayName() . " Bed", $color));
|
||||
$this->register(new Dye(new IID(Ids::DYE, $dyeMap[$color->id()] ?? $colorIdMap->toInvertedId($color)), $color->getDisplayName() . " Dye", $color));
|
||||
$this->register(new Bed(new IID(Ids::BED, $colorIdMap->toId($color)), $color->getDisplayName() . " Bed", $color));
|
||||
$this->register((new Banner(
|
||||
new ItemIdentifier(ItemIds::BANNER, 0),
|
||||
VanillaBlocks::BANNER(),
|
||||
VanillaBlocks::WALL_BANNER()
|
||||
new IID(Ids::BANNER, 0),
|
||||
Blocks::BANNER(),
|
||||
Blocks::WALL_BANNER()
|
||||
))->setColor($color));
|
||||
}
|
||||
|
||||
foreach(PotionType::getAll() as $type){
|
||||
$typeId = PotionTypeIdMap::getInstance()->toId($type);
|
||||
$this->register(new Potion(new ItemIdentifier(ItemIds::POTION, $typeId), $type->getDisplayName() . " Potion", $type));
|
||||
$this->register(new SplashPotion(new ItemIdentifier(ItemIds::SPLASH_POTION, $typeId), $type->getDisplayName() . " Splash Potion", $type));
|
||||
$this->register(new Potion(new IID(Ids::POTION, $typeId), $type->getDisplayName() . " Potion", $type));
|
||||
$this->register(new SplashPotion(new IID(Ids::SPLASH_POTION, $typeId), $type->getDisplayName() . " Splash Potion", $type));
|
||||
}
|
||||
|
||||
foreach(TreeType::getAll() as $type){
|
||||
$this->register(new Boat(new ItemIdentifier(ItemIds::BOAT, $type->getMagicNumber()), $type->getDisplayName() . " Boat", $type));
|
||||
$this->register(new Boat(new IID(Ids::BOAT, $type->getMagicNumber()), $type->getDisplayName() . " Boat", $type));
|
||||
}
|
||||
|
||||
//region --- auto-generated TODOs ---
|
||||
@ -352,17 +354,17 @@ class ItemFactory{
|
||||
|
||||
private function registerSpawnEggs() : void{
|
||||
//TODO: the meta values should probably be hardcoded; they won't change, but the EntityLegacyIds might
|
||||
$this->register(new class(new ItemIdentifier(ItemIds::SPAWN_EGG, EntityLegacyIds::ZOMBIE), "Zombie Spawn Egg") extends SpawnEgg{
|
||||
$this->register(new class(new IID(Ids::SPAWN_EGG, EntityLegacyIds::ZOMBIE), "Zombie Spawn Egg") extends SpawnEgg{
|
||||
protected function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
|
||||
return new Zombie(Location::fromObject($pos, $world, $yaw, $pitch));
|
||||
}
|
||||
});
|
||||
$this->register(new class(new ItemIdentifier(ItemIds::SPAWN_EGG, EntityLegacyIds::SQUID), "Squid Spawn Egg") extends SpawnEgg{
|
||||
$this->register(new class(new IID(Ids::SPAWN_EGG, EntityLegacyIds::SQUID), "Squid Spawn Egg") extends SpawnEgg{
|
||||
public function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
|
||||
return new Squid(Location::fromObject($pos, $world, $yaw, $pitch));
|
||||
}
|
||||
});
|
||||
$this->register(new class(new ItemIdentifier(ItemIds::SPAWN_EGG, EntityLegacyIds::VILLAGER), "Villager Spawn Egg") extends SpawnEgg{
|
||||
$this->register(new class(new IID(Ids::SPAWN_EGG, EntityLegacyIds::VILLAGER), "Villager Spawn Egg") extends SpawnEgg{
|
||||
public function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
|
||||
return new Villager(Location::fromObject($pos, $world, $yaw, $pitch));
|
||||
}
|
||||
@ -370,54 +372,54 @@ class ItemFactory{
|
||||
}
|
||||
|
||||
private function registerTierToolItems() : void{
|
||||
$this->register(new Axe(new ItemIdentifier(ItemIds::DIAMOND_AXE, 0), "Diamond Axe", ToolTier::DIAMOND()));
|
||||
$this->register(new Axe(new ItemIdentifier(ItemIds::GOLDEN_AXE, 0), "Golden Axe", ToolTier::GOLD()));
|
||||
$this->register(new Axe(new ItemIdentifier(ItemIds::IRON_AXE, 0), "Iron Axe", ToolTier::IRON()));
|
||||
$this->register(new Axe(new ItemIdentifier(ItemIds::STONE_AXE, 0), "Stone Axe", ToolTier::STONE()));
|
||||
$this->register(new Axe(new ItemIdentifier(ItemIds::WOODEN_AXE, 0), "Wooden Axe", ToolTier::WOOD()));
|
||||
$this->register(new Hoe(new ItemIdentifier(ItemIds::DIAMOND_HOE, 0), "Diamond Hoe", ToolTier::DIAMOND()));
|
||||
$this->register(new Hoe(new ItemIdentifier(ItemIds::GOLDEN_HOE, 0), "Golden Hoe", ToolTier::GOLD()));
|
||||
$this->register(new Hoe(new ItemIdentifier(ItemIds::IRON_HOE, 0), "Iron Hoe", ToolTier::IRON()));
|
||||
$this->register(new Hoe(new ItemIdentifier(ItemIds::STONE_HOE, 0), "Stone Hoe", ToolTier::STONE()));
|
||||
$this->register(new Hoe(new ItemIdentifier(ItemIds::WOODEN_HOE, 0), "Wooden Hoe", ToolTier::WOOD()));
|
||||
$this->register(new Pickaxe(new ItemIdentifier(ItemIds::DIAMOND_PICKAXE, 0), "Diamond Pickaxe", ToolTier::DIAMOND()));
|
||||
$this->register(new Pickaxe(new ItemIdentifier(ItemIds::GOLDEN_PICKAXE, 0), "Golden Pickaxe", ToolTier::GOLD()));
|
||||
$this->register(new Pickaxe(new ItemIdentifier(ItemIds::IRON_PICKAXE, 0), "Iron Pickaxe", ToolTier::IRON()));
|
||||
$this->register(new Pickaxe(new ItemIdentifier(ItemIds::STONE_PICKAXE, 0), "Stone Pickaxe", ToolTier::STONE()));
|
||||
$this->register(new Pickaxe(new ItemIdentifier(ItemIds::WOODEN_PICKAXE, 0), "Wooden Pickaxe", ToolTier::WOOD()));
|
||||
$this->register(new Shovel(new ItemIdentifier(ItemIds::DIAMOND_SHOVEL, 0), "Diamond Shovel", ToolTier::DIAMOND()));
|
||||
$this->register(new Shovel(new ItemIdentifier(ItemIds::GOLDEN_SHOVEL, 0), "Golden Shovel", ToolTier::GOLD()));
|
||||
$this->register(new Shovel(new ItemIdentifier(ItemIds::IRON_SHOVEL, 0), "Iron Shovel", ToolTier::IRON()));
|
||||
$this->register(new Shovel(new ItemIdentifier(ItemIds::STONE_SHOVEL, 0), "Stone Shovel", ToolTier::STONE()));
|
||||
$this->register(new Shovel(new ItemIdentifier(ItemIds::WOODEN_SHOVEL, 0), "Wooden Shovel", ToolTier::WOOD()));
|
||||
$this->register(new Sword(new ItemIdentifier(ItemIds::DIAMOND_SWORD, 0), "Diamond Sword", ToolTier::DIAMOND()));
|
||||
$this->register(new Sword(new ItemIdentifier(ItemIds::GOLDEN_SWORD, 0), "Golden Sword", ToolTier::GOLD()));
|
||||
$this->register(new Sword(new ItemIdentifier(ItemIds::IRON_SWORD, 0), "Iron Sword", ToolTier::IRON()));
|
||||
$this->register(new Sword(new ItemIdentifier(ItemIds::STONE_SWORD, 0), "Stone Sword", ToolTier::STONE()));
|
||||
$this->register(new Sword(new ItemIdentifier(ItemIds::WOODEN_SWORD, 0), "Wooden Sword", ToolTier::WOOD()));
|
||||
$this->register(new Axe(new IID(Ids::DIAMOND_AXE, 0), "Diamond Axe", ToolTier::DIAMOND()));
|
||||
$this->register(new Axe(new IID(Ids::GOLDEN_AXE, 0), "Golden Axe", ToolTier::GOLD()));
|
||||
$this->register(new Axe(new IID(Ids::IRON_AXE, 0), "Iron Axe", ToolTier::IRON()));
|
||||
$this->register(new Axe(new IID(Ids::STONE_AXE, 0), "Stone Axe", ToolTier::STONE()));
|
||||
$this->register(new Axe(new IID(Ids::WOODEN_AXE, 0), "Wooden Axe", ToolTier::WOOD()));
|
||||
$this->register(new Hoe(new IID(Ids::DIAMOND_HOE, 0), "Diamond Hoe", ToolTier::DIAMOND()));
|
||||
$this->register(new Hoe(new IID(Ids::GOLDEN_HOE, 0), "Golden Hoe", ToolTier::GOLD()));
|
||||
$this->register(new Hoe(new IID(Ids::IRON_HOE, 0), "Iron Hoe", ToolTier::IRON()));
|
||||
$this->register(new Hoe(new IID(Ids::STONE_HOE, 0), "Stone Hoe", ToolTier::STONE()));
|
||||
$this->register(new Hoe(new IID(Ids::WOODEN_HOE, 0), "Wooden Hoe", ToolTier::WOOD()));
|
||||
$this->register(new Pickaxe(new IID(Ids::DIAMOND_PICKAXE, 0), "Diamond Pickaxe", ToolTier::DIAMOND()));
|
||||
$this->register(new Pickaxe(new IID(Ids::GOLDEN_PICKAXE, 0), "Golden Pickaxe", ToolTier::GOLD()));
|
||||
$this->register(new Pickaxe(new IID(Ids::IRON_PICKAXE, 0), "Iron Pickaxe", ToolTier::IRON()));
|
||||
$this->register(new Pickaxe(new IID(Ids::STONE_PICKAXE, 0), "Stone Pickaxe", ToolTier::STONE()));
|
||||
$this->register(new Pickaxe(new IID(Ids::WOODEN_PICKAXE, 0), "Wooden Pickaxe", ToolTier::WOOD()));
|
||||
$this->register(new Shovel(new IID(Ids::DIAMOND_SHOVEL, 0), "Diamond Shovel", ToolTier::DIAMOND()));
|
||||
$this->register(new Shovel(new IID(Ids::GOLDEN_SHOVEL, 0), "Golden Shovel", ToolTier::GOLD()));
|
||||
$this->register(new Shovel(new IID(Ids::IRON_SHOVEL, 0), "Iron Shovel", ToolTier::IRON()));
|
||||
$this->register(new Shovel(new IID(Ids::STONE_SHOVEL, 0), "Stone Shovel", ToolTier::STONE()));
|
||||
$this->register(new Shovel(new IID(Ids::WOODEN_SHOVEL, 0), "Wooden Shovel", ToolTier::WOOD()));
|
||||
$this->register(new Sword(new IID(Ids::DIAMOND_SWORD, 0), "Diamond Sword", ToolTier::DIAMOND()));
|
||||
$this->register(new Sword(new IID(Ids::GOLDEN_SWORD, 0), "Golden Sword", ToolTier::GOLD()));
|
||||
$this->register(new Sword(new IID(Ids::IRON_SWORD, 0), "Iron Sword", ToolTier::IRON()));
|
||||
$this->register(new Sword(new IID(Ids::STONE_SWORD, 0), "Stone Sword", ToolTier::STONE()));
|
||||
$this->register(new Sword(new IID(Ids::WOODEN_SWORD, 0), "Wooden Sword", ToolTier::WOOD()));
|
||||
}
|
||||
|
||||
private function registerArmorItems() : void{
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::CHAIN_BOOTS, 0), "Chainmail Boots", new ArmorTypeInfo(1, 196, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::DIAMOND_BOOTS, 0), "Diamond Boots", new ArmorTypeInfo(3, 430, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::GOLDEN_BOOTS, 0), "Golden Boots", new ArmorTypeInfo(1, 92, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::IRON_BOOTS, 0), "Iron Boots", new ArmorTypeInfo(2, 196, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::LEATHER_BOOTS, 0), "Leather Boots", new ArmorTypeInfo(1, 66, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::CHAIN_CHESTPLATE, 0), "Chainmail Chestplate", new ArmorTypeInfo(5, 241, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::DIAMOND_CHESTPLATE, 0), "Diamond Chestplate", new ArmorTypeInfo(8, 529, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::GOLDEN_CHESTPLATE, 0), "Golden Chestplate", new ArmorTypeInfo(5, 113, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::IRON_CHESTPLATE, 0), "Iron Chestplate", new ArmorTypeInfo(6, 241, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::LEATHER_CHESTPLATE, 0), "Leather Tunic", new ArmorTypeInfo(3, 81, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::CHAIN_HELMET, 0), "Chainmail Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::DIAMOND_HELMET, 0), "Diamond Helmet", new ArmorTypeInfo(3, 364, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::GOLDEN_HELMET, 0), "Golden Helmet", new ArmorTypeInfo(2, 78, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::IRON_HELMET, 0), "Iron Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::LEATHER_HELMET, 0), "Leather Cap", new ArmorTypeInfo(1, 56, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::CHAIN_LEGGINGS, 0), "Chainmail Leggings", new ArmorTypeInfo(4, 226, ArmorInventory::SLOT_LEGS)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::DIAMOND_LEGGINGS, 0), "Diamond Leggings", new ArmorTypeInfo(6, 496, ArmorInventory::SLOT_LEGS)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::GOLDEN_LEGGINGS, 0), "Golden Leggings", new ArmorTypeInfo(3, 106, ArmorInventory::SLOT_LEGS)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::IRON_LEGGINGS, 0), "Iron Leggings", new ArmorTypeInfo(5, 226, ArmorInventory::SLOT_LEGS)));
|
||||
$this->register(new Armor(new ItemIdentifier(ItemIds::LEATHER_LEGGINGS, 0), "Leather Pants", new ArmorTypeInfo(2, 76, ArmorInventory::SLOT_LEGS)));
|
||||
$this->register(new Armor(new IID(Ids::CHAIN_BOOTS, 0), "Chainmail Boots", new ArmorTypeInfo(1, 196, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new IID(Ids::DIAMOND_BOOTS, 0), "Diamond Boots", new ArmorTypeInfo(3, 430, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new IID(Ids::GOLDEN_BOOTS, 0), "Golden Boots", new ArmorTypeInfo(1, 92, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new IID(Ids::IRON_BOOTS, 0), "Iron Boots", new ArmorTypeInfo(2, 196, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new IID(Ids::LEATHER_BOOTS, 0), "Leather Boots", new ArmorTypeInfo(1, 66, ArmorInventory::SLOT_FEET)));
|
||||
$this->register(new Armor(new IID(Ids::CHAIN_CHESTPLATE, 0), "Chainmail Chestplate", new ArmorTypeInfo(5, 241, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new IID(Ids::DIAMOND_CHESTPLATE, 0), "Diamond Chestplate", new ArmorTypeInfo(8, 529, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new IID(Ids::GOLDEN_CHESTPLATE, 0), "Golden Chestplate", new ArmorTypeInfo(5, 113, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new IID(Ids::IRON_CHESTPLATE, 0), "Iron Chestplate", new ArmorTypeInfo(6, 241, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new IID(Ids::LEATHER_CHESTPLATE, 0), "Leather Tunic", new ArmorTypeInfo(3, 81, ArmorInventory::SLOT_CHEST)));
|
||||
$this->register(new Armor(new IID(Ids::CHAIN_HELMET, 0), "Chainmail Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new IID(Ids::DIAMOND_HELMET, 0), "Diamond Helmet", new ArmorTypeInfo(3, 364, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new IID(Ids::GOLDEN_HELMET, 0), "Golden Helmet", new ArmorTypeInfo(2, 78, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new IID(Ids::IRON_HELMET, 0), "Iron Helmet", new ArmorTypeInfo(2, 166, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new IID(Ids::LEATHER_HELMET, 0), "Leather Cap", new ArmorTypeInfo(1, 56, ArmorInventory::SLOT_HEAD)));
|
||||
$this->register(new Armor(new IID(Ids::CHAIN_LEGGINGS, 0), "Chainmail Leggings", new ArmorTypeInfo(4, 226, ArmorInventory::SLOT_LEGS)));
|
||||
$this->register(new Armor(new IID(Ids::DIAMOND_LEGGINGS, 0), "Diamond Leggings", new ArmorTypeInfo(6, 496, ArmorInventory::SLOT_LEGS)));
|
||||
$this->register(new Armor(new IID(Ids::GOLDEN_LEGGINGS, 0), "Golden Leggings", new ArmorTypeInfo(3, 106, ArmorInventory::SLOT_LEGS)));
|
||||
$this->register(new Armor(new IID(Ids::IRON_LEGGINGS, 0), "Iron Leggings", new ArmorTypeInfo(5, 226, ArmorInventory::SLOT_LEGS)));
|
||||
$this->register(new Armor(new IID(Ids::LEATHER_LEGGINGS, 0), "Leather Pants", new ArmorTypeInfo(2, 76, ArmorInventory::SLOT_LEGS)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -470,21 +472,21 @@ class ItemFactory{
|
||||
if(isset($this->list[$offset = self::getListOffset($id, $meta)])){
|
||||
$item = clone $this->list[$offset];
|
||||
}elseif(isset($this->list[$zero = self::getListOffset($id, 0)]) && $this->list[$zero] instanceof Durable){
|
||||
if($meta <= $this->list[$zero]->getMaxDurability()){
|
||||
if($meta >= 0 && $meta <= $this->list[$zero]->getMaxDurability()){
|
||||
$item = clone $this->list[$zero];
|
||||
$item->setDamage($meta);
|
||||
}else{
|
||||
$item = new Item(new ItemIdentifier($id, $meta));
|
||||
$item = new Item(new IID($id, $meta));
|
||||
}
|
||||
}elseif($id < 256){ //intentionally includes negatives, for extended block IDs
|
||||
//TODO: do not assume that item IDs and block IDs are the same or related
|
||||
$item = new ItemBlock(new ItemIdentifier($id, $meta), BlockFactory::getInstance()->get(self::itemToBlockId($id), $meta & 0xf));
|
||||
$item = new ItemBlock(new IID($id, $meta), BlockFactory::getInstance()->get(self::itemToBlockId($id), $meta & 0xf));
|
||||
}
|
||||
}
|
||||
|
||||
if($item === null){
|
||||
//negative damage values will fallthru to here, to avoid crazy shit with crafting wildcard hacks
|
||||
$item = new Item(new ItemIdentifier($id, $meta));
|
||||
$item = new Item(new IID($id, $meta));
|
||||
}
|
||||
|
||||
$item->setCount($count);
|
||||
@ -499,7 +501,7 @@ class ItemFactory{
|
||||
* @see VanillaItems::AIR()
|
||||
*/
|
||||
public static function air() : Item{
|
||||
return self::getInstance()->get(ItemIds::AIR, 0, 0);
|
||||
return self::getInstance()->get(Ids::AIR, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,13 +185,16 @@ final class PotionType{
|
||||
new EffectInstance(VanillaEffects::WITHER(), 800, 1)
|
||||
]),
|
||||
new self("turtle_master", "Turtle Master", fn() => [
|
||||
//TODO
|
||||
new EffectInstance(VanillaEffects::SLOWNESS(), 20 * 20, 3),
|
||||
new EffectInstance(VanillaEffects::RESISTANCE(), 20 * 20, 2),
|
||||
]),
|
||||
new self("long_turtle_master", "Long Turtle Master", fn() => [
|
||||
//TODO
|
||||
new EffectInstance(VanillaEffects::SLOWNESS(), 40 * 20, 3),
|
||||
new EffectInstance(VanillaEffects::RESISTANCE(), 40 * 20, 2),
|
||||
]),
|
||||
new self("strong_turtle_master", "Strong Turtle Master", fn() => [
|
||||
//TODO
|
||||
new EffectInstance(VanillaEffects::SLOWNESS(), 20 * 20, 5),
|
||||
new EffectInstance(VanillaEffects::RESISTANCE(), 20 * 20, 3),
|
||||
]),
|
||||
new self("slow_falling", "Slow Falling", fn() => [
|
||||
//TODO
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -384,6 +384,7 @@ final class VanillaItems{
|
||||
|
||||
/**
|
||||
* @return Item[]
|
||||
* @phpstan-return array<string, Item>
|
||||
*/
|
||||
public static function getAll() : array{
|
||||
//phpstan doesn't support generic traits yet :(
|
||||
|
@ -35,7 +35,7 @@ final class StringToEnchantmentParser extends StringToTParser{
|
||||
use SingletonTrait;
|
||||
|
||||
private static function make() : self{
|
||||
$result = new self;
|
||||
$result = new self();
|
||||
|
||||
$result->register("blast_protection", fn() => VanillaEnchantments::BLAST_PROTECTION());
|
||||
$result->register("efficiency", fn() => VanillaEnchantments::EFFICIENCY());
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\utils\Utils;
|
||||
use Webmozart\PathUtil\Path;
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function file_exists;
|
||||
use function is_dir;
|
||||
@ -67,11 +68,15 @@ class Language{
|
||||
$result = [];
|
||||
|
||||
foreach($files as $file){
|
||||
try{
|
||||
$code = explode(".", $file)[0];
|
||||
$strings = self::loadLang($path, $code);
|
||||
if(isset($strings["language.name"])){
|
||||
$result[$code] = $strings["language.name"];
|
||||
}
|
||||
}catch(LanguageNotFoundException $e){
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -124,7 +129,10 @@ class Language{
|
||||
protected static function loadLang(string $path, string $languageCode) : array{
|
||||
$file = Path::join($path, $languageCode . ".ini");
|
||||
if(file_exists($file)){
|
||||
return array_map('\stripcslashes', Utils::assumeNotFalse(parse_ini_file($file, false, INI_SCANNER_RAW), "Missing or inaccessible required resource files"));
|
||||
$strings = array_map('stripcslashes', Utils::assumeNotFalse(parse_ini_file($file, false, INI_SCANNER_RAW), "Missing or inaccessible required resource files"));
|
||||
if(count($strings) > 0){
|
||||
return $strings;
|
||||
}
|
||||
}
|
||||
|
||||
throw new LanguageNotFoundException("Language \"$languageCode\" not found");
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
|
||||
use pocketmine\network\mcpe\protocol\LevelChunkPacket;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\types\ChunkPosition;
|
||||
use pocketmine\network\mcpe\serializer\ChunkSerializer;
|
||||
use pocketmine\scheduler\AsyncTask;
|
||||
use pocketmine\world\format\Chunk;
|
||||
@ -71,7 +72,7 @@ class ChunkRequestTask extends AsyncTask{
|
||||
$subCount = ChunkSerializer::getSubChunkCount($chunk) + ChunkSerializer::LOWER_PADDING_SIZE;
|
||||
$encoderContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
|
||||
$payload = ChunkSerializer::serializeFullChunk($chunk, RuntimeBlockMapping::getInstance(), $encoderContext, $this->tiles);
|
||||
$this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::create($this->chunkX, $this->chunkZ, $subCount, false, null, $payload))->getBuffer()));
|
||||
$this->setResult($this->compressor->compress(PacketBatch::fromPackets($encoderContext, LevelChunkPacket::create(new ChunkPosition($this->chunkX, $this->chunkZ), $subCount, false, null, $payload))->getBuffer()));
|
||||
}
|
||||
|
||||
public function onError() : void{
|
||||
|
@ -259,8 +259,10 @@ class InventoryManager{
|
||||
|
||||
public function onClientRemoveWindow(int $id) : void{
|
||||
if($id === $this->lastInventoryNetworkId){
|
||||
if(isset($this->windowMap[$id]) && $id !== $this->pendingCloseWindowId){
|
||||
$this->remove($id);
|
||||
$this->player->removeCurrentWindow();
|
||||
}
|
||||
}else{
|
||||
$this->session->getLogger()->debug("Attempted to close inventory with network ID $id, but current is $this->lastInventoryNetworkId");
|
||||
}
|
||||
@ -269,13 +271,15 @@ class InventoryManager{
|
||||
//initiated the close and expect an ack.
|
||||
$this->session->sendDataPacket(ContainerClosePacket::create($id, false));
|
||||
|
||||
if($this->pendingOpenWindowCallback !== null && $id === $this->pendingCloseWindowId){
|
||||
$this->session->getLogger()->debug("Opening deferred window after close ack of window $id");
|
||||
if($this->pendingCloseWindowId === $id){
|
||||
$this->pendingCloseWindowId = null;
|
||||
if($this->pendingOpenWindowCallback !== null){
|
||||
$this->session->getLogger()->debug("Opening deferred window after close ack of window $id");
|
||||
($this->pendingOpenWindowCallback)();
|
||||
$this->pendingOpenWindowCallback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function syncSlot(Inventory $inventory, int $slot) : void{
|
||||
$windowId = $this->getWindowId($inventory);
|
||||
|
@ -56,8 +56,8 @@ use pocketmine\network\mcpe\handler\LoginPacketHandler;
|
||||
use pocketmine\network\mcpe\handler\PacketHandler;
|
||||
use pocketmine\network\mcpe\handler\PreSpawnPacketHandler;
|
||||
use pocketmine\network\mcpe\handler\ResourcePacksPacketHandler;
|
||||
use pocketmine\network\mcpe\handler\SessionStartPacketHandler;
|
||||
use pocketmine\network\mcpe\handler\SpawnResponsePacketHandler;
|
||||
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
|
||||
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
|
||||
use pocketmine\network\mcpe\protocol\ClientboundPacket;
|
||||
@ -93,6 +93,7 @@ use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\command\CommandData;
|
||||
use pocketmine\network\mcpe\protocol\types\command\CommandEnum;
|
||||
use pocketmine\network\mcpe\protocol\types\command\CommandParameter;
|
||||
use pocketmine\network\mcpe\protocol\types\command\CommandPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\Attribute as NetworkAttribute;
|
||||
use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty;
|
||||
@ -100,9 +101,13 @@ use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;
|
||||
use pocketmine\network\mcpe\protocol\types\UpdateAbilitiesPacketLayer;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAbilitiesPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
|
||||
use pocketmine\network\NetworkSessionManager;
|
||||
use pocketmine\network\PacketHandlingException;
|
||||
use pocketmine\permission\DefaultPermissionNames;
|
||||
use pocketmine\permission\DefaultPermissions;
|
||||
use pocketmine\player\GameMode;
|
||||
use pocketmine\player\Player;
|
||||
@ -160,6 +165,7 @@ class NetworkSession{
|
||||
*/
|
||||
private \SplQueue $compressedQueue;
|
||||
private bool $forceAsyncCompression = true;
|
||||
private bool $enableCompression = false; //disabled until handshake completed
|
||||
|
||||
private PacketSerializerContext $packetSerializerContext;
|
||||
|
||||
@ -192,17 +198,10 @@ class NetworkSession{
|
||||
|
||||
$this->connectTime = time();
|
||||
|
||||
$this->setHandler(new LoginPacketHandler(
|
||||
$this->setHandler(new SessionStartPacketHandler(
|
||||
$this->server,
|
||||
$this,
|
||||
function(PlayerInfo $info) : void{
|
||||
$this->info = $info;
|
||||
$this->logger->info("Player: " . TextFormat::AQUA . $info->getUsername() . TextFormat::RESET);
|
||||
$this->logger->setPrefix($this->getLogPrefix());
|
||||
},
|
||||
function(bool $isAuthenticated, bool $authRequired, ?string $error, ?string $clientPubKey) : void{
|
||||
$this->setAuthenticationStatus($isAuthenticated, $authRequired, $error, $clientPubKey);
|
||||
}
|
||||
fn() => $this->onSessionStartSuccess()
|
||||
));
|
||||
|
||||
$this->manager->add($this);
|
||||
@ -217,6 +216,24 @@ class NetworkSession{
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
private function onSessionStartSuccess() : void{
|
||||
$this->logger->debug("Session start handshake completed, awaiting login packet");
|
||||
$this->flushSendBuffer(true);
|
||||
$this->enableCompression = true;
|
||||
$this->setHandler(new LoginPacketHandler(
|
||||
$this->server,
|
||||
$this,
|
||||
function(PlayerInfo $info) : void{
|
||||
$this->info = $info;
|
||||
$this->logger->info("Player: " . TextFormat::AQUA . $info->getUsername() . TextFormat::RESET);
|
||||
$this->logger->setPrefix($this->getLogPrefix());
|
||||
},
|
||||
function(bool $isAuthenticated, bool $authRequired, ?string $error, ?string $clientPubKey) : void{
|
||||
$this->setAuthenticationStatus($isAuthenticated, $authRequired, $error, $clientPubKey);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
protected function createPlayer() : void{
|
||||
$this->server->createPlayer($this, $this->info, $this->authenticated, $this->cachedOfflinePlayerData)->onCompletion(
|
||||
\Closure::fromCallable([$this, 'onPlayerCreated']),
|
||||
@ -250,8 +267,8 @@ class NetworkSession{
|
||||
|
||||
$permissionHooks = $this->player->getPermissionRecalculationCallbacks();
|
||||
$permissionHooks->add($permHook = function() : void{
|
||||
$this->logger->debug("Syncing available commands and adventure settings due to permission recalculation");
|
||||
$this->syncAdventureSettings($this->player);
|
||||
$this->logger->debug("Syncing available commands and abilities/permissions due to permission recalculation");
|
||||
$this->syncAbilities($this->player);
|
||||
$this->syncAvailableCommands();
|
||||
});
|
||||
$this->disposeHooks->add(static function() use ($permissionHooks, $permHook) : void{
|
||||
@ -331,18 +348,22 @@ class NetworkSession{
|
||||
}
|
||||
}
|
||||
|
||||
if($this->enableCompression){
|
||||
Timings::$playerNetworkReceiveDecompress->startTiming();
|
||||
try{
|
||||
$stream = new PacketBatch($this->compressor->decompress($payload));
|
||||
$decompressed = $this->compressor->decompress($payload);
|
||||
}catch(DecompressionException $e){
|
||||
$this->logger->debug("Failed to decompress packet: " . base64_encode($payload));
|
||||
throw PacketHandlingException::wrap($e, "Compressed packet batch decode error");
|
||||
}finally{
|
||||
Timings::$playerNetworkReceiveDecompress->stopTiming();
|
||||
}
|
||||
}else{
|
||||
$decompressed = $payload;
|
||||
}
|
||||
|
||||
try{
|
||||
foreach($stream->getPackets($this->packetPool, $this->packetSerializerContext, 500) as [$packet, $buffer]){
|
||||
foreach((new PacketBatch($decompressed))->getPackets($this->packetPool, $this->packetSerializerContext, 500) as [$packet, $buffer]){
|
||||
if($packet === null){
|
||||
$this->logger->debug("Unknown packet: " . base64_encode($buffer));
|
||||
throw new PacketHandlingException("Unknown packet received");
|
||||
@ -440,7 +461,14 @@ class NetworkSession{
|
||||
}elseif($this->forceAsyncCompression){
|
||||
$syncMode = false;
|
||||
}
|
||||
$promise = $this->server->prepareBatch(PacketBatch::fromPackets($this->packetSerializerContext, ...$this->sendBuffer), $this->compressor, $syncMode);
|
||||
|
||||
$batch = PacketBatch::fromPackets($this->packetSerializerContext, ...$this->sendBuffer);
|
||||
if($this->enableCompression){
|
||||
$promise = $this->server->prepareBatch($batch, $this->compressor, $syncMode);
|
||||
}else{
|
||||
$promise = new CompressBatchPromise();
|
||||
$promise->resolve($batch->getBuffer());
|
||||
}
|
||||
$this->sendBuffer = [];
|
||||
$this->queueCompressedNoBufferFlush($promise, $immediate);
|
||||
}
|
||||
@ -716,7 +744,7 @@ class NetworkSession{
|
||||
$this->syncAttributes($this->player, $this->player->getAttributeMap()->getAll());
|
||||
$this->player->sendData(null);
|
||||
|
||||
$this->syncAdventureSettings($this->player);
|
||||
$this->syncAbilities($this->player);
|
||||
$this->invManager->syncAll();
|
||||
$this->setHandler(new InGamePacketHandler($this->player, $this, $this->invManager));
|
||||
}
|
||||
@ -750,7 +778,7 @@ class NetworkSession{
|
||||
}
|
||||
|
||||
public function syncViewAreaCenterPoint(Vector3 $newPos, int $viewDistance) : void{
|
||||
$this->sendDataPacket(NetworkChunkPublisherUpdatePacket::create(BlockPosition::fromVector3($newPos), $viewDistance * 16)); //blocks, not chunks >.>
|
||||
$this->sendDataPacket(NetworkChunkPublisherUpdatePacket::create(BlockPosition::fromVector3($newPos), $viewDistance * 16, [])); //blocks, not chunks >.>
|
||||
}
|
||||
|
||||
public function syncPlayerSpawnPoint(Position $newSpawn) : void{
|
||||
@ -766,37 +794,60 @@ class NetworkSession{
|
||||
public function syncGameMode(GameMode $mode, bool $isRollback = false) : void{
|
||||
$this->sendDataPacket(SetPlayerGameTypePacket::create(TypeConverter::getInstance()->coreGameModeToProtocol($mode)));
|
||||
if($this->player !== null){
|
||||
$this->syncAdventureSettings($this->player);
|
||||
$this->syncAbilities($this->player);
|
||||
$this->syncAdventureSettings(); //TODO: we might be able to do this with the abilities packet alone
|
||||
}
|
||||
if(!$isRollback && $this->invManager !== null){
|
||||
$this->invManager->syncCreative();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: make this less specialized
|
||||
*/
|
||||
public function syncAdventureSettings(Player $for) : void{
|
||||
public function syncAbilities(Player $for) : void{
|
||||
$isOp = $for->hasPermission(DefaultPermissions::ROOT_OPERATOR);
|
||||
$pk = AdventureSettingsPacket::create(
|
||||
0,
|
||||
$isOp ? AdventureSettingsPacket::PERMISSION_OPERATOR : AdventureSettingsPacket::PERMISSION_NORMAL,
|
||||
0,
|
||||
|
||||
//ALL of these need to be set for the base layer, otherwise the client will cry
|
||||
$boolAbilities = [
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ALLOW_FLIGHT => $for->getAllowFlight(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_FLYING => $for->isFlying(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_NO_CLIP => !$for->hasBlockCollision(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_OPERATOR => $isOp,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_TELEPORT => $for->hasPermission(DefaultPermissionNames::COMMAND_TELEPORT),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_INVULNERABLE => $for->isCreative(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_MUTED => false,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_WORLD_BUILDER => false,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_INFINITE_RESOURCES => !$for->hasFiniteResources(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_LIGHTNING => false,
|
||||
UpdateAbilitiesPacketLayer::ABILITY_BUILD => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_MINE => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_DOORS_AND_SWITCHES => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_OPEN_CONTAINERS => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ATTACK_PLAYERS => !$for->isSpectator(),
|
||||
UpdateAbilitiesPacketLayer::ABILITY_ATTACK_MOBS => !$for->isSpectator(),
|
||||
];
|
||||
|
||||
$this->sendDataPacket(UpdateAbilitiesPacket::create(
|
||||
$isOp ? CommandPermissions::OPERATOR : CommandPermissions::NORMAL,
|
||||
$isOp ? PlayerPermissions::OPERATOR : PlayerPermissions::MEMBER,
|
||||
0,
|
||||
$for->getId()
|
||||
);
|
||||
$for->getId(),
|
||||
[
|
||||
//TODO: dynamic flying speed! FINALLY!!!!!!!!!!!!!!!!!
|
||||
new UpdateAbilitiesPacketLayer(UpdateAbilitiesPacketLayer::LAYER_BASE, $boolAbilities, 0.05, 0.1),
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
$pk->setFlag(AdventureSettingsPacket::WORLD_IMMUTABLE, $for->isSpectator());
|
||||
$pk->setFlag(AdventureSettingsPacket::NO_PVP, $for->isSpectator());
|
||||
$pk->setFlag(AdventureSettingsPacket::AUTO_JUMP, $for->hasAutoJump());
|
||||
$pk->setFlag(AdventureSettingsPacket::ALLOW_FLIGHT, $for->getAllowFlight());
|
||||
$pk->setFlag(AdventureSettingsPacket::NO_CLIP, !$for->hasBlockCollision());
|
||||
$pk->setFlag(AdventureSettingsPacket::FLYING, $for->isFlying());
|
||||
|
||||
//TODO: permission flags
|
||||
|
||||
$this->sendDataPacket($pk);
|
||||
public function syncAdventureSettings() : void{
|
||||
if($this->player === null){
|
||||
throw new \LogicException("Cannot sync adventure settings for a player that is not yet created");
|
||||
}
|
||||
//everything except auto jump is handled via UpdateAbilitiesPacket
|
||||
$this->sendDataPacket(UpdateAdventureSettingsPacket::create(
|
||||
noAttackingMobs: false,
|
||||
noAttackingPlayers: false,
|
||||
worldImmutable: false,
|
||||
showNameTags: true,
|
||||
autoJump: $this->player->hasAutoJump()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -805,7 +856,7 @@ class NetworkSession{
|
||||
public function syncAttributes(Living $entity, array $attributes) : void{
|
||||
if(count($attributes) > 0){
|
||||
$this->sendDataPacket(UpdateAttributesPacket::create($entity->getId(), array_map(function(Attribute $attr) : NetworkAttribute{
|
||||
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue());
|
||||
return new NetworkAttribute($attr->getId(), $attr->getMinValue(), $attr->getMaxValue(), $attr->getValue(), $attr->getDefaultValue(), []);
|
||||
}, $attributes), 0));
|
||||
}
|
||||
}
|
||||
|
2
src/network/mcpe/cache/ChunkCache.php
vendored
2
src/network/mcpe/cache/ChunkCache.php
vendored
@ -43,8 +43,6 @@ class ChunkCache implements ChunkListener{
|
||||
|
||||
/**
|
||||
* Fetches the ChunkCache instance for the given world. This lazily creates cache systems as needed.
|
||||
*
|
||||
* @return ChunkCache
|
||||
*/
|
||||
public static function getInstance(World $world, Compressor $compressor) : self{
|
||||
$worldId = spl_object_id($world);
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
@ -37,6 +38,7 @@ use pocketmine\item\Durable;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemFactory;
|
||||
use pocketmine\item\ItemIds;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\nbt\NbtException;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
@ -46,7 +48,9 @@ use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\NetworkInventoryAction;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\UIInventorySlotOffset;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\IntIdMetaItemDescriptor;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\RecipeIngredient;
|
||||
use pocketmine\network\mcpe\protocol\types\recipe\StringIdMetaItemDescriptor;
|
||||
use pocketmine\player\GameMode;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
@ -113,7 +117,7 @@ class TypeConverter{
|
||||
|
||||
public function coreItemStackToRecipeIngredient(Item $itemStack) : RecipeIngredient{
|
||||
if($itemStack->isNull()){
|
||||
return new RecipeIngredient(0, 0, 0);
|
||||
return new RecipeIngredient(null, 0);
|
||||
}
|
||||
if($itemStack->hasAnyDamageValue()){
|
||||
[$id, ] = ItemTranslator::getInstance()->toNetworkId($itemStack->getId(), 0);
|
||||
@ -121,16 +125,26 @@ class TypeConverter{
|
||||
}else{
|
||||
[$id, $meta] = ItemTranslator::getInstance()->toNetworkId($itemStack->getId(), $itemStack->getMeta());
|
||||
}
|
||||
return new RecipeIngredient($id, $meta, $itemStack->getCount());
|
||||
return new RecipeIngredient(new IntIdMetaItemDescriptor($id, $meta), $itemStack->getCount());
|
||||
}
|
||||
|
||||
public function recipeIngredientToCoreItemStack(RecipeIngredient $ingredient) : Item{
|
||||
if($ingredient->getId() === 0){
|
||||
return ItemFactory::getInstance()->get(ItemIds::AIR, 0, 0);
|
||||
$descriptor = $ingredient->getDescriptor();
|
||||
if($descriptor === null){
|
||||
return VanillaItems::AIR();
|
||||
}
|
||||
[$id, $meta] = ItemTranslator::getInstance()->fromNetworkIdWithWildcardHandling($ingredient->getId(), $ingredient->getMeta());
|
||||
if($descriptor instanceof IntIdMetaItemDescriptor){
|
||||
[$id, $meta] = ItemTranslator::getInstance()->fromNetworkIdWithWildcardHandling($descriptor->getId(), $descriptor->getMeta());
|
||||
return ItemFactory::getInstance()->get($id, $meta, $ingredient->getCount());
|
||||
}
|
||||
if($descriptor instanceof StringIdMetaItemDescriptor){
|
||||
$intId = GlobalItemTypeDictionary::getInstance()->getDictionary()->fromStringId($descriptor->getId());
|
||||
[$id, $meta] = ItemTranslator::getInstance()->fromNetworkIdWithWildcardHandling($intId, $descriptor->getMeta());
|
||||
return ItemFactory::getInstance()->get($id, $meta, $ingredient->getCount());
|
||||
}
|
||||
|
||||
throw new \LogicException("Unsupported conversion of recipe ingredient to core item stack");
|
||||
}
|
||||
|
||||
public function coreItemStackToNet(Item $itemStack) : ItemStack{
|
||||
if($itemStack->isNull()){
|
||||
@ -202,7 +216,7 @@ class TypeConverter{
|
||||
*/
|
||||
public function netItemStackToCore(ItemStack $itemStack) : Item{
|
||||
if($itemStack->getId() === 0){
|
||||
return ItemFactory::getInstance()->get(ItemIds::AIR, 0, 0);
|
||||
return VanillaItems::AIR();
|
||||
}
|
||||
$compound = $itemStack->getNbt();
|
||||
|
||||
@ -232,6 +246,9 @@ class TypeConverter{
|
||||
$compound = null;
|
||||
}
|
||||
}
|
||||
if($id < -0x8000 || $id >= 0x7fff){
|
||||
throw new TypeConversionException("Item ID must be in range " . -0x8000 . " ... " . 0x7fff . " (received $id)");
|
||||
}
|
||||
if($meta < 0 || $meta >= 0x7fff){ //this meta value may have been restored from the NBT
|
||||
throw new TypeConversionException("Item meta must be in range 0 ... " . 0x7fff . " (received $meta)");
|
||||
}
|
||||
|
@ -51,7 +51,6 @@ use pocketmine\network\mcpe\InventoryManager;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\ActorEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\ActorPickRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\AnimatePacket;
|
||||
use pocketmine\network\mcpe\protocol\BlockActorDataPacket;
|
||||
use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
|
||||
@ -80,6 +79,7 @@ use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerHotbarPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||
use pocketmine\network\mcpe\protocol\RequestAbilityPacket;
|
||||
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
|
||||
use pocketmine\network\mcpe\protocol\ServerSettingsRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\SetActorMotionPacket;
|
||||
@ -114,6 +114,7 @@ use function count;
|
||||
use function fmod;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_bool;
|
||||
use function is_infinite;
|
||||
use function is_nan;
|
||||
use function json_decode;
|
||||
@ -143,6 +144,11 @@ class InGamePacketHandler extends PacketHandler{
|
||||
/** @var UseItemTransactionData|null */
|
||||
protected $lastRightClickData = null;
|
||||
|
||||
protected ?Vector3 $lastPlayerAuthInputPosition = null;
|
||||
protected ?float $lastPlayerAuthInputYaw = null;
|
||||
protected ?float $lastPlayerAuthInputPitch = null;
|
||||
protected ?int $lastPlayerAuthInputFlags = null;
|
||||
|
||||
/** @var bool */
|
||||
public $forceMoveSync = false;
|
||||
|
||||
@ -166,9 +172,10 @@ class InGamePacketHandler extends PacketHandler{
|
||||
return true;
|
||||
}
|
||||
|
||||
private function resolveOnOffInputFlags(PlayerAuthInputPacket $packet, int $startFlag, int $stopFlag) : ?bool{
|
||||
$enabled = $packet->hasFlag($startFlag);
|
||||
if($enabled !== $packet->hasFlag($stopFlag)){
|
||||
private function resolveOnOffInputFlags(int $inputFlags, int $startFlag, int $stopFlag) : ?bool{
|
||||
$enabled = ($inputFlags & (1 << $startFlag)) !== 0;
|
||||
$disabled = ($inputFlags & (1 << $stopFlag)) !== 0;
|
||||
if($enabled !== $disabled){
|
||||
return $enabled;
|
||||
}
|
||||
//neither flag was set, or both were set
|
||||
@ -177,25 +184,35 @@ class InGamePacketHandler extends PacketHandler{
|
||||
|
||||
public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
|
||||
$rawPos = $packet->getPosition();
|
||||
foreach([$rawPos->x, $rawPos->y, $rawPos->z, $packet->getYaw(), $packet->getHeadYaw(), $packet->getPitch()] as $float){
|
||||
$rawYaw = $packet->getYaw();
|
||||
$rawPitch = $packet->getPitch();
|
||||
foreach([$rawPos->x, $rawPos->y, $rawPos->z, $rawYaw, $packet->getHeadYaw(), $rawPitch] as $float){
|
||||
if(is_infinite($float) || is_nan($float)){
|
||||
$this->session->getLogger()->debug("Invalid movement received, contains NAN/INF components");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$yaw = fmod($packet->getYaw(), 360);
|
||||
$pitch = fmod($packet->getPitch(), 360);
|
||||
if($rawYaw !== $this->lastPlayerAuthInputYaw || $rawPitch !== $this->lastPlayerAuthInputPitch){
|
||||
$this->lastPlayerAuthInputYaw = $rawYaw;
|
||||
$this->lastPlayerAuthInputPitch = $rawPitch;
|
||||
|
||||
$yaw = fmod($rawYaw, 360);
|
||||
$pitch = fmod($rawPitch, 360);
|
||||
if($yaw < 0){
|
||||
$yaw += 360;
|
||||
}
|
||||
|
||||
$this->player->setRotation($yaw, $pitch);
|
||||
}
|
||||
|
||||
$curPos = $this->player->getLocation();
|
||||
$hasMoved = $this->lastPlayerAuthInputPosition === null || !$this->lastPlayerAuthInputPosition->equals($rawPos);
|
||||
$newPos = $rawPos->round(4)->subtract(0, 1.62, 0);
|
||||
|
||||
if($this->forceMoveSync && $newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
|
||||
if($this->forceMoveSync && $hasMoved){
|
||||
$curPos = $this->player->getLocation();
|
||||
|
||||
if($newPos->distanceSquared($curPos) > 1){ //Tolerate up to 1 block to avoid problems with client-sided physics when spawning in blocks
|
||||
$this->session->getLogger()->debug("Got outdated pre-teleport movement, received " . $newPos . ", expected " . $curPos);
|
||||
//Still getting movements from before teleport, ignore them
|
||||
return false;
|
||||
@ -203,11 +220,16 @@ class InGamePacketHandler extends PacketHandler{
|
||||
|
||||
// Once we get a movement within a reasonable distance, treat it as a teleport ACK and remove position lock
|
||||
$this->forceMoveSync = false;
|
||||
}
|
||||
|
||||
$sneaking = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING);
|
||||
$sprinting = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING);
|
||||
$swimming = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING);
|
||||
$gliding = $this->resolveOnOffInputFlags($packet, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING);
|
||||
$inputFlags = $packet->getInputFlags();
|
||||
if($inputFlags !== $this->lastPlayerAuthInputFlags){
|
||||
$this->lastPlayerAuthInputFlags = $inputFlags;
|
||||
|
||||
$sneaking = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SNEAKING, PlayerAuthInputFlags::STOP_SNEAKING);
|
||||
$sprinting = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SPRINTING, PlayerAuthInputFlags::STOP_SPRINTING);
|
||||
$swimming = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_SWIMMING, PlayerAuthInputFlags::STOP_SWIMMING);
|
||||
$gliding = $this->resolveOnOffInputFlags($inputFlags, PlayerAuthInputFlags::START_GLIDING, PlayerAuthInputFlags::STOP_GLIDING);
|
||||
$mismatch =
|
||||
($sneaking !== null && !$this->player->toggleSneak($sneaking)) |
|
||||
($sprinting !== null && !$this->player->toggleSprint($sprinting)) |
|
||||
@ -220,8 +242,10 @@ class InGamePacketHandler extends PacketHandler{
|
||||
if($packet->hasFlag(PlayerAuthInputFlags::START_JUMPING)){
|
||||
$this->player->jump();
|
||||
}
|
||||
}
|
||||
|
||||
if(!$this->forceMoveSync){
|
||||
if(!$this->forceMoveSync && $hasMoved){
|
||||
$this->lastPlayerAuthInputPosition = $rawPos;
|
||||
//TODO: this packet has WAYYYYY more useful information that we're not using
|
||||
$this->player->handleMovement($newPos);
|
||||
}
|
||||
@ -267,7 +291,6 @@ class InGamePacketHandler extends PacketHandler{
|
||||
//TODO HACK: EATING_ITEM is sent back to the server when the server sends it for other players (1.14 bug, maybe earlier)
|
||||
return $packet->actorRuntimeId === ActorEvent::EATING_ITEM;
|
||||
}
|
||||
$this->player->removeCurrentWindow();
|
||||
|
||||
switch($packet->eventId){
|
||||
case ActorEvent::EATING_ITEM: //TODO: ignore this and handle it server-side
|
||||
@ -610,6 +633,10 @@ class InGamePacketHandler extends PacketHandler{
|
||||
case PlayerAction::CREATIVE_PLAYER_DESTROY_BLOCK:
|
||||
//TODO: do we need to handle this?
|
||||
break;
|
||||
case PlayerAction::START_ITEM_USE_ON:
|
||||
case PlayerAction::STOP_ITEM_USE_ON:
|
||||
//TODO: this has no obvious use and seems only used for analytics in vanilla - ignore it
|
||||
break;
|
||||
default:
|
||||
$this->session->getLogger()->debug("Unhandled/unknown player action type " . $action);
|
||||
return false;
|
||||
@ -641,26 +668,6 @@ class InGamePacketHandler extends PacketHandler{
|
||||
return true; //this is a broken useless packet, so we don't use it
|
||||
}
|
||||
|
||||
public function handleAdventureSettings(AdventureSettingsPacket $packet) : bool{
|
||||
if($packet->targetActorUniqueId !== $this->player->getId()){
|
||||
return false; //TODO: operators can change other people's permissions using this
|
||||
}
|
||||
|
||||
$handled = false;
|
||||
|
||||
$isFlying = $packet->getFlag(AdventureSettingsPacket::FLYING);
|
||||
if($isFlying !== $this->player->isFlying()){
|
||||
if(!$this->player->toggleFlight($isFlying)){
|
||||
$this->session->syncAdventureSettings($this->player);
|
||||
}
|
||||
$handled = true;
|
||||
}
|
||||
|
||||
//TODO: check for other changes
|
||||
|
||||
return $handled;
|
||||
}
|
||||
|
||||
public function handleBlockActorData(BlockActorDataPacket $packet) : bool{
|
||||
$pos = new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ());
|
||||
if($pos->distanceSquared($this->player->getLocation()) > 10000){
|
||||
@ -878,7 +885,14 @@ class InGamePacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
public function handleModalFormResponse(ModalFormResponsePacket $packet) : bool{
|
||||
if($packet->cancelReason !== null){
|
||||
//TODO: make APIs for this to allow plugins to use this information
|
||||
return $this->player->onFormSubmit($packet->formId, null);
|
||||
}elseif($packet->formData !== null){
|
||||
return $this->player->onFormSubmit($packet->formId, self::stupid_json_decode($packet->formData, true));
|
||||
}else{
|
||||
throw new PacketHandlingException("Expected either formData or cancelReason to be set in ModalFormResponsePacket");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -980,4 +994,22 @@ class InGamePacketHandler extends PacketHandler{
|
||||
$this->player->emote($packet->getEmoteId());
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequestAbility(RequestAbilityPacket $packet) : bool{
|
||||
if($packet->getAbilityId() === RequestAbilityPacket::ABILITY_FLYING){
|
||||
$isFlying = $packet->getAbilityValue();
|
||||
if(!is_bool($isFlying)){
|
||||
throw new PacketHandlingException("Flying ability should always have a bool value");
|
||||
}
|
||||
if($isFlying !== $this->player->isFlying()){
|
||||
if(!$this->player->toggleFlight($isFlying)){
|
||||
$this->session->syncAbilities($this->player);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -165,13 +165,13 @@ class LoginPacketHandler extends PacketHandler{
|
||||
if(!is_array($claims["extraData"])){
|
||||
throw new PacketHandlingException("'extraData' key should be an array");
|
||||
}
|
||||
$mapper = new \JsonMapper;
|
||||
$mapper = new \JsonMapper();
|
||||
$mapper->bEnforceMapType = false; //TODO: we don't really need this as an array, but right now we don't have enough models
|
||||
$mapper->bExceptionOnMissingData = true;
|
||||
$mapper->bExceptionOnUndefinedProperty = true;
|
||||
try{
|
||||
/** @var AuthenticationData $extraData */
|
||||
$extraData = $mapper->map($claims["extraData"], new AuthenticationData);
|
||||
$extraData = $mapper->map($claims["extraData"], new AuthenticationData());
|
||||
}catch(\JsonMapper_Exception $e){
|
||||
throw PacketHandlingException::wrap($e);
|
||||
}
|
||||
@ -193,12 +193,12 @@ class LoginPacketHandler extends PacketHandler{
|
||||
throw PacketHandlingException::wrap($e);
|
||||
}
|
||||
|
||||
$mapper = new \JsonMapper;
|
||||
$mapper = new \JsonMapper();
|
||||
$mapper->bEnforceMapType = false; //TODO: we don't really need this as an array, but right now we don't have enough models
|
||||
$mapper->bExceptionOnMissingData = true;
|
||||
$mapper->bExceptionOnUndefinedProperty = true;
|
||||
try{
|
||||
$clientData = $mapper->map($clientDataClaims, new ClientData);
|
||||
$clientData = $mapper->map($clientDataClaims, new ClientData());
|
||||
}catch(\JsonMapper_Exception $e){
|
||||
throw PacketHandlingException::wrap($e);
|
||||
}
|
||||
|
@ -23,16 +23,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\handler;
|
||||
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\cache\CraftingDataCache;
|
||||
use pocketmine\network\mcpe\cache\StaticPacketCache;
|
||||
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\network\mcpe\InventoryManager;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
|
||||
use pocketmine\network\mcpe\protocol\StartGamePacket;
|
||||
use pocketmine\network\mcpe\protocol\types\BlockPosition;
|
||||
use pocketmine\network\mcpe\protocol\types\BoolGameRule;
|
||||
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
||||
use pocketmine\network\mcpe\protocol\types\DimensionIds;
|
||||
use pocketmine\network\mcpe\protocol\types\Experiments;
|
||||
use pocketmine\network\mcpe\protocol\types\LevelSettings;
|
||||
@ -42,6 +45,7 @@ use pocketmine\network\mcpe\protocol\types\SpawnSettings;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\VersionInfo;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
@ -58,6 +62,7 @@ class PreSpawnPacketHandler extends PacketHandler{
|
||||
public function setUp() : void{
|
||||
$location = $this->player->getLocation();
|
||||
|
||||
$this->session->getLogger()->debug("Preparing StartGamePacket");
|
||||
$levelSettings = new LevelSettings();
|
||||
$levelSettings->seed = -1;
|
||||
$levelSettings->spawnSettings = new SpawnSettings(SpawnSettings::BIOME_TYPE_DEFAULT, "", DimensionIds::OVERWORLD); //TODO: implement this properly
|
||||
@ -82,6 +87,7 @@ class PreSpawnPacketHandler extends PacketHandler{
|
||||
$this->player->getOffsetPosition($location),
|
||||
$location->pitch,
|
||||
$location->yaw,
|
||||
new CacheableNbt(CompoundTag::create()), //TODO: we don't care about this right now
|
||||
$levelSettings,
|
||||
"",
|
||||
$this->server->getMotd(),
|
||||
@ -93,26 +99,48 @@ class PreSpawnPacketHandler extends PacketHandler{
|
||||
"",
|
||||
false,
|
||||
sprintf("%s %s", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(true)),
|
||||
Uuid::fromString(Uuid::NIL),
|
||||
false,
|
||||
[],
|
||||
0,
|
||||
GlobalItemTypeDictionary::getInstance()->getDictionary()->getEntries()
|
||||
GlobalItemTypeDictionary::getInstance()->getDictionary()->getEntries(),
|
||||
));
|
||||
|
||||
$this->session->getLogger()->debug("Sending actor identifiers");
|
||||
$this->session->sendDataPacket(StaticPacketCache::getInstance()->getAvailableActorIdentifiers());
|
||||
|
||||
$this->session->getLogger()->debug("Sending biome definitions");
|
||||
$this->session->sendDataPacket(StaticPacketCache::getInstance()->getBiomeDefs());
|
||||
|
||||
$this->session->getLogger()->debug("Sending attributes");
|
||||
$this->session->syncAttributes($this->player, $this->player->getAttributeMap()->getAll());
|
||||
|
||||
$this->session->getLogger()->debug("Sending available commands");
|
||||
$this->session->syncAvailableCommands();
|
||||
$this->session->syncAdventureSettings($this->player);
|
||||
|
||||
$this->session->getLogger()->debug("Sending abilities");
|
||||
$this->session->syncAbilities($this->player);
|
||||
$this->session->syncAdventureSettings();
|
||||
|
||||
$this->session->getLogger()->debug("Sending effects");
|
||||
foreach($this->player->getEffects()->all() as $effect){
|
||||
$this->session->onEntityEffectAdded($this->player, $effect, false);
|
||||
}
|
||||
|
||||
$this->session->getLogger()->debug("Sending actor metadata");
|
||||
$this->player->sendData([$this->player]);
|
||||
|
||||
$this->session->getLogger()->debug("Sending inventory");
|
||||
$this->inventoryManager->syncAll();
|
||||
$this->inventoryManager->syncCreative();
|
||||
$this->inventoryManager->syncSelectedHotbarSlot();
|
||||
|
||||
$this->session->getLogger()->debug("Sending creative inventory data");
|
||||
$this->inventoryManager->syncCreative();
|
||||
|
||||
$this->session->getLogger()->debug("Sending crafting data");
|
||||
$this->session->sendDataPacket(CraftingDataCache::getInstance()->getCache($this->server->getCraftingManager()));
|
||||
|
||||
$this->session->getLogger()->debug("Sending player list");
|
||||
$this->session->syncPlayerList($this->server->getOnlinePlayers());
|
||||
}
|
||||
|
||||
@ -121,4 +149,10 @@ class PreSpawnPacketHandler extends PacketHandler{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{
|
||||
//the client will send this every tick once we start sending chunks, but we don't handle it in this stage
|
||||
//this is very spammy so we filter it out
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
76
src/network/mcpe/handler/SessionStartPacketHandler.php
Normal file
76
src/network/mcpe/handler/SessionStartPacketHandler.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\handler;
|
||||
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\protocol\NetworkSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayStatusPacket;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\network\mcpe\protocol\RequestNetworkSettingsPacket;
|
||||
use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm;
|
||||
use pocketmine\Server;
|
||||
|
||||
final class SessionStartPacketHandler extends PacketHandler{
|
||||
|
||||
/**
|
||||
* @phpstan-param \Closure() : void $onSuccess
|
||||
*/
|
||||
public function __construct(
|
||||
private Server $server,
|
||||
private NetworkSession $session,
|
||||
private \Closure $onSuccess
|
||||
){}
|
||||
|
||||
public function handleRequestNetworkSettings(RequestNetworkSettingsPacket $packet) : bool{
|
||||
$protocolVersion = $packet->getProtocolVersion();
|
||||
if(!$this->isCompatibleProtocol($protocolVersion)){
|
||||
$this->session->sendDataPacket(PlayStatusPacket::create($protocolVersion < ProtocolInfo::CURRENT_PROTOCOL ? PlayStatusPacket::LOGIN_FAILED_CLIENT : PlayStatusPacket::LOGIN_FAILED_SERVER), true);
|
||||
|
||||
//This pocketmine disconnect message will only be seen by the console (PlayStatusPacket causes the messages to be shown for the client)
|
||||
$this->session->disconnect(
|
||||
$this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_disconnect_incompatibleProtocol((string) $protocolVersion)),
|
||||
false
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO: we're filling in the defaults to get pre-1.19.30 behaviour back for now, but we should explore the new options in the future
|
||||
$this->session->sendDataPacket(NetworkSettingsPacket::create(
|
||||
NetworkSettingsPacket::COMPRESS_EVERYTHING,
|
||||
CompressionAlgorithm::ZLIB,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
));
|
||||
($this->onSuccess)();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isCompatibleProtocol(int $protocolVersion) : bool{
|
||||
return $protocolVersion === ProtocolInfo::CURRENT_PROTOCOL;
|
||||
}
|
||||
}
|
@ -1,16 +1,22 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* RakLib network library
|
||||
*
|
||||
*
|
||||
* This project is not affiliated with Jenkins Software LLC nor RakNet.
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* 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);
|
||||
|
@ -58,7 +58,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
* Sometimes this gets changed when the MCPE-layer protocol gets broken to the point where old and new can't
|
||||
* communicate. It's important that we check this to avoid catastrophes.
|
||||
*/
|
||||
private const MCPE_RAKNET_PROTOCOL_VERSION = 10;
|
||||
private const MCPE_RAKNET_PROTOCOL_VERSION = 11;
|
||||
|
||||
private const MCPE_RAKNET_PACKET_ID = "\xfe";
|
||||
|
||||
@ -84,8 +84,8 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
|
||||
$this->sleeper = new SleeperNotifier();
|
||||
|
||||
$mainToThreadBuffer = new \Threaded;
|
||||
$threadToMainBuffer = new \Threaded;
|
||||
$mainToThreadBuffer = new \Threaded();
|
||||
$threadToMainBuffer = new \Threaded();
|
||||
|
||||
$this->rakLib = new RakLibServer(
|
||||
$this->server->getLogger(),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user