mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 19:24:12 +00:00
Compare commits
185 Commits
Author | SHA1 | Date | |
---|---|---|---|
d273ccf87c | |||
737f5066a0 | |||
10238d7934 | |||
6077748caa | |||
50e2c469a5 | |||
fa87602661 | |||
d3c9c137ad | |||
37322e0d50 | |||
55cf24aa02 | |||
3590d84d03 | |||
68f8fa8caf | |||
1ad190024a | |||
769a149057 | |||
ea339355bb | |||
b9288c238b | |||
16f29c775e | |||
e30e27dd57 | |||
cd6634d34b | |||
f013079ff6 | |||
c4abac4606 | |||
11fbc8db6f | |||
022362a01a | |||
98380e46bf | |||
dad9a7e6cd | |||
de6a91dabc | |||
0615afa766 | |||
d5919dc094 | |||
09904dc519 | |||
f799cfaba6 | |||
11f119551d | |||
2584314202 | |||
337e462c8f | |||
b680a1693c | |||
0e5395c59b | |||
94e0bf954b | |||
556b00d11f | |||
981f49ff56 | |||
f527a4c8fe | |||
7148c7a222 | |||
e31fd122d9 | |||
a835069564 | |||
b77193b987 | |||
11ca208d93 | |||
8d7f1a8557 | |||
7ff0ae19d6 | |||
1de66cb0de | |||
9f3533d870 | |||
2d24fac067 | |||
f193a990b0 | |||
c11c0679e3 | |||
ba48f258f3 | |||
e105c9bd76 | |||
23f4632409 | |||
264ce06cbf | |||
a6202d0442 | |||
8ec304e66e | |||
cbffbd23f9 | |||
9d7aec5891 | |||
ac8dbf8640 | |||
dbc7105e5b | |||
3b97d067a3 | |||
b0390a39fd | |||
5cb69e00d0 | |||
781e3643dd | |||
2ca50ecd36 | |||
5ad63f27bb | |||
f13eaaab05 | |||
72f3c0b4b9 | |||
b9a1ef1357 | |||
4abc36275c | |||
4b5ac53276 | |||
90409b50d1 | |||
bc2abf4b15 | |||
b2c97cf2f1 | |||
a35c3406a8 | |||
54ea404d80 | |||
98042f844f | |||
a0cca53f52 | |||
6872118355 | |||
efd113bdc8 | |||
34a5f91aa9 | |||
aee3656415 | |||
c58e599eb2 | |||
47f0119660 | |||
561ffd3da3 | |||
b744e09352 | |||
7b89dda420 | |||
db665fefdb | |||
6872661fd0 | |||
920341668f | |||
4fab518384 | |||
e06b042cd0 | |||
44ce9ca610 | |||
2616d8c5ad | |||
61d0181bfd | |||
db894e3a4a | |||
53cbc44d70 | |||
be102dc95f | |||
d211392b67 | |||
eaab1a8784 | |||
169d3e0de8 | |||
ce8fecc6ec | |||
4fcb644c51 | |||
826cbea0bc | |||
fe06bfcda0 | |||
f54ed8362d | |||
8c7a4d720a | |||
6492e7f4a2 | |||
6bb84bc46c | |||
20837c9894 | |||
f207d1bbf2 | |||
5709d727a2 | |||
234199d241 | |||
e28d20a68e | |||
81d5b9ba06 | |||
d97c8e2fd2 | |||
c7c20d4d79 | |||
c6a09e5ed8 | |||
e77cd39316 | |||
a459e3c1a9 | |||
288bd4018b | |||
9b03b082ab | |||
db3bb55a2b | |||
8372c9efc2 | |||
4db38ee452 | |||
ee977c8001 | |||
5b5c73f660 | |||
f83280ece6 | |||
19556634e3 | |||
5718a1a20e | |||
5386e86079 | |||
1b0ef468f3 | |||
b69843a8bd | |||
03619ebca9 | |||
fd1bc1b845 | |||
c05116849a | |||
7a55a6e6b6 | |||
bf99917f2a | |||
57f3a04bc5 | |||
c51b1b2812 | |||
80125f9b19 | |||
8dc28b7ea8 | |||
58ce746ae1 | |||
74cb0be868 | |||
4d9b97d2bb | |||
90af8cfd69 | |||
c8da9dea95 | |||
e1f4fd3048 | |||
d3d7f24015 | |||
944dd7d3e4 | |||
a03013d582 | |||
053abfbb6f | |||
00a8ea267c | |||
daeba95101 | |||
a750af72db | |||
61decaa2f8 | |||
06b2e61d3c | |||
b4838f5b4e | |||
b2df405cc0 | |||
d596dc571d | |||
a1748a92ca | |||
fbcf4649eb | |||
0f620fad94 | |||
bc07778434 | |||
519784460f | |||
e9c5846a06 | |||
69f197dbec | |||
13f34a500c | |||
e5c96faa4b | |||
dd98e4aaed | |||
e525699dd4 | |||
923c922960 | |||
58ea94bab8 | |||
22b10e4cb0 | |||
7a4cf8ef68 | |||
269b3d89a2 | |||
b3766834c6 | |||
50592dc269 | |||
4103631bc1 | |||
d09af2e30d | |||
bbe66e8e09 | |||
457660235e | |||
d3b7861d1a | |||
a6b36d6c3c | |||
109673382d |
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -34,7 +34,10 @@ Requires translations:
|
||||
|
||||
## Tests
|
||||
<!--
|
||||
Details should be provided of tests done. Simply saying "tested" or equivalent is not acceptable.
|
||||
|
||||
Attach scripts or actions to test this pull request, as well as the result
|
||||
PRs which have not been tested MUST be marked as draft.
|
||||
-->
|
||||
I tested this PR by doing the following (tick all that apply):
|
||||
- [ ] Writing PHPUnit tests (commit these in the `tests/phpunit` folder)
|
||||
- [ ] Playtesting using a Minecraft client (provide screenshots or a video)
|
||||
- [ ] Writing a test plugin (provide the code and sample output)
|
||||
- [ ] Other (provide details)
|
||||
|
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@ -3,7 +3,7 @@ updates:
|
||||
- package-ecosystem: composer
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
interval: weekly
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
@ -21,4 +21,4 @@ updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
interval: weekly
|
||||
|
8
.github/workflows/build-docker-image.yml
vendored
8
.github/workflows/build-docker-image.yml
vendored
@ -53,7 +53,7 @@ jobs:
|
||||
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v5.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v5.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v5.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
uses: docker/build-push-action@v5.3.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
6
.github/workflows/discord-release-notify.yml
vendored
6
.github/workflows/discord-release-notify.yml
vendored
@ -13,12 +13,12 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.28.0
|
||||
uses: shivammathur/setup-php@2.30.2
|
||||
with:
|
||||
php-version: 8.1
|
||||
php-version: 8.2
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
|
10
.github/workflows/draft-release.yml
vendored
10
.github/workflows/draft-release.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-version: [8.1]
|
||||
php-version: [8.2]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -20,12 +20,12 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.28.0
|
||||
uses: shivammathur/setup-php@2.30.2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
@ -77,7 +77,7 @@ jobs:
|
||||
> build_info.json
|
||||
|
||||
- name: Upload release artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release_artifacts
|
||||
path: |
|
||||
@ -86,7 +86,7 @@ jobs:
|
||||
${{ github.workspace }}/build_info.json
|
||||
|
||||
- name: Create draft release
|
||||
uses: ncipollo/release-action@v1.13.0
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
|
||||
commit: ${{ github.sha }}
|
||||
|
156
.github/workflows/main-php-matrix.yml
vendored
Normal file
156
.github/workflows/main-php-matrix.yml
vendored
Normal file
@ -0,0 +1,156 @@
|
||||
name: CI (all supported PHP versions)
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
php:
|
||||
description: 'PHP version in X.Y format'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
#these are parameterized to ease updating
|
||||
pm-version-major:
|
||||
description: 'PocketMine-MP major version'
|
||||
default: 5
|
||||
type: number
|
||||
image:
|
||||
description: 'Runner image to use'
|
||||
default: 'ubuntu-20.04'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
phpstan:
|
||||
name: PHPStan analysis
|
||||
runs-on: ${{ inputs.image }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: ${{ inputs.pm-version-major }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPStan
|
||||
run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
|
||||
|
||||
phpunit:
|
||||
name: PHPUnit tests
|
||||
runs-on: ${{ inputs.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: ${{ inputs.pm-version-major }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPUnit tests
|
||||
run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
|
||||
|
||||
integration:
|
||||
name: Integration tests
|
||||
runs-on: ${{ inputs.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: ${{ inputs.pm-version-major }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Run integration tests
|
||||
run: ./tests/travis.sh -t4
|
||||
|
||||
codegen:
|
||||
name: Generated Code consistency checks
|
||||
runs-on: ${{ inputs.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: ${{ inputs.pm-version-major }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ inputs.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Update generated code
|
||||
run: composer update-codegen
|
||||
|
||||
- name: Verify code is unchanged
|
||||
run: |
|
||||
git diff
|
||||
git diff --quiet
|
163
.github/workflows/main.yml
vendored
163
.github/workflows/main.yml
vendored
@ -6,162 +6,17 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
phpstan:
|
||||
name: PHPStan analysis
|
||||
runs-on: ${{ matrix.image }}
|
||||
|
||||
all-php-versions:
|
||||
name: PHP ${{ matrix.php }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: ["8.1", "8.2", "8.3"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPStan
|
||||
run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
|
||||
|
||||
phpunit:
|
||||
name: PHPUnit tests
|
||||
runs-on: ${{ matrix.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: ["8.1", "8.2", "8.3"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --prefer-dist --no-interaction
|
||||
|
||||
- name: Run PHPUnit tests
|
||||
run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
|
||||
|
||||
integration:
|
||||
name: Integration tests
|
||||
runs-on: ${{ matrix.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: ["8.1", "8.2", "8.3"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Run integration tests
|
||||
run: ./tests/travis.sh -t4
|
||||
|
||||
codegen:
|
||||
name: Generated Code consistency checks
|
||||
runs-on: ${{ matrix.image }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: ["8.1", "8.2", "8.3"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@2.0.0
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
install-path: "./bin"
|
||||
pm-version-major: "5"
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ matrix.php }}-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction
|
||||
|
||||
- name: Regenerate registry annotations
|
||||
run: php build/generate-registry-annotations.php src
|
||||
|
||||
- name: Regenerate KnownTranslation APIs
|
||||
run: php build/generate-known-translation-apis.php
|
||||
|
||||
- name: Regenerate BedrockData available files constants
|
||||
run: php build/generate-bedrockdata-path-consts.php
|
||||
|
||||
- name: Regenerate YmlServerProperties constants
|
||||
run: php build/generate-pocketmine-yml-property-consts.php
|
||||
|
||||
- name: Verify code is unchanged
|
||||
run: |
|
||||
git diff
|
||||
git diff --quiet
|
||||
uses: ./.github/workflows/main-php-matrix.yml
|
||||
with:
|
||||
php: ${{ matrix.php }}
|
||||
secrets: inherit
|
||||
|
||||
codestyle:
|
||||
name: Code Style checks
|
||||
@ -173,10 +28,10 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.28.0
|
||||
uses: shivammathur/setup-php@2.30.2
|
||||
with:
|
||||
php-version: 8.1
|
||||
tools: php-cs-fixer:3.17
|
||||
php-version: 8.2
|
||||
tools: php-cs-fixer:3.49
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
## Pre-requisites
|
||||
- A bash shell (git bash is sufficient for Windows)
|
||||
- [`git`](https://git-scm.com) available in your shell
|
||||
- PHP 8.1 or newer available in your shell
|
||||
- PHP 8.2 or newer available in your shell
|
||||
- [`composer`](https://getcomposer.org) available in your shell
|
||||
|
||||
## Custom PHP binaries
|
||||
|
133
build/generate-biome-ids.php
Normal file
133
build/generate-biome-ids.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\generate_biome_ids;
|
||||
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use function asort;
|
||||
use function dirname;
|
||||
use function fclose;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function is_array;
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
use function json_decode;
|
||||
use function str_replace;
|
||||
use function strtoupper;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
const HEADER = <<<'HEADER'
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
HEADER;
|
||||
|
||||
/** @return resource */
|
||||
function safe_fopen(string $file, string $flags){
|
||||
$result = fopen($file, $flags);
|
||||
if($result === false){
|
||||
throw new \RuntimeException("Failed to open file");
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function make_const_name(string $name) : string{
|
||||
return strtoupper(str_replace(['.', 'minecraft:'], ['_', ''], $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $map
|
||||
* @phpstan-param array<string, int> $map
|
||||
*/
|
||||
function generate(array $map, string $outputFile) : void{
|
||||
$file = safe_fopen($outputFile, 'wb');
|
||||
fwrite($file, HEADER);
|
||||
fwrite($file, <<<'CLASSHEADER'
|
||||
namespace pocketmine\data\bedrock;
|
||||
|
||||
final class BiomeIds{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
|
||||
CLASSHEADER
|
||||
);
|
||||
$list = $map;
|
||||
asort($list, SORT_NUMERIC);
|
||||
$lastId = -1;
|
||||
foreach(Utils::stringifyKeys($list) as $name => $id){
|
||||
if($name === ""){
|
||||
continue;
|
||||
}
|
||||
if($id !== $lastId + 1){
|
||||
fwrite($file, "\n");
|
||||
}
|
||||
$lastId = $id;
|
||||
fwrite($file, "\tpublic const " . make_const_name($name) . ' = ' . $id . ';' . "\n");
|
||||
}
|
||||
fwrite($file, "}\n");
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
$ids = json_decode(Filesystem::fileGetContents(BedrockDataFiles::BIOME_ID_MAP_JSON), true);
|
||||
if(!is_array($ids)){
|
||||
throw new \RuntimeException("Invalid biome ID map, expected array for root JSON object");
|
||||
}
|
||||
$cleanedIds = [];
|
||||
foreach($ids as $name => $id){
|
||||
if(!is_string($name) || !is_int($id)){
|
||||
throw new \RuntimeException("Invalid biome ID map, expected string => int map");
|
||||
}
|
||||
$cleanedIds[$name] = $id;
|
||||
}
|
||||
generate($cleanedIds, dirname(__DIR__) . '/src/data/bedrock/BiomeIds.php');
|
||||
|
||||
echo "Done. Don't forget to run CS fixup after generating code.\n";
|
@ -102,6 +102,25 @@ function generateClassHeader(string $className) : string{
|
||||
return <<<HEADER
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace $namespace;
|
||||
|
@ -21,6 +21,9 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\VersionInfo;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if(count($argv) !== 7){
|
||||
@ -30,12 +33,12 @@ if(count($argv) !== 7){
|
||||
|
||||
echo json_encode([
|
||||
"php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION), //deprecated
|
||||
"base_version" => \pocketmine\VersionInfo::BASE_VERSION,
|
||||
"base_version" => VersionInfo::BASE_VERSION,
|
||||
"build" => (int) $argv[4],
|
||||
"is_dev" => \pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD,
|
||||
"channel" => \pocketmine\VersionInfo::BUILD_CHANNEL,
|
||||
"is_dev" => VersionInfo::IS_DEVELOPMENT_BUILD,
|
||||
"channel" => VersionInfo::BUILD_CHANNEL,
|
||||
"git_commit" => $argv[1],
|
||||
"mcpe_version" => \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK,
|
||||
"mcpe_version" => ProtocolInfo::MINECRAFT_VERSION_NETWORK,
|
||||
"date" => time(), //TODO: maybe we should embed this in VersionInfo?
|
||||
"details_url" => "https://github.com/$argv[3]/releases/tag/$argv[2]",
|
||||
"download_url" => "https://github.com/$argv[3]/releases/download/$argv[2]/PocketMine-MP.phar",
|
||||
|
@ -61,6 +61,25 @@ function generateItemIds(ItemTypeDictionary $dictionary, BlockItemIdMap $blockIt
|
||||
fwrite($file, <<<'HEADER'
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\bedrock\item;
|
||||
|
Submodule build/php updated: b0ffbdbe33...084822aa9e
168
build/server-phar-stub.php
Normal file
168
build/server-phar-stub.php
Normal file
@ -0,0 +1,168 @@
|
||||
<?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\server_phar_stub;
|
||||
|
||||
use function clearstatcache;
|
||||
use function copy;
|
||||
use function fclose;
|
||||
use function fflush;
|
||||
use function flock;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function getmypid;
|
||||
use function hrtime;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function mkdir;
|
||||
use function number_format;
|
||||
use function str_replace;
|
||||
use function stream_get_contents;
|
||||
use function sys_get_temp_dir;
|
||||
use function tempnam;
|
||||
use function unlink;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const LOCK_EX;
|
||||
use const LOCK_NB;
|
||||
use const LOCK_UN;
|
||||
|
||||
/**
|
||||
* Finds the appropriate tmp directory to store the decompressed phar cache, accounting for potential file name
|
||||
* collisions.
|
||||
*/
|
||||
function preparePharCacheDirectory() : string{
|
||||
clearstatcache();
|
||||
|
||||
$i = 0;
|
||||
do{
|
||||
$tmpPath = sys_get_temp_dir() . '/PocketMine-MP-phar-cache.' . $i;
|
||||
$i++;
|
||||
}while(is_file($tmpPath));
|
||||
if(!@mkdir($tmpPath) && !is_dir($tmpPath)){
|
||||
throw new \RuntimeException("Failed to create temporary directory $tmpPath. Please ensure the disk has enough space and that the current user has permission to write to this location.");
|
||||
}
|
||||
|
||||
return $tmpPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes caches left behind by previous server instances.
|
||||
* This ensures that the tmp directory doesn't get flooded by servers crashing in restart loops.
|
||||
*/
|
||||
function cleanupPharCache(string $tmpPath) : void{
|
||||
clearstatcache();
|
||||
|
||||
/** @var string[] $matches */
|
||||
foreach(new \RegexIterator(
|
||||
new \FilesystemIterator(
|
||||
$tmpPath,
|
||||
\FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::UNIX_PATHS
|
||||
),
|
||||
'/(.+)\.lock$/',
|
||||
\RegexIterator::GET_MATCH
|
||||
) as $matches){
|
||||
$lockFilePath = $matches[0];
|
||||
$baseTmpPath = $matches[1];
|
||||
|
||||
$file = @fopen($lockFilePath, "rb");
|
||||
if($file === false){
|
||||
//another process probably deleted the lock file already
|
||||
continue;
|
||||
}
|
||||
|
||||
if(flock($file, LOCK_EX | LOCK_NB)){
|
||||
//this tmpfile is no longer in use
|
||||
flock($file, LOCK_UN);
|
||||
fclose($file);
|
||||
|
||||
unlink($lockFilePath);
|
||||
unlink($baseTmpPath . ".tar");
|
||||
unlink($baseTmpPath);
|
||||
echo "Deleted stale phar cache at $baseTmpPath\n";
|
||||
}else{
|
||||
$pid = stream_get_contents($file);
|
||||
fclose($file);
|
||||
|
||||
echo "Phar cache at $baseTmpPath is still in use by PID $pid\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convertPharToTar(string $tmpName, string $pharPath) : string{
|
||||
$tmpPharPath = $tmpName . ".phar";
|
||||
copy($pharPath, $tmpPharPath);
|
||||
|
||||
$phar = new \Phar($tmpPharPath);
|
||||
//phar requires phar.readonly=0, and zip doesn't support disabling compression - tar is the only viable option
|
||||
//we don't need phar anyway since we don't need to directly execute the file, only require files from inside it
|
||||
$phar->convertToData(\Phar::TAR, \Phar::NONE);
|
||||
unset($phar);
|
||||
\Phar::unlinkArchive($tmpPharPath);
|
||||
|
||||
return $tmpName . ".tar";
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a phar tmp cache to prevent it from being deleted by other server instances.
|
||||
* This code looks similar to Filesystem::createLockFile(), but we can't use that because it's inside the compressed
|
||||
* phar.
|
||||
*/
|
||||
function lockPharCache(string $lockFilePath) : void{
|
||||
//this static variable will keep the file(s) locked until the process ends
|
||||
static $lockFiles = [];
|
||||
|
||||
$lockFile = fopen($lockFilePath, "wb");
|
||||
if($lockFile === false){
|
||||
throw new \RuntimeException("Failed to open temporary file");
|
||||
}
|
||||
flock($lockFile, LOCK_EX); //this tells other server instances not to delete this cache file
|
||||
fwrite($lockFile, (string) getmypid()); //maybe useful for debugging
|
||||
fflush($lockFile);
|
||||
$lockFiles[$lockFilePath] = $lockFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a decompressed .tar of PocketMine-MP.phar in the system temp directory for loading code from.
|
||||
*
|
||||
* @return string path to the temporary decompressed phar (actually a .tar)
|
||||
*/
|
||||
function preparePharCache(string $tmpPath, string $pharPath) : string{
|
||||
clearstatcache();
|
||||
|
||||
$tmpName = tempnam($tmpPath, "PMMP");
|
||||
if($tmpName === false){
|
||||
throw new \RuntimeException("Failed to create temporary file");
|
||||
}
|
||||
|
||||
lockPharCache($tmpName . ".lock");
|
||||
return convertPharToTar($tmpName, $pharPath);
|
||||
}
|
||||
|
||||
$tmpDir = preparePharCacheDirectory();
|
||||
cleanupPharCache($tmpDir);
|
||||
echo "Preparing PocketMine-MP.phar decompressed cache...\n";
|
||||
$start = hrtime(true);
|
||||
$cacheName = preparePharCache($tmpDir, __FILE__);
|
||||
echo "Cache ready at $cacheName in " . number_format((hrtime(true) - $start) / 1e9, 2) . "s\n";
|
||||
|
||||
require 'phar://' . str_replace(DIRECTORY_SEPARATOR, '/', $cacheName) . '/src/PocketMine.php';
|
@ -23,7 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\server_phar;
|
||||
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Git;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function array_map;
|
||||
use function count;
|
||||
use function dirname;
|
||||
@ -32,6 +34,7 @@ use function getcwd;
|
||||
use function getopt;
|
||||
use function implode;
|
||||
use function ini_get;
|
||||
use function is_string;
|
||||
use function microtime;
|
||||
use function preg_quote;
|
||||
use function realpath;
|
||||
@ -147,8 +150,17 @@ function main() : void{
|
||||
}else{
|
||||
$build = 0;
|
||||
}
|
||||
if(isset($opts["out"])){
|
||||
if(!is_string($opts["out"])){
|
||||
echo "--out cannot be specified multiple times" . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
$pharPath = $opts["out"];
|
||||
}else{
|
||||
$pharPath = getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar";
|
||||
}
|
||||
foreach(buildPhar(
|
||||
$opts["out"] ?? getcwd() . DIRECTORY_SEPARATOR . "PocketMine-MP.phar",
|
||||
$pharPath,
|
||||
dirname(__DIR__) . DIRECTORY_SEPARATOR,
|
||||
[
|
||||
'resources',
|
||||
@ -159,21 +171,7 @@ function main() : void{
|
||||
'git' => $gitHash,
|
||||
'build' => $build
|
||||
],
|
||||
<<<'STUB'
|
||||
<?php
|
||||
|
||||
$tmpDir = sys_get_temp_dir();
|
||||
if(!is_readable($tmpDir) or !is_writable($tmpDir)){
|
||||
echo "ERROR: tmpdir $tmpDir is not accessible." . PHP_EOL;
|
||||
echo "Check that the directory exists, and that the current user has read/write permissions for it." . PHP_EOL;
|
||||
echo "Alternatively, set 'sys_temp_dir' to a different directory in your php.ini file." . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require("phar://" . __FILE__ . "/src/PocketMine.php");
|
||||
__HALT_COMPILER();
|
||||
STUB
|
||||
,
|
||||
Filesystem::fileGetContents(Path::join(__DIR__, 'server-phar-stub.php')) . "\n__HALT_COMPILER();",
|
||||
\Phar::SHA1,
|
||||
\Phar::GZ
|
||||
) as $line){
|
||||
|
46
changelogs/5.10.md
Normal file
46
changelogs/5.10.md
Normal file
@ -0,0 +1,46 @@
|
||||
# 5.10.0
|
||||
Released 14th December 2023.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.50**
|
||||
|
||||
This is a minor feature release, including new gameplay features and minor performance improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- PHP 8.2 is now used by default. PHP 8.1 is still supported, but will be removed in a future 5.x release.
|
||||
- Improved timings reports by removing `Breakdown` timings group. This group serves no purpose with tree timings and made for confusing reading.
|
||||
|
||||
## Performance
|
||||
- Improved performance of `Block::encodeFullState()` in most conditions. This in turn improves performance of `World::setBlock()` and `World::setBlockAt()`.
|
||||
- Improved network compression performance by avoiding unnecessary object allocations.
|
||||
- Timings now report time spent in individual `Snooze` handlers, making it easier to debug performance issues.
|
||||
|
||||
## Gameplay
|
||||
### Blocks
|
||||
- Implemented crop growth speed modifiers.
|
||||
- The following things now positively affect crop growth speed:
|
||||
- Being planted on or being adjacent to farmland (hydrated farmland offers a larger benefit than dry farmland)
|
||||
- Potential light level of at least 9
|
||||
- Being planted in rows with space between them (or a different type of crop)
|
||||
- The following things now negatively affect crop growth speed:
|
||||
- Improper arrangement (e.g. the same crop on all sides)
|
||||
- Insufficient light level (below 9)
|
||||
- Poorly arranged crops will grow slower in this version. Past versions behaved as if crops were always planted in ideal conditions.
|
||||
- Crops planted in ideal conditions will grow at the same speed as before.
|
||||
|
||||
### Items
|
||||
- Added the following new items:
|
||||
- All types of Smithing Template
|
||||
- Pitcher Pod is now correctly registered. In previous versions, it was mapped to the Pitcher Crop block, causing incorrect name display in commands.
|
||||
|
||||
## Internals
|
||||
- Cleaned up various getter usages where direct property access is possible.
|
||||
- Avoided unnecessary repeated getter calls in some loops.
|
||||
- `NetworkSession` may now track `string` instead of `CompressBatchPromise` when a batch was synchronously compressed. This significantly reduces object allocations and improves performance.
|
||||
- `NetworkSession` now sends less information to clients on login validation failure. This avoids leaking potentially sensitive error information to clients.
|
||||
- Clients can correlate their disconnects with server-side logs using the `Error ID` shown on the disconnect screen.
|
45
changelogs/5.11.md
Normal file
45
changelogs/5.11.md
Normal file
@ -0,0 +1,45 @@
|
||||
# 5.11.0
|
||||
Released 7th February 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.60**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.60.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.60.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed `tools/generate-item-upgrade-schema.php` not correctly handling items whose IDs were changed multiple times.
|
||||
- Fixed `ServerKiller` not working correctly in some cases (incorrectly handled wake-up conditions).
|
||||
- `ItemBlock`s of `Air` blocks are now always considered as "null" items regardless of count, and don't occupy inventory slots.
|
||||
|
||||
## Internals
|
||||
- Restructured GitHub Actions CI workflows to make them easier to maintain (no need to update PHP versions in multiple places anymore).
|
||||
- GitHub Actions CodeStyle workflow now uses php-cs-fixer 3.49.x.
|
||||
- Dependabot updates are now processed weekly instead of daily.
|
||||
|
||||
# 5.11.1
|
||||
Released 23rd February 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed subchunk count calculation in `ChunkSerializer` for non-overworld dimension (useful for dimension plugins).
|
||||
- Harden options used for processing JSON data, particularly on the network, to close security issues.
|
||||
|
||||
## Documentation
|
||||
- Fixed PHPStan signature for `Utils::cloneObjectArray()`.
|
||||
|
||||
## Internals
|
||||
- Updated GitHub Actions versions to get rid of deprecation warnings.
|
||||
|
||||
# 5.11.2
|
||||
Released 26th February 2024.
|
||||
|
||||
## Fixes
|
||||
- Added extra checks for `BookEditPacket` handling.
|
63
changelogs/5.12.md
Normal file
63
changelogs/5.12.md
Normal file
@ -0,0 +1,63 @@
|
||||
# 5.12.0
|
||||
Released 28th February 2024
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.60**
|
||||
|
||||
This is a minor feature release, with a few new features and improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added a `--version` command-line option to display the server version and exit.
|
||||
|
||||
## Tools
|
||||
- Added `tools/generate-biome-ids.php` to generate `pocketmine\data\bedrock\BiomeIds`.
|
||||
- Fixed ordering of property values generated by `tools/generate-block-palette-spec.php`.
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new classes have been added:
|
||||
- `utils\LightableTrait` - used by blocks with `getLit()` and `setLit()` methods
|
||||
- The following methods have been deprecated:
|
||||
- `Block->isSolid()` - this method returns confusing results which don't match expectations and no one really knows what it actually means
|
||||
- `CocoaBlock` now extends `Flowable` to match vanilla Minecraft behaviour.
|
||||
|
||||
### `pocketmine\plugin`
|
||||
- `PluginManager->registerEvent()` now throws an exception when given a generator function for the event handler.
|
||||
- `PluginManager->registerEvents()` now throws an exception if any of the detected event handlers are generator functions. Use `@notHandler` to have the function ignored if intended.
|
||||
|
||||
### `pocketmine\promise`
|
||||
- The following methods have been added:
|
||||
- `public static Promise::all(list<Promise> $promises) : Promise` - returns a promise that is resolved once all given promises are resolved, or is rejected if any of the promises are rejected.
|
||||
|
||||
### `pocketmine\scheduler`
|
||||
- The following methods have been deprecated:
|
||||
- `AsyncWorker->getFromThreadStore()` - use class static properties for thread-local storage
|
||||
- `AsyncWorker->removeFromThreadStore()`
|
||||
- `AsyncWorker->saveToThreadStore()`
|
||||
|
||||
## Documentation
|
||||
- Improved documentation of various methods in `Block`.
|
||||
|
||||
## Gameplay
|
||||
- The following new items have been added:
|
||||
- Name Tag
|
||||
|
||||
## Internals
|
||||
- Removed specialization of shutdown logic for `Thread` vs `Worker` (no specialization is required).
|
||||
- Authentication system no longer accepts logins signed with the old Mojang root public key.
|
||||
- ID to enum mappings in `pocketmine\data` now use a new `match` convention to allow static analysis to ensure that all enum cases are handled.
|
||||
- Updated version of `pocketmine/bedrock-protocol` allows avoiding decoding of some itemstack data from the client in most cases, improving performance.
|
||||
|
||||
# 5.12.1
|
||||
Released 13th March 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed `Player Network Receive - Decompression` timings not being stopped correctly when receiving an uncompressed packet.
|
||||
|
||||
## Internals
|
||||
- Removed hardcoded batch packet size limit. This was already covered by other limits anyway.
|
16
changelogs/5.13.md
Normal file
16
changelogs/5.13.md
Normal file
@ -0,0 +1,16 @@
|
||||
# 5.13.0
|
||||
Released 13th March 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.70**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.70.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.70.
|
||||
- Removed support for earlier versions.
|
94
changelogs/5.14.md
Normal file
94
changelogs/5.14.md
Normal file
@ -0,0 +1,94 @@
|
||||
# 5.14.0
|
||||
Released 5th April 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.70**
|
||||
|
||||
This is a minor feature release, including performance improvements, minor gameplay features, new API features, and various internal improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for a `--no-log-file` command-line option, which disables the creation of a `server.log` file.
|
||||
- **Use this with caution.** If you don't have another mechanism for collecting logs (e.g. Docker), this may make debugging harder.
|
||||
- Added support for automatic `server.log` rotation. When the `server.log` exceeds 32 MB, it will be renamed and moved to the `log_archive` folder in the server's data directory.
|
||||
- Files in the `log_archive` folder can be safely modified or deleted without stopping the server.
|
||||
- We suggest a cron job or similar to manage old log files (e.g. deleting or compressing them).
|
||||
- Added a new cache mechanism for `PocketMine-MP.phar`. This has several advantages:
|
||||
- Caches are now reused by all threads - this significantly reduces `/tmp` usage (previously every thread generated its own cache, wasting lots of space)
|
||||
- Dead cache files are automatically cleaned up by new servers - this means that a server crash loop won't flood `/tmp` anymore
|
||||
- `/status` now reports a more accurate number of threads on Windows.
|
||||
- Large resource packs are now able to be properly downloaded from the server.
|
||||
- Larger player skin sizes are now accepted by the server.
|
||||
- Improved logging from world providers to reduce spam when chunks contain invalid data.
|
||||
- Added more error logging for Anvil, PMAnvil and MCRegion worlds.
|
||||
- PHP deprecation warnings no longer cause the server to crash. This should make it easier for server owners to update to newer PHP versions.
|
||||
|
||||
## Performance
|
||||
- Improved world loading performance. This was achieved through a combination of changes:
|
||||
- Improvements to `BlockStateUpgrader` to avoid unnecessary work
|
||||
- Improvements to `BlockStateUpgradeSchema` to clean up stupid code
|
||||
- Improvements to `BlockStateReader` unused state handling
|
||||
- Optimizations to `RegistryTrait` (see below)
|
||||
- Improved performance of `RegistryTrait::__callStatic()` accessor by introducing a fast-path optimization. Ensure that you access registries with the correct function name case to benefit from this.
|
||||
- This improves the performance of `VanillaBlocks::WHATEVER()`, `VanillaItems`, etc.
|
||||
|
||||
## Tools
|
||||
- `tools/generate-blockstate-upgrade-schema.php` now supports generating schemas using `flattenedValueRemaps` (described in [BlockStateUpgradeSchema](https://github.com/pmmp/BedrockBlockUpgradeSchema/releases/tag/4.0.0)).
|
||||
|
||||
## Gameplay
|
||||
- Added sounds for armour equipping and unequipping.
|
||||
- Added sound for picking berries from a sweet berry bush.
|
||||
|
||||
## API
|
||||
### `pocketmine\block\utils`
|
||||
- The following enum cases have been added:
|
||||
- `BannerPatternType::GLOBE`
|
||||
- `BannerPatternType::PIGLIN`
|
||||
|
||||
### `pocketmine\event\player`
|
||||
- The following classes have been added:
|
||||
- `PlayerResourcePackOfferEvent` - called before the server tells a connecting client which resource packs are available to download - allows customizing the pack list and other options
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following API methods have been added:
|
||||
- `public ArmorMaterial->getEquipSound() : ?\pocketmine\world\Sound` - returns the sound to play when this armour is equipped or unequipped
|
||||
- The following API methods have signature changes:
|
||||
- `ArmorMaterial->__construct()` now accepts an optional `?Sound $equipSound` parameter
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following API methods have signature changes:
|
||||
- `MainLogger->__construct()` now accepts `null` for the `$logFile` parameter - this disables the creation of a logger thread and log file
|
||||
- `MainLogger->__construct()` now accepts an optional `?string $logArchiveDir` parameter. If set, this enables log archiving in the specified directory when the current log file exceeds 32 MB.
|
||||
|
||||
## Dependencies
|
||||
- Now uses [`pocketmine/bedrock-block-upgrade-schema` version 4.0.0](https://github.com/pmmp/BedrockBlockUpgradeSchema/releases/tag/4.0.0).
|
||||
- Now uses [`pmmp/ext-pmmpthread` version 6.1.0](https://github.com/pmmp/ext-pmmpthread/releases/tag/6.1.0).
|
||||
- Now uses [`pocketmine/errorhandler` version 0.7.0](https://github.com/pmmp/ErrorHandler/releases/tag/0.7.0).
|
||||
- Now uses [`pocketmine/raklib` version 1.1.0](https://github.com/pmmp/RakLib/releases/tag/1.1.0).
|
||||
- Now uses [`pocketmine/raklib-ipc` version 1.0.0](https://github.com/pmmp/RakLibIpc/releases/tag/1.0.0).
|
||||
|
||||
## Internals
|
||||
- (Re)Added support for RakLib packet ACK receipts. This was used to throttle resource pack sending and prevent network overloading.
|
||||
- Added `NetworkSession->sendDataPacketWithReceipt()` to make use of this feature.
|
||||
- `PacketSender` now requires an additional `?int $receiptId` parameter.
|
||||
- `ResourcePackPacketHandler` now uses `sendDataPacketWithReceipt()` to send resource packs, and delays sending the next chunk until the current one is acknowledged.
|
||||
- `ResourcePackPacketHandler` now accepts resource pack info directly in the constructor, instead of `ResourcePackManager`. This eases the implementation of `PlayerResourcePackOfferEvent`.
|
||||
- Increased `ZlibCompressor::DEFAULT_MAX_DECOMPRESSION_SIZE` to 8 MB (previously 2 MB). While this weakens server security, it appears to be necessary to deal with extremely bloated Persona skins.
|
||||
- Increased max split packet parts accepted by `RakLib` to 512 (previously 128). Again, this is necessary to deal with extremely bloated Persona skins.
|
||||
- Added a new cache mechanism for `PocketMine-MP.phar`.
|
||||
- `ext-phar`'s default mechanism is extremely wasteful (generating a separate cache file per thread), and doesn't clean up after itself.
|
||||
- The new cache mechanism is shared between all threads, and automatically cleans up stale caches.
|
||||
- The phar stub (`build/server-phar-stub.php`) now converts the phar contents into a `.tar`, and decompresses all the files into `$TMPDIR/PocketMine-MP-phar-cache.<random>/`.
|
||||
- `phar://` URIs still work with this system, but `new Phar(__FILE__)` must be replaced by `new PharData(__FILE__)` within PocketMine-MP core code.
|
||||
- Backtraces from a `phar`'d server will now point to a location in the extracted phar cache, rather than the phar itself.
|
||||
- `block_factory_consistency_check` test (actually for `RuntimeBlockStateRegistry`) now stores less data, and is no longer affected by changes to internal state ID construction.
|
||||
|
||||
# 5.14.1
|
||||
Released 5th April 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed incorrect `pmmpthread` version check in server bootstrap.
|
16
changelogs/5.15.md
Normal file
16
changelogs/5.15.md
Normal file
@ -0,0 +1,16 @@
|
||||
# 5.15.0
|
||||
Released 25th April 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.20.80**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.20.80.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.20.80.
|
||||
- Removed support for earlier versions.
|
@ -22,7 +22,7 @@
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-phar": "*",
|
||||
"ext-pmmpthread": "^6.0.7",
|
||||
"ext-pmmpthread": "^6.1.0",
|
||||
"ext-reflection": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-sockets": "*",
|
||||
@ -32,27 +32,27 @@
|
||||
"ext-zlib": ">=1.2.11",
|
||||
"composer-runtime-api": "^2.0",
|
||||
"adhocore/json-comment": "~1.2.0",
|
||||
"pocketmine/netresearch-jsonmapper": "~v4.2.1000",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~3.4.0+bedrock-1.20.50",
|
||||
"pocketmine/bedrock-data": "~2.7.0+bedrock-1.20.50",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.6.0+bedrock-1.20.50",
|
||||
"pocketmine/bedrock-protocol": "~26.0.0+bedrock-1.20.50",
|
||||
"pocketmine/netresearch-jsonmapper": "~v4.4.999",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~4.1.0+bedrock-1.20.80",
|
||||
"pocketmine/bedrock-data": "~2.10.0+bedrock-1.20.80",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.9.0+bedrock-1.20.80",
|
||||
"pocketmine/bedrock-protocol": "~30.0.0+bedrock-1.20.80",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
"pocketmine/errorhandler": "^0.6.0",
|
||||
"pocketmine/errorhandler": "^0.7.0",
|
||||
"pocketmine/locale-data": "~2.19.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/math": "~1.0.0",
|
||||
"pocketmine/nbt": "~1.0.0",
|
||||
"pocketmine/raklib": "^0.15.0",
|
||||
"pocketmine/raklib-ipc": "^0.2.0",
|
||||
"pocketmine/raklib": "~1.1.0",
|
||||
"pocketmine/raklib-ipc": "~1.0.0",
|
||||
"pocketmine/snooze": "^0.5.0",
|
||||
"ramsey/uuid": "~4.7.0",
|
||||
"symfony/filesystem": "~6.3.0"
|
||||
"symfony/filesystem": "~6.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.10.47",
|
||||
"phpstan/phpstan": "1.10.66",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "~10.3.0 || ~10.2.0 || ~10.1.0"
|
||||
@ -83,11 +83,14 @@
|
||||
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
|
||||
"@php -dphar.readonly=0 build/server-phar.php"
|
||||
],
|
||||
"update-registry-annotations": [
|
||||
"update-codegen": [
|
||||
"@php build/generate-bedrockdata-path-consts.php",
|
||||
"@php build/generate-biome-ids.php",
|
||||
"@php build/generate-block-serializer-consts.php vendor/pocketmine/bedrock-data/canonical_block_states.nbt",
|
||||
"@php build/generate-item-type-names.php vendor/pocketmine/bedrock-data/required_item_list.json",
|
||||
"@php build/generate-known-translation-apis.php",
|
||||
"@php build/generate-pocketmine-yml-property-consts.php",
|
||||
"@php build/generate-registry-annotations.php src"
|
||||
],
|
||||
"update-translation-apis": [
|
||||
"@php build/generate-known-translation-apis.php"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
377
composer.lock
generated
377
composer.lock
generated
File diff suppressed because it is too large
Load Diff
52
src/BootstrapOptions.php
Normal file
52
src/BootstrapOptions.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Constants for all the command-line options that PocketMine-MP supports.
|
||||
* Other options not listed here can be used to override server.properties and pocketmine.yml values temporarily.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class BootstrapOptions{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/** Disables the setup wizard on first startup */
|
||||
public const NO_WIZARD = "no-wizard";
|
||||
/** Force-disables console text colour and formatting */
|
||||
public const DISABLE_ANSI = "disable-ansi";
|
||||
/** Force-enables console text colour and formatting */
|
||||
public const ENABLE_ANSI = "enable-ansi";
|
||||
/** Path to look in for plugins */
|
||||
public const PLUGINS = "plugins";
|
||||
/** Path to store and load server data */
|
||||
public const DATA = "data";
|
||||
/** Shows basic server version information and exits */
|
||||
public const VERSION = "version";
|
||||
/** Disables writing logs to server.log */
|
||||
public const NO_LOG_FILE = "no-log-file";
|
||||
}
|
@ -25,6 +25,7 @@ namespace pocketmine {
|
||||
|
||||
use Composer\InstalledVersions;
|
||||
use pocketmine\errorhandler\ErrorToExceptionHandler;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\thread\ThreadManager;
|
||||
use pocketmine\thread\ThreadSafeClassLoader;
|
||||
use pocketmine\utils\Filesystem;
|
||||
@ -40,14 +41,17 @@ namespace pocketmine {
|
||||
use function extension_loaded;
|
||||
use function function_exists;
|
||||
use function getcwd;
|
||||
use function getopt;
|
||||
use function is_dir;
|
||||
use function mkdir;
|
||||
use function phpversion;
|
||||
use function preg_match;
|
||||
use function preg_quote;
|
||||
use function printf;
|
||||
use function realpath;
|
||||
use function version_compare;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const PHP_EOL;
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
@ -120,8 +124,8 @@ namespace pocketmine {
|
||||
}
|
||||
|
||||
if(($pmmpthread_version = phpversion("pmmpthread")) !== false){
|
||||
if(version_compare($pmmpthread_version, "6.0.7") < 0 || version_compare($pmmpthread_version, "7.0.0") >= 0){
|
||||
$messages[] = "pmmpthread ^6.0.7 is required, while you have $pmmpthread_version.";
|
||||
if(version_compare($pmmpthread_version, "6.1.0") < 0 || version_compare($pmmpthread_version, "7.0.0") >= 0){
|
||||
$messages[] = "pmmpthread ^6.1.0 is required, while you have $pmmpthread_version.";
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +170,7 @@ namespace pocketmine {
|
||||
* @return void
|
||||
*/
|
||||
function emit_performance_warnings(\Logger $logger){
|
||||
if(PHP_DEBUG !== 0){
|
||||
if(ZEND_DEBUG_BUILD){
|
||||
$logger->warning("This PHP binary was compiled in debug mode. This has a major impact on performance.");
|
||||
}
|
||||
if(extension_loaded("xdebug") && (!function_exists('xdebug_info') || count(xdebug_info('mode')) !== 0)){
|
||||
@ -273,9 +277,14 @@ JIT_WARNING
|
||||
|
||||
ErrorToExceptionHandler::set();
|
||||
|
||||
if(count(getopt("", [BootstrapOptions::VERSION])) > 0){
|
||||
printf("%s %s (git hash %s) for Minecraft: Bedrock Edition %s\n", VersionInfo::NAME, VersionInfo::VERSION()->getFullVersion(true), VersionInfo::GIT_HASH(), ProtocolInfo::MINECRAFT_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
|
||||
$dataPath = getopt_string("data") ?? $cwd;
|
||||
$pluginPath = getopt_string("plugins") ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
||||
$dataPath = getopt_string(BootstrapOptions::DATA) ?? $cwd;
|
||||
$pluginPath = getopt_string(BootstrapOptions::PLUGINS) ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
||||
Filesystem::addCleanedPath($pluginPath, Filesystem::CLEAN_PATH_PLUGINS_PREFIX);
|
||||
|
||||
if(!@mkdir($dataPath, 0777, true) && !is_dir($dataPath)){
|
||||
@ -308,23 +317,28 @@ JIT_WARNING
|
||||
//Logger has a dependency on timezone
|
||||
Timezone::init();
|
||||
|
||||
$opts = getopt("", ["no-wizard", "enable-ansi", "disable-ansi"]);
|
||||
if(isset($opts["enable-ansi"])){
|
||||
$opts = getopt("", [BootstrapOptions::NO_WIZARD, BootstrapOptions::ENABLE_ANSI, BootstrapOptions::DISABLE_ANSI, BootstrapOptions::NO_LOG_FILE]);
|
||||
if(isset($opts[BootstrapOptions::ENABLE_ANSI])){
|
||||
Terminal::init(true);
|
||||
}elseif(isset($opts["disable-ansi"])){
|
||||
}elseif(isset($opts[BootstrapOptions::DISABLE_ANSI])){
|
||||
Terminal::init(false);
|
||||
}else{
|
||||
Terminal::init();
|
||||
}
|
||||
$logFile = isset($opts[BootstrapOptions::NO_LOG_FILE]) ? null : Path::join($dataPath, "server.log");
|
||||
|
||||
$logger = new MainLogger($logFile, Terminal::hasFormattingCodes(), "Server", new \DateTimeZone(Timezone::get()), false, Path::join($dataPath, "log_archive"));
|
||||
if($logFile === null){
|
||||
$logger->notice("Logging to file disabled. Ensure logs are collected by other means (e.g. Docker logs).");
|
||||
}
|
||||
|
||||
$logger = new MainLogger(Path::join($dataPath, "server.log"), Terminal::hasFormattingCodes(), "Server", new \DateTimeZone(Timezone::get()));
|
||||
\GlobalLogger::set($logger);
|
||||
|
||||
emit_performance_warnings($logger);
|
||||
|
||||
$exitCode = 0;
|
||||
do{
|
||||
if(!file_exists(Path::join($dataPath, "server.properties")) && !isset($opts["no-wizard"])){
|
||||
if(!file_exists(Path::join($dataPath, "server.properties")) && !isset($opts[BootstrapOptions::NO_WIZARD])){
|
||||
$installer = new SetupWizard($dataPath);
|
||||
if(!$installer->run()){
|
||||
$exitCode = -1;
|
||||
|
125
src/Server.php
125
src/Server.php
@ -59,7 +59,7 @@ use pocketmine\network\mcpe\EntityEventBroadcaster;
|
||||
use pocketmine\network\mcpe\NetworkSession;
|
||||
use pocketmine\network\mcpe\PacketBroadcaster;
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
|
||||
use pocketmine\network\mcpe\protocol\types\CompressionAlgorithm;
|
||||
use pocketmine\network\mcpe\raklib\RakLibInterface;
|
||||
use pocketmine\network\mcpe\StandardEntityEventBroadcaster;
|
||||
use pocketmine\network\mcpe\StandardPacketBroadcaster;
|
||||
@ -125,6 +125,7 @@ use Symfony\Component\Filesystem\Path;
|
||||
use function array_fill;
|
||||
use function array_sum;
|
||||
use function base64_encode;
|
||||
use function chr;
|
||||
use function cli_set_process_title;
|
||||
use function copy;
|
||||
use function count;
|
||||
@ -523,7 +524,7 @@ class Server{
|
||||
return $this->playerDataProvider->loadData($name);
|
||||
}catch(PlayerDataLoadException $e){
|
||||
$this->logger->debug("Failed to load player data for $name: " . $e->getMessage());
|
||||
$this->logger->error($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||
$this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@ -542,7 +543,7 @@ class Server{
|
||||
try{
|
||||
$this->playerDataProvider->saveData($name, $ev->getSaveData());
|
||||
}catch(PlayerDataSaveException $e){
|
||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
||||
$this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
});
|
||||
@ -737,7 +738,7 @@ class Server{
|
||||
* @return string[][]
|
||||
*/
|
||||
public function getCommandAliases() : array{
|
||||
$section = $this->configGroup->getProperty(YmlServerProperties::ALIASES);
|
||||
$section = $this->configGroup->getProperty(Yml::ALIASES);
|
||||
$result = [];
|
||||
if(is_array($section)){
|
||||
foreach($section as $key => $value){
|
||||
@ -854,14 +855,14 @@ class Server{
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::language_selected($this->getLanguage()->getName(), $this->getLanguage()->getLang())));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::language_selected($this->language->getName(), $this->language->getLang())));
|
||||
|
||||
if(VersionInfo::IS_DEVELOPMENT_BUILD){
|
||||
if(!$this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_DEV_BUILDS, false)){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error1(VersionInfo::NAME)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error2()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error3()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4(YmlServerProperties::SETTINGS_ENABLE_DEV_BUILDS)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4(Yml::SETTINGS_ENABLE_DEV_BUILDS)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error5("https://github.com/pmmp/PocketMine-MP/releases")));
|
||||
$this->forceShutdownExit();
|
||||
|
||||
@ -877,7 +878,7 @@ class Server{
|
||||
|
||||
$this->memoryManager = new MemoryManager($this);
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
|
||||
|
||||
if(($poolSize = $this->configGroup->getPropertyString(Yml::SETTINGS_ASYNC_WORKERS, "auto")) === "auto"){
|
||||
$poolSize = 2;
|
||||
@ -937,11 +938,11 @@ class Server{
|
||||
|
||||
$this->onlineMode = $this->configGroup->getConfigBool(ServerProperties::XBOX_AUTH, true);
|
||||
if($this->onlineMode){
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
|
||||
}else{
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_disabled()));
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authWarning()));
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_disabled()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authWarning()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||
}
|
||||
|
||||
if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||
@ -952,17 +953,17 @@ class Server{
|
||||
|
||||
$this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort());
|
||||
|
||||
$this->getLogger()->debug("Server unique id: " . $this->getServerUniqueId());
|
||||
$this->getLogger()->debug("Machine unique id: " . Utils::getMachineUniqueId());
|
||||
$this->logger->debug("Server unique id: " . $this->getServerUniqueId());
|
||||
$this->logger->debug("Machine unique id: " . Utils::getMachineUniqueId());
|
||||
|
||||
$this->network = new Network($this->logger);
|
||||
$this->network->setName($this->getMotd());
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_info(
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_info(
|
||||
$this->getName(),
|
||||
(VersionInfo::IS_DEVELOPMENT_BUILD ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET
|
||||
)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
|
||||
@ -973,7 +974,7 @@ class Server{
|
||||
|
||||
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes"));
|
||||
|
||||
$this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger);
|
||||
$this->resourceManager = new ResourcePackManager(Path::join($this->dataPath, "resource_packs"), $this->logger);
|
||||
|
||||
$pluginGraylist = null;
|
||||
$graylistFile = Path::join($this->dataPath, "plugin_list.yml");
|
||||
@ -987,7 +988,7 @@ class Server{
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->dataPath, "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||
|
||||
@ -1049,9 +1050,9 @@ class Server{
|
||||
|
||||
$this->configGroup->save();
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
|
||||
|
||||
$forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language);
|
||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $forwarder);
|
||||
@ -1139,13 +1140,13 @@ class Server{
|
||||
if($this->worldManager->getDefaultWorld() === null){
|
||||
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
if(trim($default) == ""){
|
||||
$this->getLogger()->warning("level-name cannot be null, using default");
|
||||
$this->logger->warning("level-name cannot be null, using default");
|
||||
$default = "world";
|
||||
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
}
|
||||
if(!$this->worldManager->loadWorld($default, true)){
|
||||
if($this->worldManager->isWorldGenerated($default)){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1154,7 +1155,7 @@ class Server{
|
||||
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
|
||||
|
||||
if($generatorClass === null){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
return false;
|
||||
}
|
||||
$creationOptions = WorldCreationOptions::create()
|
||||
@ -1185,12 +1186,11 @@ class Server{
|
||||
bool $useQuery,
|
||||
PacketBroadcaster $packetBroadcaster,
|
||||
EntityEventBroadcaster $entityEventBroadcaster,
|
||||
PacketSerializerContext $packetSerializerContext,
|
||||
TypeConverter $typeConverter
|
||||
) : bool{
|
||||
$prettyIp = $ipV6 ? "[$ip]" : $ip;
|
||||
try{
|
||||
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter));
|
||||
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6, $packetBroadcaster, $entityEventBroadcaster, $typeConverter));
|
||||
}catch(NetworkInterfaceStartException $e){
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
|
||||
$ip,
|
||||
@ -1200,7 +1200,7 @@ class Server{
|
||||
return false;
|
||||
}
|
||||
if($rakLibRegistered){
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
|
||||
}
|
||||
if($useQuery){
|
||||
if(!$rakLibRegistered){
|
||||
@ -1208,7 +1208,7 @@ class Server{
|
||||
//if it's not registered we need to make sure Query still works
|
||||
$this->network->registerInterface(new DedicatedQueryNetworkInterface($ip, $port, $ipV6, new \PrefixedLogger($this->logger, "Dedicated Query Interface")));
|
||||
}
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1217,15 +1217,14 @@ class Server{
|
||||
$useQuery = $this->configGroup->getConfigBool(ServerProperties::ENABLE_QUERY, true);
|
||||
|
||||
$typeConverter = TypeConverter::getInstance();
|
||||
$packetSerializerContext = new PacketSerializerContext($typeConverter->getItemTypeDictionary());
|
||||
$packetBroadcaster = new StandardPacketBroadcaster($this, $packetSerializerContext);
|
||||
$packetBroadcaster = new StandardPacketBroadcaster($this);
|
||||
$entityEventBroadcaster = new StandardEntityEventBroadcaster($packetBroadcaster, $typeConverter);
|
||||
|
||||
if(
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter) ||
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $typeConverter) ||
|
||||
(
|
||||
$this->configGroup->getConfigBool(ServerProperties::ENABLE_IPV6, true) &&
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter)
|
||||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $typeConverter)
|
||||
)
|
||||
){
|
||||
return false;
|
||||
@ -1368,25 +1367,31 @@ class Server{
|
||||
*
|
||||
* @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null).
|
||||
*/
|
||||
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise{
|
||||
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise|string{
|
||||
$timings ??= Timings::$playerNetworkSendCompress;
|
||||
try{
|
||||
$timings->startTiming();
|
||||
|
||||
if($sync === null){
|
||||
$threshold = $compressor->getCompressionThreshold();
|
||||
$sync = !$this->networkCompressionAsync || $threshold === null || strlen($buffer) < $threshold;
|
||||
}
|
||||
$threshold = $compressor->getCompressionThreshold();
|
||||
if($threshold === null || strlen($buffer) < $compressor->getCompressionThreshold()){
|
||||
$compressionType = CompressionAlgorithm::NONE;
|
||||
$compressed = $buffer;
|
||||
|
||||
$promise = new CompressBatchPromise();
|
||||
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
|
||||
$task = new CompressBatchTask($buffer, $promise, $compressor);
|
||||
$this->asyncPool->submitTask($task);
|
||||
}else{
|
||||
$promise->resolve($compressor->compress($buffer));
|
||||
$sync ??= !$this->networkCompressionAsync;
|
||||
|
||||
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
|
||||
$promise = new CompressBatchPromise();
|
||||
$task = new CompressBatchTask($buffer, $promise, $compressor);
|
||||
$this->asyncPool->submitTask($task);
|
||||
return $promise;
|
||||
}
|
||||
|
||||
$compressionType = $compressor->getNetworkId();
|
||||
$compressed = $compressor->compress($buffer);
|
||||
}
|
||||
|
||||
return $promise;
|
||||
return chr($compressionType) . $compressed;
|
||||
}finally{
|
||||
$timings->stopTiming();
|
||||
}
|
||||
@ -1463,43 +1468,43 @@ class Server{
|
||||
$this->shutdown();
|
||||
|
||||
if(isset($this->pluginManager)){
|
||||
$this->getLogger()->debug("Disabling all plugins");
|
||||
$this->logger->debug("Disabling all plugins");
|
||||
$this->pluginManager->disablePlugins();
|
||||
}
|
||||
|
||||
if(isset($this->network)){
|
||||
$this->network->getSessionManager()->close($this->configGroup->getPropertyString(YmlServerProperties::SETTINGS_SHUTDOWN_MESSAGE, "Server closed"));
|
||||
$this->network->getSessionManager()->close($this->configGroup->getPropertyString(Yml::SETTINGS_SHUTDOWN_MESSAGE, "Server closed"));
|
||||
}
|
||||
|
||||
if(isset($this->worldManager)){
|
||||
$this->getLogger()->debug("Unloading all worlds");
|
||||
$this->logger->debug("Unloading all worlds");
|
||||
foreach($this->worldManager->getWorlds() as $world){
|
||||
$this->worldManager->unloadWorld($world, true);
|
||||
}
|
||||
}
|
||||
|
||||
$this->getLogger()->debug("Removing event handlers");
|
||||
$this->logger->debug("Removing event handlers");
|
||||
HandlerListManager::global()->unregisterAll();
|
||||
|
||||
if(isset($this->asyncPool)){
|
||||
$this->getLogger()->debug("Shutting down async task worker pool");
|
||||
$this->logger->debug("Shutting down async task worker pool");
|
||||
$this->asyncPool->shutdown();
|
||||
}
|
||||
|
||||
if(isset($this->configGroup)){
|
||||
$this->getLogger()->debug("Saving properties");
|
||||
$this->logger->debug("Saving properties");
|
||||
$this->configGroup->save();
|
||||
}
|
||||
|
||||
if($this->console !== null){
|
||||
$this->getLogger()->debug("Closing console");
|
||||
$this->logger->debug("Closing console");
|
||||
$this->console->quit();
|
||||
}
|
||||
|
||||
if(isset($this->network)){
|
||||
$this->getLogger()->debug("Stopping network interfaces");
|
||||
$this->logger->debug("Stopping network interfaces");
|
||||
foreach($this->network->getInterfaces() as $interface){
|
||||
$this->getLogger()->debug("Stopping network interface " . get_class($interface));
|
||||
$this->logger->debug("Stopping network interface " . get_class($interface));
|
||||
$this->network->unregisterInterface($interface);
|
||||
}
|
||||
}
|
||||
@ -1567,7 +1572,7 @@ class Server{
|
||||
}
|
||||
|
||||
private function writeCrashDumpFile(CrashDump $dump) : string{
|
||||
$crashFolder = Path::join($this->getDataPath(), "crashdumps");
|
||||
$crashFolder = Path::join($this->dataPath, "crashdumps");
|
||||
if(!is_dir($crashFolder)){
|
||||
mkdir($crashFolder);
|
||||
}
|
||||
@ -1598,17 +1603,17 @@ class Server{
|
||||
ini_set("error_reporting", '0');
|
||||
ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems
|
||||
try{
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_create()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_create()));
|
||||
$dump = new CrashDump($this, $this->pluginManager ?? null);
|
||||
|
||||
$crashDumpPath = $this->writeCrashDumpFile($dump);
|
||||
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
|
||||
|
||||
if($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_ENABLED, true)){
|
||||
$report = true;
|
||||
|
||||
$stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash");
|
||||
$stamp = Path::join($this->dataPath, "crashdumps", ".last_crash");
|
||||
$crashInterval = 120; //2 minutes
|
||||
if(($lastReportTime = @filemtime($stamp)) !== false && $lastReportTime + $crashInterval >= time()){
|
||||
$report = false;
|
||||
@ -1639,7 +1644,7 @@ class Server{
|
||||
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)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
|
||||
}elseif(isset($data->error) && is_string($data->error)){
|
||||
$this->logger->emergency("Automatic crash report submission failed: $data->error");
|
||||
}else{
|
||||
@ -1653,7 +1658,7 @@ class Server{
|
||||
}catch(\Throwable $e){
|
||||
$this->logger->logException($e);
|
||||
try{
|
||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage())));
|
||||
$this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage())));
|
||||
}catch(\Throwable $e){}
|
||||
}
|
||||
|
||||
@ -1771,7 +1776,7 @@ class Server{
|
||||
|
||||
echo "\x1b]0;" . $this->getName() . " " .
|
||||
$this->getPocketMineVersion() .
|
||||
" | Online $online/" . $this->getMaxPlayers() .
|
||||
" | Online $online/" . $this->maxPlayers .
|
||||
($connecting > 0 ? " (+$connecting connecting)" : "") .
|
||||
" | Memory " . $usage .
|
||||
" | U " . round($bandwidthStats->getSend()->getAverageBytes() / 1024, 2) .
|
||||
@ -1836,10 +1841,10 @@ class Server{
|
||||
}
|
||||
|
||||
if(($this->tickCounter % self::TICKS_PER_TPS_OVERLOAD_WARNING) === 0 && $this->getTicksPerSecondAverage() < self::TPS_OVERLOAD_WARNING_THRESHOLD){
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||
}
|
||||
|
||||
$this->getMemoryManager()->check();
|
||||
$this->memoryManager->check();
|
||||
|
||||
if($this->console !== null){
|
||||
Timings::$serverCommand->startTiming();
|
||||
|
@ -24,7 +24,9 @@ declare(strict_types=1);
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\snooze\SleeperHandlerEntry;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use pocketmine\utils\Utils;
|
||||
use function hrtime;
|
||||
|
||||
/**
|
||||
@ -35,12 +37,29 @@ final class TimeTrackingSleeperHandler extends SleeperHandler{
|
||||
|
||||
private int $notificationProcessingTimeNs = 0;
|
||||
|
||||
/**
|
||||
* @var TimingsHandler[]
|
||||
* @phpstan-var array<string, TimingsHandler>
|
||||
*/
|
||||
private static array $handlerTimings = [];
|
||||
|
||||
public function __construct(
|
||||
private TimingsHandler $timings
|
||||
){
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function addNotifier(\Closure $handler) : SleeperHandlerEntry{
|
||||
$name = Utils::getNiceClosureName($handler);
|
||||
$timings = self::$handlerTimings[$name] ??= new TimingsHandler("Snooze Handler: " . $name, $this->timings);
|
||||
|
||||
return parent::addNotifier(function() use ($timings, $handler) : void{
|
||||
$timings->startTiming();
|
||||
$handler();
|
||||
$timings->stopTiming();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in nanoseconds spent processing notifications since the last reset.
|
||||
*/
|
||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.9.0";
|
||||
public const BASE_VERSION = "5.15.0";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
@ -63,7 +63,8 @@ final class VersionInfo{
|
||||
if(\Phar::running(true) === ""){
|
||||
$gitHash = Git::getRepositoryStatePretty(\pocketmine\PATH);
|
||||
}else{
|
||||
$phar = new \Phar(\Phar::running(false));
|
||||
$pharPath = \Phar::running(false);
|
||||
$phar = \Phar::isValidPharFilename($pharPath) ? new \Phar($pharPath) : new \PharData($pharPath);
|
||||
$meta = $phar->getMetadata();
|
||||
if(isset($meta["git"])){
|
||||
$gitHash = $meta["git"];
|
||||
@ -82,7 +83,8 @@ final class VersionInfo{
|
||||
if(self::$buildNumber === null){
|
||||
self::$buildNumber = 0;
|
||||
if(\Phar::running(true) !== ""){
|
||||
$phar = new \Phar(\Phar::running(false));
|
||||
$pharPath = \Phar::running(false);
|
||||
$phar = \Phar::isValidPharFilename($pharPath) ? new \Phar($pharPath) : new \PharData($pharPath);
|
||||
$meta = $phar->getMetadata();
|
||||
if(is_array($meta) && isset($meta["build"]) && is_int($meta["build"])){
|
||||
self::$buildNumber = $meta["build"];
|
||||
|
@ -173,7 +173,7 @@ class Bamboo extends Transparent{
|
||||
$newHeight = $height + $growAmount;
|
||||
|
||||
$stemBlock = (clone $this)->setReady(false)->setLeafSize(self::NO_LEAVES);
|
||||
if($newHeight >= 4 && !$stemBlock->isThick()){ //don't change it to false if height is less, because it might have been chopped
|
||||
if($newHeight >= 4 && !$stemBlock->thick){ //don't change it to false if height is less, because it might have been chopped
|
||||
$stemBlock = $stemBlock->setThick(true);
|
||||
}
|
||||
$smallLeavesBlock = (clone $stemBlock)->setLeafSize(self::SMALL_LEAVES);
|
||||
|
@ -55,12 +55,12 @@ class Barrel extends Opaque{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
if(abs($player->getPosition()->getX() - $this->position->getX()) < 2 && abs($player->getPosition()->getZ() - $this->position->getZ()) < 2){
|
||||
$y = $player->getEyePos()->getY();
|
||||
if(abs($player->getPosition()->x - $this->position->x) < 2 && abs($player->getPosition()->z - $this->position->z) < 2){
|
||||
$y = $player->getEyePos()->y;
|
||||
|
||||
if($y - $this->position->getY() > 2){
|
||||
if($y - $this->position->y > 2){
|
||||
$this->facing = Facing::UP;
|
||||
}elseif($this->position->getY() - $y > 0){
|
||||
}elseif($this->position->y - $y > 0){
|
||||
$this->facing = Facing::DOWN;
|
||||
}else{
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
|
@ -34,7 +34,6 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function array_filter;
|
||||
use function assert;
|
||||
use function count;
|
||||
|
||||
@ -89,11 +88,12 @@ abstract class BaseBanner extends Transparent{
|
||||
* @return $this
|
||||
*/
|
||||
public function setPatterns(array $patterns) : self{
|
||||
$checked = array_filter($patterns, fn($v) => $v instanceof BannerPatternLayer);
|
||||
if(count($checked) !== count($patterns)){
|
||||
throw new \TypeError("Deque must only contain " . BannerPatternLayer::class . " objects");
|
||||
foreach($patterns as $pattern){
|
||||
if(!$pattern instanceof BannerPatternLayer){
|
||||
throw new \TypeError("Array must only contain " . BannerPatternLayer::class . " objects");
|
||||
}
|
||||
}
|
||||
$this->patterns = $checked;
|
||||
$this->patterns = $patterns;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -65,8 +65,8 @@ abstract class BaseBigDripleaf extends Transparent{
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
}
|
||||
if($block instanceof BaseBigDripleaf){
|
||||
$this->facing = $block->getFacing();
|
||||
$tx->addBlock($block->getPosition(), VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($this->facing));
|
||||
$this->facing = $block->facing;
|
||||
$tx->addBlock($block->position, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($this->facing));
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
@ -98,7 +98,7 @@ abstract class BaseBigDripleaf extends Transparent{
|
||||
if($head === null){
|
||||
return false;
|
||||
}
|
||||
$pos = $head->getPosition();
|
||||
$pos = $head->position;
|
||||
$up = $pos->up();
|
||||
$world = $pos->getWorld();
|
||||
if(
|
||||
@ -110,8 +110,8 @@ abstract class BaseBigDripleaf extends Transparent{
|
||||
|
||||
$tx = new BlockTransaction($world);
|
||||
|
||||
$tx->addBlock($pos, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($head->getFacing()));
|
||||
$tx->addBlock($up, VanillaBlocks::BIG_DRIPLEAF_HEAD()->setFacing($head->getFacing()));
|
||||
$tx->addBlock($pos, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($head->facing));
|
||||
$tx->addBlock($up, VanillaBlocks::BIG_DRIPLEAF_HEAD()->setFacing($head->facing));
|
||||
|
||||
$ev = new StructureGrowEvent($head, $tx, $player);
|
||||
$ev->call();
|
||||
|
@ -145,7 +145,7 @@ class Bed extends Transparent{
|
||||
|
||||
$b = ($this->isHeadPart() ? $this : $other);
|
||||
|
||||
if($b->isOccupied()){
|
||||
if($b->occupied){
|
||||
$player->sendMessage(KnownTranslationFactory::tile_bed_occupied()->prefix(TextFormat::GRAY));
|
||||
|
||||
return true;
|
||||
|
@ -270,11 +270,22 @@ class Block{
|
||||
}
|
||||
|
||||
private function encodeFullState() : int{
|
||||
$writer = new RuntimeDataWriter($this->requiredBlockItemStateDataBits + $this->requiredBlockOnlyStateDataBits);
|
||||
$writer->writeInt($this->requiredBlockItemStateDataBits, $this->encodeBlockItemState());
|
||||
$writer->writeInt($this->requiredBlockOnlyStateDataBits, $this->encodeBlockOnlyState());
|
||||
$blockItemBits = $this->requiredBlockItemStateDataBits;
|
||||
$blockOnlyBits = $this->requiredBlockOnlyStateDataBits;
|
||||
|
||||
return $writer->getValue();
|
||||
if($blockOnlyBits === 0 && $blockItemBits === 0){
|
||||
return 0;
|
||||
}
|
||||
|
||||
$result = 0;
|
||||
if($blockItemBits > 0){
|
||||
$result |= $this->encodeBlockItemState();
|
||||
}
|
||||
if($blockOnlyBits > 0){
|
||||
$result |= $this->encodeBlockOnlyState() << $blockItemBits;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -391,7 +402,7 @@ class Block{
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->isPlaceable
|
||||
* Returns whether this block can be placed when obtained as an item.
|
||||
*/
|
||||
public function canBePlaced() : bool{
|
||||
return true;
|
||||
@ -561,16 +572,28 @@ class Block{
|
||||
return $this->getLightFilter() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this block allows any light to pass through it.
|
||||
*/
|
||||
public function isTransparent() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated TL;DR: Don't use this function. Its results are confusing and inconsistent.
|
||||
*
|
||||
* No one is sure what the meaning of this property actually is. It's borrowed from Minecraft Java Edition, and is
|
||||
* used by various blocks for support checks.
|
||||
*
|
||||
* Things like signs and banners are considered "solid" despite having no collision box, and things like skulls and
|
||||
* flower pots are considered non-solid despite obviously being "solid" in the conventional, real-world sense.
|
||||
*/
|
||||
public function isSolid() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* AKA: Block->isFlowable
|
||||
* Returns whether this block can be destroyed by liquid flowing into its cell.
|
||||
*/
|
||||
public function canBeFlowedInto() : bool{
|
||||
return false;
|
||||
|
@ -97,7 +97,7 @@ class ChiseledBookshelf extends Opaque{
|
||||
return false;
|
||||
}
|
||||
|
||||
$x = Facing::axis($face) === Axis::X ? $clickVector->getZ() : $clickVector->getX();
|
||||
$x = Facing::axis($face) === Axis::X ? $clickVector->z : $clickVector->x;
|
||||
$slot = ChiseledBookshelfSlot::fromBlockFaceCoordinates(
|
||||
Facing::isPositive(Facing::rotateY($face, true)) ? 1 - $x : $x,
|
||||
$clickVector->y
|
||||
|
@ -54,7 +54,7 @@ final class ChorusFlower extends Flowable{
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
$position = $block->getPosition();
|
||||
$position = $block->position;
|
||||
$world = $position->getWorld();
|
||||
$down = $world->getBlock($position->down());
|
||||
|
||||
@ -152,7 +152,7 @@ final class ChorusFlower extends Flowable{
|
||||
if($tx === null){
|
||||
$tx = new BlockTransaction($this->position->getWorld());
|
||||
}
|
||||
$tx->addBlock($this->position->getSide($facing), (clone $this)->setAge(min(self::MAX_AGE, $this->getAge() + $ageChange)));
|
||||
$tx->addBlock($this->position->getSide($facing), (clone $this)->setAge(min(self::MAX_AGE, $this->age + $ageChange)));
|
||||
|
||||
return $tx;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ final class ChorusPlant extends Flowable{
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
$position = $block->getPosition();
|
||||
$position = $block->position;
|
||||
$world = $position->getWorld();
|
||||
|
||||
$down = $world->getBlock($position->down());
|
||||
|
@ -26,7 +26,6 @@ namespace pocketmine\block;
|
||||
use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Fertilizer;
|
||||
@ -40,7 +39,7 @@ use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function mt_rand;
|
||||
|
||||
class CocoaBlock extends Transparent{
|
||||
class CocoaBlock extends Flowable{
|
||||
use HorizontalFacingTrait;
|
||||
use AgeableTrait;
|
||||
|
||||
@ -65,10 +64,6 @@ class CocoaBlock extends Transparent{
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
private function canAttachTo(Block $block) : bool{
|
||||
return $block instanceof Wood && $block->getWoodType() === WoodType::JUNGLE;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\CropGrowthHelper;
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
@ -66,7 +67,7 @@ abstract class Crops extends Flowable{
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if($this->age < self::MAX_AGE && mt_rand(0, 2) === 1){
|
||||
if($this->age < self::MAX_AGE && CropGrowthHelper::canGrow($this)){
|
||||
$block = clone $this;
|
||||
++$block->age;
|
||||
BlockEventHelper::grow($this, $block, null);
|
||||
|
@ -24,17 +24,18 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\block\utils\CropGrowthHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function mt_rand;
|
||||
|
||||
final class DoublePitcherCrop extends DoublePlant{
|
||||
use AgeableTrait {
|
||||
@ -101,10 +102,19 @@ final class DoublePitcherCrop extends DoublePlant{
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
//TODO: the growth speed is influenced by farmland and nearby crops
|
||||
//only the bottom half of the plant can grow randomly
|
||||
if(mt_rand(0, 2) === 0 && !$this->top){
|
||||
if(CropGrowthHelper::canGrow($this) && !$this->top){
|
||||
$this->grow(null);
|
||||
}
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
$this->age >= self::MAX_AGE ? VanillaBlocks::PITCHER_PLANT()->asItem() : VanillaItems::PITCHER_POD()
|
||||
];
|
||||
}
|
||||
|
||||
public function asItem() : Item{
|
||||
return VanillaItems::PITCHER_POD();
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ class Farmland extends Transparent{
|
||||
$ev = new EntityTrampleFarmlandEvent($entity, $this);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getPosition()->getWorld()->setBlock($this->getPosition(), VanillaBlocks::DIRT());
|
||||
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::DIRT());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -140,7 +140,7 @@ class Fire extends BaseFire{
|
||||
$block->onIncinerate();
|
||||
|
||||
$world = $this->position->getWorld();
|
||||
if($world->getBlock($block->getPosition())->isSameState($block)){
|
||||
if($world->getBlock($block->position)->isSameState($block)){
|
||||
$spreadedFire = false;
|
||||
if(mt_rand(0, $this->age + 9) < 5){ //TODO: check rain
|
||||
$fire = clone $this;
|
||||
|
@ -58,7 +58,7 @@ final class FloorCoralFan extends BaseCoral{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$playerBlockPos = $player->getPosition()->floor();
|
||||
$directionVector = $blockReplace->getPosition()->subtractVector($playerBlockPos)->normalize();
|
||||
$directionVector = $blockReplace->position->subtractVector($playerBlockPos)->normalize();
|
||||
$angle = rad2deg(atan2($directionVector->getZ(), $directionVector->getX()));
|
||||
|
||||
if($angle <= 45 || 315 <= $angle || (135 <= $angle && $angle <= 225)){
|
||||
|
@ -25,6 +25,7 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\tile\Furnace as TileFurnace;
|
||||
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
|
||||
use pocketmine\block\utils\LightableTrait;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
@ -34,11 +35,10 @@ use function mt_rand;
|
||||
|
||||
class Furnace extends Opaque{
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
use LightableTrait;
|
||||
|
||||
protected FurnaceType $furnaceType;
|
||||
|
||||
protected bool $lit = false;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, FurnaceType $furnaceType){
|
||||
$this->furnaceType = $furnaceType;
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
@ -57,18 +57,6 @@ class Furnace extends Opaque{
|
||||
return $this->lit ? 13 : 0;
|
||||
}
|
||||
|
||||
public function isLit() : bool{
|
||||
return $this->lit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setLit(bool $lit = true) : self{
|
||||
$this->lit = $lit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($player instanceof Player){
|
||||
$furnace = $this->position->getWorld()->getTile($this->position);
|
||||
|
@ -61,7 +61,7 @@ class Jukebox extends Opaque{
|
||||
|
||||
public function ejectRecord() : void{
|
||||
if($this->record !== null){
|
||||
$this->getPosition()->getWorld()->dropItem($this->getPosition()->add(0.5, 1, 0.5), $this->record);
|
||||
$this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $this->record);
|
||||
$this->record = null;
|
||||
$this->stopSound();
|
||||
}
|
||||
@ -76,12 +76,12 @@ class Jukebox extends Opaque{
|
||||
|
||||
public function startSound() : void{
|
||||
if($this->record !== null){
|
||||
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordSound($this->record->getRecordType()));
|
||||
$this->position->getWorld()->addSound($this->position, new RecordSound($this->record->getRecordType()));
|
||||
}
|
||||
}
|
||||
|
||||
public function stopSound() : void{
|
||||
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordStopSound());
|
||||
$this->position->getWorld()->addSound($this->position, new RecordStopSound());
|
||||
}
|
||||
|
||||
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
|
@ -34,6 +34,7 @@ final class NetherRoots extends Flowable{
|
||||
$supportBlock = $block->getSide(Facing::DOWN);
|
||||
return
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::DIRT) ||
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::MUD);
|
||||
$supportBlock->hasTypeTag(BlockTypeTags::MUD) ||
|
||||
$supportBlock->getTypeId() === BlockTypeIds::SOUL_SOIL;
|
||||
}
|
||||
}
|
||||
|
@ -108,8 +108,8 @@ class NetherVines extends Flowable{
|
||||
|
||||
private function grow(?Player $player, int $growthAmount = 1) : bool{
|
||||
$top = $this->seekToTip();
|
||||
$age = $top->getAge();
|
||||
$pos = $top->getPosition();
|
||||
$age = $top->age;
|
||||
$pos = $top->position;
|
||||
$world = $pos->getWorld();
|
||||
$changedBlocks = 0;
|
||||
|
||||
|
@ -70,13 +70,13 @@ class PinkPetals extends Flowable{
|
||||
}
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return ($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT) || $this->supportedWhenPlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
return ($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT) || $this->supportedWhenPlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT){
|
||||
$this->count = $blockReplace->getCount() + 1;
|
||||
$this->facing = $blockReplace->getFacing();
|
||||
if($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT){
|
||||
$this->count = $blockReplace->count + 1;
|
||||
$this->facing = $blockReplace->facing;
|
||||
}elseif($player !== null){
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
}
|
||||
|
@ -25,17 +25,18 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\AgeableTrait;
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\CropGrowthHelper;
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function mt_rand;
|
||||
|
||||
final class PitcherCrop extends Flowable{
|
||||
use AgeableTrait;
|
||||
@ -97,9 +98,12 @@ final class PitcherCrop extends Flowable{
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
//TODO: the growth speed is influenced by farmland and nearby crops
|
||||
if(mt_rand(0, 2) === 0){
|
||||
if(CropGrowthHelper::canGrow($this)){
|
||||
$this->grow(null);
|
||||
}
|
||||
}
|
||||
|
||||
public function asItem() : Item{
|
||||
return VanillaItems::PITCHER_POD();
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ 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);
|
||||
$position = $this->getPosition();
|
||||
$position = $this->position;
|
||||
$lightLevel = $position->getWorld()->getFullLightAt($position->x, $position->y, $position->z);
|
||||
$downId = $down->getTypeId();
|
||||
//TODO: nylium support
|
||||
|
@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\block\utils\LightableTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Vector3;
|
||||
@ -32,23 +32,7 @@ use pocketmine\player\Player;
|
||||
use function mt_rand;
|
||||
|
||||
class RedstoneOre extends Opaque{
|
||||
protected bool $lit = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->bool($this->lit);
|
||||
}
|
||||
|
||||
public function isLit() : bool{
|
||||
return $this->lit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setLit(bool $lit = true) : self{
|
||||
$this->lit = $lit;
|
||||
return $this;
|
||||
}
|
||||
use LightableTrait;
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return $this->lit ? 9 : 0;
|
||||
|
@ -23,28 +23,22 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\LightableTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
|
||||
class RedstoneTorch extends Torch{
|
||||
protected bool $lit = true;
|
||||
use LightableTrait;
|
||||
|
||||
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
|
||||
$this->lit = true;
|
||||
parent::__construct($idInfo, $name, $typeInfo);
|
||||
}
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
parent::describeBlockOnlyState($w);
|
||||
$w->bool($this->lit);
|
||||
}
|
||||
|
||||
public function isLit() : bool{
|
||||
return $this->lit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setLit(bool $lit = true) : self{
|
||||
$this->lit = $lit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return $this->lit ? 7 : 0;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class SmallDripleaf extends Transparent{
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
}
|
||||
|
||||
$tx->addBlock($block->getPosition(), VanillaBlocks::SMALL_DRIPLEAF()
|
||||
$tx->addBlock($block->position, VanillaBlocks::SMALL_DRIPLEAF()
|
||||
->setFacing($this->facing)
|
||||
->setTop(true)
|
||||
);
|
||||
@ -117,7 +117,7 @@ class SmallDripleaf extends Transparent{
|
||||
$height = mt_rand(2, 5);
|
||||
$grown = 0;
|
||||
for($i = 0; $i < $height; $i++){
|
||||
$pos = $bottomBlock->getSide(Facing::UP, $i)->getPosition();
|
||||
$pos = $bottomBlock->getSide(Facing::UP, $i)->position;
|
||||
if(!$this->canGrowTo($pos)){
|
||||
break;
|
||||
}
|
||||
|
@ -106,8 +106,8 @@ class Stair extends Transparent{
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
if(
|
||||
$facing === Facing::UP && $this->isUpsideDown() ||
|
||||
$facing === Facing::DOWN && !$this->isUpsideDown() ||
|
||||
$facing === Facing::UP && $this->upsideDown ||
|
||||
$facing === Facing::DOWN && !$this->upsideDown ||
|
||||
($facing === $this->facing && $this->shape !== StairShape::OUTER_LEFT && $this->shape !== StairShape::OUTER_RIGHT) ||
|
||||
($facing === Facing::rotate($this->facing, Axis::Y, false) && $this->shape === StairShape::INNER_LEFT) ||
|
||||
($facing === Facing::rotate($this->facing, Axis::Y, true) && $this->shape === StairShape::INNER_RIGHT)
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\CropGrowthHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
@ -63,7 +64,7 @@ abstract class Stem extends Crops{
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if($this->facing === Facing::UP && mt_rand(0, 2) === 1){
|
||||
if($this->facing === Facing::UP && CropGrowthHelper::canGrow($this)){
|
||||
$world = $this->position->getWorld();
|
||||
if($this->age < self::MAX_AGE){
|
||||
$block = clone $this;
|
||||
|
@ -36,6 +36,7 @@ use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\sound\SweetBerriesPickSound;
|
||||
use function mt_rand;
|
||||
|
||||
class SweetBerryBush extends Flowable{
|
||||
@ -81,6 +82,7 @@ class SweetBerryBush extends Flowable{
|
||||
}elseif(($dropAmount = $this->getBerryDropAmount()) > 0){
|
||||
$world->setBlock($this->position, $this->setAge(self::STAGE_BUSH_NO_BERRIES));
|
||||
$world->dropItem($this->position, $this->asItem()->setCount($dropAmount));
|
||||
$world->addSound($this->position, new SweetBerriesPickSound());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\CropGrowthHelper;
|
||||
use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Fertilizer;
|
||||
@ -32,7 +33,6 @@ use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use function mt_rand;
|
||||
|
||||
final class TorchflowerCrop extends Flowable{
|
||||
use StaticSupportTrait;
|
||||
@ -79,7 +79,7 @@ final class TorchflowerCrop extends Flowable{
|
||||
}
|
||||
|
||||
public function onRandomTick() : void{
|
||||
if(mt_rand(0, 2) === 1){
|
||||
if(CropGrowthHelper::canGrow($this)){
|
||||
BlockEventHelper::grow($this, $this->getNextState(), null);
|
||||
}
|
||||
}
|
||||
|
@ -788,7 +788,7 @@ final class VanillaBlocks{
|
||||
}
|
||||
|
||||
protected static function setup() : void{
|
||||
$railBreakInfo = new Info(new BlockBreakInfo(0.7));
|
||||
$railBreakInfo = new Info(new BreakInfo(0.7));
|
||||
self::register("activator_rail", new ActivatorRail(new BID(Ids::ACTIVATOR_RAIL), "Activator Rail", $railBreakInfo));
|
||||
self::register("air", new Air(new BID(Ids::AIR), "Air", new Info(BreakInfo::indestructible(-1.0))));
|
||||
self::register("anvil", new Anvil(new BID(Ids::ANVIL), "Anvil", new Info(BreakInfo::pickaxe(5.0, ToolTier::WOOD, 6000.0))));
|
||||
@ -1638,7 +1638,7 @@ final class VanillaBlocks{
|
||||
|
||||
self::register("cave_vines", new CaveVines(new BID(Ids::CAVE_VINES), "Cave Vines", new Info(BreakInfo::instant())));
|
||||
|
||||
self::register("small_dripleaf", new SmallDripleaf(new BID(Ids::SMALL_DRIPLEAF), "Small Dripleaf", new Info(BreakInfo::instant(BlockToolType::SHEARS, toolHarvestLevel: 1))));
|
||||
self::register("small_dripleaf", new SmallDripleaf(new BID(Ids::SMALL_DRIPLEAF), "Small Dripleaf", new Info(BreakInfo::instant(ToolType::SHEARS, toolHarvestLevel: 1))));
|
||||
self::register("big_dripleaf_head", new BigDripleafHead(new BID(Ids::BIG_DRIPLEAF_HEAD), "Big Dripleaf", new Info(BreakInfo::instant())));
|
||||
self::register("big_dripleaf_stem", new BigDripleafStem(new BID(Ids::BIG_DRIPLEAF_STEM), "Big Dripleaf Stem", new Info(BreakInfo::instant())));
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ final class WoodLikeBlockIdHelper{
|
||||
};
|
||||
}
|
||||
|
||||
public static function getTrapdoorIdentifier(WoodType $treeType) : BlockIdentifier{
|
||||
public static function getTrapdoorIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_TRAPDOOR,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_TRAPDOOR,
|
||||
@ -186,7 +186,7 @@ final class WoodLikeBlockIdHelper{
|
||||
});
|
||||
}
|
||||
|
||||
public static function getButtonIdentifier(WoodType $treeType) : BlockIdentifier{
|
||||
public static function getButtonIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_BUTTON,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_BUTTON,
|
||||
@ -201,7 +201,7 @@ final class WoodLikeBlockIdHelper{
|
||||
});
|
||||
}
|
||||
|
||||
public static function getPressurePlateIdentifier(WoodType $treeType) : BlockIdentifier{
|
||||
public static function getPressurePlateIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_PRESSURE_PLATE,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_PRESSURE_PLATE,
|
||||
@ -216,7 +216,7 @@ final class WoodLikeBlockIdHelper{
|
||||
});
|
||||
}
|
||||
|
||||
public static function getDoorIdentifier(WoodType $treeType) : BlockIdentifier{
|
||||
public static function getDoorIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_DOOR,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_DOOR,
|
||||
@ -231,7 +231,7 @@ final class WoodLikeBlockIdHelper{
|
||||
});
|
||||
}
|
||||
|
||||
public static function getFenceGateIdentifier(WoodType $treeType) : BlockIdentifier{
|
||||
public static function getFenceGateIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_FENCE_GATE,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_FENCE_GATE,
|
||||
@ -246,7 +246,7 @@ final class WoodLikeBlockIdHelper{
|
||||
});
|
||||
}
|
||||
|
||||
public static function getStairsIdentifier(WoodType $treeType) : BlockIdentifier{
|
||||
public static function getStairsIdentifier(WoodType $treeType) : BID{
|
||||
return new BID(match($treeType){
|
||||
WoodType::OAK => Ids::OAK_STAIRS,
|
||||
WoodType::SPRUCE => Ids::SPRUCE_STAIRS,
|
||||
|
@ -47,20 +47,20 @@ trait AnimatedBlockInventoryTrait{
|
||||
public function onOpen(Player $who) : void{
|
||||
parent::onOpen($who);
|
||||
|
||||
if($this->getHolder()->isValid() && $this->getViewerCount() === 1){
|
||||
if($this->holder->isValid() && $this->getViewerCount() === 1){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->animateBlock(true);
|
||||
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
||||
$this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected function animateBlock(bool $isOpen) : void;
|
||||
|
||||
public function onClose(Player $who) : void{
|
||||
if($this->getHolder()->isValid() && $this->getViewerCount() === 1){
|
||||
if($this->holder->isValid() && $this->getViewerCount() === 1){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->animateBlock(false);
|
||||
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
||||
$this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
||||
}
|
||||
parent::onClose($who);
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class Chest extends Spawnable implements Container, Nameable{
|
||||
if($pair->doubleInventory !== null){
|
||||
$this->doubleInventory = $pair->doubleInventory;
|
||||
}else{
|
||||
if(($pair->getPosition()->x + ($pair->getPosition()->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly
|
||||
if(($pair->position->x + ($pair->position->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly
|
||||
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($pair->inventory, $this->inventory);
|
||||
}else{
|
||||
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($this->inventory, $pair->inventory);
|
||||
|
@ -82,6 +82,7 @@ enum BannerPatternType{
|
||||
case DIAGONAL_UP_LEFT;
|
||||
case DIAGONAL_UP_RIGHT;
|
||||
case FLOWER;
|
||||
case GLOBE;
|
||||
case GRADIENT;
|
||||
case GRADIENT_UP;
|
||||
case HALF_HORIZONTAL;
|
||||
@ -89,6 +90,7 @@ enum BannerPatternType{
|
||||
case HALF_VERTICAL;
|
||||
case HALF_VERTICAL_RIGHT;
|
||||
case MOJANG;
|
||||
case PIGLIN;
|
||||
case RHOMBUS;
|
||||
case SKULL;
|
||||
case SMALL_STRIPES;
|
||||
|
@ -24,7 +24,6 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
@ -38,24 +37,12 @@ use pocketmine\world\sound\FireExtinguishSound;
|
||||
use pocketmine\world\sound\FlintSteelSound;
|
||||
|
||||
trait CandleTrait{
|
||||
private bool $lit = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->bool($this->lit);
|
||||
}
|
||||
use LightableTrait;
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return $this->lit ? 3 : 0;
|
||||
}
|
||||
|
||||
public function isLit() : bool{ return $this->lit; }
|
||||
|
||||
/** @return $this */
|
||||
public function setLit(bool $lit) : self{
|
||||
$this->lit = $lit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @see Block::onInteract() */
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE || $item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
|
||||
|
120
src/block/utils/CropGrowthHelper.php
Normal file
120
src/block/utils/CropGrowthHelper.php
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\Farmland;
|
||||
use function mt_rand;
|
||||
|
||||
final class CropGrowthHelper{
|
||||
|
||||
private const ON_HYDRATED_FARMLAND_BONUS = 3;
|
||||
private const ON_DRY_FARMLAND_BONUS = 1;
|
||||
private const ADJACENT_HYDRATED_FARMLAND_BONUS = 3 / 4;
|
||||
private const ADJACENT_DRY_FARMLAND_BONUS = 1 / 4;
|
||||
|
||||
private const IMPROPER_ARRANGEMENT_DIVISOR = 2;
|
||||
|
||||
private const MIN_LIGHT_LEVEL = 9;
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the speed at which this crop will grow, depending on its surroundings.
|
||||
* The default is once every 26 random ticks.
|
||||
*
|
||||
* Things which influence this include nearby farmland (bonus for hydrated farmland) and the position of other
|
||||
* nearby crops of the same type (nearby crops of the same type will negatively influence growth speed unless
|
||||
* planted in rows and properly spaced apart).
|
||||
*/
|
||||
public static function calculateMultiplier(Block $block) : float{
|
||||
$result = 1;
|
||||
|
||||
$position = $block->getPosition();
|
||||
|
||||
$world = $position->getWorld();
|
||||
$baseX = $position->getFloorX();
|
||||
$baseY = $position->getFloorY();
|
||||
$baseZ = $position->getFloorZ();
|
||||
|
||||
$farmland = $world->getBlockAt($baseX, $baseY - 1, $baseZ);
|
||||
|
||||
if($farmland instanceof Farmland){
|
||||
$result += $farmland->getWetness() > 0 ? self::ON_HYDRATED_FARMLAND_BONUS : self::ON_DRY_FARMLAND_BONUS;
|
||||
}
|
||||
|
||||
$xRow = false;
|
||||
$zRow = false;
|
||||
$improperArrangement = false;
|
||||
|
||||
for($x = -1; $x <= 1; $x++){
|
||||
for($z = -1; $z <= 1; $z++){
|
||||
if($x === 0 && $z === 0){
|
||||
continue;
|
||||
}
|
||||
$nextFarmland = $world->getBlockAt($baseX + $x, $baseY - 1, $baseZ + $z);
|
||||
|
||||
if(!$nextFarmland instanceof Farmland){
|
||||
continue;
|
||||
}
|
||||
|
||||
$result += $nextFarmland->getWetness() > 0 ? self::ADJACENT_HYDRATED_FARMLAND_BONUS : self::ADJACENT_DRY_FARMLAND_BONUS;
|
||||
|
||||
if(!$improperArrangement){
|
||||
$nextCrop = $world->getBlockAt($baseX + $x, $baseY, $baseZ + $z);
|
||||
if($nextCrop->hasSameTypeId($block)){
|
||||
match(0){
|
||||
$x => $zRow ? $improperArrangement = true : $xRow = true,
|
||||
$z => $xRow ? $improperArrangement = true : $zRow = true,
|
||||
default => $improperArrangement = true,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//crops can be arranged in rows, but the rows must not cross and must be spaced apart by at least one block
|
||||
if($improperArrangement){
|
||||
$result /= self::IMPROPER_ARRANGEMENT_DIVISOR;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function hasEnoughLight(Block $block, int $minLevel = self::MIN_LIGHT_LEVEL) : bool{
|
||||
$position = $block->getPosition();
|
||||
$world = $position->getWorld();
|
||||
|
||||
//crop growth is not affected by time of day since 1.11 or so
|
||||
return $world->getPotentialLightAt($position->x, $position->y, $position->z) >= $minLevel;
|
||||
}
|
||||
|
||||
public static function canGrow(Block $block) : bool{
|
||||
//while it may be tempting to use mt_rand(0, 25) < multiplier, this would make crops grow a bit faster than
|
||||
//vanilla in most cases due to the remainder of 25 / multiplier not being discarded
|
||||
return mt_rand(0, (int) (25 / self::calculateMultiplier($block))) === 0 && self::hasEnoughLight($block);
|
||||
}
|
||||
}
|
46
src/block/utils/LightableTrait.php
Normal file
46
src/block/utils/LightableTrait.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
|
||||
trait LightableTrait{
|
||||
protected bool $lit = false;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->bool($this->lit);
|
||||
}
|
||||
|
||||
public function isLit() : bool{
|
||||
return $this->lit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setLit(bool $lit = true) : self{
|
||||
$this->lit = $lit;
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -63,6 +63,12 @@ use function strpos;
|
||||
use function substr;
|
||||
use function zend_version;
|
||||
use function zlib_encode;
|
||||
use const E_COMPILE_ERROR;
|
||||
use const E_CORE_ERROR;
|
||||
use const E_ERROR;
|
||||
use const E_PARSE;
|
||||
use const E_RECOVERABLE_ERROR;
|
||||
use const E_USER_ERROR;
|
||||
use const FILE_IGNORE_NEW_LINES;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
@ -85,6 +91,9 @@ class CrashDump{
|
||||
public const PLUGIN_INVOLVEMENT_DIRECT = "direct";
|
||||
public const PLUGIN_INVOLVEMENT_INDIRECT = "indirect";
|
||||
|
||||
public const FATAL_ERROR_MASK =
|
||||
E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
|
||||
|
||||
private CrashDumpData $data;
|
||||
private string $encodedData;
|
||||
|
||||
@ -186,7 +195,7 @@ class CrashDump{
|
||||
$error = $lastExceptionError;
|
||||
}else{
|
||||
$error = error_get_last();
|
||||
if($error === null){
|
||||
if($error === null || ($error["type"] & self::FATAL_ERROR_MASK) === 0){
|
||||
throw new \RuntimeException("Crash error information missing - did something use exit()?");
|
||||
}
|
||||
$error["trace"] = Utils::printableTrace(Utils::currentTrace(3)); //Skipping CrashDump->baseCrash, CrashDump->construct, Server->crashDump
|
||||
|
@ -43,44 +43,50 @@ final class BannerPatternTypeIdMap{
|
||||
private array $enumToId = [];
|
||||
|
||||
public function __construct(){
|
||||
$this->register("bo", BannerPatternType::BORDER);
|
||||
$this->register("bri", BannerPatternType::BRICKS);
|
||||
$this->register("mc", BannerPatternType::CIRCLE);
|
||||
$this->register("cre", BannerPatternType::CREEPER);
|
||||
$this->register("cr", BannerPatternType::CROSS);
|
||||
$this->register("cbo", BannerPatternType::CURLY_BORDER);
|
||||
$this->register("lud", BannerPatternType::DIAGONAL_LEFT);
|
||||
$this->register("rd", BannerPatternType::DIAGONAL_RIGHT);
|
||||
$this->register("ld", BannerPatternType::DIAGONAL_UP_LEFT);
|
||||
$this->register("rud", BannerPatternType::DIAGONAL_UP_RIGHT);
|
||||
$this->register("flo", BannerPatternType::FLOWER);
|
||||
$this->register("gra", BannerPatternType::GRADIENT);
|
||||
$this->register("gru", BannerPatternType::GRADIENT_UP);
|
||||
$this->register("hh", BannerPatternType::HALF_HORIZONTAL);
|
||||
$this->register("hhb", BannerPatternType::HALF_HORIZONTAL_BOTTOM);
|
||||
$this->register("vh", BannerPatternType::HALF_VERTICAL);
|
||||
$this->register("vhr", BannerPatternType::HALF_VERTICAL_RIGHT);
|
||||
$this->register("moj", BannerPatternType::MOJANG);
|
||||
$this->register("mr", BannerPatternType::RHOMBUS);
|
||||
$this->register("sku", BannerPatternType::SKULL);
|
||||
$this->register("ss", BannerPatternType::SMALL_STRIPES);
|
||||
$this->register("bl", BannerPatternType::SQUARE_BOTTOM_LEFT);
|
||||
$this->register("br", BannerPatternType::SQUARE_BOTTOM_RIGHT);
|
||||
$this->register("tl", BannerPatternType::SQUARE_TOP_LEFT);
|
||||
$this->register("tr", BannerPatternType::SQUARE_TOP_RIGHT);
|
||||
$this->register("sc", BannerPatternType::STRAIGHT_CROSS);
|
||||
$this->register("bs", BannerPatternType::STRIPE_BOTTOM);
|
||||
$this->register("cs", BannerPatternType::STRIPE_CENTER);
|
||||
$this->register("dls", BannerPatternType::STRIPE_DOWNLEFT);
|
||||
$this->register("drs", BannerPatternType::STRIPE_DOWNRIGHT);
|
||||
$this->register("ls", BannerPatternType::STRIPE_LEFT);
|
||||
$this->register("ms", BannerPatternType::STRIPE_MIDDLE);
|
||||
$this->register("rs", BannerPatternType::STRIPE_RIGHT);
|
||||
$this->register("ts", BannerPatternType::STRIPE_TOP);
|
||||
$this->register("bt", BannerPatternType::TRIANGLE_BOTTOM);
|
||||
$this->register("tt", BannerPatternType::TRIANGLE_TOP);
|
||||
$this->register("bts", BannerPatternType::TRIANGLES_BOTTOM);
|
||||
$this->register("tts", BannerPatternType::TRIANGLES_TOP);
|
||||
foreach(BannerPatternType::cases() as $case){
|
||||
$this->register(match($case){
|
||||
BannerPatternType::BORDER => "bo",
|
||||
BannerPatternType::BRICKS => "bri",
|
||||
BannerPatternType::CIRCLE => "mc",
|
||||
BannerPatternType::CREEPER => "cre",
|
||||
BannerPatternType::CROSS => "cr",
|
||||
BannerPatternType::CURLY_BORDER => "cbo",
|
||||
BannerPatternType::DIAGONAL_LEFT => "lud",
|
||||
BannerPatternType::DIAGONAL_RIGHT => "rd",
|
||||
BannerPatternType::DIAGONAL_UP_LEFT => "ld",
|
||||
BannerPatternType::DIAGONAL_UP_RIGHT => "rud",
|
||||
BannerPatternType::FLOWER => "flo",
|
||||
BannerPatternType::GLOBE => "glb",
|
||||
BannerPatternType::GRADIENT => "gra",
|
||||
BannerPatternType::GRADIENT_UP => "gru",
|
||||
BannerPatternType::HALF_HORIZONTAL => "hh",
|
||||
BannerPatternType::HALF_HORIZONTAL_BOTTOM => "hhb",
|
||||
BannerPatternType::HALF_VERTICAL => "vh",
|
||||
BannerPatternType::HALF_VERTICAL_RIGHT => "vhr",
|
||||
BannerPatternType::MOJANG => "moj",
|
||||
BannerPatternType::PIGLIN => "pig",
|
||||
BannerPatternType::RHOMBUS => "mr",
|
||||
BannerPatternType::SKULL => "sku",
|
||||
BannerPatternType::SMALL_STRIPES => "ss",
|
||||
BannerPatternType::SQUARE_BOTTOM_LEFT => "bl",
|
||||
BannerPatternType::SQUARE_BOTTOM_RIGHT => "br",
|
||||
BannerPatternType::SQUARE_TOP_LEFT => "tl",
|
||||
BannerPatternType::SQUARE_TOP_RIGHT => "tr",
|
||||
BannerPatternType::STRAIGHT_CROSS => "sc",
|
||||
BannerPatternType::STRIPE_BOTTOM => "bs",
|
||||
BannerPatternType::STRIPE_CENTER => "cs",
|
||||
BannerPatternType::STRIPE_DOWNLEFT => "dls",
|
||||
BannerPatternType::STRIPE_DOWNRIGHT => "drs",
|
||||
BannerPatternType::STRIPE_LEFT => "ls",
|
||||
BannerPatternType::STRIPE_MIDDLE => "ms",
|
||||
BannerPatternType::STRIPE_RIGHT => "rs",
|
||||
BannerPatternType::STRIPE_TOP => "ts",
|
||||
BannerPatternType::TRIANGLE_BOTTOM => "bt",
|
||||
BannerPatternType::TRIANGLE_TOP => "tt",
|
||||
BannerPatternType::TRIANGLES_BOTTOM => "bts",
|
||||
BannerPatternType::TRIANGLES_TOP => "tts",
|
||||
}, $case);
|
||||
}
|
||||
}
|
||||
|
||||
public function register(string $stringId, BannerPatternType $type) : void{
|
||||
|
@ -111,4 +111,15 @@ final class BiomeIds{
|
||||
public const CRIMSON_FOREST = 179;
|
||||
public const WARPED_FOREST = 180;
|
||||
public const BASALT_DELTAS = 181;
|
||||
public const JAGGED_PEAKS = 182;
|
||||
public const FROZEN_PEAKS = 183;
|
||||
public const SNOWY_SLOPES = 184;
|
||||
public const GROVE = 185;
|
||||
public const MEADOW = 186;
|
||||
public const LUSH_CAVES = 187;
|
||||
public const DRIPSTONE_CAVES = 188;
|
||||
public const STONY_PEAKS = 189;
|
||||
public const DEEP_DARK = 190;
|
||||
public const MANGROVE_SWAMP = 191;
|
||||
public const CHERRY_GROVE = 192;
|
||||
}
|
||||
|
@ -48,22 +48,28 @@ final class DyeColorIdMap{
|
||||
private array $enumToItemId = [];
|
||||
|
||||
private function __construct(){
|
||||
$this->register(0, ItemTypeNames::WHITE_DYE, DyeColor::WHITE);
|
||||
$this->register(1, ItemTypeNames::ORANGE_DYE, DyeColor::ORANGE);
|
||||
$this->register(2, ItemTypeNames::MAGENTA_DYE, DyeColor::MAGENTA);
|
||||
$this->register(3, ItemTypeNames::LIGHT_BLUE_DYE, DyeColor::LIGHT_BLUE);
|
||||
$this->register(4, ItemTypeNames::YELLOW_DYE, DyeColor::YELLOW);
|
||||
$this->register(5, ItemTypeNames::LIME_DYE, DyeColor::LIME);
|
||||
$this->register(6, ItemTypeNames::PINK_DYE, DyeColor::PINK);
|
||||
$this->register(7, ItemTypeNames::GRAY_DYE, DyeColor::GRAY);
|
||||
$this->register(8, ItemTypeNames::LIGHT_GRAY_DYE, DyeColor::LIGHT_GRAY);
|
||||
$this->register(9, ItemTypeNames::CYAN_DYE, DyeColor::CYAN);
|
||||
$this->register(10, ItemTypeNames::PURPLE_DYE, DyeColor::PURPLE);
|
||||
$this->register(11, ItemTypeNames::BLUE_DYE, DyeColor::BLUE);
|
||||
$this->register(12, ItemTypeNames::BROWN_DYE, DyeColor::BROWN);
|
||||
$this->register(13, ItemTypeNames::GREEN_DYE, DyeColor::GREEN);
|
||||
$this->register(14, ItemTypeNames::RED_DYE, DyeColor::RED);
|
||||
$this->register(15, ItemTypeNames::BLACK_DYE, DyeColor::BLACK);
|
||||
foreach(DyeColor::cases() as $case){
|
||||
[$colorId, $dyeItemId] = match($case){
|
||||
DyeColor::WHITE => [0, ItemTypeNames::WHITE_DYE],
|
||||
DyeColor::ORANGE => [1, ItemTypeNames::ORANGE_DYE],
|
||||
DyeColor::MAGENTA => [2, ItemTypeNames::MAGENTA_DYE],
|
||||
DyeColor::LIGHT_BLUE => [3, ItemTypeNames::LIGHT_BLUE_DYE],
|
||||
DyeColor::YELLOW => [4, ItemTypeNames::YELLOW_DYE],
|
||||
DyeColor::LIME => [5, ItemTypeNames::LIME_DYE],
|
||||
DyeColor::PINK => [6, ItemTypeNames::PINK_DYE],
|
||||
DyeColor::GRAY => [7, ItemTypeNames::GRAY_DYE],
|
||||
DyeColor::LIGHT_GRAY => [8, ItemTypeNames::LIGHT_GRAY_DYE],
|
||||
DyeColor::CYAN => [9, ItemTypeNames::CYAN_DYE],
|
||||
DyeColor::PURPLE => [10, ItemTypeNames::PURPLE_DYE],
|
||||
DyeColor::BLUE => [11, ItemTypeNames::BLUE_DYE],
|
||||
DyeColor::BROWN => [12, ItemTypeNames::BROWN_DYE],
|
||||
DyeColor::GREEN => [13, ItemTypeNames::GREEN_DYE],
|
||||
DyeColor::RED => [14, ItemTypeNames::RED_DYE],
|
||||
DyeColor::BLACK => [15, ItemTypeNames::BLACK_DYE],
|
||||
};
|
||||
|
||||
$this->register($colorId, $dyeItemId, $case);
|
||||
}
|
||||
}
|
||||
|
||||
private function register(int $id, string $itemId, DyeColor $color) : void{
|
||||
|
@ -32,9 +32,13 @@ final class MedicineTypeIdMap{
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(MedicineTypeIds::ANTIDOTE, MedicineType::ANTIDOTE);
|
||||
$this->register(MedicineTypeIds::ELIXIR, MedicineType::ELIXIR);
|
||||
$this->register(MedicineTypeIds::EYE_DROPS, MedicineType::EYE_DROPS);
|
||||
$this->register(MedicineTypeIds::TONIC, MedicineType::TONIC);
|
||||
foreach(MedicineType::cases() as $case){
|
||||
$this->register(match($case){
|
||||
MedicineType::ANTIDOTE => MedicineTypeIds::ANTIDOTE,
|
||||
MedicineType::ELIXIR => MedicineTypeIds::ELIXIR,
|
||||
MedicineType::EYE_DROPS => MedicineTypeIds::EYE_DROPS,
|
||||
MedicineType::TONIC => MedicineTypeIds::TONIC,
|
||||
}, $case);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,12 +32,16 @@ final class MobHeadTypeIdMap{
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(0, MobHeadType::SKELETON);
|
||||
$this->register(1, MobHeadType::WITHER_SKELETON);
|
||||
$this->register(2, MobHeadType::ZOMBIE);
|
||||
$this->register(3, MobHeadType::PLAYER);
|
||||
$this->register(4, MobHeadType::CREEPER);
|
||||
$this->register(5, MobHeadType::DRAGON);
|
||||
$this->register(6, MobHeadType::PIGLIN);
|
||||
foreach(MobHeadType::cases() as $case){
|
||||
$this->register(match($case){
|
||||
MobHeadType::SKELETON => 0,
|
||||
MobHeadType::WITHER_SKELETON => 1,
|
||||
MobHeadType::ZOMBIE => 2,
|
||||
MobHeadType::PLAYER => 3,
|
||||
MobHeadType::CREEPER => 4,
|
||||
MobHeadType::DRAGON => 5,
|
||||
MobHeadType::PIGLIN => 6,
|
||||
}, $case);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,16 +33,20 @@ final class MushroomBlockTypeIdMap{
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
public function __construct(){
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_ALL_PORES, MushroomBlockType::PORES);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER, MushroomBlockType::CAP_NORTHWEST);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_NORTH_SIDE, MushroomBlockType::CAP_NORTH);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHEAST_CORNER, MushroomBlockType::CAP_NORTHEAST);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_WEST_SIDE, MushroomBlockType::CAP_WEST);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_TOP_ONLY, MushroomBlockType::CAP_MIDDLE);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_EAST_SIDE, MushroomBlockType::CAP_EAST);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHWEST_CORNER, MushroomBlockType::CAP_SOUTHWEST);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTH_SIDE, MushroomBlockType::CAP_SOUTH);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER, MushroomBlockType::CAP_SOUTHEAST);
|
||||
$this->register(LegacyMeta::MUSHROOM_BLOCK_ALL_CAP, MushroomBlockType::ALL_CAP);
|
||||
foreach(MushroomBlockType::cases() as $case){
|
||||
$this->register(match($case){
|
||||
MushroomBlockType::PORES => LegacyMeta::MUSHROOM_BLOCK_ALL_PORES,
|
||||
MushroomBlockType::CAP_NORTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER,
|
||||
MushroomBlockType::CAP_NORTH => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTH_SIDE,
|
||||
MushroomBlockType::CAP_NORTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHEAST_CORNER,
|
||||
MushroomBlockType::CAP_WEST => LegacyMeta::MUSHROOM_BLOCK_CAP_WEST_SIDE,
|
||||
MushroomBlockType::CAP_MIDDLE => LegacyMeta::MUSHROOM_BLOCK_CAP_TOP_ONLY,
|
||||
MushroomBlockType::CAP_EAST => LegacyMeta::MUSHROOM_BLOCK_CAP_EAST_SIDE,
|
||||
MushroomBlockType::CAP_SOUTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHWEST_CORNER,
|
||||
MushroomBlockType::CAP_SOUTH => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTH_SIDE,
|
||||
MushroomBlockType::CAP_SOUTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER,
|
||||
MushroomBlockType::ALL_CAP => LegacyMeta::MUSHROOM_BLOCK_ALL_CAP,
|
||||
}, $case);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,21 +32,25 @@ final class NoteInstrumentIdMap{
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(0, NoteInstrument::PIANO);
|
||||
$this->register(1, NoteInstrument::BASS_DRUM);
|
||||
$this->register(2, NoteInstrument::SNARE);
|
||||
$this->register(3, NoteInstrument::CLICKS_AND_STICKS);
|
||||
$this->register(4, NoteInstrument::DOUBLE_BASS);
|
||||
$this->register(5, NoteInstrument::BELL);
|
||||
$this->register(6, NoteInstrument::FLUTE);
|
||||
$this->register(7, NoteInstrument::CHIME);
|
||||
$this->register(8, NoteInstrument::GUITAR);
|
||||
$this->register(9, NoteInstrument::XYLOPHONE);
|
||||
$this->register(10, NoteInstrument::IRON_XYLOPHONE);
|
||||
$this->register(11, NoteInstrument::COW_BELL);
|
||||
$this->register(12, NoteInstrument::DIDGERIDOO);
|
||||
$this->register(13, NoteInstrument::BIT);
|
||||
$this->register(14, NoteInstrument::BANJO);
|
||||
$this->register(15, NoteInstrument::PLING);
|
||||
foreach(NoteInstrument::cases() as $case){
|
||||
$this->register(match($case){
|
||||
NoteInstrument::PIANO => 0,
|
||||
NoteInstrument::BASS_DRUM => 1,
|
||||
NoteInstrument::SNARE => 2,
|
||||
NoteInstrument::CLICKS_AND_STICKS => 3,
|
||||
NoteInstrument::DOUBLE_BASS => 4,
|
||||
NoteInstrument::BELL => 5,
|
||||
NoteInstrument::FLUTE => 6,
|
||||
NoteInstrument::CHIME => 7,
|
||||
NoteInstrument::GUITAR => 8,
|
||||
NoteInstrument::XYLOPHONE => 9,
|
||||
NoteInstrument::IRON_XYLOPHONE => 10,
|
||||
NoteInstrument::COW_BELL => 11,
|
||||
NoteInstrument::DIDGERIDOO => 12,
|
||||
NoteInstrument::BIT => 13,
|
||||
NoteInstrument::BANJO => 14,
|
||||
NoteInstrument::PLING => 15,
|
||||
}, $case);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,48 +32,52 @@ final class PotionTypeIdMap{
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(PotionTypeIds::WATER, PotionType::WATER);
|
||||
$this->register(PotionTypeIds::MUNDANE, PotionType::MUNDANE);
|
||||
$this->register(PotionTypeIds::LONG_MUNDANE, PotionType::LONG_MUNDANE);
|
||||
$this->register(PotionTypeIds::THICK, PotionType::THICK);
|
||||
$this->register(PotionTypeIds::AWKWARD, PotionType::AWKWARD);
|
||||
$this->register(PotionTypeIds::NIGHT_VISION, PotionType::NIGHT_VISION);
|
||||
$this->register(PotionTypeIds::LONG_NIGHT_VISION, PotionType::LONG_NIGHT_VISION);
|
||||
$this->register(PotionTypeIds::INVISIBILITY, PotionType::INVISIBILITY);
|
||||
$this->register(PotionTypeIds::LONG_INVISIBILITY, PotionType::LONG_INVISIBILITY);
|
||||
$this->register(PotionTypeIds::LEAPING, PotionType::LEAPING);
|
||||
$this->register(PotionTypeIds::LONG_LEAPING, PotionType::LONG_LEAPING);
|
||||
$this->register(PotionTypeIds::STRONG_LEAPING, PotionType::STRONG_LEAPING);
|
||||
$this->register(PotionTypeIds::FIRE_RESISTANCE, PotionType::FIRE_RESISTANCE);
|
||||
$this->register(PotionTypeIds::LONG_FIRE_RESISTANCE, PotionType::LONG_FIRE_RESISTANCE);
|
||||
$this->register(PotionTypeIds::SWIFTNESS, PotionType::SWIFTNESS);
|
||||
$this->register(PotionTypeIds::LONG_SWIFTNESS, PotionType::LONG_SWIFTNESS);
|
||||
$this->register(PotionTypeIds::STRONG_SWIFTNESS, PotionType::STRONG_SWIFTNESS);
|
||||
$this->register(PotionTypeIds::SLOWNESS, PotionType::SLOWNESS);
|
||||
$this->register(PotionTypeIds::LONG_SLOWNESS, PotionType::LONG_SLOWNESS);
|
||||
$this->register(PotionTypeIds::WATER_BREATHING, PotionType::WATER_BREATHING);
|
||||
$this->register(PotionTypeIds::LONG_WATER_BREATHING, PotionType::LONG_WATER_BREATHING);
|
||||
$this->register(PotionTypeIds::HEALING, PotionType::HEALING);
|
||||
$this->register(PotionTypeIds::STRONG_HEALING, PotionType::STRONG_HEALING);
|
||||
$this->register(PotionTypeIds::HARMING, PotionType::HARMING);
|
||||
$this->register(PotionTypeIds::STRONG_HARMING, PotionType::STRONG_HARMING);
|
||||
$this->register(PotionTypeIds::POISON, PotionType::POISON);
|
||||
$this->register(PotionTypeIds::LONG_POISON, PotionType::LONG_POISON);
|
||||
$this->register(PotionTypeIds::STRONG_POISON, PotionType::STRONG_POISON);
|
||||
$this->register(PotionTypeIds::REGENERATION, PotionType::REGENERATION);
|
||||
$this->register(PotionTypeIds::LONG_REGENERATION, PotionType::LONG_REGENERATION);
|
||||
$this->register(PotionTypeIds::STRONG_REGENERATION, PotionType::STRONG_REGENERATION);
|
||||
$this->register(PotionTypeIds::STRENGTH, PotionType::STRENGTH);
|
||||
$this->register(PotionTypeIds::LONG_STRENGTH, PotionType::LONG_STRENGTH);
|
||||
$this->register(PotionTypeIds::STRONG_STRENGTH, PotionType::STRONG_STRENGTH);
|
||||
$this->register(PotionTypeIds::WEAKNESS, PotionType::WEAKNESS);
|
||||
$this->register(PotionTypeIds::LONG_WEAKNESS, PotionType::LONG_WEAKNESS);
|
||||
$this->register(PotionTypeIds::WITHER, PotionType::WITHER);
|
||||
$this->register(PotionTypeIds::TURTLE_MASTER, PotionType::TURTLE_MASTER);
|
||||
$this->register(PotionTypeIds::LONG_TURTLE_MASTER, PotionType::LONG_TURTLE_MASTER);
|
||||
$this->register(PotionTypeIds::STRONG_TURTLE_MASTER, PotionType::STRONG_TURTLE_MASTER);
|
||||
$this->register(PotionTypeIds::SLOW_FALLING, PotionType::SLOW_FALLING);
|
||||
$this->register(PotionTypeIds::LONG_SLOW_FALLING, PotionType::LONG_SLOW_FALLING);
|
||||
$this->register(PotionTypeIds::STRONG_SLOWNESS, PotionType::STRONG_SLOWNESS);
|
||||
foreach(PotionType::cases() as $case){
|
||||
$this->register(match($case){
|
||||
PotionType::WATER => PotionTypeIds::WATER,
|
||||
PotionType::MUNDANE => PotionTypeIds::MUNDANE,
|
||||
PotionType::LONG_MUNDANE => PotionTypeIds::LONG_MUNDANE,
|
||||
PotionType::THICK => PotionTypeIds::THICK,
|
||||
PotionType::AWKWARD => PotionTypeIds::AWKWARD,
|
||||
PotionType::NIGHT_VISION => PotionTypeIds::NIGHT_VISION,
|
||||
PotionType::LONG_NIGHT_VISION => PotionTypeIds::LONG_NIGHT_VISION,
|
||||
PotionType::INVISIBILITY => PotionTypeIds::INVISIBILITY,
|
||||
PotionType::LONG_INVISIBILITY => PotionTypeIds::LONG_INVISIBILITY,
|
||||
PotionType::LEAPING => PotionTypeIds::LEAPING,
|
||||
PotionType::LONG_LEAPING => PotionTypeIds::LONG_LEAPING,
|
||||
PotionType::STRONG_LEAPING => PotionTypeIds::STRONG_LEAPING,
|
||||
PotionType::FIRE_RESISTANCE => PotionTypeIds::FIRE_RESISTANCE,
|
||||
PotionType::LONG_FIRE_RESISTANCE => PotionTypeIds::LONG_FIRE_RESISTANCE,
|
||||
PotionType::SWIFTNESS => PotionTypeIds::SWIFTNESS,
|
||||
PotionType::LONG_SWIFTNESS => PotionTypeIds::LONG_SWIFTNESS,
|
||||
PotionType::STRONG_SWIFTNESS => PotionTypeIds::STRONG_SWIFTNESS,
|
||||
PotionType::SLOWNESS => PotionTypeIds::SLOWNESS,
|
||||
PotionType::LONG_SLOWNESS => PotionTypeIds::LONG_SLOWNESS,
|
||||
PotionType::WATER_BREATHING => PotionTypeIds::WATER_BREATHING,
|
||||
PotionType::LONG_WATER_BREATHING => PotionTypeIds::LONG_WATER_BREATHING,
|
||||
PotionType::HEALING => PotionTypeIds::HEALING,
|
||||
PotionType::STRONG_HEALING => PotionTypeIds::STRONG_HEALING,
|
||||
PotionType::HARMING => PotionTypeIds::HARMING,
|
||||
PotionType::STRONG_HARMING => PotionTypeIds::STRONG_HARMING,
|
||||
PotionType::POISON => PotionTypeIds::POISON,
|
||||
PotionType::LONG_POISON => PotionTypeIds::LONG_POISON,
|
||||
PotionType::STRONG_POISON => PotionTypeIds::STRONG_POISON,
|
||||
PotionType::REGENERATION => PotionTypeIds::REGENERATION,
|
||||
PotionType::LONG_REGENERATION => PotionTypeIds::LONG_REGENERATION,
|
||||
PotionType::STRONG_REGENERATION => PotionTypeIds::STRONG_REGENERATION,
|
||||
PotionType::STRENGTH => PotionTypeIds::STRENGTH,
|
||||
PotionType::LONG_STRENGTH => PotionTypeIds::LONG_STRENGTH,
|
||||
PotionType::STRONG_STRENGTH => PotionTypeIds::STRONG_STRENGTH,
|
||||
PotionType::WEAKNESS => PotionTypeIds::WEAKNESS,
|
||||
PotionType::LONG_WEAKNESS => PotionTypeIds::LONG_WEAKNESS,
|
||||
PotionType::WITHER => PotionTypeIds::WITHER,
|
||||
PotionType::TURTLE_MASTER => PotionTypeIds::TURTLE_MASTER,
|
||||
PotionType::LONG_TURTLE_MASTER => PotionTypeIds::LONG_TURTLE_MASTER,
|
||||
PotionType::STRONG_TURTLE_MASTER => PotionTypeIds::STRONG_TURTLE_MASTER,
|
||||
PotionType::SLOW_FALLING => PotionTypeIds::SLOW_FALLING,
|
||||
PotionType::LONG_SLOW_FALLING => PotionTypeIds::LONG_SLOW_FALLING,
|
||||
PotionType::STRONG_SLOWNESS => PotionTypeIds::STRONG_SLOWNESS,
|
||||
}, $case);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,15 +32,20 @@ final class SuspiciousStewTypeIdMap{
|
||||
use IntSaveIdMapTrait;
|
||||
|
||||
private function __construct(){
|
||||
$this->register(SuspiciousStewTypeIds::POPPY, SuspiciousStewType::POPPY);
|
||||
$this->register(SuspiciousStewTypeIds::CORNFLOWER, SuspiciousStewType::CORNFLOWER);
|
||||
$this->register(SuspiciousStewTypeIds::TULIP, SuspiciousStewType::TULIP);
|
||||
$this->register(SuspiciousStewTypeIds::AZURE_BLUET, SuspiciousStewType::AZURE_BLUET);
|
||||
$this->register(SuspiciousStewTypeIds::LILY_OF_THE_VALLEY, SuspiciousStewType::LILY_OF_THE_VALLEY);
|
||||
$this->register(SuspiciousStewTypeIds::DANDELION, SuspiciousStewType::DANDELION);
|
||||
$this->register(SuspiciousStewTypeIds::BLUE_ORCHID, SuspiciousStewType::BLUE_ORCHID);
|
||||
$this->register(SuspiciousStewTypeIds::ALLIUM, SuspiciousStewType::ALLIUM);
|
||||
$this->register(SuspiciousStewTypeIds::OXEYE_DAISY, SuspiciousStewType::OXEYE_DAISY);
|
||||
$this->register(SuspiciousStewTypeIds::WITHER_ROSE, SuspiciousStewType::WITHER_ROSE);
|
||||
foreach(SuspiciousStewType::cases() as $case){
|
||||
$this->register(match($case){
|
||||
SuspiciousStewType::POPPY => SuspiciousStewTypeIds::POPPY,
|
||||
SuspiciousStewType::CORNFLOWER => SuspiciousStewTypeIds::CORNFLOWER,
|
||||
SuspiciousStewType::TULIP => SuspiciousStewTypeIds::TULIP,
|
||||
SuspiciousStewType::AZURE_BLUET => SuspiciousStewTypeIds::AZURE_BLUET,
|
||||
SuspiciousStewType::LILY_OF_THE_VALLEY => SuspiciousStewTypeIds::LILY_OF_THE_VALLEY,
|
||||
SuspiciousStewType::DANDELION => SuspiciousStewTypeIds::DANDELION,
|
||||
SuspiciousStewType::BLUE_ORCHID => SuspiciousStewTypeIds::BLUE_ORCHID,
|
||||
SuspiciousStewType::ALLIUM => SuspiciousStewTypeIds::ALLIUM,
|
||||
SuspiciousStewType::OXEYE_DAISY => SuspiciousStewTypeIds::OXEYE_DAISY,
|
||||
SuspiciousStewType::WITHER_ROSE => SuspiciousStewTypeIds::WITHER_ROSE,
|
||||
}, $case);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ final class BlockStateData{
|
||||
public const CURRENT_VERSION =
|
||||
(1 << 24) | //major
|
||||
(20 << 16) | //minor
|
||||
(50 << 8) | //patch
|
||||
(1); //revision
|
||||
(80 << 8) | //patch
|
||||
(3); //revision
|
||||
|
||||
public const TAG_NAME = "name";
|
||||
public const TAG_STATES = "states";
|
||||
|
@ -56,7 +56,6 @@ final class BlockStateNames{
|
||||
public const CHEMISTRY_TABLE_TYPE = "chemistry_table_type";
|
||||
public const CHISEL_TYPE = "chisel_type";
|
||||
public const CLUSTER_COUNT = "cluster_count";
|
||||
public const COLOR = "color";
|
||||
public const COLOR_BIT = "color_bit";
|
||||
public const COMPOSTER_FILL_LEVEL = "composter_fill_level";
|
||||
public const CONDITIONAL_BIT = "conditional_bit";
|
||||
@ -82,7 +81,6 @@ final class BlockStateNames{
|
||||
public const EXTINGUISHED = "extinguished";
|
||||
public const FACING_DIRECTION = "facing_direction";
|
||||
public const FILL_LEVEL = "fill_level";
|
||||
public const FLOWER_TYPE = "flower_type";
|
||||
public const GROUND_SIGN_DIRECTION = "ground_sign_direction";
|
||||
public const GROWING_PLANT_AGE = "growing_plant_age";
|
||||
public const GROWTH = "growth";
|
||||
@ -106,9 +104,7 @@ final class BlockStateNames{
|
||||
public const MOISTURIZED_AMOUNT = "moisturized_amount";
|
||||
public const MONSTER_EGG_STONE_TYPE = "monster_egg_stone_type";
|
||||
public const MULTI_FACE_DIRECTION_BITS = "multi_face_direction_bits";
|
||||
public const NEW_LEAF_TYPE = "new_leaf_type";
|
||||
public const OCCUPIED_BIT = "occupied_bit";
|
||||
public const OLD_LEAF_TYPE = "old_leaf_type";
|
||||
public const OPEN_BIT = "open_bit";
|
||||
public const ORIENTATION = "orientation";
|
||||
public const OUTPUT_LIT_BIT = "output_lit_bit";
|
||||
@ -127,7 +123,6 @@ final class BlockStateNames{
|
||||
public const ROTATION = "rotation";
|
||||
public const SAND_STONE_TYPE = "sand_stone_type";
|
||||
public const SAND_TYPE = "sand_type";
|
||||
public const SAPLING_TYPE = "sapling_type";
|
||||
public const SCULK_SENSOR_PHASE = "sculk_sensor_phase";
|
||||
public const SEA_GRASS_TYPE = "sea_grass_type";
|
||||
public const SPONGE_TYPE = "sponge_type";
|
||||
@ -145,12 +140,14 @@ final class BlockStateNames{
|
||||
public const TALL_GRASS_TYPE = "tall_grass_type";
|
||||
public const TOGGLE_BIT = "toggle_bit";
|
||||
public const TORCH_FACING_DIRECTION = "torch_facing_direction";
|
||||
public const TRIAL_SPAWNER_STATE = "trial_spawner_state";
|
||||
public const TRIGGERED_BIT = "triggered_bit";
|
||||
public const TURTLE_EGG_COUNT = "turtle_egg_count";
|
||||
public const TWISTING_VINES_AGE = "twisting_vines_age";
|
||||
public const UPDATE_BIT = "update_bit";
|
||||
public const UPPER_BLOCK_BIT = "upper_block_bit";
|
||||
public const UPSIDE_DOWN_BIT = "upside_down_bit";
|
||||
public const VAULT_STATE = "vault_state";
|
||||
public const VINE_DIRECTION_BITS = "vine_direction_bits";
|
||||
public const WALL_BLOCK_TYPE = "wall_block_type";
|
||||
public const WALL_CONNECTION_TYPE_EAST = "wall_connection_type_east";
|
||||
@ -160,5 +157,4 @@ final class BlockStateNames{
|
||||
public const WALL_POST_BIT = "wall_post_bit";
|
||||
public const WEEPING_VINES_AGE = "weeping_vines_age";
|
||||
public const WEIRDO_DIRECTION = "weirdo_direction";
|
||||
public const WOOD_TYPE = "wood_type";
|
||||
}
|
||||
|
@ -62,23 +62,6 @@ final class BlockStateStringValues{
|
||||
public const CHISEL_TYPE_LINES = "lines";
|
||||
public const CHISEL_TYPE_SMOOTH = "smooth";
|
||||
|
||||
public const COLOR_BLACK = "black";
|
||||
public const COLOR_BLUE = "blue";
|
||||
public const COLOR_BROWN = "brown";
|
||||
public const COLOR_CYAN = "cyan";
|
||||
public const COLOR_GRAY = "gray";
|
||||
public const COLOR_GREEN = "green";
|
||||
public const COLOR_LIGHT_BLUE = "light_blue";
|
||||
public const COLOR_LIME = "lime";
|
||||
public const COLOR_MAGENTA = "magenta";
|
||||
public const COLOR_ORANGE = "orange";
|
||||
public const COLOR_PINK = "pink";
|
||||
public const COLOR_PURPLE = "purple";
|
||||
public const COLOR_RED = "red";
|
||||
public const COLOR_SILVER = "silver";
|
||||
public const COLOR_WHITE = "white";
|
||||
public const COLOR_YELLOW = "yellow";
|
||||
|
||||
public const CORAL_COLOR_BLUE = "blue";
|
||||
public const CORAL_COLOR_PINK = "pink";
|
||||
public const CORAL_COLOR_PURPLE = "purple";
|
||||
@ -110,18 +93,6 @@ final class BlockStateStringValues{
|
||||
public const DRIPSTONE_THICKNESS_MIDDLE = "middle";
|
||||
public const DRIPSTONE_THICKNESS_TIP = "tip";
|
||||
|
||||
public const FLOWER_TYPE_ALLIUM = "allium";
|
||||
public const FLOWER_TYPE_CORNFLOWER = "cornflower";
|
||||
public const FLOWER_TYPE_HOUSTONIA = "houstonia";
|
||||
public const FLOWER_TYPE_LILY_OF_THE_VALLEY = "lily_of_the_valley";
|
||||
public const FLOWER_TYPE_ORCHID = "orchid";
|
||||
public const FLOWER_TYPE_OXEYE = "oxeye";
|
||||
public const FLOWER_TYPE_POPPY = "poppy";
|
||||
public const FLOWER_TYPE_TULIP_ORANGE = "tulip_orange";
|
||||
public const FLOWER_TYPE_TULIP_PINK = "tulip_pink";
|
||||
public const FLOWER_TYPE_TULIP_RED = "tulip_red";
|
||||
public const FLOWER_TYPE_TULIP_WHITE = "tulip_white";
|
||||
|
||||
public const LEVER_DIRECTION_DOWN_EAST_WEST = "down_east_west";
|
||||
public const LEVER_DIRECTION_DOWN_NORTH_SOUTH = "down_north_south";
|
||||
public const LEVER_DIRECTION_EAST = "east";
|
||||
@ -160,14 +131,6 @@ final class BlockStateStringValues{
|
||||
public const MONSTER_EGG_STONE_TYPE_STONE = "stone";
|
||||
public const MONSTER_EGG_STONE_TYPE_STONE_BRICK = "stone_brick";
|
||||
|
||||
public const NEW_LEAF_TYPE_ACACIA = "acacia";
|
||||
public const NEW_LEAF_TYPE_DARK_OAK = "dark_oak";
|
||||
|
||||
public const OLD_LEAF_TYPE_BIRCH = "birch";
|
||||
public const OLD_LEAF_TYPE_JUNGLE = "jungle";
|
||||
public const OLD_LEAF_TYPE_OAK = "oak";
|
||||
public const OLD_LEAF_TYPE_SPRUCE = "spruce";
|
||||
|
||||
public const ORIENTATION_DOWN_EAST = "down_east";
|
||||
public const ORIENTATION_DOWN_NORTH = "down_north";
|
||||
public const ORIENTATION_DOWN_SOUTH = "down_south";
|
||||
@ -201,13 +164,6 @@ final class BlockStateStringValues{
|
||||
public const SAND_TYPE_NORMAL = "normal";
|
||||
public const SAND_TYPE_RED = "red";
|
||||
|
||||
public const SAPLING_TYPE_ACACIA = "acacia";
|
||||
public const SAPLING_TYPE_BIRCH = "birch";
|
||||
public const SAPLING_TYPE_DARK_OAK = "dark_oak";
|
||||
public const SAPLING_TYPE_JUNGLE = "jungle";
|
||||
public const SAPLING_TYPE_OAK = "oak";
|
||||
public const SAPLING_TYPE_SPRUCE = "spruce";
|
||||
|
||||
public const SEA_GRASS_TYPE_DEFAULT = "default";
|
||||
public const SEA_GRASS_TYPE_DOUBLE_BOT = "double_bot";
|
||||
public const SEA_GRASS_TYPE_DOUBLE_TOP = "double_top";
|
||||
@ -281,6 +237,11 @@ final class BlockStateStringValues{
|
||||
public const TURTLE_EGG_COUNT_THREE_EGG = "three_egg";
|
||||
public const TURTLE_EGG_COUNT_TWO_EGG = "two_egg";
|
||||
|
||||
public const VAULT_STATE_ACTIVE = "active";
|
||||
public const VAULT_STATE_EJECTING = "ejecting";
|
||||
public const VAULT_STATE_INACTIVE = "inactive";
|
||||
public const VAULT_STATE_UNLOCKING = "unlocking";
|
||||
|
||||
public const WALL_BLOCK_TYPE_ANDESITE = "andesite";
|
||||
public const WALL_BLOCK_TYPE_BRICK = "brick";
|
||||
public const WALL_BLOCK_TYPE_COBBLESTONE = "cobblestone";
|
||||
@ -312,11 +273,4 @@ final class BlockStateStringValues{
|
||||
public const WALL_CONNECTION_TYPE_WEST_SHORT = "short";
|
||||
public const WALL_CONNECTION_TYPE_WEST_TALL = "tall";
|
||||
|
||||
public const WOOD_TYPE_ACACIA = "acacia";
|
||||
public const WOOD_TYPE_BIRCH = "birch";
|
||||
public const WOOD_TYPE_DARK_OAK = "dark_oak";
|
||||
public const WOOD_TYPE_JUNGLE = "jungle";
|
||||
public const WOOD_TYPE_OAK = "oak";
|
||||
public const WOOD_TYPE_SPRUCE = "spruce";
|
||||
|
||||
}
|
||||
|
@ -33,18 +33,24 @@ final class BlockTypeNames{
|
||||
|
||||
public const ACACIA_BUTTON = "minecraft:acacia_button";
|
||||
public const ACACIA_DOOR = "minecraft:acacia_door";
|
||||
public const ACACIA_DOUBLE_SLAB = "minecraft:acacia_double_slab";
|
||||
public const ACACIA_FENCE = "minecraft:acacia_fence";
|
||||
public const ACACIA_FENCE_GATE = "minecraft:acacia_fence_gate";
|
||||
public const ACACIA_HANGING_SIGN = "minecraft:acacia_hanging_sign";
|
||||
public const ACACIA_LEAVES = "minecraft:acacia_leaves";
|
||||
public const ACACIA_LOG = "minecraft:acacia_log";
|
||||
public const ACACIA_PLANKS = "minecraft:acacia_planks";
|
||||
public const ACACIA_PRESSURE_PLATE = "minecraft:acacia_pressure_plate";
|
||||
public const ACACIA_SAPLING = "minecraft:acacia_sapling";
|
||||
public const ACACIA_SLAB = "minecraft:acacia_slab";
|
||||
public const ACACIA_STAIRS = "minecraft:acacia_stairs";
|
||||
public const ACACIA_STANDING_SIGN = "minecraft:acacia_standing_sign";
|
||||
public const ACACIA_TRAPDOOR = "minecraft:acacia_trapdoor";
|
||||
public const ACACIA_WALL_SIGN = "minecraft:acacia_wall_sign";
|
||||
public const ACACIA_WOOD = "minecraft:acacia_wood";
|
||||
public const ACTIVATOR_RAIL = "minecraft:activator_rail";
|
||||
public const AIR = "minecraft:air";
|
||||
public const ALLIUM = "minecraft:allium";
|
||||
public const ALLOW = "minecraft:allow";
|
||||
public const AMETHYST_BLOCK = "minecraft:amethyst_block";
|
||||
public const AMETHYST_CLUSTER = "minecraft:amethyst_cluster";
|
||||
@ -55,6 +61,7 @@ final class BlockTypeNames{
|
||||
public const AZALEA = "minecraft:azalea";
|
||||
public const AZALEA_LEAVES = "minecraft:azalea_leaves";
|
||||
public const AZALEA_LEAVES_FLOWERED = "minecraft:azalea_leaves_flowered";
|
||||
public const AZURE_BLUET = "minecraft:azure_bluet";
|
||||
public const BAMBOO = "minecraft:bamboo";
|
||||
public const BAMBOO_BLOCK = "minecraft:bamboo_block";
|
||||
public const BAMBOO_BUTTON = "minecraft:bamboo_button";
|
||||
@ -88,16 +95,21 @@ final class BlockTypeNames{
|
||||
public const BIG_DRIPLEAF = "minecraft:big_dripleaf";
|
||||
public const BIRCH_BUTTON = "minecraft:birch_button";
|
||||
public const BIRCH_DOOR = "minecraft:birch_door";
|
||||
public const BIRCH_DOUBLE_SLAB = "minecraft:birch_double_slab";
|
||||
public const BIRCH_FENCE = "minecraft:birch_fence";
|
||||
public const BIRCH_FENCE_GATE = "minecraft:birch_fence_gate";
|
||||
public const BIRCH_HANGING_SIGN = "minecraft:birch_hanging_sign";
|
||||
public const BIRCH_LEAVES = "minecraft:birch_leaves";
|
||||
public const BIRCH_LOG = "minecraft:birch_log";
|
||||
public const BIRCH_PLANKS = "minecraft:birch_planks";
|
||||
public const BIRCH_PRESSURE_PLATE = "minecraft:birch_pressure_plate";
|
||||
public const BIRCH_SAPLING = "minecraft:birch_sapling";
|
||||
public const BIRCH_SLAB = "minecraft:birch_slab";
|
||||
public const BIRCH_STAIRS = "minecraft:birch_stairs";
|
||||
public const BIRCH_STANDING_SIGN = "minecraft:birch_standing_sign";
|
||||
public const BIRCH_TRAPDOOR = "minecraft:birch_trapdoor";
|
||||
public const BIRCH_WALL_SIGN = "minecraft:birch_wall_sign";
|
||||
public const BIRCH_WOOD = "minecraft:birch_wood";
|
||||
public const BLACK_CANDLE = "minecraft:black_candle";
|
||||
public const BLACK_CANDLE_CAKE = "minecraft:black_candle_cake";
|
||||
public const BLACK_CARPET = "minecraft:black_carpet";
|
||||
@ -122,6 +134,7 @@ final class BlockTypeNames{
|
||||
public const BLUE_CONCRETE_POWDER = "minecraft:blue_concrete_powder";
|
||||
public const BLUE_GLAZED_TERRACOTTA = "minecraft:blue_glazed_terracotta";
|
||||
public const BLUE_ICE = "minecraft:blue_ice";
|
||||
public const BLUE_ORCHID = "minecraft:blue_orchid";
|
||||
public const BLUE_SHULKER_BOX = "minecraft:blue_shulker_box";
|
||||
public const BLUE_STAINED_GLASS = "minecraft:blue_stained_glass";
|
||||
public const BLUE_STAINED_GLASS_PANE = "minecraft:blue_stained_glass_pane";
|
||||
@ -131,6 +144,7 @@ final class BlockTypeNames{
|
||||
public const BOOKSHELF = "minecraft:bookshelf";
|
||||
public const BORDER_BLOCK = "minecraft:border_block";
|
||||
public const BRAIN_CORAL = "minecraft:brain_coral";
|
||||
public const BRAIN_CORAL_FAN = "minecraft:brain_coral_fan";
|
||||
public const BREWING_STAND = "minecraft:brewing_stand";
|
||||
public const BRICK_BLOCK = "minecraft:brick_block";
|
||||
public const BRICK_STAIRS = "minecraft:brick_stairs";
|
||||
@ -149,6 +163,7 @@ final class BlockTypeNames{
|
||||
public const BROWN_WOOL = "minecraft:brown_wool";
|
||||
public const BUBBLE_COLUMN = "minecraft:bubble_column";
|
||||
public const BUBBLE_CORAL = "minecraft:bubble_coral";
|
||||
public const BUBBLE_CORAL_FAN = "minecraft:bubble_coral_fan";
|
||||
public const BUDDING_AMETHYST = "minecraft:budding_amethyst";
|
||||
public const CACTUS = "minecraft:cactus";
|
||||
public const CAKE = "minecraft:cake";
|
||||
@ -220,11 +235,10 @@ final class BlockTypeNames{
|
||||
public const COPPER_ORE = "minecraft:copper_ore";
|
||||
public const COPPER_TRAPDOOR = "minecraft:copper_trapdoor";
|
||||
public const CORAL_BLOCK = "minecraft:coral_block";
|
||||
public const CORAL_FAN = "minecraft:coral_fan";
|
||||
public const CORAL_FAN_DEAD = "minecraft:coral_fan_dead";
|
||||
public const CORAL_FAN_HANG = "minecraft:coral_fan_hang";
|
||||
public const CORAL_FAN_HANG2 = "minecraft:coral_fan_hang2";
|
||||
public const CORAL_FAN_HANG3 = "minecraft:coral_fan_hang3";
|
||||
public const CORNFLOWER = "minecraft:cornflower";
|
||||
public const CRACKED_DEEPSLATE_BRICKS = "minecraft:cracked_deepslate_bricks";
|
||||
public const CRACKED_DEEPSLATE_TILES = "minecraft:cracked_deepslate_tiles";
|
||||
public const CRACKED_NETHER_BRICKS = "minecraft:cracked_nether_bricks";
|
||||
@ -266,24 +280,34 @@ final class BlockTypeNames{
|
||||
public const CYAN_WOOL = "minecraft:cyan_wool";
|
||||
public const DARK_OAK_BUTTON = "minecraft:dark_oak_button";
|
||||
public const DARK_OAK_DOOR = "minecraft:dark_oak_door";
|
||||
public const DARK_OAK_DOUBLE_SLAB = "minecraft:dark_oak_double_slab";
|
||||
public const DARK_OAK_FENCE = "minecraft:dark_oak_fence";
|
||||
public const DARK_OAK_FENCE_GATE = "minecraft:dark_oak_fence_gate";
|
||||
public const DARK_OAK_HANGING_SIGN = "minecraft:dark_oak_hanging_sign";
|
||||
public const DARK_OAK_LEAVES = "minecraft:dark_oak_leaves";
|
||||
public const DARK_OAK_LOG = "minecraft:dark_oak_log";
|
||||
public const DARK_OAK_PLANKS = "minecraft:dark_oak_planks";
|
||||
public const DARK_OAK_PRESSURE_PLATE = "minecraft:dark_oak_pressure_plate";
|
||||
public const DARK_OAK_SAPLING = "minecraft:dark_oak_sapling";
|
||||
public const DARK_OAK_SLAB = "minecraft:dark_oak_slab";
|
||||
public const DARK_OAK_STAIRS = "minecraft:dark_oak_stairs";
|
||||
public const DARK_OAK_TRAPDOOR = "minecraft:dark_oak_trapdoor";
|
||||
public const DARK_OAK_WOOD = "minecraft:dark_oak_wood";
|
||||
public const DARK_PRISMARINE_STAIRS = "minecraft:dark_prismarine_stairs";
|
||||
public const DARKOAK_STANDING_SIGN = "minecraft:darkoak_standing_sign";
|
||||
public const DARKOAK_WALL_SIGN = "minecraft:darkoak_wall_sign";
|
||||
public const DAYLIGHT_DETECTOR = "minecraft:daylight_detector";
|
||||
public const DAYLIGHT_DETECTOR_INVERTED = "minecraft:daylight_detector_inverted";
|
||||
public const DEAD_BRAIN_CORAL = "minecraft:dead_brain_coral";
|
||||
public const DEAD_BRAIN_CORAL_FAN = "minecraft:dead_brain_coral_fan";
|
||||
public const DEAD_BUBBLE_CORAL = "minecraft:dead_bubble_coral";
|
||||
public const DEAD_BUBBLE_CORAL_FAN = "minecraft:dead_bubble_coral_fan";
|
||||
public const DEAD_FIRE_CORAL = "minecraft:dead_fire_coral";
|
||||
public const DEAD_FIRE_CORAL_FAN = "minecraft:dead_fire_coral_fan";
|
||||
public const DEAD_HORN_CORAL = "minecraft:dead_horn_coral";
|
||||
public const DEAD_HORN_CORAL_FAN = "minecraft:dead_horn_coral_fan";
|
||||
public const DEAD_TUBE_CORAL = "minecraft:dead_tube_coral";
|
||||
public const DEAD_TUBE_CORAL_FAN = "minecraft:dead_tube_coral_fan";
|
||||
public const DEADBUSH = "minecraft:deadbush";
|
||||
public const DECORATED_POT = "minecraft:decorated_pot";
|
||||
public const DEEPSLATE = "minecraft:deepslate";
|
||||
@ -320,7 +344,6 @@ final class BlockTypeNames{
|
||||
public const DOUBLE_STONE_BLOCK_SLAB2 = "minecraft:double_stone_block_slab2";
|
||||
public const DOUBLE_STONE_BLOCK_SLAB3 = "minecraft:double_stone_block_slab3";
|
||||
public const DOUBLE_STONE_BLOCK_SLAB4 = "minecraft:double_stone_block_slab4";
|
||||
public const DOUBLE_WOODEN_SLAB = "minecraft:double_wooden_slab";
|
||||
public const DRAGON_EGG = "minecraft:dragon_egg";
|
||||
public const DRIED_KELP_BLOCK = "minecraft:dried_kelp_block";
|
||||
public const DRIPSTONE_BLOCK = "minecraft:dripstone_block";
|
||||
@ -469,6 +492,7 @@ final class BlockTypeNames{
|
||||
public const FENCE_GATE = "minecraft:fence_gate";
|
||||
public const FIRE = "minecraft:fire";
|
||||
public const FIRE_CORAL = "minecraft:fire_coral";
|
||||
public const FIRE_CORAL_FAN = "minecraft:fire_coral_fan";
|
||||
public const FLETCHING_TABLE = "minecraft:fletching_table";
|
||||
public const FLOWER_POT = "minecraft:flower_pot";
|
||||
public const FLOWERING_AZALEA = "minecraft:flowering_azalea";
|
||||
@ -490,7 +514,7 @@ final class BlockTypeNames{
|
||||
public const GOLDEN_RAIL = "minecraft:golden_rail";
|
||||
public const GRANITE = "minecraft:granite";
|
||||
public const GRANITE_STAIRS = "minecraft:granite_stairs";
|
||||
public const GRASS = "minecraft:grass";
|
||||
public const GRASS_BLOCK = "minecraft:grass_block";
|
||||
public const GRASS_PATH = "minecraft:grass_path";
|
||||
public const GRAVEL = "minecraft:gravel";
|
||||
public const GRAY_CANDLE = "minecraft:gray_candle";
|
||||
@ -517,17 +541,49 @@ final class BlockTypeNames{
|
||||
public const GREEN_WOOL = "minecraft:green_wool";
|
||||
public const GRINDSTONE = "minecraft:grindstone";
|
||||
public const HANGING_ROOTS = "minecraft:hanging_roots";
|
||||
public const HARD_BLACK_STAINED_GLASS = "minecraft:hard_black_stained_glass";
|
||||
public const HARD_BLACK_STAINED_GLASS_PANE = "minecraft:hard_black_stained_glass_pane";
|
||||
public const HARD_BLUE_STAINED_GLASS = "minecraft:hard_blue_stained_glass";
|
||||
public const HARD_BLUE_STAINED_GLASS_PANE = "minecraft:hard_blue_stained_glass_pane";
|
||||
public const HARD_BROWN_STAINED_GLASS = "minecraft:hard_brown_stained_glass";
|
||||
public const HARD_BROWN_STAINED_GLASS_PANE = "minecraft:hard_brown_stained_glass_pane";
|
||||
public const HARD_CYAN_STAINED_GLASS = "minecraft:hard_cyan_stained_glass";
|
||||
public const HARD_CYAN_STAINED_GLASS_PANE = "minecraft:hard_cyan_stained_glass_pane";
|
||||
public const HARD_GLASS = "minecraft:hard_glass";
|
||||
public const HARD_GLASS_PANE = "minecraft:hard_glass_pane";
|
||||
public const HARD_STAINED_GLASS = "minecraft:hard_stained_glass";
|
||||
public const HARD_STAINED_GLASS_PANE = "minecraft:hard_stained_glass_pane";
|
||||
public const HARD_GRAY_STAINED_GLASS = "minecraft:hard_gray_stained_glass";
|
||||
public const HARD_GRAY_STAINED_GLASS_PANE = "minecraft:hard_gray_stained_glass_pane";
|
||||
public const HARD_GREEN_STAINED_GLASS = "minecraft:hard_green_stained_glass";
|
||||
public const HARD_GREEN_STAINED_GLASS_PANE = "minecraft:hard_green_stained_glass_pane";
|
||||
public const HARD_LIGHT_BLUE_STAINED_GLASS = "minecraft:hard_light_blue_stained_glass";
|
||||
public const HARD_LIGHT_BLUE_STAINED_GLASS_PANE = "minecraft:hard_light_blue_stained_glass_pane";
|
||||
public const HARD_LIGHT_GRAY_STAINED_GLASS = "minecraft:hard_light_gray_stained_glass";
|
||||
public const HARD_LIGHT_GRAY_STAINED_GLASS_PANE = "minecraft:hard_light_gray_stained_glass_pane";
|
||||
public const HARD_LIME_STAINED_GLASS = "minecraft:hard_lime_stained_glass";
|
||||
public const HARD_LIME_STAINED_GLASS_PANE = "minecraft:hard_lime_stained_glass_pane";
|
||||
public const HARD_MAGENTA_STAINED_GLASS = "minecraft:hard_magenta_stained_glass";
|
||||
public const HARD_MAGENTA_STAINED_GLASS_PANE = "minecraft:hard_magenta_stained_glass_pane";
|
||||
public const HARD_ORANGE_STAINED_GLASS = "minecraft:hard_orange_stained_glass";
|
||||
public const HARD_ORANGE_STAINED_GLASS_PANE = "minecraft:hard_orange_stained_glass_pane";
|
||||
public const HARD_PINK_STAINED_GLASS = "minecraft:hard_pink_stained_glass";
|
||||
public const HARD_PINK_STAINED_GLASS_PANE = "minecraft:hard_pink_stained_glass_pane";
|
||||
public const HARD_PURPLE_STAINED_GLASS = "minecraft:hard_purple_stained_glass";
|
||||
public const HARD_PURPLE_STAINED_GLASS_PANE = "minecraft:hard_purple_stained_glass_pane";
|
||||
public const HARD_RED_STAINED_GLASS = "minecraft:hard_red_stained_glass";
|
||||
public const HARD_RED_STAINED_GLASS_PANE = "minecraft:hard_red_stained_glass_pane";
|
||||
public const HARD_WHITE_STAINED_GLASS = "minecraft:hard_white_stained_glass";
|
||||
public const HARD_WHITE_STAINED_GLASS_PANE = "minecraft:hard_white_stained_glass_pane";
|
||||
public const HARD_YELLOW_STAINED_GLASS = "minecraft:hard_yellow_stained_glass";
|
||||
public const HARD_YELLOW_STAINED_GLASS_PANE = "minecraft:hard_yellow_stained_glass_pane";
|
||||
public const HARDENED_CLAY = "minecraft:hardened_clay";
|
||||
public const HAY_BLOCK = "minecraft:hay_block";
|
||||
public const HEAVY_CORE = "minecraft:heavy_core";
|
||||
public const HEAVY_WEIGHTED_PRESSURE_PLATE = "minecraft:heavy_weighted_pressure_plate";
|
||||
public const HONEY_BLOCK = "minecraft:honey_block";
|
||||
public const HONEYCOMB_BLOCK = "minecraft:honeycomb_block";
|
||||
public const HOPPER = "minecraft:hopper";
|
||||
public const HORN_CORAL = "minecraft:horn_coral";
|
||||
public const HORN_CORAL_FAN = "minecraft:horn_coral_fan";
|
||||
public const ICE = "minecraft:ice";
|
||||
public const INFESTED_DEEPSLATE = "minecraft:infested_deepslate";
|
||||
public const INFO_UPDATE = "minecraft:info_update";
|
||||
@ -542,16 +598,21 @@ final class BlockTypeNames{
|
||||
public const JUKEBOX = "minecraft:jukebox";
|
||||
public const JUNGLE_BUTTON = "minecraft:jungle_button";
|
||||
public const JUNGLE_DOOR = "minecraft:jungle_door";
|
||||
public const JUNGLE_DOUBLE_SLAB = "minecraft:jungle_double_slab";
|
||||
public const JUNGLE_FENCE = "minecraft:jungle_fence";
|
||||
public const JUNGLE_FENCE_GATE = "minecraft:jungle_fence_gate";
|
||||
public const JUNGLE_HANGING_SIGN = "minecraft:jungle_hanging_sign";
|
||||
public const JUNGLE_LEAVES = "minecraft:jungle_leaves";
|
||||
public const JUNGLE_LOG = "minecraft:jungle_log";
|
||||
public const JUNGLE_PLANKS = "minecraft:jungle_planks";
|
||||
public const JUNGLE_PRESSURE_PLATE = "minecraft:jungle_pressure_plate";
|
||||
public const JUNGLE_SAPLING = "minecraft:jungle_sapling";
|
||||
public const JUNGLE_SLAB = "minecraft:jungle_slab";
|
||||
public const JUNGLE_STAIRS = "minecraft:jungle_stairs";
|
||||
public const JUNGLE_STANDING_SIGN = "minecraft:jungle_standing_sign";
|
||||
public const JUNGLE_TRAPDOOR = "minecraft:jungle_trapdoor";
|
||||
public const JUNGLE_WALL_SIGN = "minecraft:jungle_wall_sign";
|
||||
public const JUNGLE_WOOD = "minecraft:jungle_wood";
|
||||
public const KELP = "minecraft:kelp";
|
||||
public const LADDER = "minecraft:ladder";
|
||||
public const LANTERN = "minecraft:lantern";
|
||||
@ -559,8 +620,6 @@ final class BlockTypeNames{
|
||||
public const LAPIS_ORE = "minecraft:lapis_ore";
|
||||
public const LARGE_AMETHYST_BUD = "minecraft:large_amethyst_bud";
|
||||
public const LAVA = "minecraft:lava";
|
||||
public const LEAVES = "minecraft:leaves";
|
||||
public const LEAVES2 = "minecraft:leaves2";
|
||||
public const LECTERN = "minecraft:lectern";
|
||||
public const LEVER = "minecraft:lever";
|
||||
public const LIGHT_BLOCK = "minecraft:light_block";
|
||||
@ -587,6 +646,7 @@ final class BlockTypeNames{
|
||||
public const LIGHT_GRAY_WOOL = "minecraft:light_gray_wool";
|
||||
public const LIGHT_WEIGHTED_PRESSURE_PLATE = "minecraft:light_weighted_pressure_plate";
|
||||
public const LIGHTNING_ROD = "minecraft:lightning_rod";
|
||||
public const LILY_OF_THE_VALLEY = "minecraft:lily_of_the_valley";
|
||||
public const LIME_CANDLE = "minecraft:lime_candle";
|
||||
public const LIME_CANDLE_CAKE = "minecraft:lime_candle_cake";
|
||||
public const LIME_CARPET = "minecraft:lime_carpet";
|
||||
@ -668,11 +728,16 @@ final class BlockTypeNames{
|
||||
public const NETHERREACTOR = "minecraft:netherreactor";
|
||||
public const NORMAL_STONE_STAIRS = "minecraft:normal_stone_stairs";
|
||||
public const NOTEBLOCK = "minecraft:noteblock";
|
||||
public const OAK_DOUBLE_SLAB = "minecraft:oak_double_slab";
|
||||
public const OAK_FENCE = "minecraft:oak_fence";
|
||||
public const OAK_HANGING_SIGN = "minecraft:oak_hanging_sign";
|
||||
public const OAK_LEAVES = "minecraft:oak_leaves";
|
||||
public const OAK_LOG = "minecraft:oak_log";
|
||||
public const OAK_PLANKS = "minecraft:oak_planks";
|
||||
public const OAK_SAPLING = "minecraft:oak_sapling";
|
||||
public const OAK_SLAB = "minecraft:oak_slab";
|
||||
public const OAK_STAIRS = "minecraft:oak_stairs";
|
||||
public const OAK_WOOD = "minecraft:oak_wood";
|
||||
public const OBSERVER = "minecraft:observer";
|
||||
public const OBSIDIAN = "minecraft:obsidian";
|
||||
public const OCHRE_FROGLIGHT = "minecraft:ochre_froglight";
|
||||
@ -686,7 +751,9 @@ final class BlockTypeNames{
|
||||
public const ORANGE_STAINED_GLASS = "minecraft:orange_stained_glass";
|
||||
public const ORANGE_STAINED_GLASS_PANE = "minecraft:orange_stained_glass_pane";
|
||||
public const ORANGE_TERRACOTTA = "minecraft:orange_terracotta";
|
||||
public const ORANGE_TULIP = "minecraft:orange_tulip";
|
||||
public const ORANGE_WOOL = "minecraft:orange_wool";
|
||||
public const OXEYE_DAISY = "minecraft:oxeye_daisy";
|
||||
public const OXIDIZED_CHISELED_COPPER = "minecraft:oxidized_chiseled_copper";
|
||||
public const OXIDIZED_COPPER = "minecraft:oxidized_copper";
|
||||
public const OXIDIZED_COPPER_BULB = "minecraft:oxidized_copper_bulb";
|
||||
@ -711,6 +778,7 @@ final class BlockTypeNames{
|
||||
public const PINK_STAINED_GLASS = "minecraft:pink_stained_glass";
|
||||
public const PINK_STAINED_GLASS_PANE = "minecraft:pink_stained_glass_pane";
|
||||
public const PINK_TERRACOTTA = "minecraft:pink_terracotta";
|
||||
public const PINK_TULIP = "minecraft:pink_tulip";
|
||||
public const PINK_WOOL = "minecraft:pink_wool";
|
||||
public const PISTON = "minecraft:piston";
|
||||
public const PISTON_ARM_COLLISION = "minecraft:piston_arm_collision";
|
||||
@ -747,6 +815,7 @@ final class BlockTypeNames{
|
||||
public const POLISHED_TUFF_SLAB = "minecraft:polished_tuff_slab";
|
||||
public const POLISHED_TUFF_STAIRS = "minecraft:polished_tuff_stairs";
|
||||
public const POLISHED_TUFF_WALL = "minecraft:polished_tuff_wall";
|
||||
public const POPPY = "minecraft:poppy";
|
||||
public const PORTAL = "minecraft:portal";
|
||||
public const POTATOES = "minecraft:potatoes";
|
||||
public const POWDER_SNOW = "minecraft:powder_snow";
|
||||
@ -783,7 +852,6 @@ final class BlockTypeNames{
|
||||
public const RED_CARPET = "minecraft:red_carpet";
|
||||
public const RED_CONCRETE = "minecraft:red_concrete";
|
||||
public const RED_CONCRETE_POWDER = "minecraft:red_concrete_powder";
|
||||
public const RED_FLOWER = "minecraft:red_flower";
|
||||
public const RED_GLAZED_TERRACOTTA = "minecraft:red_glazed_terracotta";
|
||||
public const RED_MUSHROOM = "minecraft:red_mushroom";
|
||||
public const RED_MUSHROOM_BLOCK = "minecraft:red_mushroom_block";
|
||||
@ -795,6 +863,7 @@ final class BlockTypeNames{
|
||||
public const RED_STAINED_GLASS = "minecraft:red_stained_glass";
|
||||
public const RED_STAINED_GLASS_PANE = "minecraft:red_stained_glass_pane";
|
||||
public const RED_TERRACOTTA = "minecraft:red_terracotta";
|
||||
public const RED_TULIP = "minecraft:red_tulip";
|
||||
public const RED_WOOL = "minecraft:red_wool";
|
||||
public const REDSTONE_BLOCK = "minecraft:redstone_block";
|
||||
public const REDSTONE_LAMP = "minecraft:redstone_lamp";
|
||||
@ -809,7 +878,6 @@ final class BlockTypeNames{
|
||||
public const SAND = "minecraft:sand";
|
||||
public const SANDSTONE = "minecraft:sandstone";
|
||||
public const SANDSTONE_STAIRS = "minecraft:sandstone_stairs";
|
||||
public const SAPLING = "minecraft:sapling";
|
||||
public const SCAFFOLDING = "minecraft:scaffolding";
|
||||
public const SCULK = "minecraft:sculk";
|
||||
public const SCULK_CATALYST = "minecraft:sculk_catalyst";
|
||||
@ -845,16 +913,21 @@ final class BlockTypeNames{
|
||||
public const SPORE_BLOSSOM = "minecraft:spore_blossom";
|
||||
public const SPRUCE_BUTTON = "minecraft:spruce_button";
|
||||
public const SPRUCE_DOOR = "minecraft:spruce_door";
|
||||
public const SPRUCE_DOUBLE_SLAB = "minecraft:spruce_double_slab";
|
||||
public const SPRUCE_FENCE = "minecraft:spruce_fence";
|
||||
public const SPRUCE_FENCE_GATE = "minecraft:spruce_fence_gate";
|
||||
public const SPRUCE_HANGING_SIGN = "minecraft:spruce_hanging_sign";
|
||||
public const SPRUCE_LEAVES = "minecraft:spruce_leaves";
|
||||
public const SPRUCE_LOG = "minecraft:spruce_log";
|
||||
public const SPRUCE_PLANKS = "minecraft:spruce_planks";
|
||||
public const SPRUCE_PRESSURE_PLATE = "minecraft:spruce_pressure_plate";
|
||||
public const SPRUCE_SAPLING = "minecraft:spruce_sapling";
|
||||
public const SPRUCE_SLAB = "minecraft:spruce_slab";
|
||||
public const SPRUCE_STAIRS = "minecraft:spruce_stairs";
|
||||
public const SPRUCE_STANDING_SIGN = "minecraft:spruce_standing_sign";
|
||||
public const SPRUCE_TRAPDOOR = "minecraft:spruce_trapdoor";
|
||||
public const SPRUCE_WALL_SIGN = "minecraft:spruce_wall_sign";
|
||||
public const SPRUCE_WOOD = "minecraft:spruce_wood";
|
||||
public const STANDING_BANNER = "minecraft:standing_banner";
|
||||
public const STANDING_SIGN = "minecraft:standing_sign";
|
||||
public const STICKY_PISTON = "minecraft:sticky_piston";
|
||||
@ -872,18 +945,24 @@ final class BlockTypeNames{
|
||||
public const STONECUTTER = "minecraft:stonecutter";
|
||||
public const STONECUTTER_BLOCK = "minecraft:stonecutter_block";
|
||||
public const STRIPPED_ACACIA_LOG = "minecraft:stripped_acacia_log";
|
||||
public const STRIPPED_ACACIA_WOOD = "minecraft:stripped_acacia_wood";
|
||||
public const STRIPPED_BAMBOO_BLOCK = "minecraft:stripped_bamboo_block";
|
||||
public const STRIPPED_BIRCH_LOG = "minecraft:stripped_birch_log";
|
||||
public const STRIPPED_BIRCH_WOOD = "minecraft:stripped_birch_wood";
|
||||
public const STRIPPED_CHERRY_LOG = "minecraft:stripped_cherry_log";
|
||||
public const STRIPPED_CHERRY_WOOD = "minecraft:stripped_cherry_wood";
|
||||
public const STRIPPED_CRIMSON_HYPHAE = "minecraft:stripped_crimson_hyphae";
|
||||
public const STRIPPED_CRIMSON_STEM = "minecraft:stripped_crimson_stem";
|
||||
public const STRIPPED_DARK_OAK_LOG = "minecraft:stripped_dark_oak_log";
|
||||
public const STRIPPED_DARK_OAK_WOOD = "minecraft:stripped_dark_oak_wood";
|
||||
public const STRIPPED_JUNGLE_LOG = "minecraft:stripped_jungle_log";
|
||||
public const STRIPPED_JUNGLE_WOOD = "minecraft:stripped_jungle_wood";
|
||||
public const STRIPPED_MANGROVE_LOG = "minecraft:stripped_mangrove_log";
|
||||
public const STRIPPED_MANGROVE_WOOD = "minecraft:stripped_mangrove_wood";
|
||||
public const STRIPPED_OAK_LOG = "minecraft:stripped_oak_log";
|
||||
public const STRIPPED_OAK_WOOD = "minecraft:stripped_oak_wood";
|
||||
public const STRIPPED_SPRUCE_LOG = "minecraft:stripped_spruce_log";
|
||||
public const STRIPPED_SPRUCE_WOOD = "minecraft:stripped_spruce_wood";
|
||||
public const STRIPPED_WARPED_HYPHAE = "minecraft:stripped_warped_hyphae";
|
||||
public const STRIPPED_WARPED_STEM = "minecraft:stripped_warped_stem";
|
||||
public const STRUCTURE_BLOCK = "minecraft:structure_block";
|
||||
@ -900,9 +979,11 @@ final class BlockTypeNames{
|
||||
public const TORCHFLOWER_CROP = "minecraft:torchflower_crop";
|
||||
public const TRAPDOOR = "minecraft:trapdoor";
|
||||
public const TRAPPED_CHEST = "minecraft:trapped_chest";
|
||||
public const TRIAL_SPAWNER = "minecraft:trial_spawner";
|
||||
public const TRIP_WIRE = "minecraft:trip_wire";
|
||||
public const TRIPWIRE_HOOK = "minecraft:tripwire_hook";
|
||||
public const TUBE_CORAL = "minecraft:tube_coral";
|
||||
public const TUBE_CORAL_FAN = "minecraft:tube_coral_fan";
|
||||
public const TUFF = "minecraft:tuff";
|
||||
public const TUFF_BRICK_DOUBLE_SLAB = "minecraft:tuff_brick_double_slab";
|
||||
public const TUFF_BRICK_SLAB = "minecraft:tuff_brick_slab";
|
||||
@ -921,6 +1002,7 @@ final class BlockTypeNames{
|
||||
public const UNLIT_REDSTONE_TORCH = "minecraft:unlit_redstone_torch";
|
||||
public const UNPOWERED_COMPARATOR = "minecraft:unpowered_comparator";
|
||||
public const UNPOWERED_REPEATER = "minecraft:unpowered_repeater";
|
||||
public const VAULT = "minecraft:vault";
|
||||
public const VERDANT_FROGLIGHT = "minecraft:verdant_froglight";
|
||||
public const VINE = "minecraft:vine";
|
||||
public const WALL_BANNER = "minecraft:wall_banner";
|
||||
@ -1009,13 +1091,12 @@ final class BlockTypeNames{
|
||||
public const WHITE_STAINED_GLASS = "minecraft:white_stained_glass";
|
||||
public const WHITE_STAINED_GLASS_PANE = "minecraft:white_stained_glass_pane";
|
||||
public const WHITE_TERRACOTTA = "minecraft:white_terracotta";
|
||||
public const WHITE_TULIP = "minecraft:white_tulip";
|
||||
public const WHITE_WOOL = "minecraft:white_wool";
|
||||
public const WITHER_ROSE = "minecraft:wither_rose";
|
||||
public const WOOD = "minecraft:wood";
|
||||
public const WOODEN_BUTTON = "minecraft:wooden_button";
|
||||
public const WOODEN_DOOR = "minecraft:wooden_door";
|
||||
public const WOODEN_PRESSURE_PLATE = "minecraft:wooden_pressure_plate";
|
||||
public const WOODEN_SLAB = "minecraft:wooden_slab";
|
||||
public const YELLOW_CANDLE = "minecraft:yellow_candle";
|
||||
public const YELLOW_CANDLE_CAKE = "minecraft:yellow_candle_cake";
|
||||
public const YELLOW_CARPET = "minecraft:yellow_carpet";
|
||||
|
@ -203,8 +203,8 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->registerFlatCoralSerializers();
|
||||
$this->registerCauldronSerializers();
|
||||
$this->registerFlatWoodBlockSerializers();
|
||||
$this->registerLegacyWoodBlockSerializers();
|
||||
$this->registerLeavesSerializers();
|
||||
$this->registerSaplingSerializers();
|
||||
$this->registerSimpleSerializers();
|
||||
$this->registerSerializers();
|
||||
}
|
||||
@ -315,6 +315,44 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
}
|
||||
|
||||
public function registerFlatColorBlockSerializers() : void{
|
||||
$this->map(Blocks::STAINED_HARDENED_GLASS(), fn(StainedHardenedGlass $block) => Writer::create(match($block->getColor()){
|
||||
DyeColor::BLACK => Ids::HARD_BLACK_STAINED_GLASS,
|
||||
DyeColor::BLUE => Ids::HARD_BLUE_STAINED_GLASS,
|
||||
DyeColor::BROWN => Ids::HARD_BROWN_STAINED_GLASS,
|
||||
DyeColor::CYAN => Ids::HARD_CYAN_STAINED_GLASS,
|
||||
DyeColor::GRAY => Ids::HARD_GRAY_STAINED_GLASS,
|
||||
DyeColor::GREEN => Ids::HARD_GREEN_STAINED_GLASS,
|
||||
DyeColor::LIGHT_BLUE => Ids::HARD_LIGHT_BLUE_STAINED_GLASS,
|
||||
DyeColor::LIGHT_GRAY => Ids::HARD_LIGHT_GRAY_STAINED_GLASS,
|
||||
DyeColor::LIME => Ids::HARD_LIME_STAINED_GLASS,
|
||||
DyeColor::MAGENTA => Ids::HARD_MAGENTA_STAINED_GLASS,
|
||||
DyeColor::ORANGE => Ids::HARD_ORANGE_STAINED_GLASS,
|
||||
DyeColor::PINK => Ids::HARD_PINK_STAINED_GLASS,
|
||||
DyeColor::PURPLE => Ids::HARD_PURPLE_STAINED_GLASS,
|
||||
DyeColor::RED => Ids::HARD_RED_STAINED_GLASS,
|
||||
DyeColor::WHITE => Ids::HARD_WHITE_STAINED_GLASS,
|
||||
DyeColor::YELLOW => Ids::HARD_YELLOW_STAINED_GLASS,
|
||||
}));
|
||||
|
||||
$this->map(Blocks::STAINED_HARDENED_GLASS_PANE(), fn(StainedHardenedGlassPane $block) => Writer::create(match($block->getColor()){
|
||||
DyeColor::BLACK => Ids::HARD_BLACK_STAINED_GLASS_PANE,
|
||||
DyeColor::BLUE => Ids::HARD_BLUE_STAINED_GLASS_PANE,
|
||||
DyeColor::BROWN => Ids::HARD_BROWN_STAINED_GLASS_PANE,
|
||||
DyeColor::CYAN => Ids::HARD_CYAN_STAINED_GLASS_PANE,
|
||||
DyeColor::GRAY => Ids::HARD_GRAY_STAINED_GLASS_PANE,
|
||||
DyeColor::GREEN => Ids::HARD_GREEN_STAINED_GLASS_PANE,
|
||||
DyeColor::LIGHT_BLUE => Ids::HARD_LIGHT_BLUE_STAINED_GLASS_PANE,
|
||||
DyeColor::LIGHT_GRAY => Ids::HARD_LIGHT_GRAY_STAINED_GLASS_PANE,
|
||||
DyeColor::LIME => Ids::HARD_LIME_STAINED_GLASS_PANE,
|
||||
DyeColor::MAGENTA => Ids::HARD_MAGENTA_STAINED_GLASS_PANE,
|
||||
DyeColor::ORANGE => Ids::HARD_ORANGE_STAINED_GLASS_PANE,
|
||||
DyeColor::PINK => Ids::HARD_PINK_STAINED_GLASS_PANE,
|
||||
DyeColor::PURPLE => Ids::HARD_PURPLE_STAINED_GLASS_PANE,
|
||||
DyeColor::RED => Ids::HARD_RED_STAINED_GLASS_PANE,
|
||||
DyeColor::WHITE => Ids::HARD_WHITE_STAINED_GLASS_PANE,
|
||||
DyeColor::YELLOW => Ids::HARD_YELLOW_STAINED_GLASS_PANE,
|
||||
}));
|
||||
|
||||
$this->map(Blocks::GLAZED_TERRACOTTA(), function(GlazedTerracotta $block) : Writer{
|
||||
return Writer::create(match($block->getColor()){
|
||||
DyeColor::BLACK => Ids::BLACK_GLAZED_TERRACOTTA,
|
||||
@ -500,6 +538,20 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL : Ids::TUBE_CORAL,
|
||||
}
|
||||
));
|
||||
|
||||
$this->map(Blocks::CORAL_FAN(), fn(FloorCoralFan $block) => Writer::create(
|
||||
match($block->getCoralType()){
|
||||
CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_FAN : Ids::BRAIN_CORAL_FAN,
|
||||
CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_FAN : Ids::BUBBLE_CORAL_FAN,
|
||||
CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_FAN : Ids::FIRE_CORAL_FAN,
|
||||
CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_FAN : Ids::HORN_CORAL_FAN,
|
||||
CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_FAN : Ids::TUBE_CORAL_FAN,
|
||||
})
|
||||
->writeInt(StateNames::CORAL_FAN_DIRECTION, match($axis = $block->getAxis()){
|
||||
Axis::X => 0,
|
||||
Axis::Z => 1,
|
||||
default => throw new BlockStateSerializeException("Invalid axis {$axis}"),
|
||||
}));
|
||||
}
|
||||
|
||||
private function registerCauldronSerializers() : void{
|
||||
@ -520,9 +572,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::ACACIA_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::ACACIA_TRAPDOOR)));
|
||||
$this->map(Blocks::ACACIA_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::ACACIA_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::ACACIA_LOG(), Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG);
|
||||
$this->mapLog(Blocks::ACACIA_WOOD(), Ids::ACACIA_WOOD, Ids::STRIPPED_ACACIA_WOOD);
|
||||
$this->mapSimple(Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE);
|
||||
$this->mapSimple(Blocks::ACACIA_PLANKS(), Ids::ACACIA_PLANKS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
$this->mapSlab(Blocks::ACACIA_SLAB(), Ids::ACACIA_SLAB, Ids::ACACIA_DOUBLE_SLAB);
|
||||
|
||||
$this->map(Blocks::BIRCH_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::BIRCH_BUTTON)));
|
||||
$this->map(Blocks::BIRCH_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::BIRCH_DOOR)));
|
||||
@ -532,10 +585,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::BIRCH_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::BIRCH_TRAPDOOR)));
|
||||
$this->map(Blocks::BIRCH_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::BIRCH_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::BIRCH_LOG(), Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG);
|
||||
$this->mapLog(Blocks::BIRCH_WOOD(), Ids::BIRCH_WOOD, Ids::STRIPPED_BIRCH_WOOD);
|
||||
$this->mapSimple(Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE);
|
||||
$this->mapSimple(Blocks::BIRCH_PLANKS(), Ids::BIRCH_PLANKS);
|
||||
$this->mapSlab(Blocks::BIRCH_SLAB(), Ids::BIRCH_SLAB, Ids::BIRCH_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Blocks::CHERRY_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::CHERRY_BUTTON)));
|
||||
$this->map(Blocks::CHERRY_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::CHERRY_DOOR)));
|
||||
@ -583,10 +637,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::DARK_OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::DARK_OAK_TRAPDOOR)));
|
||||
$this->map(Blocks::DARK_OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::DARKOAK_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::DARK_OAK_LOG(), Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG);
|
||||
$this->mapLog(Blocks::DARK_OAK_WOOD(), Ids::DARK_OAK_WOOD, Ids::STRIPPED_DARK_OAK_WOOD);
|
||||
$this->mapSimple(Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE);
|
||||
$this->mapSimple(Blocks::DARK_OAK_PLANKS(), Ids::DARK_OAK_PLANKS);
|
||||
$this->mapSlab(Blocks::DARK_OAK_SLAB(), Ids::DARK_OAK_SLAB, Ids::DARK_OAK_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Blocks::JUNGLE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::JUNGLE_BUTTON)));
|
||||
$this->map(Blocks::JUNGLE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::JUNGLE_DOOR)));
|
||||
@ -596,10 +651,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::JUNGLE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::JUNGLE_TRAPDOOR)));
|
||||
$this->map(Blocks::JUNGLE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::JUNGLE_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::JUNGLE_LOG(), Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG);
|
||||
$this->mapLog(Blocks::JUNGLE_WOOD(), Ids::JUNGLE_WOOD, Ids::STRIPPED_JUNGLE_WOOD);
|
||||
$this->mapSimple(Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE);
|
||||
$this->mapSimple(Blocks::JUNGLE_PLANKS(), Ids::JUNGLE_PLANKS);
|
||||
$this->mapSlab(Blocks::JUNGLE_SLAB(), Ids::JUNGLE_SLAB, Ids::JUNGLE_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Blocks::MANGROVE_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::MANGROVE_BUTTON)));
|
||||
$this->map(Blocks::MANGROVE_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::MANGROVE_DOOR)));
|
||||
@ -633,10 +689,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::TRAPDOOR)));
|
||||
$this->map(Blocks::OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::WALL_SIGN)));
|
||||
$this->mapLog(Blocks::OAK_LOG(), Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG);
|
||||
$this->mapLog(Blocks::OAK_WOOD(), Ids::OAK_WOOD, Ids::STRIPPED_OAK_WOOD);
|
||||
$this->mapSimple(Blocks::OAK_FENCE(), Ids::OAK_FENCE);
|
||||
$this->mapSimple(Blocks::OAK_PLANKS(), Ids::OAK_PLANKS);
|
||||
$this->mapSlab(Blocks::OAK_SLAB(), Ids::OAK_SLAB, Ids::OAK_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::OAK_STAIRS(), Ids::OAK_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Blocks::SPRUCE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::SPRUCE_BUTTON)));
|
||||
$this->map(Blocks::SPRUCE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::SPRUCE_DOOR)));
|
||||
@ -646,8 +703,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::SPRUCE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::SPRUCE_TRAPDOOR)));
|
||||
$this->map(Blocks::SPRUCE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::SPRUCE_WALL_SIGN)));
|
||||
$this->mapLog(Blocks::SPRUCE_LOG(), Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG);
|
||||
$this->mapLog(Blocks::SPRUCE_WOOD(), Ids::SPRUCE_WOOD, Ids::STRIPPED_SPRUCE_WOOD);
|
||||
$this->mapSimple(Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE);
|
||||
$this->mapSimple(Blocks::SPRUCE_PLANKS(), Ids::SPRUCE_PLANKS);
|
||||
$this->mapSlab(Blocks::SPRUCE_SLAB(), Ids::SPRUCE_SLAB, Ids::SPRUCE_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS);
|
||||
//wood and slabs still use the old way of storing wood type
|
||||
|
||||
@ -666,30 +725,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapStairs(Blocks::WARPED_STAIRS(), Ids::WARPED_STAIRS);
|
||||
}
|
||||
|
||||
private function registerLegacyWoodBlockSerializers() : void{
|
||||
foreach([
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_SLAB(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_SLAB(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_SLAB(),
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_SLAB(),
|
||||
] as $woodType => $block){
|
||||
$this->map($block, fn(Slab $block) => Helper::encodeWoodenSlab($block, $woodType));
|
||||
}
|
||||
|
||||
foreach([
|
||||
Blocks::ACACIA_WOOD(),
|
||||
Blocks::BIRCH_WOOD(),
|
||||
Blocks::DARK_OAK_WOOD(),
|
||||
Blocks::JUNGLE_WOOD(),
|
||||
Blocks::OAK_WOOD(),
|
||||
Blocks::SPRUCE_WOOD(),
|
||||
] as $block){
|
||||
$this->map($block, fn(Wood $block) => Helper::encodeAllSidedLog($block));
|
||||
}
|
||||
}
|
||||
|
||||
private function registerLeavesSerializers() : void{
|
||||
//flattened IDs
|
||||
$this->map(Blocks::AZALEA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::AZALEA_LEAVES)));
|
||||
@ -698,12 +733,25 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::MANGROVE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::MANGROVE_LEAVES)));
|
||||
|
||||
//legacy mess
|
||||
$this->map(Blocks::ACACIA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves2($block, StringValues::NEW_LEAF_TYPE_ACACIA));
|
||||
$this->map(Blocks::BIRCH_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_BIRCH));
|
||||
$this->map(Blocks::DARK_OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves2($block, StringValues::NEW_LEAF_TYPE_DARK_OAK));
|
||||
$this->map(Blocks::JUNGLE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_JUNGLE));
|
||||
$this->map(Blocks::OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_OAK));
|
||||
$this->map(Blocks::SPRUCE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves1($block, StringValues::OLD_LEAF_TYPE_SPRUCE));
|
||||
$this->map(Blocks::ACACIA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::ACACIA_LEAVES)));
|
||||
$this->map(Blocks::BIRCH_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::BIRCH_LEAVES)));
|
||||
$this->map(Blocks::DARK_OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::DARK_OAK_LEAVES)));
|
||||
$this->map(Blocks::JUNGLE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::JUNGLE_LEAVES)));
|
||||
$this->map(Blocks::OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::OAK_LEAVES)));
|
||||
$this->map(Blocks::SPRUCE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::SPRUCE_LEAVES)));
|
||||
}
|
||||
|
||||
private function registerSaplingSerializers() : void{
|
||||
foreach([
|
||||
Ids::ACACIA_SAPLING => Blocks::ACACIA_SAPLING(),
|
||||
Ids::BIRCH_SAPLING => Blocks::BIRCH_SAPLING(),
|
||||
Ids::DARK_OAK_SAPLING => Blocks::DARK_OAK_SAPLING(),
|
||||
Ids::JUNGLE_SAPLING => Blocks::JUNGLE_SAPLING(),
|
||||
Ids::OAK_SAPLING => Blocks::OAK_SAPLING(),
|
||||
Ids::SPRUCE_SAPLING => Blocks::SPRUCE_SAPLING(),
|
||||
] as $id => $block){
|
||||
$this->map($block, fn(Sapling $block) => Helper::encodeSapling($block, new Writer($id)));
|
||||
}
|
||||
}
|
||||
|
||||
private function registerSimpleSerializers() : void{
|
||||
@ -889,7 +937,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapSimple(Blocks::GOLD(), Ids::GOLD_BLOCK);
|
||||
$this->mapSimple(Blocks::GOLD_ORE(), Ids::GOLD_ORE);
|
||||
$this->mapSimple(Blocks::GRANITE(), Ids::GRANITE);
|
||||
$this->mapSimple(Blocks::GRASS(), Ids::GRASS);
|
||||
$this->mapSimple(Blocks::GRASS(), Ids::GRASS_BLOCK);
|
||||
$this->mapSimple(Blocks::GRASS_PATH(), Ids::GRASS_PATH);
|
||||
$this->mapSimple(Blocks::GRAVEL(), Ids::GRAVEL);
|
||||
$this->mapSimple(Blocks::HANGING_ROOTS(), Ids::HANGING_ROOTS);
|
||||
@ -964,16 +1012,26 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapSimple(Blocks::WARPED_WART_BLOCK(), Ids::WARPED_WART_BLOCK);
|
||||
$this->mapSimple(Blocks::WARPED_ROOTS(), Ids::WARPED_ROOTS);
|
||||
$this->mapSimple(Blocks::WITHER_ROSE(), Ids::WITHER_ROSE);
|
||||
|
||||
$this->mapSimple(Blocks::ALLIUM(), Ids::ALLIUM);
|
||||
$this->mapSimple(Blocks::CORNFLOWER(), Ids::CORNFLOWER);
|
||||
$this->mapSimple(Blocks::AZURE_BLUET(), Ids::AZURE_BLUET);
|
||||
$this->mapSimple(Blocks::LILY_OF_THE_VALLEY(), Ids::LILY_OF_THE_VALLEY);
|
||||
$this->mapSimple(Blocks::BLUE_ORCHID(), Ids::BLUE_ORCHID);
|
||||
$this->mapSimple(Blocks::OXEYE_DAISY(), Ids::OXEYE_DAISY);
|
||||
$this->mapSimple(Blocks::POPPY(), Ids::POPPY);
|
||||
$this->mapSimple(Blocks::ORANGE_TULIP(), Ids::ORANGE_TULIP);
|
||||
$this->mapSimple(Blocks::PINK_TULIP(), Ids::PINK_TULIP);
|
||||
$this->mapSimple(Blocks::RED_TULIP(), Ids::RED_TULIP);
|
||||
$this->mapSimple(Blocks::WHITE_TULIP(), Ids::WHITE_TULIP);
|
||||
}
|
||||
|
||||
private function registerSerializers() : void{
|
||||
$this->map(Blocks::ACACIA_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_ACACIA));
|
||||
$this->map(Blocks::ACTIVATOR_RAIL(), function(ActivatorRail $block) : Writer{
|
||||
return Writer::create(Ids::ACTIVATOR_RAIL)
|
||||
->writeBool(StateNames::RAIL_DATA_BIT, $block->isPowered())
|
||||
->writeInt(StateNames::RAIL_DIRECTION, $block->getShape());
|
||||
});
|
||||
$this->map(Blocks::ALLIUM(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_ALLIUM));
|
||||
$this->map(Blocks::ALL_SIDED_MUSHROOM_STEM(), fn() => Writer::create(Ids::BROWN_MUSHROOM_BLOCK)
|
||||
->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM));
|
||||
$this->map(Blocks::AMETHYST_CLUSTER(), fn(AmethystCluster $block) => Writer::create(
|
||||
@ -999,7 +1057,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
default => throw new BlockStateSerializeException("Invalid Anvil damage {$damage}"),
|
||||
});
|
||||
});
|
||||
$this->map(Blocks::AZURE_BLUET(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_HOUSTONIA));
|
||||
$this->map(Blocks::BAMBOO(), function(Bamboo $block) : Writer{
|
||||
return Writer::create(Ids::BAMBOO)
|
||||
->writeBool(StateNames::AGE_BIT, $block->isReady())
|
||||
@ -1013,10 +1070,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
});
|
||||
$this->map(Blocks::BAMBOO_SAPLING(), function(BambooSapling $block) : Writer{
|
||||
return Writer::create(Ids::BAMBOO_SAPLING)
|
||||
->writeBool(StateNames::AGE_BIT, $block->isReady())
|
||||
|
||||
//TODO: bug in MCPE
|
||||
->writeString(StateNames::SAPLING_TYPE, StringValues::SAPLING_TYPE_OAK);
|
||||
->writeBool(StateNames::AGE_BIT, $block->isReady());
|
||||
});
|
||||
$this->map(Blocks::BANNER(), function(FloorBanner $block) : Writer{
|
||||
return Writer::create(Ids::STANDING_BANNER)
|
||||
@ -1066,12 +1120,10 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->writeString(StateNames::BIG_DRIPLEAF_TILT, StringValues::BIG_DRIPLEAF_TILT_NONE)
|
||||
->writeBool(StateNames::BIG_DRIPLEAF_HEAD, false);
|
||||
});
|
||||
$this->map(Blocks::BIRCH_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_BIRCH));
|
||||
$this->mapSlab(Blocks::BLACKSTONE_SLAB(), Ids::BLACKSTONE_SLAB, Ids::BLACKSTONE_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::BLACKSTONE_STAIRS(), Ids::BLACKSTONE_STAIRS);
|
||||
$this->map(Blocks::BLACKSTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::BLACKSTONE_WALL)));
|
||||
$this->map(Blocks::BLAST_FURNACE(), fn(Furnace $block) => Helper::encodeFurnace($block, Ids::BLAST_FURNACE, Ids::LIT_BLAST_FURNACE));
|
||||
$this->map(Blocks::BLUE_ORCHID(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_ORCHID));
|
||||
$this->map(Blocks::BLUE_TORCH(), fn(Torch $block) => Helper::encodeColoredTorch($block, false, Writer::create(Ids::COLORED_TORCH_BP)));
|
||||
$this->map(Blocks::BONE_BLOCK(), function(BoneBlock $block) : Writer{
|
||||
return Writer::create(Ids::BONE_BLOCK)
|
||||
@ -1228,22 +1280,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->writeBool(StateNames::DEAD_BIT, $block->isDead())
|
||||
->writeCoralType($block->getCoralType());
|
||||
});
|
||||
$this->map(Blocks::CORAL_FAN(), function(FloorCoralFan $block) : Writer{
|
||||
return Writer::create($block->isDead() ? Ids::CORAL_FAN_DEAD : Ids::CORAL_FAN)
|
||||
->writeCoralType($block->getCoralType())
|
||||
->writeInt(StateNames::CORAL_FAN_DIRECTION, match($axis = $block->getAxis()){
|
||||
Axis::X => 0,
|
||||
Axis::Z => 1,
|
||||
default => throw new BlockStateSerializeException("Invalid axis {$axis}"),
|
||||
});
|
||||
});
|
||||
$this->map(Blocks::CORNFLOWER(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_CORNFLOWER));
|
||||
$this->map(Blocks::CRACKED_STONE_BRICKS(), fn() => Helper::encodeStoneBricks(StringValues::STONE_BRICK_TYPE_CRACKED));
|
||||
$this->map(Blocks::CUT_RED_SANDSTONE(), fn() => Helper::encodeSandstone(Ids::RED_SANDSTONE, StringValues::SAND_STONE_TYPE_CUT));
|
||||
$this->map(Blocks::CUT_RED_SANDSTONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab4($block, StringValues::STONE_SLAB_TYPE_4_CUT_RED_SANDSTONE));
|
||||
$this->map(Blocks::CUT_SANDSTONE(), fn() => Helper::encodeSandstone(Ids::SANDSTONE, StringValues::SAND_STONE_TYPE_CUT));
|
||||
$this->map(Blocks::CUT_SANDSTONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab4($block, StringValues::STONE_SLAB_TYPE_4_CUT_SANDSTONE));
|
||||
$this->map(Blocks::DARK_OAK_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_DARK_OAK));
|
||||
$this->map(Blocks::DARK_PRISMARINE(), fn() => Writer::create(Ids::PRISMARINE)
|
||||
->writeString(StateNames::PRISMARINE_BLOCK_TYPE, StringValues::PRISMARINE_BLOCK_TYPE_DARK));
|
||||
$this->map(Blocks::DARK_PRISMARINE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab2($block, StringValues::STONE_SLAB_TYPE_2_PRISMARINE_DARK));
|
||||
@ -1363,7 +1404,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->map(Blocks::IRON_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::IRON_DOOR)));
|
||||
$this->map(Blocks::IRON_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::IRON_TRAPDOOR)));
|
||||
$this->map(Blocks::ITEM_FRAME(), fn(ItemFrame $block) => Helper::encodeItemFrame($block, Ids::FRAME));
|
||||
$this->map(Blocks::JUNGLE_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_JUNGLE));
|
||||
$this->map(Blocks::LAB_TABLE(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, StringValues::CHEMISTRY_TABLE_TYPE_LAB_TABLE, new Writer(Ids::CHEMISTRY_TABLE)));
|
||||
$this->map(Blocks::LADDER(), function(Ladder $block) : Writer{
|
||||
return Writer::create(Ids::LADDER)
|
||||
@ -1403,7 +1443,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->writeFacingDirection($block->getFacing());
|
||||
});
|
||||
$this->map(Blocks::LILAC(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_SYRINGA, Writer::create(Ids::DOUBLE_PLANT)));
|
||||
$this->map(Blocks::LILY_OF_THE_VALLEY(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_LILY_OF_THE_VALLEY));
|
||||
$this->map(Blocks::LIT_PUMPKIN(), function(LitPumpkin $block) : Writer{
|
||||
return Writer::create(Ids::LIT_PUMPKIN)
|
||||
->writeCardinalHorizontalFacing($block->getFacing());
|
||||
@ -1447,16 +1486,12 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
return Writer::create(Ids::NETHER_WART)
|
||||
->writeInt(StateNames::AGE, $block->getAge());
|
||||
});
|
||||
$this->map(Blocks::OAK_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_OAK));
|
||||
$this->map(Blocks::ORANGE_TULIP(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_TULIP_ORANGE));
|
||||
$this->map(Blocks::OXEYE_DAISY(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_OXEYE));
|
||||
$this->map(Blocks::PEONY(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_PAEONIA, Writer::create(Ids::DOUBLE_PLANT)));
|
||||
$this->map(Blocks::PINK_PETALS(), function(PinkPetals $block) : Writer{
|
||||
return Writer::create(Ids::PINK_PETALS)
|
||||
->writeCardinalHorizontalFacing($block->getFacing())
|
||||
->writeInt(StateNames::GROWTH, $block->getCount() - 1);
|
||||
});
|
||||
$this->map(Blocks::PINK_TULIP(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_TULIP_PINK));
|
||||
$this->map(Blocks::PITCHER_PLANT(), function(DoublePlant $block) : Writer{
|
||||
return Writer::create(Ids::PITCHER_PLANT)
|
||||
->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
|
||||
@ -1492,7 +1527,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapStairs(Blocks::POLISHED_DIORITE_STAIRS(), Ids::POLISHED_DIORITE_STAIRS);
|
||||
$this->map(Blocks::POLISHED_GRANITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_POLISHED_GRANITE));
|
||||
$this->mapStairs(Blocks::POLISHED_GRANITE_STAIRS(), Ids::POLISHED_GRANITE_STAIRS);
|
||||
$this->map(Blocks::POPPY(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_POPPY));
|
||||
$this->map(Blocks::POTATOES(), fn(Potato $block) => Helper::encodeCrops($block, new Writer(Ids::POTATOES)));
|
||||
$this->map(Blocks::POWERED_RAIL(), function(PoweredRail $block) : Writer{
|
||||
return Writer::create(Ids::GOLDEN_RAIL)
|
||||
@ -1566,7 +1600,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapStairs(Blocks::RED_SANDSTONE_STAIRS(), Ids::RED_SANDSTONE_STAIRS);
|
||||
$this->map(Blocks::RED_SANDSTONE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_RED_SANDSTONE));
|
||||
$this->map(Blocks::RED_TORCH(), fn(Torch $block) => Helper::encodeColoredTorch($block, false, Writer::create(Ids::COLORED_TORCH_RG)));
|
||||
$this->map(Blocks::RED_TULIP(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_TULIP_RED));
|
||||
$this->map(Blocks::ROSE_BUSH(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_ROSE, Writer::create(Ids::DOUBLE_PLANT)));
|
||||
$this->map(Blocks::SAND(), fn() => Writer::create(Ids::SAND)
|
||||
->writeString(StateNames::SAND_TYPE, StringValues::SAND_TYPE_NORMAL));
|
||||
@ -1616,15 +1649,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
return Writer::create(Ids::SPONGE)
|
||||
->writeString(StateNames::SPONGE_TYPE, $block->isWet() ? StringValues::SPONGE_TYPE_WET : StringValues::SPONGE_TYPE_DRY);
|
||||
});
|
||||
$this->map(Blocks::SPRUCE_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_SPRUCE));
|
||||
$this->map(Blocks::STAINED_HARDENED_GLASS(), function(StainedHardenedGlass $block) : Writer{
|
||||
return Writer::create(Ids::HARD_STAINED_GLASS)
|
||||
->writeColor($block->getColor());
|
||||
});
|
||||
$this->map(Blocks::STAINED_HARDENED_GLASS_PANE(), function(StainedHardenedGlassPane $block) : Writer{
|
||||
return Writer::create(Ids::HARD_STAINED_GLASS_PANE)
|
||||
->writeColor($block->getColor());
|
||||
});
|
||||
$this->map(Blocks::STONECUTTER(), fn(Stonecutter $block) => Writer::create(Ids::STONECUTTER_BLOCK)
|
||||
->writeCardinalHorizontalFacing($block->getFacing()));
|
||||
$this->map(Blocks::STONE_BRICKS(), fn() => Helper::encodeStoneBricks(StringValues::STONE_BRICK_TYPE_DEFAULT));
|
||||
@ -1717,6 +1741,5 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength());
|
||||
});
|
||||
$this->map(Blocks::WHEAT(), fn(Wheat $block) => Helper::encodeCrops($block, new Writer(Ids::WHEAT)));
|
||||
$this->map(Blocks::WHITE_TULIP(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_TULIP_WHITE));
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ use pocketmine\block\Liquid;
|
||||
use pocketmine\block\RedMushroomBlock;
|
||||
use pocketmine\block\RedstoneComparator;
|
||||
use pocketmine\block\RedstoneRepeater;
|
||||
use pocketmine\block\Sapling;
|
||||
use pocketmine\block\SimplePressurePlate;
|
||||
use pocketmine\block\Slab;
|
||||
use pocketmine\block\Stair;
|
||||
@ -149,7 +150,6 @@ final class BlockStateDeserializerHelper{
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public static function decodeFloorCoralFan(FloorCoralFan $block, BlockStateReader $in) : FloorCoralFan{
|
||||
return $block
|
||||
->setCoralType($in->readCoralType())
|
||||
->setAxis(match($in->readBoundedInt(BlockStateNames::CORAL_FAN_DIRECTION, 0, 1)){
|
||||
0 => Axis::X,
|
||||
1 => Axis::Z,
|
||||
@ -220,6 +220,12 @@ final class BlockStateDeserializerHelper{
|
||||
->setDelay($in->readBoundedInt(BlockStateNames::REPEATER_DELAY, 0, 3) + 1);
|
||||
}
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public static function decodeSapling(Sapling $block, BlockStateReader $in) : Sapling{
|
||||
return $block
|
||||
->setReady($in->readBool(BlockStateNames::AGE_BIT));
|
||||
}
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public static function decodeSimplePressurePlate(SimplePressurePlate $block, BlockStateReader $in) : SimplePressurePlate{
|
||||
//TODO: not sure what the deal is here ... seems like a mojang bug / artifact of bad implementation?
|
||||
@ -362,18 +368,4 @@ final class BlockStateDeserializerHelper{
|
||||
default => throw $in->badValueException(BlockStateNames::STONE_SLAB_TYPE_4, $type),
|
||||
};
|
||||
}
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public static function mapWoodenSlabType(BlockStateReader $in) : Slab{
|
||||
// * wood_type (StringTag) = acacia, birch, dark_oak, jungle, oak, spruce
|
||||
return match($type = $in->readString(BlockStateNames::WOOD_TYPE)){
|
||||
StringValues::WOOD_TYPE_ACACIA => VanillaBlocks::ACACIA_SLAB(),
|
||||
StringValues::WOOD_TYPE_BIRCH => VanillaBlocks::BIRCH_SLAB(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => VanillaBlocks::DARK_OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => VanillaBlocks::JUNGLE_SLAB(),
|
||||
StringValues::WOOD_TYPE_OAK => VanillaBlocks::OAK_SLAB(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => VanillaBlocks::SPRUCE_SLAB(),
|
||||
default => throw $in->badValueException(BlockStateNames::WOOD_TYPE, $type),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ namespace pocketmine\data\bedrock\block\convert;
|
||||
|
||||
use pocketmine\block\utils\BellAttachmentType;
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\SlabType;
|
||||
use pocketmine\block\utils\WallConnectionType;
|
||||
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
|
||||
@ -39,20 +38,24 @@ use pocketmine\nbt\tag\ByteTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\nbt\tag\Tag;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_keys;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function implode;
|
||||
|
||||
final class BlockStateReader{
|
||||
|
||||
/**
|
||||
* @var true[]
|
||||
* @phpstan-var array<string, true>
|
||||
* @var Tag[]
|
||||
* @phpstan-var array<string, Tag>
|
||||
*/
|
||||
private array $usedStates = [];
|
||||
private array $unusedStates;
|
||||
|
||||
public function __construct(
|
||||
private BlockStateData $data
|
||||
){}
|
||||
){
|
||||
$this->unusedStates = $this->data->getStates();
|
||||
}
|
||||
|
||||
public function missingOrWrongTypeException(string $name, ?Tag $tag) : BlockStateDeserializeException{
|
||||
return new BlockStateDeserializeException("Property \"$name\" " . ($tag !== null ? "has unexpected type " . get_class($tag) : "is missing"));
|
||||
@ -67,7 +70,7 @@ final class BlockStateReader{
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public function readBool(string $name) : bool{
|
||||
$this->usedStates[$name] = true;
|
||||
unset($this->unusedStates[$name]);
|
||||
$tag = $this->data->getState($name);
|
||||
if($tag instanceof ByteTag){
|
||||
switch($tag->getValue()){
|
||||
@ -81,7 +84,7 @@ final class BlockStateReader{
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public function readInt(string $name) : int{
|
||||
$this->usedStates[$name] = true;
|
||||
unset($this->unusedStates[$name]);
|
||||
$tag = $this->data->getState($name);
|
||||
if($tag instanceof IntTag){
|
||||
return $tag->getValue();
|
||||
@ -100,7 +103,7 @@ final class BlockStateReader{
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public function readString(string $name) : string{
|
||||
$this->usedStates[$name] = true;
|
||||
unset($this->unusedStates[$name]);
|
||||
//TODO: only allow a specific set of values (strings are primarily used for enums)
|
||||
$tag = $this->data->getState($name);
|
||||
if($tag instanceof StringTag){
|
||||
@ -236,30 +239,6 @@ final class BlockStateReader{
|
||||
};
|
||||
}
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public function readColor() : DyeColor{
|
||||
// * color (StringTag) = black, blue, brown, cyan, gray, green, light_blue, lime, magenta, orange, pink, purple, red, silver, white, yellow
|
||||
return match($color = $this->readString(BlockStateNames::COLOR)){
|
||||
StringValues::COLOR_BLACK => DyeColor::BLACK,
|
||||
StringValues::COLOR_BLUE => DyeColor::BLUE,
|
||||
StringValues::COLOR_BROWN => DyeColor::BROWN,
|
||||
StringValues::COLOR_CYAN => DyeColor::CYAN,
|
||||
StringValues::COLOR_GRAY => DyeColor::GRAY,
|
||||
StringValues::COLOR_GREEN => DyeColor::GREEN,
|
||||
StringValues::COLOR_LIGHT_BLUE => DyeColor::LIGHT_BLUE,
|
||||
StringValues::COLOR_LIME => DyeColor::LIME,
|
||||
StringValues::COLOR_MAGENTA => DyeColor::MAGENTA,
|
||||
StringValues::COLOR_ORANGE => DyeColor::ORANGE,
|
||||
StringValues::COLOR_PINK => DyeColor::PINK,
|
||||
StringValues::COLOR_PURPLE => DyeColor::PURPLE,
|
||||
StringValues::COLOR_RED => DyeColor::RED,
|
||||
StringValues::COLOR_SILVER => DyeColor::LIGHT_GRAY,
|
||||
StringValues::COLOR_WHITE => DyeColor::WHITE,
|
||||
StringValues::COLOR_YELLOW => DyeColor::YELLOW,
|
||||
default => throw $this->badValueException(BlockStateNames::COLOR, $color),
|
||||
};
|
||||
}
|
||||
|
||||
/** @throws BlockStateDeserializeException */
|
||||
public function readCoralFacing() : int{
|
||||
return $this->parseFacingValue($this->readInt(BlockStateNames::CORAL_DIRECTION), [
|
||||
@ -371,7 +350,7 @@ final class BlockStateReader{
|
||||
*/
|
||||
public function ignored(string $name) : void{
|
||||
if($this->data->getState($name) !== null){
|
||||
$this->usedStates[$name] = true;
|
||||
unset($this->unusedStates[$name]);
|
||||
}else{
|
||||
throw $this->missingOrWrongTypeException($name, null);
|
||||
}
|
||||
@ -388,10 +367,8 @@ final class BlockStateReader{
|
||||
* @throws BlockStateDeserializeException
|
||||
*/
|
||||
public function checkUnreadProperties() : void{
|
||||
foreach(Utils::stringifyKeys($this->data->getStates()) as $name => $tag){
|
||||
if(!isset($this->usedStates[$name])){
|
||||
throw new BlockStateDeserializeException("Unread property \"$name\"");
|
||||
}
|
||||
if(count($this->unusedStates) > 0){
|
||||
throw new BlockStateDeserializeException("Unread properties: " . implode(", ", array_keys($this->unusedStates)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,43 +56,35 @@ use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
|
||||
use pocketmine\math\Facing;
|
||||
|
||||
final class BlockStateSerializerHelper{
|
||||
|
||||
public static function encodeAllSidedLog(Wood $block) : BlockStateWriter{
|
||||
return BlockStateWriter::create(Ids::WOOD)
|
||||
->writeBool(BlockStateNames::STRIPPED_BIT, $block->isStripped())
|
||||
->writePillarAxis($block->getAxis())
|
||||
->writeLegacyWoodType($block->getWoodType());
|
||||
}
|
||||
|
||||
public static function encodeButton(Button $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeButton(Button $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeFacingDirection($block->getFacing())
|
||||
->writeBool(BlockStateNames::BUTTON_PRESSED_BIT, $block->isPressed());
|
||||
}
|
||||
|
||||
public static function encodeCandle(Candle $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeCandle(Candle $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeBool(StateNames::LIT, $block->isLit())
|
||||
->writeInt(StateNames::CANDLES, $block->getCount() - 1);
|
||||
}
|
||||
|
||||
public static function encodeChemistryTable(ChemistryTable $block, string $chemistryTableType, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeChemistryTable(ChemistryTable $block, string $chemistryTableType, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeString(BlockStateNames::CHEMISTRY_TABLE_TYPE, $chemistryTableType)
|
||||
->writeLegacyHorizontalFacing(Facing::opposite($block->getFacing()));
|
||||
}
|
||||
|
||||
public static function encodeCrops(Crops $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeCrops(Crops $block, Writer $out) : Writer{
|
||||
return $out->writeInt(BlockStateNames::GROWTH, $block->getAge());
|
||||
}
|
||||
|
||||
public static function encodeColoredTorch(Torch $block, bool $highBit, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeColoredTorch(Torch $block, bool $highBit, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeBool(BlockStateNames::COLOR_BIT, $highBit)
|
||||
->writeTorchFacing($block->getFacing());
|
||||
}
|
||||
|
||||
public static function encodeCauldron(string $liquid, int $fillLevel) : BlockStateWriter{
|
||||
public static function encodeCauldron(string $liquid, int $fillLevel) : Writer{
|
||||
return Writer::create(Ids::CAULDRON)
|
||||
->writeString(BlockStateNames::CAULDRON_LIQUID, $liquid)
|
||||
->writeInt(BlockStateNames::FILL_LEVEL, $fillLevel);
|
||||
@ -107,7 +99,7 @@ final class BlockStateSerializerHelper{
|
||||
};
|
||||
}
|
||||
|
||||
public static function encodeDoor(Door $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeDoor(Door $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
|
||||
->writeLegacyHorizontalFacing(Facing::rotateY($block->getFacing(), true))
|
||||
@ -115,111 +107,96 @@ final class BlockStateSerializerHelper{
|
||||
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
|
||||
}
|
||||
|
||||
public static function encodeDoublePlant(DoublePlant $block, string $doublePlantType, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeDoublePlant(DoublePlant $block, string $doublePlantType, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
|
||||
->writeString(BlockStateNames::DOUBLE_PLANT_TYPE, $doublePlantType);
|
||||
}
|
||||
|
||||
public static function encodeFenceGate(FenceGate $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeFenceGate(FenceGate $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeLegacyHorizontalFacing($block->getFacing())
|
||||
->writeBool(BlockStateNames::IN_WALL_BIT, $block->isInWall())
|
||||
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
|
||||
}
|
||||
|
||||
public static function encodeFloorSign(FloorSign $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeFloorSign(FloorSign $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeInt(BlockStateNames::GROUND_SIGN_DIRECTION, $block->getRotation());
|
||||
}
|
||||
|
||||
public static function encodeFurnace(Furnace $block, string $unlitId, string $litId) : BlockStateWriter{
|
||||
return BlockStateWriter::create($block->isLit() ? $litId : $unlitId)
|
||||
public static function encodeFurnace(Furnace $block, string $unlitId, string $litId) : Writer{
|
||||
return Writer::create($block->isLit() ? $litId : $unlitId)
|
||||
->writeCardinalHorizontalFacing($block->getFacing());
|
||||
}
|
||||
|
||||
public static function encodeItemFrame(ItemFrame $block, string $id) : BlockStateWriter{
|
||||
public static function encodeItemFrame(ItemFrame $block, string $id) : Writer{
|
||||
return Writer::create($id)
|
||||
->writeBool(StateNames::ITEM_FRAME_MAP_BIT, $block->hasMap())
|
||||
->writeBool(StateNames::ITEM_FRAME_PHOTO_BIT, false)
|
||||
->writeFacingDirection($block->getFacing());
|
||||
}
|
||||
|
||||
public static function encodeLeaves(Leaves $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeLeaves(Leaves $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeBool(BlockStateNames::PERSISTENT_BIT, $block->isNoDecay())
|
||||
->writeBool(BlockStateNames::UPDATE_BIT, $block->isCheckDecay());
|
||||
}
|
||||
|
||||
public static function encodeLeaves1(Leaves $block, string $type) : BlockStateWriter{
|
||||
return self::encodeLeaves($block, BlockStateWriter::create(Ids::LEAVES)
|
||||
->writeString(BlockStateNames::OLD_LEAF_TYPE, $type));
|
||||
}
|
||||
|
||||
public static function encodeLeaves2(Leaves $block, string $type) : BlockStateWriter{
|
||||
return self::encodeLeaves($block, BlockStateWriter::create(Ids::LEAVES2)
|
||||
->writeString(BlockStateNames::NEW_LEAF_TYPE, $type));
|
||||
}
|
||||
|
||||
public static function encodeLiquid(Liquid $block, string $stillId, string $flowingId) : BlockStateWriter{
|
||||
return BlockStateWriter::create($block->isStill() ? $stillId : $flowingId)
|
||||
public static function encodeLiquid(Liquid $block, string $stillId, string $flowingId) : Writer{
|
||||
return Writer::create($block->isStill() ? $stillId : $flowingId)
|
||||
->writeInt(BlockStateNames::LIQUID_DEPTH, $block->getDecay() | ($block->isFalling() ? 0x8 : 0));
|
||||
}
|
||||
|
||||
public static function encodeLog(Wood $block, string $unstrippedId, string $strippedId) : BlockStateWriter{
|
||||
public static function encodeLog(Wood $block, string $unstrippedId, string $strippedId) : Writer{
|
||||
$out = $block->isStripped() ?
|
||||
BlockStateWriter::create($strippedId) :
|
||||
BlockStateWriter::create($unstrippedId);
|
||||
Writer::create($strippedId) :
|
||||
Writer::create($unstrippedId);
|
||||
return $out
|
||||
->writePillarAxis($block->getAxis());
|
||||
}
|
||||
|
||||
public static function encodeMushroomBlock(RedMushroomBlock $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeMushroomBlock(RedMushroomBlock $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeInt(BlockStateNames::HUGE_MUSHROOM_BITS, MushroomBlockTypeIdMap::getInstance()->toId($block->getMushroomBlockType()));
|
||||
}
|
||||
|
||||
public static function encodeQuartz(string $type, int $axis) : BlockStateWriter{
|
||||
return BlockStateWriter::create(Ids::QUARTZ_BLOCK)
|
||||
public static function encodeQuartz(string $type, int $axis) : Writer{
|
||||
return Writer::create(Ids::QUARTZ_BLOCK)
|
||||
->writeString(BlockStateNames::CHISEL_TYPE, $type)
|
||||
->writePillarAxis($axis); //this isn't needed for all types, but we have to write it anyway
|
||||
}
|
||||
|
||||
public static function encodeRedFlower(string $type) : BlockStateWriter{
|
||||
return BlockStateWriter::create(Ids::RED_FLOWER)->writeString(BlockStateNames::FLOWER_TYPE, $type);
|
||||
public static function encodeSandstone(string $id, string $type) : Writer{
|
||||
return Writer::create($id)->writeString(BlockStateNames::SAND_STONE_TYPE, $type);
|
||||
}
|
||||
|
||||
public static function encodeSandstone(string $id, string $type) : BlockStateWriter{
|
||||
return BlockStateWriter::create($id)->writeString(BlockStateNames::SAND_STONE_TYPE, $type);
|
||||
public static function encodeSapling(Sapling $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeBool(BlockStateNames::AGE_BIT, $block->isReady());
|
||||
}
|
||||
|
||||
public static function encodeSapling(Sapling $block, string $type) : BlockStateWriter{
|
||||
return BlockStateWriter::create(Ids::SAPLING)
|
||||
->writeBool(BlockStateNames::AGE_BIT, $block->isReady())
|
||||
->writeString(BlockStateNames::SAPLING_TYPE, $type);
|
||||
}
|
||||
|
||||
public static function encodeSimplePressurePlate(SimplePressurePlate $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeSimplePressurePlate(SimplePressurePlate $block, Writer $out) : Writer{
|
||||
//TODO: not sure what the deal is here ... seems like a mojang bug / artifact of bad implementation?
|
||||
//best to keep this separate from weighted plates anyway...
|
||||
return $out
|
||||
->writeInt(BlockStateNames::REDSTONE_SIGNAL, $block->isPressed() ? 15 : 0);
|
||||
}
|
||||
|
||||
public static function encodeSlab(Slab $block, string $singleId, string $doubleId) : BlockStateWriter{
|
||||
public static function encodeSlab(Slab $block, string $singleId, string $doubleId) : Writer{
|
||||
$slabType = $block->getSlabType();
|
||||
return BlockStateWriter::create($slabType === SlabType::DOUBLE ? $doubleId : $singleId)
|
||||
return Writer::create($slabType === SlabType::DOUBLE ? $doubleId : $singleId)
|
||||
//this is (intentionally) also written for double slabs (as zero) to maintain bug parity with MCPE
|
||||
->writeSlabPosition($slabType === SlabType::DOUBLE ? SlabType::BOTTOM : $slabType);
|
||||
}
|
||||
|
||||
public static function encodeStairs(Stair $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeStairs(Stair $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeBool(BlockStateNames::UPSIDE_DOWN_BIT, $block->isUpsideDown())
|
||||
->writeWeirdoHorizontalFacing($block->getFacing());
|
||||
}
|
||||
|
||||
public static function encodeStem(Stem $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeStem(Stem $block, Writer $out) : Writer{
|
||||
//In PM, we use Facing::UP to indicate that the stem is not attached to a pumpkin/melon, since this makes the
|
||||
//most intuitive sense (the stem is pointing at the sky). However, Bedrock uses the DOWN state for this, which
|
||||
//is absurd, and I refuse to make our API similarly absurd.
|
||||
@ -228,40 +205,40 @@ final class BlockStateSerializerHelper{
|
||||
->writeFacingWithoutUp($facing === Facing::UP ? Facing::DOWN : $facing);
|
||||
}
|
||||
|
||||
public static function encodeStoneBricks(string $type) : BlockStateWriter{
|
||||
return BlockStateWriter::create(Ids::STONEBRICK)
|
||||
public static function encodeStoneBricks(string $type) : Writer{
|
||||
return Writer::create(Ids::STONEBRICK)
|
||||
->writeString(BlockStateNames::STONE_BRICK_TYPE, $type);
|
||||
}
|
||||
|
||||
private static function encodeStoneSlab(Slab $block, string $singleId, string $doubleId, string $typeKey, string $typeValue) : BlockStateWriter{
|
||||
private static function encodeStoneSlab(Slab $block, string $singleId, string $doubleId, string $typeKey, string $typeValue) : Writer{
|
||||
return self::encodeSlab($block, $singleId, $doubleId)
|
||||
->writeString($typeKey, $typeValue);
|
||||
}
|
||||
|
||||
public static function encodeStoneSlab1(Slab $block, string $typeValue) : BlockStateWriter{
|
||||
public static function encodeStoneSlab1(Slab $block, string $typeValue) : Writer{
|
||||
return self::encodeStoneSlab($block, Ids::STONE_BLOCK_SLAB, Ids::DOUBLE_STONE_BLOCK_SLAB, BlockStateNames::STONE_SLAB_TYPE, $typeValue);
|
||||
}
|
||||
|
||||
public static function encodeStoneSlab2(Slab $block, string $typeValue) : BlockStateWriter{
|
||||
public static function encodeStoneSlab2(Slab $block, string $typeValue) : Writer{
|
||||
return self::encodeStoneSlab($block, Ids::STONE_BLOCK_SLAB2, Ids::DOUBLE_STONE_BLOCK_SLAB2, BlockStateNames::STONE_SLAB_TYPE_2, $typeValue);
|
||||
}
|
||||
|
||||
public static function encodeStoneSlab3(Slab $block, string $typeValue) : BlockStateWriter{
|
||||
public static function encodeStoneSlab3(Slab $block, string $typeValue) : Writer{
|
||||
return self::encodeStoneSlab($block, Ids::STONE_BLOCK_SLAB3, Ids::DOUBLE_STONE_BLOCK_SLAB3, BlockStateNames::STONE_SLAB_TYPE_3, $typeValue);
|
||||
}
|
||||
|
||||
public static function encodeStoneSlab4(Slab $block, string $typeValue) : BlockStateWriter{
|
||||
public static function encodeStoneSlab4(Slab $block, string $typeValue) : Writer{
|
||||
return self::encodeStoneSlab($block, Ids::STONE_BLOCK_SLAB4, Ids::DOUBLE_STONE_BLOCK_SLAB4, BlockStateNames::STONE_SLAB_TYPE_4, $typeValue);
|
||||
}
|
||||
|
||||
public static function encodeTrapdoor(Trapdoor $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeTrapdoor(Trapdoor $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->write5MinusHorizontalFacing($block->getFacing())
|
||||
->writeBool(BlockStateNames::UPSIDE_DOWN_BIT, $block->isTop())
|
||||
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
|
||||
}
|
||||
|
||||
public static function encodeWall(Wall $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeWall(Wall $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeBool(BlockStateNames::WALL_POST_BIT, $block->isPost())
|
||||
->writeWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_EAST, $block->getConnection(Facing::EAST))
|
||||
@ -270,18 +247,13 @@ final class BlockStateSerializerHelper{
|
||||
->writeWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_WEST, $block->getConnection(Facing::WEST));
|
||||
}
|
||||
|
||||
public static function encodeLegacyWall(Wall $block, string $type) : BlockStateWriter{
|
||||
return self::encodeWall($block, BlockStateWriter::create(Ids::COBBLESTONE_WALL))
|
||||
public static function encodeLegacyWall(Wall $block, string $type) : Writer{
|
||||
return self::encodeWall($block, Writer::create(Ids::COBBLESTONE_WALL))
|
||||
->writeString(BlockStateNames::WALL_BLOCK_TYPE, $type);
|
||||
}
|
||||
|
||||
public static function encodeWallSign(WallSign $block, BlockStateWriter $out) : BlockStateWriter{
|
||||
public static function encodeWallSign(WallSign $block, Writer $out) : Writer{
|
||||
return $out
|
||||
->writeHorizontalFacing($block->getFacing());
|
||||
}
|
||||
|
||||
public static function encodeWoodenSlab(Slab $block, string $typeValue) : BlockStateWriter{
|
||||
return self::encodeSlab($block, Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB)
|
||||
->writeString(BlockStateNames::WOOD_TYPE, $typeValue);
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +82,8 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->registerFlatCoralDeserializers();
|
||||
$this->registerCauldronDeserializers();
|
||||
$this->registerFlatWoodBlockDeserializers();
|
||||
$this->registerLegacyWoodBlockDeserializers();
|
||||
$this->registerLeavesDeserializers();
|
||||
$this->registerSaplingDeserializers();
|
||||
$this->registerSimpleDeserializers();
|
||||
$this->registerDeserializers();
|
||||
}
|
||||
@ -185,6 +185,48 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
}
|
||||
|
||||
private function registerFlatColorBlockDeserializers() : void{
|
||||
foreach([
|
||||
Ids::HARD_BLACK_STAINED_GLASS => DyeColor::BLACK,
|
||||
Ids::HARD_BLUE_STAINED_GLASS => DyeColor::BLUE,
|
||||
Ids::HARD_BROWN_STAINED_GLASS => DyeColor::BROWN,
|
||||
Ids::HARD_CYAN_STAINED_GLASS => DyeColor::CYAN,
|
||||
Ids::HARD_GRAY_STAINED_GLASS => DyeColor::GRAY,
|
||||
Ids::HARD_GREEN_STAINED_GLASS => DyeColor::GREEN,
|
||||
Ids::HARD_LIGHT_BLUE_STAINED_GLASS => DyeColor::LIGHT_BLUE,
|
||||
Ids::HARD_LIGHT_GRAY_STAINED_GLASS => DyeColor::LIGHT_GRAY,
|
||||
Ids::HARD_LIME_STAINED_GLASS => DyeColor::LIME,
|
||||
Ids::HARD_MAGENTA_STAINED_GLASS => DyeColor::MAGENTA,
|
||||
Ids::HARD_ORANGE_STAINED_GLASS => DyeColor::ORANGE,
|
||||
Ids::HARD_PINK_STAINED_GLASS => DyeColor::PINK,
|
||||
Ids::HARD_PURPLE_STAINED_GLASS => DyeColor::PURPLE,
|
||||
Ids::HARD_RED_STAINED_GLASS => DyeColor::RED,
|
||||
Ids::HARD_WHITE_STAINED_GLASS => DyeColor::WHITE,
|
||||
Ids::HARD_YELLOW_STAINED_GLASS => DyeColor::YELLOW,
|
||||
] as $id => $color){
|
||||
$this->map($id, fn(Reader $in) => Blocks::STAINED_HARDENED_GLASS()->setColor($color));
|
||||
}
|
||||
|
||||
foreach([
|
||||
Ids::HARD_BLACK_STAINED_GLASS_PANE => DyeColor::BLACK,
|
||||
Ids::HARD_BLUE_STAINED_GLASS_PANE => DyeColor::BLUE,
|
||||
Ids::HARD_BROWN_STAINED_GLASS_PANE => DyeColor::BROWN,
|
||||
Ids::HARD_CYAN_STAINED_GLASS_PANE => DyeColor::CYAN,
|
||||
Ids::HARD_GRAY_STAINED_GLASS_PANE => DyeColor::GRAY,
|
||||
Ids::HARD_GREEN_STAINED_GLASS_PANE => DyeColor::GREEN,
|
||||
Ids::HARD_LIGHT_BLUE_STAINED_GLASS_PANE => DyeColor::LIGHT_BLUE,
|
||||
Ids::HARD_LIGHT_GRAY_STAINED_GLASS_PANE => DyeColor::LIGHT_GRAY,
|
||||
Ids::HARD_LIME_STAINED_GLASS_PANE => DyeColor::LIME,
|
||||
Ids::HARD_MAGENTA_STAINED_GLASS_PANE => DyeColor::MAGENTA,
|
||||
Ids::HARD_ORANGE_STAINED_GLASS_PANE => DyeColor::ORANGE,
|
||||
Ids::HARD_PINK_STAINED_GLASS_PANE => DyeColor::PINK,
|
||||
Ids::HARD_PURPLE_STAINED_GLASS_PANE => DyeColor::PURPLE,
|
||||
Ids::HARD_RED_STAINED_GLASS_PANE => DyeColor::RED,
|
||||
Ids::HARD_WHITE_STAINED_GLASS_PANE => DyeColor::WHITE,
|
||||
Ids::HARD_YELLOW_STAINED_GLASS_PANE => DyeColor::YELLOW,
|
||||
] as $id => $color){
|
||||
$this->map($id, fn(Reader $in) => Blocks::STAINED_HARDENED_GLASS_PANE()->setColor($color));
|
||||
}
|
||||
|
||||
foreach([
|
||||
Ids::BLACK_GLAZED_TERRACOTTA => DyeColor::BLACK,
|
||||
Ids::BLUE_GLAZED_TERRACOTTA => DyeColor::BLUE,
|
||||
@ -397,6 +439,17 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
] as $id => $coralType){
|
||||
$this->mapSimple($id, fn() => Blocks::CORAL()->setCoralType($coralType)->setDead(true));
|
||||
}
|
||||
|
||||
foreach([
|
||||
[CoralType::BRAIN, Ids::BRAIN_CORAL_FAN, Ids::DEAD_BRAIN_CORAL_FAN],
|
||||
[CoralType::BUBBLE, Ids::BUBBLE_CORAL_FAN, Ids::DEAD_BUBBLE_CORAL_FAN],
|
||||
[CoralType::FIRE, Ids::FIRE_CORAL_FAN, Ids::DEAD_FIRE_CORAL_FAN],
|
||||
[CoralType::HORN, Ids::HORN_CORAL_FAN, Ids::DEAD_HORN_CORAL_FAN],
|
||||
[CoralType::TUBE, Ids::TUBE_CORAL_FAN, Ids::DEAD_TUBE_CORAL_FAN],
|
||||
] as [$coralType, $aliveId, $deadId]){
|
||||
$this->map($aliveId, fn(Reader $in) => Helper::decodeFloorCoralFan(Blocks::CORAL_FAN()->setCoralType($coralType)->setDead(false), $in));
|
||||
$this->map($deadId, fn(Reader $in) => Helper::decodeFloorCoralFan(Blocks::CORAL_FAN()->setCoralType($coralType)->setDead(true), $in));
|
||||
}
|
||||
}
|
||||
|
||||
private function registerCauldronDeserializers() : void{
|
||||
@ -426,10 +479,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::ACACIA_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::ACACIA_TRAPDOOR(), $in));
|
||||
$this->map(Ids::ACACIA_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::ACACIA_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG, fn() => Blocks::ACACIA_LOG());
|
||||
$this->mapLog(Ids::ACACIA_WOOD, Ids::STRIPPED_ACACIA_WOOD, fn() => Blocks::ACACIA_WOOD());
|
||||
$this->mapSimple(Ids::ACACIA_FENCE, fn() => Blocks::ACACIA_FENCE());
|
||||
$this->mapSimple(Ids::ACACIA_PLANKS, fn() => Blocks::ACACIA_PLANKS());
|
||||
$this->mapSlab(Ids::ACACIA_SLAB, Ids::ACACIA_DOUBLE_SLAB, fn() => Blocks::ACACIA_SLAB());
|
||||
$this->mapStairs(Ids::ACACIA_STAIRS, fn() => Blocks::ACACIA_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::BIRCH_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::BIRCH_BUTTON(), $in));
|
||||
$this->map(Ids::BIRCH_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::BIRCH_DOOR(), $in));
|
||||
@ -439,10 +493,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::BIRCH_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::BIRCH_TRAPDOOR(), $in));
|
||||
$this->map(Ids::BIRCH_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::BIRCH_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG, fn() => Blocks::BIRCH_LOG());
|
||||
$this->mapLog(Ids::BIRCH_WOOD, Ids::STRIPPED_BIRCH_WOOD, fn() => Blocks::BIRCH_WOOD());
|
||||
$this->mapSimple(Ids::BIRCH_FENCE, fn() => Blocks::BIRCH_FENCE());
|
||||
$this->mapSimple(Ids::BIRCH_PLANKS, fn() => Blocks::BIRCH_PLANKS());
|
||||
$this->mapSlab(Ids::BIRCH_SLAB, Ids::BIRCH_DOUBLE_SLAB, fn() => Blocks::BIRCH_SLAB());
|
||||
$this->mapStairs(Ids::BIRCH_STAIRS, fn() => Blocks::BIRCH_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::CHERRY_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::CHERRY_BUTTON(), $in));
|
||||
$this->map(Ids::CHERRY_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::CHERRY_DOOR(), $in));
|
||||
@ -484,10 +539,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::DARK_OAK_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::DARK_OAK_PRESSURE_PLATE(), $in));
|
||||
$this->map(Ids::DARK_OAK_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::DARK_OAK_TRAPDOOR(), $in));
|
||||
$this->mapLog(Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG, fn() => Blocks::DARK_OAK_LOG());
|
||||
$this->mapLog(Ids::DARK_OAK_WOOD, Ids::STRIPPED_DARK_OAK_WOOD, fn() => Blocks::DARK_OAK_WOOD());
|
||||
$this->mapSimple(Ids::DARK_OAK_FENCE, fn() => Blocks::DARK_OAK_FENCE());
|
||||
$this->mapSimple(Ids::DARK_OAK_PLANKS, fn() => Blocks::DARK_OAK_PLANKS());
|
||||
$this->mapSlab(Ids::DARK_OAK_SLAB, Ids::DARK_OAK_DOUBLE_SLAB, fn() => Blocks::DARK_OAK_SLAB());
|
||||
$this->mapStairs(Ids::DARK_OAK_STAIRS, fn() => Blocks::DARK_OAK_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::JUNGLE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::JUNGLE_BUTTON(), $in));
|
||||
$this->map(Ids::JUNGLE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::JUNGLE_DOOR(), $in));
|
||||
@ -497,10 +553,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::JUNGLE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::JUNGLE_TRAPDOOR(), $in));
|
||||
$this->map(Ids::JUNGLE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::JUNGLE_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG, fn() => Blocks::JUNGLE_LOG());
|
||||
$this->mapLog(Ids::JUNGLE_WOOD, Ids::STRIPPED_JUNGLE_WOOD, fn() => Blocks::JUNGLE_WOOD());
|
||||
$this->mapSimple(Ids::JUNGLE_FENCE, fn() => Blocks::JUNGLE_FENCE());
|
||||
$this->mapSimple(Ids::JUNGLE_PLANKS, fn() => Blocks::JUNGLE_PLANKS());
|
||||
$this->mapSlab(Ids::JUNGLE_SLAB, Ids::JUNGLE_DOUBLE_SLAB, fn() => Blocks::JUNGLE_SLAB());
|
||||
$this->mapStairs(Ids::JUNGLE_STAIRS, fn() => Blocks::JUNGLE_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::MANGROVE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::MANGROVE_BUTTON(), $in));
|
||||
$this->map(Ids::MANGROVE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::MANGROVE_DOOR(), $in));
|
||||
@ -529,10 +586,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::OAK_TRAPDOOR(), $in));
|
||||
$this->map(Ids::WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::OAK_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG, fn() => Blocks::OAK_LOG());
|
||||
$this->mapLog(Ids::OAK_WOOD, Ids::STRIPPED_OAK_WOOD, fn() => Blocks::OAK_WOOD());
|
||||
$this->mapSimple(Ids::OAK_FENCE, fn() => Blocks::OAK_FENCE());
|
||||
$this->mapSimple(Ids::OAK_PLANKS, fn() => Blocks::OAK_PLANKS());
|
||||
$this->mapSlab(Ids::OAK_SLAB, Ids::OAK_DOUBLE_SLAB, fn() => Blocks::OAK_SLAB());
|
||||
$this->mapStairs(Ids::OAK_STAIRS, fn() => Blocks::OAK_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::SPRUCE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::SPRUCE_BUTTON(), $in));
|
||||
$this->map(Ids::SPRUCE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::SPRUCE_DOOR(), $in));
|
||||
@ -542,10 +600,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::SPRUCE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::SPRUCE_TRAPDOOR(), $in));
|
||||
$this->map(Ids::SPRUCE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::SPRUCE_WALL_SIGN(), $in));
|
||||
$this->mapLog(Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG, fn() => Blocks::SPRUCE_LOG());
|
||||
$this->mapLog(Ids::SPRUCE_WOOD, Ids::STRIPPED_SPRUCE_WOOD, fn() => Blocks::SPRUCE_WOOD());
|
||||
$this->mapSimple(Ids::SPRUCE_FENCE, fn() => Blocks::SPRUCE_FENCE());
|
||||
$this->mapSimple(Ids::SPRUCE_PLANKS, fn() => Blocks::SPRUCE_PLANKS());
|
||||
$this->mapSlab(Ids::SPRUCE_SLAB, Ids::SPRUCE_DOUBLE_SLAB, fn() => Blocks::SPRUCE_SLAB());
|
||||
$this->mapStairs(Ids::SPRUCE_STAIRS, fn() => Blocks::SPRUCE_STAIRS());
|
||||
//wood, planks and slabs still use the old way of storing wood type
|
||||
|
||||
$this->map(Ids::WARPED_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::WARPED_BUTTON(), $in));
|
||||
$this->map(Ids::WARPED_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::WARPED_DOOR(), $in));
|
||||
@ -562,40 +621,30 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapStairs(Ids::WARPED_STAIRS, fn() => Blocks::WARPED_STAIRS());
|
||||
}
|
||||
|
||||
private function registerLegacyWoodBlockDeserializers() : void{
|
||||
$this->mapSlab(Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB, fn(Reader $in) => Helper::mapWoodenSlabType($in));
|
||||
|
||||
$this->map(Ids::WOOD, fn(Reader $in) : Block => Helper::decodeLog(match($woodType = $in->readString(StateNames::WOOD_TYPE)){
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_WOOD(),
|
||||
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_WOOD(),
|
||||
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_WOOD(),
|
||||
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_WOOD(),
|
||||
StringValues::WOOD_TYPE_OAK => Blocks::OAK_WOOD(),
|
||||
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_WOOD(),
|
||||
default => throw $in->badValueException(StateNames::WOOD_TYPE, $woodType),
|
||||
}, $in->readBool(StateNames::STRIPPED_BIT), $in));
|
||||
}
|
||||
|
||||
private function registerLeavesDeserializers() : void{
|
||||
//flattened IDs
|
||||
$this->map(Ids::ACACIA_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::ACACIA_LEAVES(), $in));
|
||||
$this->map(Ids::AZALEA_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::AZALEA_LEAVES(), $in));
|
||||
$this->map(Ids::AZALEA_LEAVES_FLOWERED, fn(Reader $in) => Helper::decodeLeaves(Blocks::FLOWERING_AZALEA_LEAVES(), $in));
|
||||
$this->map(Ids::BIRCH_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::BIRCH_LEAVES(), $in));
|
||||
$this->map(Ids::CHERRY_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::CHERRY_LEAVES(), $in));
|
||||
$this->map(Ids::DARK_OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::DARK_OAK_LEAVES(), $in));
|
||||
$this->map(Ids::JUNGLE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::JUNGLE_LEAVES(), $in));
|
||||
$this->map(Ids::MANGROVE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::MANGROVE_LEAVES(), $in));
|
||||
$this->map(Ids::OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::OAK_LEAVES(), $in));
|
||||
$this->map(Ids::SPRUCE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::SPRUCE_LEAVES(), $in));
|
||||
}
|
||||
|
||||
//legacy mess
|
||||
$this->map(Ids::LEAVES, fn(Reader $in) => Helper::decodeLeaves(match($type = $in->readString(StateNames::OLD_LEAF_TYPE)){
|
||||
StringValues::OLD_LEAF_TYPE_BIRCH => Blocks::BIRCH_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_JUNGLE => Blocks::JUNGLE_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_OAK => Blocks::OAK_LEAVES(),
|
||||
StringValues::OLD_LEAF_TYPE_SPRUCE => Blocks::SPRUCE_LEAVES(),
|
||||
default => throw $in->badValueException(StateNames::OLD_LEAF_TYPE, $type),
|
||||
}, $in));
|
||||
$this->map(Ids::LEAVES2, fn(Reader $in) => Helper::decodeLeaves(match($type = $in->readString(StateNames::NEW_LEAF_TYPE)){
|
||||
StringValues::NEW_LEAF_TYPE_ACACIA => Blocks::ACACIA_LEAVES(),
|
||||
StringValues::NEW_LEAF_TYPE_DARK_OAK => Blocks::DARK_OAK_LEAVES(),
|
||||
default => throw $in->badValueException(StateNames::NEW_LEAF_TYPE, $type),
|
||||
}, $in));
|
||||
private function registerSaplingDeserializers() : void{
|
||||
foreach([
|
||||
Ids::ACACIA_SAPLING => fn() => Blocks::ACACIA_SAPLING(),
|
||||
Ids::BIRCH_SAPLING => fn() => Blocks::BIRCH_SAPLING(),
|
||||
Ids::DARK_OAK_SAPLING => fn() => Blocks::DARK_OAK_SAPLING(),
|
||||
Ids::JUNGLE_SAPLING => fn() => Blocks::JUNGLE_SAPLING(),
|
||||
Ids::OAK_SAPLING => fn() => Blocks::OAK_SAPLING(),
|
||||
Ids::SPRUCE_SAPLING => fn() => Blocks::SPRUCE_SAPLING(),
|
||||
] as $id => $getBlock){
|
||||
$this->map($id, fn(Reader $in) => Helper::decodeSapling($getBlock(), $in));
|
||||
}
|
||||
}
|
||||
|
||||
private function registerSimpleDeserializers() : void{
|
||||
@ -779,7 +828,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapSimple(Ids::GOLD_BLOCK, fn() => Blocks::GOLD());
|
||||
$this->mapSimple(Ids::GOLD_ORE, fn() => Blocks::GOLD_ORE());
|
||||
$this->mapSimple(Ids::GRANITE, fn() => Blocks::GRANITE());
|
||||
$this->mapSimple(Ids::GRASS, fn() => Blocks::GRASS());
|
||||
$this->mapSimple(Ids::GRASS_BLOCK, fn() => Blocks::GRASS());
|
||||
$this->mapSimple(Ids::GRASS_PATH, fn() => Blocks::GRASS_PATH());
|
||||
$this->mapSimple(Ids::GRAVEL, fn() => Blocks::GRAVEL());
|
||||
$this->mapSimple(Ids::HANGING_ROOTS, fn() => Blocks::HANGING_ROOTS());
|
||||
@ -856,6 +905,18 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapSimple(Ids::WEB, fn() => Blocks::COBWEB());
|
||||
$this->mapSimple(Ids::WITHER_ROSE, fn() => Blocks::WITHER_ROSE());
|
||||
$this->mapSimple(Ids::YELLOW_FLOWER, fn() => Blocks::DANDELION());
|
||||
|
||||
$this->mapSimple(Ids::ALLIUM, fn() => Blocks::ALLIUM());
|
||||
$this->mapSimple(Ids::CORNFLOWER, fn() => Blocks::CORNFLOWER());
|
||||
$this->mapSimple(Ids::AZURE_BLUET, fn() => Blocks::AZURE_BLUET());
|
||||
$this->mapSimple(Ids::LILY_OF_THE_VALLEY, fn() => Blocks::LILY_OF_THE_VALLEY());
|
||||
$this->mapSimple(Ids::BLUE_ORCHID, fn() => Blocks::BLUE_ORCHID());
|
||||
$this->mapSimple(Ids::OXEYE_DAISY, fn() => Blocks::OXEYE_DAISY());
|
||||
$this->mapSimple(Ids::POPPY, fn() => Blocks::POPPY());
|
||||
$this->mapSimple(Ids::ORANGE_TULIP, fn() => Blocks::ORANGE_TULIP());
|
||||
$this->mapSimple(Ids::PINK_TULIP, fn() => Blocks::PINK_TULIP());
|
||||
$this->mapSimple(Ids::RED_TULIP, fn() => Blocks::RED_TULIP());
|
||||
$this->mapSimple(Ids::WHITE_TULIP, fn() => Blocks::WHITE_TULIP());
|
||||
}
|
||||
|
||||
private function registerDeserializers() : void{
|
||||
@ -897,7 +958,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
});
|
||||
});
|
||||
$this->map(Ids::BAMBOO_SAPLING, function(Reader $in) : Block{
|
||||
$in->ignored(StateNames::SAPLING_TYPE); //bug in MCPE
|
||||
return Blocks::BAMBOO_SAPLING()->setReady($in->readBool(StateNames::AGE_BIT));
|
||||
});
|
||||
$this->map(Ids::BARREL, function(Reader $in) : Block{
|
||||
@ -1054,10 +1114,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setCoralType($in->readCoralType())
|
||||
->setDead($in->readBool(StateNames::DEAD_BIT));
|
||||
});
|
||||
$this->map(Ids::CORAL_FAN, fn(Reader $in) => Helper::decodeFloorCoralFan(Blocks::CORAL_FAN(), $in)
|
||||
->setDead(false));
|
||||
$this->map(Ids::CORAL_FAN_DEAD, fn(Reader $in) => Helper::decodeFloorCoralFan(Blocks::CORAL_FAN(), $in)
|
||||
->setDead(true));
|
||||
$this->map(Ids::CORAL_FAN_HANG, fn(Reader $in) => Helper::decodeWallCoralFan(Blocks::WALL_CORAL_FAN(), $in)
|
||||
->setCoralType($in->readBool(StateNames::CORAL_HANG_TYPE_BIT) ? CoralType::BRAIN : CoralType::TUBE));
|
||||
$this->map(Ids::CORAL_FAN_HANG2, fn(Reader $in) => Helper::decodeWallCoralFan(Blocks::WALL_CORAL_FAN(), $in)
|
||||
@ -1159,14 +1215,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 5));
|
||||
});
|
||||
$this->mapStairs(Ids::GRANITE_STAIRS, fn() => Blocks::GRANITE_STAIRS());
|
||||
$this->map(Ids::HARD_STAINED_GLASS, function(Reader $in) : Block{
|
||||
return Blocks::STAINED_HARDENED_GLASS()
|
||||
->setColor($in->readColor());
|
||||
});
|
||||
$this->map(Ids::HARD_STAINED_GLASS_PANE, function(Reader $in) : Block{
|
||||
return Blocks::STAINED_HARDENED_GLASS_PANE()
|
||||
->setColor($in->readColor());
|
||||
});
|
||||
$this->map(Ids::HAY_BLOCK, function(Reader $in) : Block{
|
||||
$in->ignored(StateNames::DEPRECATED);
|
||||
return Blocks::HAY_BALE()->setAxis($in->readPillarAxis());
|
||||
@ -1397,22 +1445,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::RAIL()
|
||||
->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 9));
|
||||
});
|
||||
$this->map(Ids::RED_FLOWER, function(Reader $in) : Block{
|
||||
return match($type = $in->readString(StateNames::FLOWER_TYPE)){
|
||||
StringValues::FLOWER_TYPE_ALLIUM => Blocks::ALLIUM(),
|
||||
StringValues::FLOWER_TYPE_CORNFLOWER => Blocks::CORNFLOWER(),
|
||||
StringValues::FLOWER_TYPE_HOUSTONIA => Blocks::AZURE_BLUET(), //wtf ???
|
||||
StringValues::FLOWER_TYPE_LILY_OF_THE_VALLEY => Blocks::LILY_OF_THE_VALLEY(),
|
||||
StringValues::FLOWER_TYPE_ORCHID => Blocks::BLUE_ORCHID(),
|
||||
StringValues::FLOWER_TYPE_OXEYE => Blocks::OXEYE_DAISY(),
|
||||
StringValues::FLOWER_TYPE_POPPY => Blocks::POPPY(),
|
||||
StringValues::FLOWER_TYPE_TULIP_ORANGE => Blocks::ORANGE_TULIP(),
|
||||
StringValues::FLOWER_TYPE_TULIP_PINK => Blocks::PINK_TULIP(),
|
||||
StringValues::FLOWER_TYPE_TULIP_RED => Blocks::RED_TULIP(),
|
||||
StringValues::FLOWER_TYPE_TULIP_WHITE => Blocks::WHITE_TULIP(),
|
||||
default => throw $in->badValueException(StateNames::FLOWER_TYPE, $type),
|
||||
};
|
||||
});
|
||||
$this->map(Ids::RED_MUSHROOM_BLOCK, fn(Reader $in) => Helper::decodeMushroomBlock(Blocks::RED_MUSHROOM_BLOCK(), $in));
|
||||
$this->mapStairs(Ids::RED_NETHER_BRICK_STAIRS, fn() => Blocks::RED_NETHER_BRICK_STAIRS());
|
||||
$this->map(Ids::RED_SANDSTONE, function(Reader $in) : Block{
|
||||
@ -1463,18 +1495,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
};
|
||||
});
|
||||
$this->mapStairs(Ids::SANDSTONE_STAIRS, fn() => Blocks::SANDSTONE_STAIRS());
|
||||
$this->map(Ids::SAPLING, function(Reader $in) : Block{
|
||||
return (match($type = $in->readString(StateNames::SAPLING_TYPE)){
|
||||
StringValues::SAPLING_TYPE_ACACIA => Blocks::ACACIA_SAPLING(),
|
||||
StringValues::SAPLING_TYPE_BIRCH => Blocks::BIRCH_SAPLING(),
|
||||
StringValues::SAPLING_TYPE_DARK_OAK => Blocks::DARK_OAK_SAPLING(),
|
||||
StringValues::SAPLING_TYPE_JUNGLE => Blocks::JUNGLE_SAPLING(),
|
||||
StringValues::SAPLING_TYPE_OAK => Blocks::OAK_SAPLING(),
|
||||
StringValues::SAPLING_TYPE_SPRUCE => Blocks::SPRUCE_SAPLING(),
|
||||
default => throw $in->badValueException(StateNames::SAPLING_TYPE, $type),
|
||||
})
|
||||
->setReady($in->readBool(StateNames::AGE_BIT));
|
||||
});
|
||||
$this->map(Ids::SEA_PICKLE, function(Reader $in) : Block{
|
||||
return Blocks::SEA_PICKLE()
|
||||
->setCount($in->readBoundedInt(StateNames::CLUSTER_COUNT, 0, 3) + 1)
|
||||
|
@ -25,10 +25,8 @@ namespace pocketmine\data\bedrock\block\convert;
|
||||
|
||||
use pocketmine\block\utils\BellAttachmentType;
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\DyeColor;
|
||||
use pocketmine\block\utils\SlabType;
|
||||
use pocketmine\block\utils\WallConnectionType;
|
||||
use pocketmine\block\utils\WoodType;
|
||||
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
|
||||
use pocketmine\data\bedrock\block\BlockStateData;
|
||||
use pocketmine\data\bedrock\block\BlockStateNames;
|
||||
@ -193,29 +191,6 @@ final class BlockStateWriter{
|
||||
});
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function writeColor(DyeColor $color) : self{
|
||||
$this->writeString(BlockStateNames::COLOR, match($color){
|
||||
DyeColor::BLACK => StringValues::COLOR_BLACK,
|
||||
DyeColor::BLUE => StringValues::COLOR_BLUE,
|
||||
DyeColor::BROWN => StringValues::COLOR_BROWN,
|
||||
DyeColor::CYAN => StringValues::COLOR_CYAN,
|
||||
DyeColor::GRAY => StringValues::COLOR_GRAY,
|
||||
DyeColor::GREEN => StringValues::COLOR_GREEN,
|
||||
DyeColor::LIGHT_BLUE => StringValues::COLOR_LIGHT_BLUE,
|
||||
DyeColor::LIGHT_GRAY => StringValues::COLOR_SILVER,
|
||||
DyeColor::LIME => StringValues::COLOR_LIME,
|
||||
DyeColor::MAGENTA => StringValues::COLOR_MAGENTA,
|
||||
DyeColor::ORANGE => StringValues::COLOR_ORANGE,
|
||||
DyeColor::PINK => StringValues::COLOR_PINK,
|
||||
DyeColor::PURPLE => StringValues::COLOR_PURPLE,
|
||||
DyeColor::RED => StringValues::COLOR_RED,
|
||||
DyeColor::WHITE => StringValues::COLOR_WHITE,
|
||||
DyeColor::YELLOW => StringValues::COLOR_YELLOW,
|
||||
});
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function writeCoralFacing(int $value) : self{
|
||||
$this->writeInt(BlockStateNames::CORAL_DIRECTION, match($value){
|
||||
@ -281,20 +256,6 @@ final class BlockStateWriter{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function writeLegacyWoodType(WoodType $treeType) : self{
|
||||
$this->writeString(BlockStateNames::WOOD_TYPE, match($treeType){
|
||||
WoodType::OAK => StringValues::WOOD_TYPE_OAK,
|
||||
WoodType::SPRUCE => StringValues::WOOD_TYPE_SPRUCE,
|
||||
WoodType::BIRCH => StringValues::WOOD_TYPE_BIRCH,
|
||||
WoodType::JUNGLE => StringValues::WOOD_TYPE_JUNGLE,
|
||||
WoodType::ACACIA => StringValues::WOOD_TYPE_ACACIA,
|
||||
WoodType::DARK_OAK => StringValues::WOOD_TYPE_DARK_OAK,
|
||||
default => throw new BlockStateSerializeException("Invalid legacy wood type " . $treeType->name)
|
||||
});
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function writeCoralType(CoralType $coralType) : self{
|
||||
$this->writeString(BlockStateNames::CORAL_COLOR, match($coralType){
|
||||
|
@ -64,20 +64,24 @@ final class BlockStateUpgradeSchema{
|
||||
*/
|
||||
public array $remappedStates = [];
|
||||
|
||||
public readonly int $versionId;
|
||||
|
||||
public function __construct(
|
||||
public int $maxVersionMajor,
|
||||
public int $maxVersionMinor,
|
||||
public int $maxVersionPatch,
|
||||
public int $maxVersionRevision,
|
||||
public readonly int $maxVersionMajor,
|
||||
public readonly int $maxVersionMinor,
|
||||
public readonly int $maxVersionPatch,
|
||||
public readonly int $maxVersionRevision,
|
||||
private int $schemaId
|
||||
){}
|
||||
){
|
||||
$this->versionId = ($this->maxVersionMajor << 24) | ($this->maxVersionMinor << 16) | ($this->maxVersionPatch << 8) | $this->maxVersionRevision;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This is defined by Mojang, and therefore cannot be relied on. Use getSchemaId() instead for
|
||||
* internal version management.
|
||||
*/
|
||||
public function getVersionId() : int{
|
||||
return ($this->maxVersionMajor << 24) | ($this->maxVersionMinor << 16) | ($this->maxVersionPatch << 8) | $this->maxVersionRevision;
|
||||
return $this->versionId;
|
||||
}
|
||||
|
||||
public function getSchemaId() : int{ return $this->schemaId; }
|
||||
|
@ -23,17 +23,28 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\bedrock\block\upgrade;
|
||||
|
||||
use function ksort;
|
||||
use const SORT_STRING;
|
||||
|
||||
final class BlockStateUpgradeSchemaFlattenedName{
|
||||
|
||||
/**
|
||||
* @param string[] $flattenedValueRemaps
|
||||
* @phpstan-param array<string, string> $flattenedValueRemaps
|
||||
*/
|
||||
public function __construct(
|
||||
public string $prefix,
|
||||
public string $flattenedProperty,
|
||||
public string $suffix
|
||||
){}
|
||||
public string $suffix,
|
||||
public array $flattenedValueRemaps
|
||||
){
|
||||
ksort($this->flattenedValueRemaps, SORT_STRING);
|
||||
}
|
||||
|
||||
public function equals(self $that) : bool{
|
||||
return $this->prefix === $that->prefix &&
|
||||
$this->flattenedProperty === $that->flattenedProperty &&
|
||||
$this->suffix === $that->suffix;
|
||||
$this->suffix === $that->suffix &&
|
||||
$this->flattenedValueRemaps === $that->flattenedValueRemaps;
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +166,8 @@ final class BlockStateUpgradeSchemaUtils{
|
||||
$remap->newName ?? new BlockStateUpgradeSchemaFlattenedName(
|
||||
$remap->newFlattenedName->prefix,
|
||||
$remap->newFlattenedName->flattenedProperty,
|
||||
$remap->newFlattenedName->suffix
|
||||
$remap->newFlattenedName->suffix,
|
||||
$remap->newFlattenedName->flattenedValueRemaps ?? [],
|
||||
),
|
||||
array_map(fn(BlockStateUpgradeSchemaModelTag $tag) => self::jsonModelToTag($tag), $remap->newState ?? []),
|
||||
$remap->copiedState ?? []
|
||||
@ -301,7 +302,8 @@ final class BlockStateUpgradeSchemaUtils{
|
||||
new BlockStateUpgradeSchemaModelFlattenedName(
|
||||
$remap->newName->prefix,
|
||||
$remap->newName->flattenedProperty,
|
||||
$remap->newName->suffix
|
||||
$remap->newName->suffix,
|
||||
$remap->newName->flattenedValueRemaps
|
||||
),
|
||||
array_map(fn(Tag $tag) => self::tagToJsonModel($tag), $remap->newState),
|
||||
$remap->copiedState
|
||||
@ -389,6 +391,9 @@ final class BlockStateUpgradeSchemaUtils{
|
||||
}
|
||||
|
||||
$jsonMapper = new \JsonMapper();
|
||||
$jsonMapper->bExceptionOnMissingData = true;
|
||||
$jsonMapper->bExceptionOnUndefinedProperty = true;
|
||||
$jsonMapper->bStrictObjectTypeChecking = true;
|
||||
try{
|
||||
$model = $jsonMapper->map($json, new BlockStateUpgradeSchemaModel());
|
||||
}catch(\JsonMapper_Exception $e){
|
||||
|
@ -35,9 +35,14 @@ use function sprintf;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
final class BlockStateUpgrader{
|
||||
/** @var BlockStateUpgradeSchema[] */
|
||||
/**
|
||||
* @var BlockStateUpgradeSchema[][] versionId => [schemaId => schema]
|
||||
* @phpstan-var array<int, array<int, BlockStateUpgradeSchema>>
|
||||
*/
|
||||
private array $upgradeSchemas = [];
|
||||
|
||||
private int $outputVersion = 0;
|
||||
|
||||
/**
|
||||
* @param BlockStateUpgradeSchema[] $upgradeSchemas
|
||||
* @phpstan-param array<int, BlockStateUpgradeSchema> $upgradeSchemas
|
||||
@ -50,87 +55,116 @@ final class BlockStateUpgrader{
|
||||
|
||||
public function addSchema(BlockStateUpgradeSchema $schema) : void{
|
||||
$schemaId = $schema->getSchemaId();
|
||||
if(isset($this->upgradeSchemas[$schemaId])){
|
||||
throw new \InvalidArgumentException("Cannot add two schemas with the same schema ID");
|
||||
$versionId = $schema->getVersionId();
|
||||
if(isset($this->upgradeSchemas[$versionId][$schemaId])){
|
||||
throw new \InvalidArgumentException("Cannot add two schemas with the same schema ID and version ID");
|
||||
}
|
||||
$this->upgradeSchemas[$schemaId] = $schema;
|
||||
|
||||
//schema ID tells us the order when multiple schemas use the same version ID
|
||||
$this->upgradeSchemas[$versionId][$schemaId] = $schema;
|
||||
|
||||
ksort($this->upgradeSchemas, SORT_NUMERIC);
|
||||
ksort($this->upgradeSchemas[$versionId], SORT_NUMERIC);
|
||||
|
||||
$this->outputVersion = max($this->outputVersion, $schema->getVersionId());
|
||||
}
|
||||
|
||||
public function upgrade(BlockStateData $blockStateData) : BlockStateData{
|
||||
$version = $blockStateData->getVersion();
|
||||
$highestVersion = $version;
|
||||
foreach($this->upgradeSchemas as $schema){
|
||||
$resultVersion = $schema->getVersionId();
|
||||
$highestVersion = max($highestVersion, $resultVersion);
|
||||
if($version > $resultVersion){
|
||||
//even if this is actually the same version, we have to apply it anyway because mojang are dumb and
|
||||
//didn't always bump the blockstate version when changing it :(
|
||||
foreach($this->upgradeSchemas as $resultVersion => $schemaList){
|
||||
/*
|
||||
* Sometimes Mojang made changes without bumping the version ID.
|
||||
* A notable example is 0131_1.18.20.27_beta_to_1.18.30.json, which renamed a bunch of blockIDs.
|
||||
* When this happens, all the schemas must be applied even if the version is the same, because the input
|
||||
* version doesn't tell us which of the schemas have already been applied.
|
||||
* If there's only one schema for a version (the norm), we can safely assume it's already been applied if
|
||||
* the version is the same, and skip over it.
|
||||
*/
|
||||
if($version > $resultVersion || (count($schemaList) === 1 && $version === $resultVersion)){
|
||||
continue;
|
||||
}
|
||||
$oldName = $blockStateData->getName();
|
||||
$oldState = $blockStateData->getStates();
|
||||
if(isset($schema->remappedStates[$oldName])){
|
||||
foreach($schema->remappedStates[$oldName] as $remap){
|
||||
if(count($remap->oldState) > count($oldState)){
|
||||
//match criteria has more requirements than we have state properties
|
||||
continue; //try next state
|
||||
}
|
||||
foreach(Utils::stringifyKeys($remap->oldState) as $k => $v){
|
||||
if(!isset($oldState[$k]) || !$oldState[$k]->equals($v)){
|
||||
continue 2; //try next state
|
||||
}
|
||||
}
|
||||
|
||||
if(is_string($remap->newName)){
|
||||
$newName = $remap->newName;
|
||||
}else{
|
||||
$flattenedValue = $oldState[$remap->newName->flattenedProperty] ?? null;
|
||||
if($flattenedValue instanceof StringTag){
|
||||
$newName = sprintf("%s%s%s", $remap->newName->prefix, $flattenedValue->getValue(), $remap->newName->suffix);
|
||||
unset($oldState[$remap->newName->flattenedProperty]);
|
||||
}else{
|
||||
//flattened property is not a TAG_String, so this transformation is not applicable
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$newState = $remap->newState;
|
||||
foreach($remap->copiedState as $stateName){
|
||||
if(isset($oldState[$stateName])){
|
||||
$newState[$stateName] = $oldState[$stateName];
|
||||
}
|
||||
}
|
||||
|
||||
$blockStateData = new BlockStateData($newName, $newState, $resultVersion);
|
||||
continue 2; //try next schema
|
||||
}
|
||||
}
|
||||
$newName = $schema->renamedIds[$oldName] ?? null;
|
||||
|
||||
$stateChanges = 0;
|
||||
$states = $blockStateData->getStates();
|
||||
|
||||
$states = $this->applyPropertyAdded($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyRemoved($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyRenamedOrValueChanged($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyValueChanged($schema, $oldName, $states, $stateChanges);
|
||||
|
||||
if($newName !== null || $stateChanges > 0){
|
||||
$blockStateData = new BlockStateData($newName ?? $oldName, $states, $resultVersion);
|
||||
//don't break out; we may need to further upgrade the state
|
||||
foreach($schemaList as $schema){
|
||||
$blockStateData = $this->applySchema($schema, $blockStateData);
|
||||
}
|
||||
}
|
||||
|
||||
if($highestVersion > $version){
|
||||
if($this->outputVersion > $version){
|
||||
//always update the version number of the blockstate, even if it didn't change - this is needed for
|
||||
//external tools
|
||||
$blockStateData = new BlockStateData($blockStateData->getName(), $blockStateData->getStates(), $highestVersion);
|
||||
$blockStateData = new BlockStateData($blockStateData->getName(), $blockStateData->getStates(), $this->outputVersion);
|
||||
}
|
||||
return $blockStateData;
|
||||
}
|
||||
|
||||
private function applySchema(BlockStateUpgradeSchema $schema, BlockStateData $blockStateData) : BlockStateData{
|
||||
$newStateData = $this->applyStateRemapped($schema, $blockStateData);
|
||||
if($newStateData !== null){
|
||||
return $newStateData;
|
||||
}
|
||||
|
||||
$oldName = $blockStateData->getName();
|
||||
$newName = $schema->renamedIds[$oldName] ?? null;
|
||||
|
||||
$stateChanges = 0;
|
||||
$states = $blockStateData->getStates();
|
||||
|
||||
$states = $this->applyPropertyAdded($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyRemoved($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyRenamedOrValueChanged($schema, $oldName, $states, $stateChanges);
|
||||
$states = $this->applyPropertyValueChanged($schema, $oldName, $states, $stateChanges);
|
||||
|
||||
if($newName !== null || $stateChanges > 0){
|
||||
return new BlockStateData($newName ?? $oldName, $states, $schema->getVersionId());
|
||||
}
|
||||
|
||||
return $blockStateData;
|
||||
}
|
||||
|
||||
private function applyStateRemapped(BlockStateUpgradeSchema $schema, BlockStateData $blockStateData) : ?BlockStateData{
|
||||
$oldName = $blockStateData->getName();
|
||||
$oldState = $blockStateData->getStates();
|
||||
|
||||
if(isset($schema->remappedStates[$oldName])){
|
||||
foreach($schema->remappedStates[$oldName] as $remap){
|
||||
if(count($remap->oldState) > count($oldState)){
|
||||
//match criteria has more requirements than we have state properties
|
||||
continue; //try next state
|
||||
}
|
||||
foreach(Utils::stringifyKeys($remap->oldState) as $k => $v){
|
||||
if(!isset($oldState[$k]) || !$oldState[$k]->equals($v)){
|
||||
continue 2; //try next state
|
||||
}
|
||||
}
|
||||
|
||||
if(is_string($remap->newName)){
|
||||
$newName = $remap->newName;
|
||||
}else{
|
||||
$flattenedValue = $oldState[$remap->newName->flattenedProperty] ?? null;
|
||||
if($flattenedValue instanceof StringTag){
|
||||
$embedValue = $remap->newName->flattenedValueRemaps[$flattenedValue->getValue()] ?? $flattenedValue->getValue();
|
||||
$newName = sprintf("%s%s%s", $remap->newName->prefix, $embedValue, $remap->newName->suffix);
|
||||
unset($oldState[$remap->newName->flattenedProperty]);
|
||||
}else{
|
||||
//flattened property is not a TAG_String, so this transformation is not applicable
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$newState = $remap->newState;
|
||||
foreach($remap->copiedState as $stateName){
|
||||
if(isset($oldState[$stateName])){
|
||||
$newState[$stateName] = $oldState[$stateName];
|
||||
}
|
||||
}
|
||||
|
||||
return new BlockStateData($newName, $newState, $schema->getVersionId());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag[] $states
|
||||
* @phpstan-param array<string, Tag> $states
|
||||
|
@ -23,7 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\data\bedrock\block\upgrade\model;
|
||||
|
||||
final class BlockStateUpgradeSchemaModelFlattenedName{
|
||||
use function count;
|
||||
|
||||
final class BlockStateUpgradeSchemaModelFlattenedName implements \JsonSerializable{
|
||||
|
||||
/** @required */
|
||||
public string $prefix;
|
||||
@ -31,10 +33,31 @@ final class BlockStateUpgradeSchemaModelFlattenedName{
|
||||
public string $flattenedProperty;
|
||||
/** @required */
|
||||
public string $suffix;
|
||||
/**
|
||||
* @var string[]
|
||||
* @phpstan-var array<string, string>
|
||||
*/
|
||||
public array $flattenedValueRemaps;
|
||||
|
||||
public function __construct(string $prefix, string $flattenedProperty, string $suffix){
|
||||
/**
|
||||
* @param string[] $flattenedValueRemaps
|
||||
* @phpstan-param array<string, string> $flattenedValueRemaps
|
||||
*/
|
||||
public function __construct(string $prefix, string $flattenedProperty, string $suffix, array $flattenedValueRemaps){
|
||||
$this->prefix = $prefix;
|
||||
$this->flattenedProperty = $flattenedProperty;
|
||||
$this->suffix = $suffix;
|
||||
$this->flattenedValueRemaps = $flattenedValueRemaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function jsonSerialize() : array{
|
||||
$result = (array) $this;
|
||||
if(count($this->flattenedValueRemaps) === 0){
|
||||
unset($result["flattenedValueRemaps"]);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,6 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Block(Ids::JUNGLE_DOOR, Blocks::JUNGLE_DOOR());
|
||||
$this->map1to1Block(Ids::MANGROVE_DOOR, Blocks::MANGROVE_DOOR());
|
||||
$this->map1to1Block(Ids::NETHER_WART, Blocks::NETHER_WART());
|
||||
$this->map1to1Block(Ids::PITCHER_POD, Blocks::PITCHER_CROP());
|
||||
$this->map1to1Block(Ids::REPEATER, Blocks::REDSTONE_REPEATER());
|
||||
$this->map1to1Block(Ids::SPRUCE_DOOR, Blocks::SPRUCE_DOOR());
|
||||
$this->map1to1Block(Ids::SUGAR_CANE, Blocks::SUGARCANE());
|
||||
@ -193,6 +192,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::CLAY_BALL, Items::CLAY());
|
||||
$this->map1to1Item(Ids::CLOCK, Items::CLOCK());
|
||||
$this->map1to1Item(Ids::COAL, Items::COAL());
|
||||
$this->map1to1Item(Ids::COAST_ARMOR_TRIM_SMITHING_TEMPLATE, Items::COAST_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::COCOA_BEANS, Items::COCOA_BEANS());
|
||||
$this->map1to1Item(Ids::COD, Items::RAW_FISH());
|
||||
$this->map1to1Item(Ids::COMPASS, Items::COMPASS());
|
||||
@ -221,6 +221,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::DISC_FRAGMENT_5, Items::DISC_FRAGMENT_5());
|
||||
$this->map1to1Item(Ids::DRAGON_BREATH, Items::DRAGON_BREATH());
|
||||
$this->map1to1Item(Ids::DRIED_KELP, Items::DRIED_KELP());
|
||||
$this->map1to1Item(Ids::DUNE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::DUNE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::ECHO_SHARD, Items::ECHO_SHARD());
|
||||
$this->map1to1Item(Ids::EGG, Items::EGG());
|
||||
$this->map1to1Item(Ids::EMERALD, Items::EMERALD());
|
||||
@ -228,6 +229,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::ENCHANTED_GOLDEN_APPLE, Items::ENCHANTED_GOLDEN_APPLE());
|
||||
$this->map1to1Item(Ids::ENDER_PEARL, Items::ENDER_PEARL());
|
||||
$this->map1to1Item(Ids::EXPERIENCE_BOTTLE, Items::EXPERIENCE_BOTTLE());
|
||||
$this->map1to1Item(Ids::EYE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::EYE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::FEATHER, Items::FEATHER());
|
||||
$this->map1to1Item(Ids::FERMENTED_SPIDER_EYE, Items::FERMENTED_SPIDER_EYE());
|
||||
$this->map1to1Item(Ids::FIRE_CHARGE, Items::FIRE_CHARGE());
|
||||
@ -257,6 +259,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::HEART_OF_THE_SEA, Items::HEART_OF_THE_SEA());
|
||||
$this->map1to1Item(Ids::HONEY_BOTTLE, Items::HONEY_BOTTLE());
|
||||
$this->map1to1Item(Ids::HONEYCOMB, Items::HONEYCOMB());
|
||||
$this->map1to1Item(Ids::HOST_ARMOR_TRIM_SMITHING_TEMPLATE, Items::HOST_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::INK_SAC, Items::INK_SAC());
|
||||
$this->map1to1Item(Ids::IRON_AXE, Items::IRON_AXE());
|
||||
$this->map1to1Item(Ids::IRON_BOOTS, Items::IRON_BOOTS());
|
||||
@ -302,6 +305,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::MUSIC_DISC_WAIT, Items::RECORD_WAIT());
|
||||
$this->map1to1Item(Ids::MUSIC_DISC_WARD, Items::RECORD_WARD());
|
||||
$this->map1to1Item(Ids::MUTTON, Items::RAW_MUTTON());
|
||||
$this->map1to1Item(Ids::NAME_TAG, Items::NAME_TAG());
|
||||
$this->map1to1Item(Ids::NAUTILUS_SHELL, Items::NAUTILUS_SHELL());
|
||||
$this->map1to1Item(Ids::NETHER_STAR, Items::NETHER_STAR());
|
||||
$this->map1to1Item(Ids::NETHERBRICK, Items::NETHER_BRICK());
|
||||
@ -316,11 +320,13 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::NETHERITE_SCRAP, Items::NETHERITE_SCRAP());
|
||||
$this->map1to1Item(Ids::NETHERITE_SHOVEL, Items::NETHERITE_SHOVEL());
|
||||
$this->map1to1Item(Ids::NETHERITE_SWORD, Items::NETHERITE_SWORD());
|
||||
$this->map1to1Item(Ids::NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items::NETHERITE_UPGRADE_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::OAK_BOAT, Items::OAK_BOAT());
|
||||
$this->map1to1Item(Ids::OAK_SIGN, Items::OAK_SIGN());
|
||||
$this->map1to1Item(Ids::PAINTING, Items::PAINTING());
|
||||
$this->map1to1Item(Ids::PAPER, Items::PAPER());
|
||||
$this->map1to1Item(Ids::PHANTOM_MEMBRANE, Items::PHANTOM_MEMBRANE());
|
||||
$this->map1to1Item(Ids::PITCHER_POD, Items::PITCHER_POD());
|
||||
$this->map1to1Item(Ids::POISONOUS_POTATO, Items::POISONOUS_POTATO());
|
||||
$this->map1to1Item(Ids::POPPED_CHORUS_FRUIT, Items::POPPED_CHORUS_FRUIT());
|
||||
$this->map1to1Item(Ids::PORKCHOP, Items::RAW_PORKCHOP());
|
||||
@ -335,18 +341,25 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::RABBIT_FOOT, Items::RABBIT_FOOT());
|
||||
$this->map1to1Item(Ids::RABBIT_HIDE, Items::RABBIT_HIDE());
|
||||
$this->map1to1Item(Ids::RABBIT_STEW, Items::RABBIT_STEW());
|
||||
$this->map1to1Item(Ids::RAISER_ARMOR_TRIM_SMITHING_TEMPLATE, Items::RAISER_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::RAW_COPPER, Items::RAW_COPPER());
|
||||
$this->map1to1Item(Ids::RAW_GOLD, Items::RAW_GOLD());
|
||||
$this->map1to1Item(Ids::RAW_IRON, Items::RAW_IRON());
|
||||
$this->map1to1Item(Ids::REDSTONE, Items::REDSTONE_DUST());
|
||||
$this->map1to1Item(Ids::RIB_ARMOR_TRIM_SMITHING_TEMPLATE, Items::RIB_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::ROTTEN_FLESH, Items::ROTTEN_FLESH());
|
||||
$this->map1to1Item(Ids::SALMON, Items::RAW_SALMON());
|
||||
$this->map1to1Item(Ids::SCUTE, Items::SCUTE());
|
||||
$this->map1to1Item(Ids::TURTLE_SCUTE, Items::SCUTE());
|
||||
$this->map1to1Item(Ids::SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::SHEARS, Items::SHEARS());
|
||||
$this->map1to1Item(Ids::SHULKER_SHELL, Items::SHULKER_SHELL());
|
||||
$this->map1to1Item(Ids::SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::SLIME_BALL, Items::SLIMEBALL());
|
||||
$this->map1to1Item(Ids::SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::SNOWBALL, Items::SNOWBALL());
|
||||
$this->map1to1Item(Ids::SPIDER_EYE, Items::SPIDER_EYE());
|
||||
$this->map1to1Item(Ids::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::SPRUCE_BOAT, Items::SPRUCE_BOAT());
|
||||
$this->map1to1Item(Ids::SPRUCE_SIGN, Items::SPRUCE_SIGN());
|
||||
$this->map1to1Item(Ids::SPYGLASS, Items::SPYGLASS());
|
||||
@ -361,14 +374,19 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::SUGAR, Items::SUGAR());
|
||||
$this->map1to1Item(Ids::SWEET_BERRIES, Items::SWEET_BERRIES());
|
||||
$this->map1to1Item(Ids::TORCHFLOWER_SEEDS, Items::TORCHFLOWER_SEEDS());
|
||||
$this->map1to1Item(Ids::TIDE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::TIDE_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::TOTEM_OF_UNDYING, Items::TOTEM());
|
||||
$this->map1to1Item(Ids::TROPICAL_FISH, Items::CLOWNFISH());
|
||||
$this->map1to1Item(Ids::TURTLE_HELMET, Items::TURTLE_HELMET());
|
||||
$this->map1to1Item(Ids::VEX_ARMOR_TRIM_SMITHING_TEMPLATE, Items::VEX_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::VILLAGER_SPAWN_EGG, Items::VILLAGER_SPAWN_EGG());
|
||||
$this->map1to1Item(Ids::WARD_ARMOR_TRIM_SMITHING_TEMPLATE, Items::WARD_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::WARPED_SIGN, Items::WARPED_SIGN());
|
||||
$this->map1to1Item(Ids::WATER_BUCKET, Items::WATER_BUCKET());
|
||||
$this->map1to1Item(Ids::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE, Items::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::WHEAT, Items::WHEAT());
|
||||
$this->map1to1Item(Ids::WHEAT_SEEDS, Items::WHEAT_SEEDS());
|
||||
$this->map1to1Item(Ids::WILD_ARMOR_TRIM_SMITHING_TEMPLATE, Items::WILD_ARMOR_TRIM_SMITHING_TEMPLATE());
|
||||
$this->map1to1Item(Ids::WOODEN_AXE, Items::WOODEN_AXE());
|
||||
$this->map1to1Item(Ids::WOODEN_HOE, Items::WOODEN_HOE());
|
||||
$this->map1to1Item(Ids::WOODEN_PICKAXE, Items::WOODEN_PICKAXE());
|
||||
|
@ -38,6 +38,8 @@ final class ItemTypeNames{
|
||||
public const ANGLER_POTTERY_SHERD = "minecraft:angler_pottery_sherd";
|
||||
public const APPLE = "minecraft:apple";
|
||||
public const ARCHER_POTTERY_SHERD = "minecraft:archer_pottery_sherd";
|
||||
public const ARMADILLO_SCUTE = "minecraft:armadillo_scute";
|
||||
public const ARMADILLO_SPAWN_EGG = "minecraft:armadillo_spawn_egg";
|
||||
public const ARMOR_STAND = "minecraft:armor_stand";
|
||||
public const ARMS_UP_POTTERY_SHERD = "minecraft:arms_up_pottery_sherd";
|
||||
public const ARROW = "minecraft:arrow";
|
||||
@ -72,6 +74,8 @@ final class ItemTypeNames{
|
||||
public const BLEACH = "minecraft:bleach";
|
||||
public const BLUE_DYE = "minecraft:blue_dye";
|
||||
public const BOAT = "minecraft:boat";
|
||||
public const BOGGED_SPAWN_EGG = "minecraft:bogged_spawn_egg";
|
||||
public const BOLT_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:bolt_armor_trim_smithing_template";
|
||||
public const BONE = "minecraft:bone";
|
||||
public const BONE_MEAL = "minecraft:bone_meal";
|
||||
public const BOOK = "minecraft:book";
|
||||
@ -79,6 +83,8 @@ final class ItemTypeNames{
|
||||
public const BOW = "minecraft:bow";
|
||||
public const BOWL = "minecraft:bowl";
|
||||
public const BREAD = "minecraft:bread";
|
||||
public const BREEZE_ROD = "minecraft:breeze_rod";
|
||||
public const BREEZE_SPAWN_EGG = "minecraft:breeze_spawn_egg";
|
||||
public const BREWER_POTTERY_SHERD = "minecraft:brewer_pottery_sherd";
|
||||
public const BREWING_STAND = "minecraft:brewing_stand";
|
||||
public const BRICK = "minecraft:brick";
|
||||
@ -137,6 +143,8 @@ final class ItemTypeNames{
|
||||
public const COPPER_DOOR = "minecraft:copper_door";
|
||||
public const COPPER_INGOT = "minecraft:copper_ingot";
|
||||
public const CORAL = "minecraft:coral";
|
||||
public const CORAL_FAN = "minecraft:coral_fan";
|
||||
public const CORAL_FAN_DEAD = "minecraft:coral_fan_dead";
|
||||
public const COW_SPAWN_EGG = "minecraft:cow_spawn_egg";
|
||||
public const CREEPER_BANNER_PATTERN = "minecraft:creeper_banner_pattern";
|
||||
public const CREEPER_SPAWN_EGG = "minecraft:creeper_spawn_egg";
|
||||
@ -151,7 +159,6 @@ final class ItemTypeNames{
|
||||
public const DARK_OAK_DOOR = "minecraft:dark_oak_door";
|
||||
public const DARK_OAK_HANGING_SIGN = "minecraft:dark_oak_hanging_sign";
|
||||
public const DARK_OAK_SIGN = "minecraft:dark_oak_sign";
|
||||
public const DEBUG_STICK = "minecraft:debug_stick";
|
||||
public const DIAMOND = "minecraft:diamond";
|
||||
public const DIAMOND_AXE = "minecraft:diamond_axe";
|
||||
public const DIAMOND_BOOTS = "minecraft:diamond_boots";
|
||||
@ -201,6 +208,9 @@ final class ItemTypeNames{
|
||||
public const FISHING_ROD = "minecraft:fishing_rod";
|
||||
public const FLINT = "minecraft:flint";
|
||||
public const FLINT_AND_STEEL = "minecraft:flint_and_steel";
|
||||
public const FLOW_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:flow_armor_trim_smithing_template";
|
||||
public const FLOW_BANNER_PATTERN = "minecraft:flow_banner_pattern";
|
||||
public const FLOW_POTTERY_SHERD = "minecraft:flow_pottery_sherd";
|
||||
public const FLOWER_BANNER_PATTERN = "minecraft:flower_banner_pattern";
|
||||
public const FLOWER_POT = "minecraft:flower_pot";
|
||||
public const FOX_SPAWN_EGG = "minecraft:fox_spawn_egg";
|
||||
@ -238,6 +248,10 @@ final class ItemTypeNames{
|
||||
public const GREEN_DYE = "minecraft:green_dye";
|
||||
public const GUARDIAN_SPAWN_EGG = "minecraft:guardian_spawn_egg";
|
||||
public const GUNPOWDER = "minecraft:gunpowder";
|
||||
public const GUSTER_BANNER_PATTERN = "minecraft:guster_banner_pattern";
|
||||
public const GUSTER_POTTERY_SHERD = "minecraft:guster_pottery_sherd";
|
||||
public const HARD_STAINED_GLASS = "minecraft:hard_stained_glass";
|
||||
public const HARD_STAINED_GLASS_PANE = "minecraft:hard_stained_glass_pane";
|
||||
public const HEART_OF_THE_SEA = "minecraft:heart_of_the_sea";
|
||||
public const HEART_POTTERY_SHERD = "minecraft:heart_pottery_sherd";
|
||||
public const HEARTBREAK_POTTERY_SHERD = "minecraft:heartbreak_pottery_sherd";
|
||||
@ -281,6 +295,8 @@ final class ItemTypeNames{
|
||||
public const LEATHER_HELMET = "minecraft:leather_helmet";
|
||||
public const LEATHER_HORSE_ARMOR = "minecraft:leather_horse_armor";
|
||||
public const LEATHER_LEGGINGS = "minecraft:leather_leggings";
|
||||
public const LEAVES = "minecraft:leaves";
|
||||
public const LEAVES2 = "minecraft:leaves2";
|
||||
public const LIGHT_BLUE_DYE = "minecraft:light_blue_dye";
|
||||
public const LIGHT_GRAY_DYE = "minecraft:light_gray_dye";
|
||||
public const LIME_DYE = "minecraft:lime_dye";
|
||||
@ -289,6 +305,7 @@ final class ItemTypeNames{
|
||||
public const LODESTONE_COMPASS = "minecraft:lodestone_compass";
|
||||
public const LOG = "minecraft:log";
|
||||
public const LOG2 = "minecraft:log2";
|
||||
public const MACE = "minecraft:mace";
|
||||
public const MAGENTA_DYE = "minecraft:magenta_dye";
|
||||
public const MAGMA_CREAM = "minecraft:magma_cream";
|
||||
public const MAGMA_CUBE_SPAWN_EGG = "minecraft:magma_cube_spawn_egg";
|
||||
@ -396,6 +413,7 @@ final class ItemTypeNames{
|
||||
public const RAW_IRON = "minecraft:raw_iron";
|
||||
public const RECOVERY_COMPASS = "minecraft:recovery_compass";
|
||||
public const RED_DYE = "minecraft:red_dye";
|
||||
public const RED_FLOWER = "minecraft:red_flower";
|
||||
public const REDSTONE = "minecraft:redstone";
|
||||
public const REPEATER = "minecraft:repeater";
|
||||
public const RIB_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:rib_armor_trim_smithing_template";
|
||||
@ -404,7 +422,8 @@ final class ItemTypeNames{
|
||||
public const SALMON = "minecraft:salmon";
|
||||
public const SALMON_BUCKET = "minecraft:salmon_bucket";
|
||||
public const SALMON_SPAWN_EGG = "minecraft:salmon_spawn_egg";
|
||||
public const SCUTE = "minecraft:scute";
|
||||
public const SAPLING = "minecraft:sapling";
|
||||
public const SCRAPE_POTTERY_SHERD = "minecraft:scrape_pottery_sherd";
|
||||
public const SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:sentry_armor_trim_smithing_template";
|
||||
public const SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:shaper_armor_trim_smithing_template";
|
||||
public const SHEAF_POTTERY_SHERD = "minecraft:sheaf_pottery_sherd";
|
||||
@ -466,11 +485,13 @@ final class ItemTypeNames{
|
||||
public const TORCHFLOWER_SEEDS = "minecraft:torchflower_seeds";
|
||||
public const TOTEM_OF_UNDYING = "minecraft:totem_of_undying";
|
||||
public const TRADER_LLAMA_SPAWN_EGG = "minecraft:trader_llama_spawn_egg";
|
||||
public const TRIAL_KEY = "minecraft:trial_key";
|
||||
public const TRIDENT = "minecraft:trident";
|
||||
public const TROPICAL_FISH = "minecraft:tropical_fish";
|
||||
public const TROPICAL_FISH_BUCKET = "minecraft:tropical_fish_bucket";
|
||||
public const TROPICAL_FISH_SPAWN_EGG = "minecraft:tropical_fish_spawn_egg";
|
||||
public const TURTLE_HELMET = "minecraft:turtle_helmet";
|
||||
public const TURTLE_SCUTE = "minecraft:turtle_scute";
|
||||
public const TURTLE_SPAWN_EGG = "minecraft:turtle_spawn_egg";
|
||||
public const VEX_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:vex_armor_trim_smithing_template";
|
||||
public const VEX_SPAWN_EGG = "minecraft:vex_spawn_egg";
|
||||
@ -494,15 +515,19 @@ final class ItemTypeNames{
|
||||
public const WHEAT_SEEDS = "minecraft:wheat_seeds";
|
||||
public const WHITE_DYE = "minecraft:white_dye";
|
||||
public const WILD_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:wild_armor_trim_smithing_template";
|
||||
public const WIND_CHARGE = "minecraft:wind_charge";
|
||||
public const WITCH_SPAWN_EGG = "minecraft:witch_spawn_egg";
|
||||
public const WITHER_SKELETON_SPAWN_EGG = "minecraft:wither_skeleton_spawn_egg";
|
||||
public const WITHER_SPAWN_EGG = "minecraft:wither_spawn_egg";
|
||||
public const WOLF_ARMOR = "minecraft:wolf_armor";
|
||||
public const WOLF_SPAWN_EGG = "minecraft:wolf_spawn_egg";
|
||||
public const WOOD = "minecraft:wood";
|
||||
public const WOODEN_AXE = "minecraft:wooden_axe";
|
||||
public const WOODEN_DOOR = "minecraft:wooden_door";
|
||||
public const WOODEN_HOE = "minecraft:wooden_hoe";
|
||||
public const WOODEN_PICKAXE = "minecraft:wooden_pickaxe";
|
||||
public const WOODEN_SHOVEL = "minecraft:wooden_shovel";
|
||||
public const WOODEN_SLAB = "minecraft:wooden_slab";
|
||||
public const WOODEN_SWORD = "minecraft:wooden_sword";
|
||||
public const WOOL = "minecraft:wool";
|
||||
public const WRITABLE_BOOK = "minecraft:writable_book";
|
||||
|
@ -88,6 +88,9 @@ final class ItemIdMetaUpgradeSchemaUtils{
|
||||
}
|
||||
|
||||
$jsonMapper = new \JsonMapper();
|
||||
$jsonMapper->bExceptionOnMissingData = true;
|
||||
$jsonMapper->bExceptionOnUndefinedProperty = true;
|
||||
$jsonMapper->bStrictObjectTypeChecking = true;
|
||||
try{
|
||||
$model = $jsonMapper->map($json, new ItemIdMetaUpgradeSchemaModel());
|
||||
}catch(\JsonMapper_Exception $e){
|
||||
|
@ -44,10 +44,14 @@ final class GameModeIdMap{
|
||||
private array $enumToId = [];
|
||||
|
||||
public function __construct(){
|
||||
$this->register(0, GameMode::SURVIVAL);
|
||||
$this->register(1, GameMode::CREATIVE);
|
||||
$this->register(2, GameMode::ADVENTURE);
|
||||
$this->register(3, GameMode::SPECTATOR);
|
||||
foreach(GameMode::cases() as $case){
|
||||
$this->register(match($case){
|
||||
GameMode::SURVIVAL => 0,
|
||||
GameMode::CREATIVE => 1,
|
||||
GameMode::ADVENTURE => 2,
|
||||
GameMode::SPECTATOR => 3,
|
||||
}, $case);
|
||||
}
|
||||
}
|
||||
|
||||
private function register(int $id, GameMode $type) : void{
|
||||
|
@ -29,11 +29,6 @@ namespace pocketmine\data\runtime;
|
||||
* @deprecated
|
||||
*/
|
||||
trait LegacyRuntimeEnumDescriberTrait{
|
||||
|
||||
/**
|
||||
* @phpstan-template T of \UnitEnum
|
||||
* @phpstan-param T $case
|
||||
*/
|
||||
abstract protected function enum(\UnitEnum &$case) : void;
|
||||
|
||||
public function bellAttachmentType(\pocketmine\block\utils\BellAttachmentType &$value) : void{
|
||||
|
@ -89,10 +89,6 @@ interface RuntimeDataDescriber extends RuntimeEnumDescriber{
|
||||
|
||||
public function straightOnlyRailShape(int &$railShape) : void;
|
||||
|
||||
/**
|
||||
* @phpstan-template T of \UnitEnum
|
||||
* @phpstan-param T $case
|
||||
*/
|
||||
public function enum(\UnitEnum &$case) : void;
|
||||
|
||||
/**
|
||||
|
@ -252,6 +252,14 @@ abstract class Entity{
|
||||
return $this->alwaysShowNameTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether players can rename this entity using a name tag.
|
||||
* Note that plugins can still name entities using setNameTag().
|
||||
*/
|
||||
public function canBeRenamed() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function setNameTag(string $name) : void{
|
||||
$this->nameTag = $name;
|
||||
$this->networkPropertiesDirty = true;
|
||||
@ -792,7 +800,7 @@ abstract class Entity{
|
||||
}
|
||||
|
||||
protected function broadcastMotion() : void{
|
||||
NetworkBroadcastUtils::broadcastPackets($this->hasSpawned, [SetActorMotionPacket::create($this->id, $this->getMotion())]);
|
||||
NetworkBroadcastUtils::broadcastPackets($this->hasSpawned, [SetActorMotionPacket::create($this->id, $this->getMotion(), tick: 0)]);
|
||||
}
|
||||
|
||||
public function getGravity() : float{
|
||||
|
@ -132,6 +132,10 @@ abstract class Living extends Entity{
|
||||
|
||||
abstract public function getName() : string;
|
||||
|
||||
public function canBeRenamed() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function initEntity(CompoundTag $nbt) : void{
|
||||
parent::initEntity($nbt);
|
||||
|
||||
|
@ -173,8 +173,9 @@ abstract class Projectile extends Entity{
|
||||
$entityHit = null;
|
||||
$hitResult = null;
|
||||
|
||||
$world = $this->getWorld();
|
||||
foreach(VoxelRayTrace::betweenPoints($start, $end) as $vector3){
|
||||
$block = $this->getWorld()->getBlockAt($vector3->x, $vector3->y, $vector3->z);
|
||||
$block = $world->getBlockAt($vector3->x, $vector3->y, $vector3->z);
|
||||
|
||||
$blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end);
|
||||
if($blockHitResult !== null){
|
||||
@ -188,7 +189,7 @@ abstract class Projectile extends Entity{
|
||||
$entityDistance = PHP_INT_MAX;
|
||||
|
||||
$newDiff = $end->subtractVector($start);
|
||||
foreach($this->getWorld()->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){
|
||||
foreach($world->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){
|
||||
if($entity->getId() === $this->getOwningEntityId() && $this->ticksLived < 5){
|
||||
continue;
|
||||
}
|
||||
@ -256,7 +257,7 @@ abstract class Projectile extends Entity{
|
||||
);
|
||||
}
|
||||
|
||||
$this->getWorld()->onEntityMoved($this);
|
||||
$world->onEntityMoved($this);
|
||||
$this->checkBlockIntersections();
|
||||
|
||||
Timings::$projectileMove->stopTiming();
|
||||
|
@ -31,8 +31,9 @@ class Snowball extends Throwable{
|
||||
public static function getNetworkTypeId() : string{ return EntityIds::SNOWBALL; }
|
||||
|
||||
protected function onHit(ProjectileHitEvent $event) : void{
|
||||
$world = $this->getWorld();
|
||||
for($i = 0; $i < 6; ++$i){
|
||||
$this->getWorld()->addParticle($this->location, new SnowballPoofParticle());
|
||||
$world->addParticle($this->location, new SnowballPoofParticle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user