Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into major-next

This commit is contained in:
Dylan K. Taylor 2024-08-09 13:33:07 +01:00
commit c9e8d382c5
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
66 changed files with 1327 additions and 328 deletions

View File

@ -12,6 +12,22 @@ updates:
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
groups:
production-patch-updates:
dependency-type: production
patterns:
- "*"
update-types:
- "patch"
development-patch-updates:
dependency-type: development
patterns:
- "*"
update-types:
- "patch"
phpstan:
patterns:
- "phpstan/*"
- package-ecosystem: gitsubmodule
directory: "/"

View File

@ -53,7 +53,7 @@ jobs:
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
- name: Build image for tag
uses: docker/build-push-action@v5.3.0
uses: docker/build-push-action@v6.5.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.3.0
uses: docker/build-push-action@v6.5.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.3.0
uses: docker/build-push-action@v6.5.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.3.0
uses: docker/build-push-action@v6.5.0
with:
push: true
context: ./pocketmine-mp

View File

@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.30.4
uses: shivammathur/setup-php@2.31.1
with:
php-version: 8.2

View File

@ -20,7 +20,7 @@ jobs:
submodules: true
- name: Setup PHP
uses: shivammathur/setup-php@2.30.4
uses: shivammathur/setup-php@2.31.1
with:
php-version: ${{ matrix.php-version }}
@ -76,6 +76,9 @@ jobs:
${{ steps.php-binary-url.outputs.PHP_BINARY_URL }} \
> build_info.json
- name: Generate core permission doc for doc.pmmp.io
run: php tools/generate-permission-doc.php rst
- name: Upload release artifacts
uses: actions/upload-artifact@v4
with:
@ -84,11 +87,12 @@ jobs:
${{ github.workspace }}/PocketMine-MP.phar
${{ github.workspace }}/start.*
${{ github.workspace }}/build_info.json
${{ github.workspace }}/core-permissions.rst
- name: Create draft release
uses: ncipollo/release-action@v1.14.0
with:
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json,${{ github.workspace }}/core-permissions.rst
commit: ${{ github.sha }}
draft: true
prerelease: ${{ steps.get-pm-version.outputs.PRERELEASE }}

View File

@ -28,7 +28,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.30.4
uses: shivammathur/setup-php@2.31.1
with:
php-version: 8.2
tools: php-cs-fixer:3.49

3
.gitignore vendored
View File

@ -53,3 +53,6 @@ Documentation/*
# php-cs-fixer
/.php_cs.cache
/.php-cs-fixer.cache
# install-local-protocol.sh
/composer-local-protocol.*

26
changelogs/5.16.md Normal file
View File

@ -0,0 +1,26 @@
# 5.16.0
Released 13th June 2024.
**For Minecraft: Bedrock Edition 1.21.0**
This is a support release for Minecraft: Bedrock Edition 1.21.0.
**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.21.0.
- Removed support for earlier versions.
- Generated permission docs are now included with every release.
- Crash throttle message (which appears when the server crashed after being up for less than 120 seconds) now shows the server uptime as well as the wait time. This should make it clearer how the wait time is decided.
## Tools
- Added `install-local-protocol.sh` script. This allows installing local copies of protocol dependencies without needing to create releases. Useful for integration testing when doing protocol updates.
## Fixes
- Attacking an entity with a higher damage weapon while it's on attack cooldown from a lower damage weapon (switching) no longer causes additional knockback to the victim.
- Wooden stairs can now be used as fuel in furnaces.
- Fixed incorrect description of the permission `pocketmine.command.save.perform`.

25
changelogs/5.17.md Normal file
View File

@ -0,0 +1,25 @@
# 5.17.0
Released 10th July 2024.
**For Minecraft: Bedrock Edition 1.21.2**
This is a support release for Minecraft: Bedrock Edition 1.21.2.
**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.21.2.
- Removed support for earlier versions.
## API
### `pocketmine\player`
- The following methods have been added:
- `public function closeAllForms() : void` - closes the current viewing form and forms in queue.
## Fixes
- Bowl can now be used as fuel.
- Bells always drops themselves even when using an incompatible tool.

View File

@ -33,10 +33,10 @@
"composer-runtime-api": "^2.0",
"adhocore/json-comment": "~1.2.0",
"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/bedrock-block-upgrade-schema": "~4.2.0+bedrock-1.21.0",
"pocketmine/bedrock-data": "~2.11.0+bedrock-1.21.0",
"pocketmine/bedrock-item-upgrade-schema": "~1.10.0+bedrock-1.21.0",
"pocketmine/bedrock-protocol": "~32.1.0+bedrock-1.21.2",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/color": "^0.3.0",
@ -52,10 +52,10 @@
"symfony/filesystem": "~6.4.0"
},
"require-dev": {
"phpstan/phpstan": "1.10.67",
"phpstan/phpstan": "1.11.9",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "~10.3.0 || ~10.2.0 || ~10.1.0"
"phpunit/phpunit": "^10.5.24"
},
"autoload": {
"psr-4": {

273
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "99069514f4fb8ee6b03b0da07a77a486",
"content-hash": "cddee8096f4b575629ff671000543d3f",
"packages": [
{
"name": "adhocore/json-comment",
@ -67,25 +67,25 @@
},
{
"name": "brick/math",
"version": "0.11.0",
"version": "0.12.1",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478"
"reference": "f510c0a40911935b77b86859eb5223d58d660df1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478",
"reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478",
"url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1",
"reference": "f510c0a40911935b77b86859eb5223d58d660df1",
"shasum": ""
},
"require": {
"php": "^8.0"
"php": "^8.1"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^9.0",
"vimeo/psalm": "5.0.0"
"phpunit/phpunit": "^10.1",
"vimeo/psalm": "5.16.0"
},
"type": "library",
"autoload": {
@ -105,12 +105,17 @@
"arithmetic",
"bigdecimal",
"bignum",
"bignumber",
"brick",
"math"
"decimal",
"integer",
"math",
"mathematics",
"rational"
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.11.0"
"source": "https://github.com/brick/math/tree/0.12.1"
},
"funding": [
{
@ -118,20 +123,20 @@
"type": "github"
}
],
"time": "2023-01-15T23:15:59+00:00"
"time": "2023-11-29T23:19:16+00:00"
},
{
"name": "pocketmine/bedrock-block-upgrade-schema",
"version": "4.1.0",
"version": "4.2.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
"reference": "d6b10cb0a5e69fb1dfe3b7f493bf4f519723a9cb"
"reference": "8a327197b3b462fa282f40f76b070ffe585a25d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/d6b10cb0a5e69fb1dfe3b7f493bf4f519723a9cb",
"reference": "d6b10cb0a5e69fb1dfe3b7f493bf4f519723a9cb",
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/8a327197b3b462fa282f40f76b070ffe585a25d2",
"reference": "8a327197b3b462fa282f40f76b070ffe585a25d2",
"shasum": ""
},
"type": "library",
@ -142,22 +147,22 @@
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
"support": {
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/4.1.0"
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/4.2.0"
},
"time": "2024-04-05T17:28:14+00:00"
"time": "2024-06-13T17:28:26+00:00"
},
{
"name": "pocketmine/bedrock-data",
"version": "2.10.0+bedrock-1.20.80",
"version": "2.11.0+bedrock-1.21.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
"reference": "d7d709fec3848f56ca77f5ff0e5d4741b59f9d69"
"reference": "cae40bde98081b388c4d3ab59d45b8d1cf5d8761"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/d7d709fec3848f56ca77f5ff0e5d4741b59f9d69",
"reference": "d7d709fec3848f56ca77f5ff0e5d4741b59f9d69",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/cae40bde98081b388c4d3ab59d45b8d1cf5d8761",
"reference": "cae40bde98081b388c4d3ab59d45b8d1cf5d8761",
"shasum": ""
},
"type": "library",
@ -168,22 +173,22 @@
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/BedrockData/issues",
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.80"
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.0"
},
"time": "2024-04-25T10:08:23+00:00"
"time": "2024-06-13T17:17:55+00:00"
},
{
"name": "pocketmine/bedrock-item-upgrade-schema",
"version": "1.9.0",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
"reference": "24a89457c17c271b5378b195931e720873865a79"
"reference": "b4687afa19f91eacebd46c40d487f4cc515be504"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/24a89457c17c271b5378b195931e720873865a79",
"reference": "24a89457c17c271b5378b195931e720873865a79",
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/b4687afa19f91eacebd46c40d487f4cc515be504",
"reference": "b4687afa19f91eacebd46c40d487f4cc515be504",
"shasum": ""
},
"type": "library",
@ -194,22 +199,22 @@
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
"support": {
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.9.0"
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.10.0"
},
"time": "2024-04-05T18:46:07+00:00"
"time": "2024-05-15T15:15:55+00:00"
},
{
"name": "pocketmine/bedrock-protocol",
"version": "30.0.0+bedrock-1.20.80",
"version": "32.1.0+bedrock-1.21.2",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "dc7606a9f778eeeeccfae393bd58e0b62ec6f85a"
"reference": "bb23db51365bdc91d3135c3885986a691ae1cb44"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/dc7606a9f778eeeeccfae393bd58e0b62ec6f85a",
"reference": "dc7606a9f778eeeeccfae393bd58e0b62ec6f85a",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/bb23db51365bdc91d3135c3885986a691ae1cb44",
"reference": "bb23db51365bdc91d3135c3885986a691ae1cb44",
"shasum": ""
},
"require": {
@ -222,7 +227,7 @@
"ramsey/uuid": "^4.1"
},
"require-dev": {
"phpstan/phpstan": "1.10.59",
"phpstan/phpstan": "1.11.2",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5 || ^10.0"
@ -240,9 +245,9 @@
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
"support": {
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
"source": "https://github.com/pmmp/BedrockProtocol/tree/30.0.0+bedrock-1.20.80"
"source": "https://github.com/pmmp/BedrockProtocol/tree/32.1.0+bedrock-1.21.2"
},
"time": "2024-04-05T17:53:35+00:00"
"time": "2024-07-10T01:38:43+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -829,20 +834,20 @@
},
{
"name": "ramsey/uuid",
"version": "4.7.5",
"version": "4.7.6",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
"reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e"
"reference": "91039bc1faa45ba123c4328958e620d382ec7088"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e",
"reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088",
"reference": "91039bc1faa45ba123c4328958e620d382ec7088",
"shasum": ""
},
"require": {
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11",
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12",
"ext-json": "*",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
@ -905,7 +910,7 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.7.5"
"source": "https://github.com/ramsey/uuid/tree/4.7.6"
},
"funding": [
{
@ -917,27 +922,29 @@
"type": "tidelift"
}
],
"time": "2023-11-08T05:53:05+00:00"
"time": "2024-04-27T21:32:50+00:00"
},
{
"name": "symfony/filesystem",
"version": "v6.4.7",
"version": "v6.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "78dde75f8f6dbbca4ec436a4b0087f7af02076d4"
"reference": "b51ef8059159330b74a4d52f68e671033c0fe463"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/78dde75f8f6dbbca4ec436a4b0087f7af02076d4",
"reference": "78dde75f8f6dbbca4ec436a4b0087f7af02076d4",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/b51ef8059159330b74a4d52f68e671033c0fe463",
"reference": "b51ef8059159330b74a4d52f68e671033c0fe463",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8",
"symfony/process": "^5.4|^6.4"
"symfony/polyfill-mbstring": "~1.8"
},
"require-dev": {
"symfony/process": "^5.4|^6.4|^7.0"
},
"type": "library",
"autoload": {
@ -965,7 +972,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v6.4.7"
"source": "https://github.com/symfony/filesystem/tree/v6.4.9"
},
"funding": [
{
@ -981,20 +988,20 @@
"type": "tidelift"
}
],
"time": "2024-04-18T09:22:46+00:00"
"time": "2024-06-28T09:49:33+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.29.0",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
"reference": "0424dff1c58f028c451efff2045f5d92410bd540"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
"reference": "0424dff1c58f028c451efff2045f5d92410bd540",
"shasum": ""
},
"require": {
@ -1044,7 +1051,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
},
"funding": [
{
@ -1060,20 +1067,20 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-05-31T15:07:36+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.29.0",
"version": "v1.30.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c",
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c",
"shasum": ""
},
"require": {
@ -1124,7 +1131,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0"
},
"funding": [
{
@ -1140,83 +1147,22 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/process",
"version": "v6.4.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "cdb1c81c145fd5aa9b0038bab694035020943381"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/cdb1c81c145fd5aa9b0038bab694035020943381",
"reference": "cdb1c81c145fd5aa9b0038bab694035020943381",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v6.4.7"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-04-18T09:22:46+00:00"
"time": "2024-06-19T12:30:46+00:00"
}
],
"packages-dev": [
{
"name": "myclabs/deep-copy",
"version": "1.11.1",
"version": "1.12.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
"shasum": ""
},
"require": {
@ -1224,11 +1170,12 @@
},
"conflict": {
"doctrine/collections": "<1.6.8",
"doctrine/common": "<2.13.3 || >=3,<3.2.2"
"doctrine/common": "<2.13.3 || >=3 <3.2.2"
},
"require-dev": {
"doctrine/collections": "^1.6.8",
"doctrine/common": "^2.13.3 || ^3.2.2",
"phpspec/prophecy": "^1.10",
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
},
"type": "library",
@ -1254,7 +1201,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
},
"funding": [
{
@ -1262,7 +1209,7 @@
"type": "tidelift"
}
],
"time": "2023-03-08T13:26:56+00:00"
"time": "2024-06-12T14:39:25+00:00"
},
{
"name": "nikic/php-parser",
@ -1442,16 +1389,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.10.67",
"version": "1.11.9",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493"
"reference": "e370bcddadaede0c1716338b262346f40d296f82"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/16ddbe776f10da6a95ebd25de7c1dbed397dc493",
"reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e370bcddadaede0c1716338b262346f40d296f82",
"reference": "e370bcddadaede0c1716338b262346f40d296f82",
"shasum": ""
},
"require": {
@ -1496,25 +1443,25 @@
"type": "github"
}
],
"time": "2024-04-16T07:22:02+00:00"
"time": "2024-08-01T16:25:18+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "1.3.16",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "d5242a59d035e46774f2e634b374bc39ff62cb95"
"reference": "f3ea021866f4263f07ca3636bf22c64be9610c11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d5242a59d035e46774f2e634b374bc39ff62cb95",
"reference": "d5242a59d035e46774f2e634b374bc39ff62cb95",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/f3ea021866f4263f07ca3636bf22c64be9610c11",
"reference": "f3ea021866f4263f07ca3636bf22c64be9610c11",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.10"
"phpstan/phpstan": "^1.11"
},
"conflict": {
"phpunit/phpunit": "<7.0"
@ -1546,27 +1493,27 @@
"description": "PHPUnit extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.16"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.0"
},
"time": "2024-02-23T09:51:20+00:00"
"time": "2024-04-20T06:39:00+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "1.5.5",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "2e193a07651a6f4be3baa44ddb21d822681f5918"
"reference": "363f921dd8441777d4fc137deb99beb486c77df1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/2e193a07651a6f4be3baa44ddb21d822681f5918",
"reference": "2e193a07651a6f4be3baa44ddb21d822681f5918",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/363f921dd8441777d4fc137deb99beb486c77df1",
"reference": "363f921dd8441777d4fc137deb99beb486c77df1",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.10.60"
"phpstan/phpstan": "^1.11"
},
"require-dev": {
"nikic/php-parser": "^4.13.0",
@ -1595,22 +1542,22 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.5"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.0"
},
"time": "2024-04-19T15:12:26+00:00"
"time": "2024-04-20T06:37:51+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "10.1.14",
"version": "10.1.15",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b"
"reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
"reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae",
"reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae",
"shasum": ""
},
"require": {
@ -1667,7 +1614,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.15"
},
"funding": [
{
@ -1675,7 +1622,7 @@
"type": "github"
}
],
"time": "2024-03-12T15:33:41+00:00"
"time": "2024-06-29T08:25:15+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -1922,16 +1869,16 @@
},
{
"name": "phpunit/phpunit",
"version": "10.3.5",
"version": "10.5.24",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503"
"reference": "5f124e3e3e561006047b532fd0431bf5bb6b9015"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/747c3b2038f1139e3dcd9886a3f5a948648b7503",
"reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5f124e3e3e561006047b532fd0431bf5bb6b9015",
"reference": "5f124e3e3e561006047b532fd0431bf5bb6b9015",
"shasum": ""
},
"require": {
@ -1971,7 +1918,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "10.3-dev"
"dev-main": "10.5-dev"
}
},
"autoload": {
@ -2003,7 +1950,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.5"
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.24"
},
"funding": [
{
@ -2019,7 +1966,7 @@
"type": "tidelift"
}
],
"time": "2023-09-19T05:42:37+00:00"
"time": "2024-06-20T13:09:54+00:00"
},
{
"name": "sebastian/cli-parser",

21
install-local-protocol.sh Normal file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
echo "--- Installing BedrockProtocol, BedrockData, BedrockBlockUpgradeSchema, BedrockItemUpgradeSchema dependencies from local repositories."
echo "--- This allows you to perform integration tests using PocketMine-MP, without immediately publishing new versions of these libraries."
cp composer.json composer-local-protocol.json
cp composer.lock composer-local-protocol.lock
export COMPOSER=composer-local-protocol.json
composer config repositories.bedrock-protocol path ../deps/BedrockProtocol
composer config repositories.bedrock-data path ../deps/BedrockData
composer config repositories.bedrock-block-upgrade-schema path ../deps/BedrockBlockUpgradeSchema
composer config repositories.bedrock-item-upgrade-schema path ../deps/BedrockItemUpgradeSchema
composer require pocketmine/bedrock-protocol:*@dev pocketmine/bedrock-data:*@dev pocketmine/bedrock-block-upgrade-schema:*@dev pocketmine/bedrock-item-upgrade-schema:*@dev
composer install
echo "--- Local dependencies have been successfully installed."
echo "--- This script does not modify composer.json. To go back to the original dependency versions, simply run 'composer install'."

View File

@ -31,7 +31,7 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "5.15.1";
public const BASE_VERSION = "5.17.1";
public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";

View File

@ -150,6 +150,10 @@ final class Bell extends Transparent{
}
}
public function getDropsForIncompatibleTool(Item $item) : array{
return [$this->asItem()];
}
private function isValidFaceToRing(int $faceHit) : bool{
return match($this->attachmentType){
BellAttachmentType::CEILING => true,

View File

@ -745,8 +745,23 @@ final class BlockTypeIds{
public const PITCHER_PLANT = 10715;
public const PITCHER_CROP = 10716;
public const DOUBLE_PITCHER_CROP = 10717;
public const CAMPFIRE = 10718;
public const SOUL_CAMPFIRE = 10719;
public const TUFF_SLAB = 10720;
public const TUFF_STAIRS = 10721;
public const TUFF_WALL = 10722;
public const CHISELED_TUFF = 10723;
public const TUFF_BRICKS = 10724;
public const TUFF_BRICK_SLAB = 10725;
public const TUFF_BRICK_STAIRS = 10726;
public const TUFF_BRICK_WALL = 10727;
public const CHISELED_TUFF_BRICKS = 10728;
public const POLISHED_TUFF = 10729;
public const POLISHED_TUFF_SLAB = 10730;
public const POLISHED_TUFF_STAIRS = 10731;
public const POLISHED_TUFF_WALL = 10732;
public const FIRST_UNUSED_BLOCK_ID = 10718;
public const FIRST_UNUSED_BLOCK_ID = 10733;
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;

277
src/block/Campfire.php Normal file
View File

@ -0,0 +1,277 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\CampfireInventory;
use pocketmine\block\tile\Campfire as TileCampfire;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\LightableTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\crafting\FurnaceRecipe;
use pocketmine\crafting\FurnaceType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\entity\Living;
use pocketmine\entity\projectile\Projectile;
use pocketmine\entity\projectile\SplashPotion;
use pocketmine\event\block\CampfireCookEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Durable;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\item\PotionType;
use pocketmine\item\Shovel;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\BlazeShootSound;
use pocketmine\world\sound\FireExtinguishSound;
use pocketmine\world\sound\FlintSteelSound;
use pocketmine\world\sound\ItemFrameAddItemSound;
use function count;
use function min;
use function mt_rand;
class Campfire extends Transparent{
use HorizontalFacingTrait{
HorizontalFacingTrait::describeBlockOnlyState as encodeFacingState;
}
use LightableTrait{
LightableTrait::describeBlockOnlyState as encodeLitState;
}
private const UPDATE_INTERVAL_TICKS = 10;
protected CampfireInventory $inventory;
/**
* @var int[] slot => ticks
* @phpstan-var array<int, int>
*/
protected array $cookingTimes = [];
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$this->encodeFacingState($w);
$this->encodeLitState($w);
}
public function readStateFromWorld() : Block{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileCampfire){
$this->inventory = $tile->getInventory();
$this->cookingTimes = $tile->getCookingTimes();
}else{
$this->inventory = new CampfireInventory($this->position);
}
return $this;
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileCampfire){
$tile->setCookingTimes($this->cookingTimes);
}
}
public function hasEntityCollision() : bool{
return true;
}
public function getLightLevel() : int{
return $this->lit ? 15 : 0;
}
public function isAffectedBySilkTouch() : bool{
return true;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaItems::CHARCOAL()->setCount(2)
];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE;
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 9 / 16)];
}
public function getInventory() : CampfireInventory{
return $this->inventory;
}
protected function getFurnaceType() : FurnaceType{
return FurnaceType::CAMPFIRE;
}
protected function getEntityCollisionDamage() : int{
return 1;
}
/**
* Sets the number of ticks during the item in the given slot has been cooked.
*/
public function setCookingTime(int $slot, int $time) : void{
if($slot < 0 || $slot > 3){
throw new \InvalidArgumentException("Slot must be in range 0-3");
}
if($time < 0 || $time > $this->getFurnaceType()->getCookDurationTicks()){
throw new \InvalidArgumentException("CookingTime must be in range 0-" . $this->getFurnaceType()->getCookDurationTicks());
}
$this->cookingTimes[$slot] = $time;
}
/**
* Returns the number of ticks during the item in the given slot has been cooked.
*/
public function getCookingTime(int $slot) : int{
return $this->cookingTimes[$slot] ?? 0;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->getSide(Facing::DOWN) instanceof Campfire){
return false;
}
if($player !== null){
$this->facing = $player->getHorizontalFacing();
}
$this->lit = true;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if(!$this->lit){
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE){
$item->pop();
$this->ignite();
$this->position->getWorld()->addSound($this->position, new BlazeShootSound());
return true;
}elseif($item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
if($item instanceof Durable){
$item->applyDamage(1);
}
$this->ignite();
return true;
}
}elseif($item instanceof Shovel){
$item->applyDamage(1);
$this->extinguish();
return true;
}
if($this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($this->getFurnaceType())->match($item) !== null){
$ingredient = clone $item;
$ingredient->setCount(1);
if(count($this->inventory->addItem($ingredient)) === 0){
$item->pop();
$this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
return true;
}
}
return false;
}
public function onNearbyBlockChange() : void{
if($this->lit && $this->getSide(Facing::UP)->getTypeId() === BlockTypeIds::WATER){
$this->extinguish();
//TODO: Waterlogging
}
}
public function onEntityInside(Entity $entity) : bool{
if(!$this->lit){
if($entity->isOnFire()){
$this->ignite();
return false;
}
}elseif($entity instanceof Living){
$entity->attack(new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, $this->getEntityCollisionDamage()));
}
return true;
}
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
if($this->lit && $projectile instanceof SplashPotion && $projectile->getPotionType() === PotionType::WATER){
$this->extinguish();
}
}
public function onScheduledUpdate() : void{
if($this->lit){
$items = $this->inventory->getContents();
$furnaceType = $this->getFurnaceType();
$maxCookDuration = $furnaceType->getCookDurationTicks();
foreach($items as $slot => $item){
$this->setCookingTime($slot, min($maxCookDuration, $this->getCookingTime($slot) + self::UPDATE_INTERVAL_TICKS));
if($this->getCookingTime($slot) >= $maxCookDuration){
$result =
($recipe = $this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($furnaceType)->match($item)) instanceof FurnaceRecipe ?
$recipe->getResult() :
VanillaItems::AIR();
$ev = new CampfireCookEvent($this, $slot, $item, $result);
$ev->call();
if ($ev->isCancelled()){
continue;
}
$this->inventory->setItem($slot, VanillaItems::AIR());
$this->setCookingTime($slot, 0);
$this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $ev->getResult());
}
}
if(count($items) > 0){
$this->position->getWorld()->setBlock($this->position, $this);
}
if(mt_rand(1, 6) === 1){
$this->position->getWorld()->addSound($this->position, $furnaceType->getCookSound());
}
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS);
}
}
private function extinguish() : void{
$this->position->getWorld()->addSound($this->position, new FireExtinguishSound());
$this->position->getWorld()->setBlock($this->position, $this->setLit(false));
}
private function ignite() : void{
$this->position->getWorld()->addSound($this->position, new FlintSteelSound());
$this->position->getWorld()->setBlock($this->position, $this->setLit(true));
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS);
}
}

View File

@ -24,7 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CopperTrait;
use pocketmine\block\utils\ICopper;
class Copper extends Opaque{
class Copper extends Opaque implements ICopper{
use CopperTrait;
}

View File

@ -24,7 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CopperTrait;
use pocketmine\block\utils\ICopper;
class CopperSlab extends Slab{
class CopperSlab extends Slab implements ICopper{
use CopperTrait;
}

View File

@ -24,7 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CopperTrait;
use pocketmine\block\utils\ICopper;
class CopperStairs extends Stair{
class CopperStairs extends Stair implements ICopper{
use CopperTrait;
}

View File

@ -0,0 +1,48 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\crafting\FurnaceType;
use pocketmine\item\Item;
class SoulCampfire extends Campfire{
public function getLightLevel() : int{
return $this->lit ? 10 : 0;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaBlocks::SOUL_SOIL()->asItem()
];
}
protected function getEntityCollisionDamage() : int{
return 2;
}
protected function getFurnaceType() : FurnaceType{
return FurnaceType::SOUL_CAMPFIRE;
}
}

View File

@ -36,6 +36,7 @@ use pocketmine\block\tile\Bed as TileBed;
use pocketmine\block\tile\Bell as TileBell;
use pocketmine\block\tile\BlastFurnace as TileBlastFurnace;
use pocketmine\block\tile\BrewingStand as TileBrewingStand;
use pocketmine\block\tile\Campfire as TileCampfire;
use pocketmine\block\tile\Cauldron as TileCauldron;
use pocketmine\block\tile\Chest as TileChest;
use pocketmine\block\tile\ChiseledBookshelf as TileChiseledBookshelf;
@ -154,6 +155,7 @@ use function strtolower;
* @method static CakeWithCandle CAKE_WITH_CANDLE()
* @method static CakeWithDyedCandle CAKE_WITH_DYED_CANDLE()
* @method static Opaque CALCITE()
* @method static Campfire CAMPFIRE()
* @method static Candle CANDLE()
* @method static Carpet CARPET()
* @method static Carrot CARROTS()
@ -186,6 +188,8 @@ use function strtolower;
* @method static Opaque CHISELED_RED_SANDSTONE()
* @method static Opaque CHISELED_SANDSTONE()
* @method static Opaque CHISELED_STONE_BRICKS()
* @method static Opaque CHISELED_TUFF()
* @method static Opaque CHISELED_TUFF_BRICKS()
* @method static ChorusFlower CHORUS_FLOWER()
* @method static ChorusPlant CHORUS_PLANT()
* @method static Clay CLAY()
@ -607,6 +611,10 @@ use function strtolower;
* @method static Opaque POLISHED_GRANITE()
* @method static Slab POLISHED_GRANITE_SLAB()
* @method static Stair POLISHED_GRANITE_STAIRS()
* @method static Opaque POLISHED_TUFF()
* @method static Slab POLISHED_TUFF_SLAB()
* @method static Stair POLISHED_TUFF_STAIRS()
* @method static Wall POLISHED_TUFF_WALL()
* @method static Flower POPPY()
* @method static Potato POTATOES()
* @method static PotionCauldron POTION_CAULDRON()
@ -685,6 +693,7 @@ use function strtolower;
* @method static Slab SMOOTH_STONE_SLAB()
* @method static Snow SNOW()
* @method static SnowLayer SNOW_LAYER()
* @method static SoulCampfire SOUL_CAMPFIRE()
* @method static SoulFire SOUL_FIRE()
* @method static Lantern SOUL_LANTERN()
* @method static SoulSand SOUL_SAND()
@ -735,6 +744,13 @@ use function strtolower;
* @method static Tripwire TRIPWIRE()
* @method static TripwireHook TRIPWIRE_HOOK()
* @method static Opaque TUFF()
* @method static Opaque TUFF_BRICKS()
* @method static Slab TUFF_BRICK_SLAB()
* @method static Stair TUFF_BRICK_STAIRS()
* @method static Wall TUFF_BRICK_WALL()
* @method static Slab TUFF_SLAB()
* @method static Stair TUFF_STAIRS()
* @method static Wall TUFF_WALL()
* @method static NetherVines TWISTING_VINES()
* @method static UnderwaterTorch UNDERWATER_TORCH()
* @method static Vine VINES()
@ -826,6 +842,11 @@ final class VanillaBlocks{
self::register("brown_mushroom", new BrownMushroom(new BID(Ids::BROWN_MUSHROOM), "Brown Mushroom", new Info(BreakInfo::instant(), [Tags::POTTABLE_PLANTS])));
self::register("cactus", new Cactus(new BID(Ids::CACTUS), "Cactus", new Info(new BreakInfo(0.4), [Tags::POTTABLE_PLANTS])));
self::register("cake", new Cake(new BID(Ids::CAKE), "Cake", new Info(new BreakInfo(0.5))));
$campfireBreakInfo = new Info(BreakInfo::axe(2.0));
self::register("campfire", new Campfire(new BID(Ids::CAMPFIRE, TileCampfire::class), "Campfire", $campfireBreakInfo));
self::register("soul_campfire", new SoulCampfire(new BID(Ids::SOUL_CAMPFIRE, TileCampfire::class), "Soul Campfire", $campfireBreakInfo));
self::register("carrots", new Carrot(new BID(Ids::CARROTS), "Carrot Block", new Info(BreakInfo::instant())));
$chestBreakInfo = new Info(BreakInfo::axe(2.5));
@ -1261,6 +1282,7 @@ final class VanillaBlocks{
self::registerBlocksR17();
self::registerBlocksR18();
self::registerMudBlocks();
self::registerTuffBlocks();
self::registerCraftingTables();
self::registerChorusBlocks();
@ -1568,7 +1590,6 @@ final class VanillaBlocks{
self::register("amethyst_cluster", new AmethystCluster(new BID(Ids::AMETHYST_CLUSTER), "Amethyst Cluster", $amethystInfo));
self::register("calcite", new Opaque(new BID(Ids::CALCITE), "Calcite", new Info(BreakInfo::pickaxe(0.75, ToolTier::WOOD))));
self::register("tuff", new Opaque(new BID(Ids::TUFF), "Tuff", new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD, 30.0))));
self::register("raw_copper", new Opaque(new BID(Ids::RAW_COPPER), "Raw Copper Block", new Info(BreakInfo::pickaxe(5, ToolTier::STONE, 30.0))));
self::register("raw_gold", new Opaque(new BID(Ids::RAW_GOLD), "Raw Gold Block", new Info(BreakInfo::pickaxe(5, ToolTier::IRON, 30.0))));
@ -1659,6 +1680,27 @@ final class VanillaBlocks{
self::register("mud_brick_wall", new Wall(new BID(Ids::MUD_BRICK_WALL), "Mud Brick Wall", $mudBricksBreakInfo));
}
private static function registerTuffBlocks() : void{
$tuffBreakInfo = new Info(BreakInfo::pickaxe(1.5, ToolTier::WOOD, 30.0));
self::register("tuff", new Opaque(new BID(Ids::TUFF), "Tuff", $tuffBreakInfo));
self::register("tuff_slab", new Slab(new BID(Ids::TUFF_SLAB), "Tuff", $tuffBreakInfo));
self::register("tuff_stairs", new Stair(new BID(Ids::TUFF_STAIRS), "Tuff Stairs", $tuffBreakInfo));
self::register("tuff_wall", new Wall(new BID(Ids::TUFF_WALL), "Tuff Wall", $tuffBreakInfo));
self::register("chiseled_tuff", new Opaque(new BID(Ids::CHISELED_TUFF), "Chiseled Tuff", $tuffBreakInfo));
self::register("tuff_bricks", new Opaque(new BID(Ids::TUFF_BRICKS), "Tuff Bricks", $tuffBreakInfo));
self::register("tuff_brick_slab", new Slab(new BID(Ids::TUFF_BRICK_SLAB), "Tuff Brick", $tuffBreakInfo));
self::register("tuff_brick_stairs", new Stair(new BID(Ids::TUFF_BRICK_STAIRS), "Tuff Brick Stairs", $tuffBreakInfo));
self::register("tuff_brick_wall", new Wall(new BID(Ids::TUFF_BRICK_WALL), "Tuff Brick Wall", $tuffBreakInfo));
self::register("chiseled_tuff_bricks", new Opaque(new BID(Ids::CHISELED_TUFF_BRICKS), "Chiseled Tuff Bricks", $tuffBreakInfo));
self::register("polished_tuff", new Opaque(new BID(Ids::POLISHED_TUFF), "Polished Tuff", $tuffBreakInfo));
self::register("polished_tuff_slab", new Slab(new BID(Ids::POLISHED_TUFF_SLAB), "Polished Tuff", $tuffBreakInfo));
self::register("polished_tuff_stairs", new Stair(new BID(Ids::POLISHED_TUFF_STAIRS), "Polished Tuff Stairs", $tuffBreakInfo));
self::register("polished_tuff_wall", new Wall(new BID(Ids::POLISHED_TUFF_WALL), "Polished Tuff Wall", $tuffBreakInfo));
}
private static function registerCauldronBlocks() : void{
$cauldronBreakInfo = new Info(BreakInfo::pickaxe(2, ToolTier::WOOD));

View File

@ -28,6 +28,10 @@ use pocketmine\block\utils\WoodTypeTrait;
class WoodenStairs extends Stair{
use WoodTypeTrait;
public function getFuelTime() : int{
return $this->woodType->isFlammable() ? 300 : 0;
}
public function getFlameEncouragement() : int{
return 5;
}

View File

@ -0,0 +1,40 @@
<?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\inventory;
use pocketmine\inventory\SimpleInventory;
use pocketmine\world\Position;
class CampfireInventory extends SimpleInventory implements BlockInventory{
use BlockInventoryTrait;
public function __construct(Position $holder){
$this->holder = $holder;
parent::__construct(4);
}
public function getMaxStackSize() : int{
return 1;
}
}

143
src/block/tile/Campfire.php Normal file
View File

@ -0,0 +1,143 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block\tile;
use pocketmine\block\Campfire as BlockCampfire;
use pocketmine\block\inventory\CampfireInventory;
use pocketmine\inventory\CallbackInventoryListener;
use pocketmine\inventory\Inventory;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\world\World;
class Campfire extends Spawnable implements Container{
use ContainerTrait;
private const TAG_FIRST_INPUT_ITEM = "Item1"; //TAG_Compound
private const TAG_SECOND_INPUT_ITEM = "Item2"; //TAG_Compound
private const TAG_THIRD_INPUT_ITEM = "Item3"; //TAG_Compound
private const TAG_FOURTH_INPUT_ITEM = "Item4"; //TAG_Compound
private const TAG_FIRST_COOKING_TIME = "ItemTime1"; //TAG_Int
private const TAG_SECOND_COOKING_TIME = "ItemTime2"; //TAG_Int
private const TAG_THIRD_COOKING_TIME = "ItemTime3"; //TAG_Int
private const TAG_FOURTH_COOKING_TIME = "ItemTime4"; //TAG_Int
protected CampfireInventory $inventory;
/** @var array<int, int> */
private array $cookingTimes = [];
public function __construct(World $world, Vector3 $pos){
parent::__construct($world, $pos);
$this->inventory = new CampfireInventory($this->position);
$this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(
static function(Inventory $unused) use ($world, $pos) : void{
$block = $world->getBlock($pos);
if($block instanceof BlockCampfire){
$world->setBlock($pos, $block);
}
})
);
}
public function getInventory() : CampfireInventory{
return $this->inventory;
}
public function getRealInventory() : CampfireInventory{
return $this->inventory;
}
/**
* @return int[]
* @phpstan-return array<int, int>
*/
public function getCookingTimes() : array{
return $this->cookingTimes;
}
/**
* @param int[] $cookingTimes
* @phpstan-param array<int, int> $cookingTimes
*/
public function setCookingTimes(array $cookingTimes) : void{
$this->cookingTimes = $cookingTimes;
}
public function readSaveData(CompoundTag $nbt) : void{
$items = [];
$listeners = $this->inventory->getListeners()->toArray();
$this->inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization
foreach([
[0, self::TAG_FIRST_INPUT_ITEM, self::TAG_FIRST_COOKING_TIME],
[1, self::TAG_SECOND_INPUT_ITEM, self::TAG_SECOND_COOKING_TIME],
[2, self::TAG_THIRD_INPUT_ITEM, self::TAG_THIRD_COOKING_TIME],
[3, self::TAG_FOURTH_INPUT_ITEM, self::TAG_FOURTH_COOKING_TIME],
] as [$slot, $itemTag, $cookingTimeTag]){
if(($tag = $nbt->getTag($itemTag)) instanceof CompoundTag){
$items[$slot] = Item::nbtDeserialize($tag);
}
if(($tag = $nbt->getTag($cookingTimeTag)) instanceof IntTag){
$this->cookingTimes[$slot] = $tag->getValue();
}
}
$this->inventory->setContents($items);
$this->inventory->getListeners()->add(...$listeners);
}
protected function writeSaveData(CompoundTag $nbt) : void{
foreach([
[0, self::TAG_FIRST_INPUT_ITEM, self::TAG_FIRST_COOKING_TIME],
[1, self::TAG_SECOND_INPUT_ITEM, self::TAG_SECOND_COOKING_TIME],
[2, self::TAG_THIRD_INPUT_ITEM, self::TAG_THIRD_COOKING_TIME],
[3, self::TAG_FOURTH_INPUT_ITEM, self::TAG_FOURTH_COOKING_TIME],
] as [$slot, $itemTag, $cookingTimeTag]){
$item = $this->inventory->getItem($slot);
if(!$item->isNull()){
$nbt->setTag($itemTag, $item->nbtSerialize());
if(isset($this->cookingTimes[$slot])){
$nbt->setInt($cookingTimeTag, $this->cookingTimes[$slot]);
}
}
}
}
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
foreach([
0 => self::TAG_FIRST_INPUT_ITEM,
1 => self::TAG_SECOND_INPUT_ITEM,
2 => self::TAG_THIRD_INPUT_ITEM,
3 => self::TAG_FOURTH_INPUT_ITEM
] as $slot => $tag){
$item = $this->inventory->getItem($slot);
if(!$item->isNull()){
$nbt->setTag($tag, TypeConverter::getInstance()->getItemTranslator()->toNetworkNbt($item));
}
}
}
}

View File

@ -57,6 +57,7 @@ final class TileFactory{
$this->register(Bell::class, ["Bell", "minecraft:bell"]);
$this->register(BlastFurnace::class, ["BlastFurnace", "minecraft:blast_furnace"]);
$this->register(BrewingStand::class, ["BrewingStand", "minecraft:brewing_stand"]);
$this->register(Campfire::class, ["Campfire", "minecraft:campfire"]);
$this->register(Cauldron::class, ["Cauldron", "minecraft:cauldron"]);
$this->register(Chest::class, ["Chest", "minecraft:chest"]);
$this->register(ChiseledBookshelf::class, ["ChiseledBookshelf", "minecraft:chiseled_bookshelf"]);
@ -79,7 +80,6 @@ final class TileFactory{
$this->register(MobHead::class, ["Skull", "minecraft:skull"]);
$this->register(GlowingItemFrame::class, ["GlowItemFrame"]);
//TODO: Campfire
//TODO: ChalkboardBlock
//TODO: ChemistryTable
//TODO: CommandBlock

View File

@ -34,10 +34,12 @@ enum BannerPatternType{
case DIAGONAL_RIGHT;
case DIAGONAL_UP_LEFT;
case DIAGONAL_UP_RIGHT;
case FLOW;
case FLOWER;
case GLOBE;
case GRADIENT;
case GRADIENT_UP;
case GUSTER;
case HALF_HORIZONTAL;
case HALF_HORIZONTAL_BOTTOM;
case HALF_VERTICAL;

View File

@ -0,0 +1,38 @@
<?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;
/**
* Represents copper blocks that have oxidized and waxed variations.
*/
interface ICopper{
public function getOxidation() : CopperOxidation;
public function setOxidation(CopperOxidation $oxidation) : ICopper;
public function isWaxed() : bool;
public function setWaxed(bool $waxed) : ICopper;
}

View File

@ -236,6 +236,7 @@ final class CraftingManagerFromDataHelper{
}
$outputs[] = $output;
}
//TODO: check unlocking requirements - our current system doesn't support this
$result->registerShapelessRecipe(new ShapelessRecipe(
$inputs,
$outputs,
@ -262,6 +263,7 @@ final class CraftingManagerFromDataHelper{
}
$outputs[] = $output;
}
//TODO: check unlocking requirements - our current system doesn't support this
$result->registerShapedRecipe(new ShapedRecipe(
$recipe->shape,
$inputs,
@ -273,7 +275,8 @@ final class CraftingManagerFromDataHelper{
"furnace" => FurnaceType::FURNACE,
"blast_furnace" => FurnaceType::BLAST_FURNACE,
"smoker" => FurnaceType::SMOKER,
//TODO: campfire
"campfire" => FurnaceType::CAMPFIRE,
"soul_campfire" => FurnaceType::SOUL_CAMPFIRE,
default => null
};
if($furnaceType === null){

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\crafting;
use pocketmine\world\sound\BlastFurnaceSound;
use pocketmine\world\sound\CampfireSound;
use pocketmine\world\sound\FurnaceSound;
use pocketmine\world\sound\SmokerSound;
use pocketmine\world\sound\Sound;
@ -36,6 +37,8 @@ enum FurnaceType{
case FURNACE;
case BLAST_FURNACE;
case SMOKER;
case CAMPFIRE;
case SOUL_CAMPFIRE;
/**
* @phpstan-return TMetadata
@ -48,6 +51,7 @@ enum FurnaceType{
self::FURNACE => [200, new FurnaceSound()],
self::BLAST_FURNACE => [100, new BlastFurnaceSound()],
self::SMOKER => [100, new SmokerSound()],
self::CAMPFIRE, self::SOUL_CAMPFIRE => [600, new CampfireSound()]
};
}

View File

@ -23,7 +23,9 @@ declare(strict_types=1);
namespace pocketmine\crafting\json;
final class ShapedRecipeData{
use function count;
final class ShapedRecipeData implements \JsonSerializable{
/**
* @required
* @var string[]
@ -51,22 +53,39 @@ final class ShapedRecipeData{
/** @required */
public int $priority;
/** @var RecipeIngredientData[] */
public array $unlockingIngredients = [];
/**
* TODO: convert this to use promoted properties - avoiding them for now since it would break JsonMapper
*
* @param string[] $shape
* @param RecipeIngredientData[] $input
* @param ItemStackData[] $output
* @param RecipeIngredientData[] $unlockingIngredients
*
* @phpstan-param list<string> $shape
* @phpstan-param array<string, RecipeIngredientData> $input
* @phpstan-param list<ItemStackData> $output
* @phpstan-param list<RecipeIngredientData> $unlockingIngredients
*/
public function __construct(array $shape, array $input, array $output, string $block, int $priority){
public function __construct(array $shape, array $input, array $output, string $block, int $priority, array $unlockingIngredients = []){
$this->block = $block;
$this->priority = $priority;
$this->shape = $shape;
$this->input = $input;
$this->output = $output;
$this->unlockingIngredients = $unlockingIngredients;
}
/**
* @return mixed[]
*/
public function jsonSerialize() : array{
$result = (array) $this;
if(count($this->unlockingIngredients) === 0){
unset($result["unlockingIngredients"]);
}
return $result;
}
}

View File

@ -23,7 +23,9 @@ declare(strict_types=1);
namespace pocketmine\crafting\json;
final class ShapelessRecipeData{
use function count;
final class ShapelessRecipeData implements \JsonSerializable{
/**
* @required
@ -45,17 +47,34 @@ final class ShapelessRecipeData{
/** @required */
public int $priority;
/** @var RecipeIngredientData[] */
public array $unlockingIngredients = [];
/**
* @param RecipeIngredientData[] $input
* @param ItemStackData[] $output
* @param RecipeIngredientData[] $unlockingIngredients
*
* @phpstan-param list<RecipeIngredientData> $input
* @phpstan-param list<ItemStackData> $output
* @phpstan-param list<RecipeIngredientData> $unlockingIngredients
*/
public function __construct(array $input, array $output, string $block, int $priority){
public function __construct(array $input, array $output, string $block, int $priority, array $unlockingIngredients = []){
$this->block = $block;
$this->priority = $priority;
$this->input = $input;
$this->output = $output;
$this->unlockingIngredients = $unlockingIngredients;
}
/**
* @return mixed[]
*/
public function jsonSerialize() : array{
$result = (array) $this;
if(count($this->unlockingIngredients) === 0){
unset($result["unlockingIngredients"]);
}
return $result;
}
}

View File

@ -56,9 +56,11 @@ final class BannerPatternTypeIdMap{
BannerPatternType::DIAGONAL_UP_LEFT => "ld",
BannerPatternType::DIAGONAL_UP_RIGHT => "rud",
BannerPatternType::FLOWER => "flo",
BannerPatternType::FLOW => "flw",
BannerPatternType::GLOBE => "glb",
BannerPatternType::GRADIENT => "gra",
BannerPatternType::GRADIENT_UP => "gru",
BannerPatternType::GUSTER => "gus",
BannerPatternType::HALF_HORIZONTAL => "hh",
BannerPatternType::HALF_HORIZONTAL_BOTTOM => "hhb",
BannerPatternType::HALF_VERTICAL => "vh",

View File

@ -43,6 +43,7 @@ final class EnchantmentIdMap{
$this->register(EnchantmentIds::PROJECTILE_PROTECTION, VanillaEnchantments::PROJECTILE_PROTECTION());
$this->register(EnchantmentIds::THORNS, VanillaEnchantments::THORNS());
$this->register(EnchantmentIds::RESPIRATION, VanillaEnchantments::RESPIRATION());
$this->register(EnchantmentIds::AQUA_AFFINITY, VanillaEnchantments::AQUA_AFFINITY());
$this->register(EnchantmentIds::SHARPNESS, VanillaEnchantments::SHARPNESS());
//TODO: smite, bane of arthropods (these don't make sense now because their applicable mobs don't exist yet)

View File

@ -38,11 +38,14 @@ use function implode;
final class BlockStateData{
/**
* Bedrock version of the most recent backwards-incompatible change to blockstates.
*
* This is *not* the same as current game version. It should match the numbers in the
* newest blockstate upgrade schema used in BedrockBlockUpgradeSchema.
*/
public const CURRENT_VERSION =
(1 << 24) | //major
(20 << 16) | //minor
(80 << 8) | //patch
(21 << 16) | //minor
(0 << 8) | //patch
(3); //revision
public const TAG_NAME = "name";

View File

@ -59,7 +59,6 @@ final class BlockStateNames{
public const COLOR_BIT = "color_bit";
public const COMPOSTER_FILL_LEVEL = "composter_fill_level";
public const CONDITIONAL_BIT = "conditional_bit";
public const CORAL_COLOR = "coral_color";
public const CORAL_DIRECTION = "coral_direction";
public const CORAL_FAN_DIRECTION = "coral_fan_direction";
public const CORAL_HANG_TYPE_BIT = "coral_hang_type_bit";
@ -73,7 +72,6 @@ final class BlockStateNames{
public const DIRT_TYPE = "dirt_type";
public const DISARMED_BIT = "disarmed_bit";
public const DOOR_HINGE_BIT = "door_hinge_bit";
public const DOUBLE_PLANT_TYPE = "double_plant_type";
public const DRAG_DOWN = "drag_down";
public const DRIPSTONE_THICKNESS = "dripstone_thickness";
public const END_PORTAL_EYE_BIT = "end_portal_eye_bit";
@ -105,6 +103,7 @@ final class BlockStateNames{
public const MONSTER_EGG_STONE_TYPE = "monster_egg_stone_type";
public const MULTI_FACE_DIRECTION_BITS = "multi_face_direction_bits";
public const OCCUPIED_BIT = "occupied_bit";
public const OMINOUS = "ominous";
public const OPEN_BIT = "open_bit";
public const ORIENTATION = "orientation";
public const OUTPUT_LIT_BIT = "output_lit_bit";
@ -137,7 +136,6 @@ final class BlockStateNames{
public const STRUCTURE_BLOCK_TYPE = "structure_block_type";
public const STRUCTURE_VOID_TYPE = "structure_void_type";
public const SUSPENDED_BIT = "suspended_bit";
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";

View File

@ -62,12 +62,6 @@ final class BlockStateStringValues{
public const CHISEL_TYPE_LINES = "lines";
public const CHISEL_TYPE_SMOOTH = "smooth";
public const CORAL_COLOR_BLUE = "blue";
public const CORAL_COLOR_PINK = "pink";
public const CORAL_COLOR_PURPLE = "purple";
public const CORAL_COLOR_RED = "red";
public const CORAL_COLOR_YELLOW = "yellow";
public const CRACKED_STATE_CRACKED = "cracked";
public const CRACKED_STATE_MAX_CRACKED = "max_cracked";
public const CRACKED_STATE_NO_CRACKS = "no_cracks";
@ -80,13 +74,6 @@ final class BlockStateStringValues{
public const DIRT_TYPE_COARSE = "coarse";
public const DIRT_TYPE_NORMAL = "normal";
public const DOUBLE_PLANT_TYPE_FERN = "fern";
public const DOUBLE_PLANT_TYPE_GRASS = "grass";
public const DOUBLE_PLANT_TYPE_PAEONIA = "paeonia";
public const DOUBLE_PLANT_TYPE_ROSE = "rose";
public const DOUBLE_PLANT_TYPE_SUNFLOWER = "sunflower";
public const DOUBLE_PLANT_TYPE_SYRINGA = "syringa";
public const DRIPSTONE_THICKNESS_BASE = "base";
public const DRIPSTONE_THICKNESS_FRUSTUM = "frustum";
public const DRIPSTONE_THICKNESS_MERGE = "merge";
@ -220,11 +207,6 @@ final class BlockStateStringValues{
public const STRUCTURE_VOID_TYPE_AIR = "air";
public const STRUCTURE_VOID_TYPE_VOID = "void";
public const TALL_GRASS_TYPE_DEFAULT = "default";
public const TALL_GRASS_TYPE_FERN = "fern";
public const TALL_GRASS_TYPE_SNOW = "snow";
public const TALL_GRASS_TYPE_TALL = "tall";
public const TORCH_FACING_DIRECTION_EAST = "east";
public const TORCH_FACING_DIRECTION_NORTH = "north";
public const TORCH_FACING_DIRECTION_SOUTH = "south";

View File

@ -144,9 +144,11 @@ 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_BLOCK = "minecraft:brain_coral_block";
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_SLAB = "minecraft:brick_slab";
public const BRICK_STAIRS = "minecraft:brick_stairs";
public const BROWN_CANDLE = "minecraft:brown_candle";
public const BROWN_CANDLE_CAKE = "minecraft:brown_candle_cake";
@ -163,6 +165,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_BLOCK = "minecraft:bubble_coral_block";
public const BUBBLE_CORAL_FAN = "minecraft:bubble_coral_fan";
public const BUDDING_AMETHYST = "minecraft:budding_amethyst";
public const CACTUS = "minecraft:cactus";
@ -221,6 +224,7 @@ final class BlockTypeNames{
public const COBBLED_DEEPSLATE_STAIRS = "minecraft:cobbled_deepslate_stairs";
public const COBBLED_DEEPSLATE_WALL = "minecraft:cobbled_deepslate_wall";
public const COBBLESTONE = "minecraft:cobblestone";
public const COBBLESTONE_SLAB = "minecraft:cobblestone_slab";
public const COBBLESTONE_WALL = "minecraft:cobblestone_wall";
public const COCOA = "minecraft:cocoa";
public const COLORED_TORCH_BP = "minecraft:colored_torch_bp";
@ -234,7 +238,6 @@ final class BlockTypeNames{
public const COPPER_GRATE = "minecraft:copper_grate";
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_HANG = "minecraft:coral_fan_hang";
public const CORAL_FAN_HANG2 = "minecraft:coral_fan_hang2";
public const CORAL_FAN_HANG3 = "minecraft:coral_fan_hang3";
@ -299,14 +302,19 @@ final class BlockTypeNames{
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_BLOCK = "minecraft:dead_brain_coral_block";
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_BLOCK = "minecraft:dead_bubble_coral_block";
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_BLOCK = "minecraft:dead_fire_coral_block";
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_BLOCK = "minecraft:dead_horn_coral_block";
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_BLOCK = "minecraft:dead_tube_coral_block";
public const DEAD_TUBE_CORAL_FAN = "minecraft:dead_tube_coral_fan";
public const DEADBUSH = "minecraft:deadbush";
public const DECORATED_POT = "minecraft:decorated_pot";
@ -339,7 +347,6 @@ final class BlockTypeNames{
public const DIRT_WITH_ROOTS = "minecraft:dirt_with_roots";
public const DISPENSER = "minecraft:dispenser";
public const DOUBLE_CUT_COPPER_SLAB = "minecraft:double_cut_copper_slab";
public const DOUBLE_PLANT = "minecraft:double_plant";
public const DOUBLE_STONE_BLOCK_SLAB = "minecraft:double_stone_block_slab";
public const DOUBLE_STONE_BLOCK_SLAB2 = "minecraft:double_stone_block_slab2";
public const DOUBLE_STONE_BLOCK_SLAB3 = "minecraft:double_stone_block_slab3";
@ -490,8 +497,10 @@ final class BlockTypeNames{
public const EXPOSED_DOUBLE_CUT_COPPER_SLAB = "minecraft:exposed_double_cut_copper_slab";
public const FARMLAND = "minecraft:farmland";
public const FENCE_GATE = "minecraft:fence_gate";
public const FERN = "minecraft:fern";
public const FIRE = "minecraft:fire";
public const FIRE_CORAL = "minecraft:fire_coral";
public const FIRE_CORAL_BLOCK = "minecraft:fire_coral_block";
public const FIRE_CORAL_FAN = "minecraft:fire_coral_fan";
public const FLETCHING_TABLE = "minecraft:fletching_table";
public const FLOWER_POT = "minecraft:flower_pot";
@ -583,6 +592,7 @@ final class BlockTypeNames{
public const HONEYCOMB_BLOCK = "minecraft:honeycomb_block";
public const HOPPER = "minecraft:hopper";
public const HORN_CORAL = "minecraft:horn_coral";
public const HORN_CORAL_BLOCK = "minecraft:horn_coral_block";
public const HORN_CORAL_FAN = "minecraft:horn_coral_fan";
public const ICE = "minecraft:ice";
public const INFESTED_DEEPSLATE = "minecraft:infested_deepslate";
@ -619,6 +629,7 @@ final class BlockTypeNames{
public const LAPIS_BLOCK = "minecraft:lapis_block";
public const LAPIS_ORE = "minecraft:lapis_ore";
public const LARGE_AMETHYST_BUD = "minecraft:large_amethyst_bud";
public const LARGE_FERN = "minecraft:large_fern";
public const LAVA = "minecraft:lava";
public const LECTERN = "minecraft:lectern";
public const LEVER = "minecraft:lever";
@ -646,6 +657,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 LILAC = "minecraft:lilac";
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";
@ -718,6 +730,7 @@ final class BlockTypeNames{
public const MYCELIUM = "minecraft:mycelium";
public const NETHER_BRICK = "minecraft:nether_brick";
public const NETHER_BRICK_FENCE = "minecraft:nether_brick_fence";
public const NETHER_BRICK_SLAB = "minecraft:nether_brick_slab";
public const NETHER_BRICK_STAIRS = "minecraft:nether_brick_stairs";
public const NETHER_GOLD_ORE = "minecraft:nether_gold_ore";
public const NETHER_SPROUTS = "minecraft:nether_sprouts";
@ -767,6 +780,8 @@ final class BlockTypeNames{
public const PACKED_ICE = "minecraft:packed_ice";
public const PACKED_MUD = "minecraft:packed_mud";
public const PEARLESCENT_FROGLIGHT = "minecraft:pearlescent_froglight";
public const PEONY = "minecraft:peony";
public const PETRIFIED_OAK_SLAB = "minecraft:petrified_oak_slab";
public const PINK_CANDLE = "minecraft:pink_candle";
public const PINK_CANDLE_CAKE = "minecraft:pink_candle_cake";
public const PINK_CARPET = "minecraft:pink_carpet";
@ -842,6 +857,7 @@ final class BlockTypeNames{
public const QUARTZ_BLOCK = "minecraft:quartz_block";
public const QUARTZ_BRICKS = "minecraft:quartz_bricks";
public const QUARTZ_ORE = "minecraft:quartz_ore";
public const QUARTZ_SLAB = "minecraft:quartz_slab";
public const QUARTZ_STAIRS = "minecraft:quartz_stairs";
public const RAIL = "minecraft:rail";
public const RAW_COPPER_BLOCK = "minecraft:raw_copper_block";
@ -875,8 +891,10 @@ final class BlockTypeNames{
public const REPEATING_COMMAND_BLOCK = "minecraft:repeating_command_block";
public const RESERVED6 = "minecraft:reserved6";
public const RESPAWN_ANCHOR = "minecraft:respawn_anchor";
public const ROSE_BUSH = "minecraft:rose_bush";
public const SAND = "minecraft:sand";
public const SANDSTONE = "minecraft:sandstone";
public const SANDSTONE_SLAB = "minecraft:sandstone_slab";
public const SANDSTONE_STAIRS = "minecraft:sandstone_stairs";
public const SCAFFOLDING = "minecraft:scaffolding";
public const SCULK = "minecraft:sculk";
@ -887,6 +905,7 @@ final class BlockTypeNames{
public const SEA_LANTERN = "minecraft:sea_lantern";
public const SEA_PICKLE = "minecraft:sea_pickle";
public const SEAGRASS = "minecraft:seagrass";
public const SHORT_GRASS = "minecraft:short_grass";
public const SHROOMLIGHT = "minecraft:shroomlight";
public const SILVER_GLAZED_TERRACOTTA = "minecraft:silver_glazed_terracotta";
public const SKULL = "minecraft:skull";
@ -900,6 +919,7 @@ final class BlockTypeNames{
public const SMOOTH_RED_SANDSTONE_STAIRS = "minecraft:smooth_red_sandstone_stairs";
public const SMOOTH_SANDSTONE_STAIRS = "minecraft:smooth_sandstone_stairs";
public const SMOOTH_STONE = "minecraft:smooth_stone";
public const SMOOTH_STONE_SLAB = "minecraft:smooth_stone_slab";
public const SNIFFER_EGG = "minecraft:sniffer_egg";
public const SNOW = "minecraft:snow";
public const SNOW_LAYER = "minecraft:snow_layer";
@ -933,10 +953,10 @@ final class BlockTypeNames{
public const STICKY_PISTON = "minecraft:sticky_piston";
public const STICKY_PISTON_ARM_COLLISION = "minecraft:sticky_piston_arm_collision";
public const STONE = "minecraft:stone";
public const STONE_BLOCK_SLAB = "minecraft:stone_block_slab";
public const STONE_BLOCK_SLAB2 = "minecraft:stone_block_slab2";
public const STONE_BLOCK_SLAB3 = "minecraft:stone_block_slab3";
public const STONE_BLOCK_SLAB4 = "minecraft:stone_block_slab4";
public const STONE_BRICK_SLAB = "minecraft:stone_brick_slab";
public const STONE_BRICK_STAIRS = "minecraft:stone_brick_stairs";
public const STONE_BUTTON = "minecraft:stone_button";
public const STONE_PRESSURE_PLATE = "minecraft:stone_pressure_plate";
@ -967,10 +987,11 @@ final class BlockTypeNames{
public const STRIPPED_WARPED_STEM = "minecraft:stripped_warped_stem";
public const STRUCTURE_BLOCK = "minecraft:structure_block";
public const STRUCTURE_VOID = "minecraft:structure_void";
public const SUNFLOWER = "minecraft:sunflower";
public const SUSPICIOUS_GRAVEL = "minecraft:suspicious_gravel";
public const SUSPICIOUS_SAND = "minecraft:suspicious_sand";
public const SWEET_BERRY_BUSH = "minecraft:sweet_berry_bush";
public const TALLGRASS = "minecraft:tallgrass";
public const TALL_GRASS = "minecraft:tall_grass";
public const TARGET = "minecraft:target";
public const TINTED_GLASS = "minecraft:tinted_glass";
public const TNT = "minecraft:tnt";
@ -983,6 +1004,7 @@ final class BlockTypeNames{
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_BLOCK = "minecraft:tube_coral_block";
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";

View File

@ -43,6 +43,7 @@ use pocketmine\block\Cactus;
use pocketmine\block\Cake;
use pocketmine\block\CakeWithCandle;
use pocketmine\block\CakeWithDyedCandle;
use pocketmine\block\Campfire;
use pocketmine\block\Candle;
use pocketmine\block\Carpet;
use pocketmine\block\Carrot;
@ -124,6 +125,7 @@ use pocketmine\block\SimplePressurePlate;
use pocketmine\block\Slab;
use pocketmine\block\SmallDripleaf;
use pocketmine\block\SnowLayer;
use pocketmine\block\SoulCampfire;
use pocketmine\block\Sponge;
use pocketmine\block\StainedGlass;
use pocketmine\block\StainedGlassPane;
@ -551,6 +553,16 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
Axis::Z => 1,
default => throw new BlockStateSerializeException("Invalid axis {$axis}"),
}));
$this->map(Blocks::CORAL_BLOCK(), fn(CoralBlock $block) => Writer::create(
match($block->getCoralType()){
CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_BLOCK : Ids::BRAIN_CORAL_BLOCK,
CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_BLOCK : Ids::BUBBLE_CORAL_BLOCK,
CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_BLOCK : Ids::FIRE_CORAL_BLOCK,
CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_BLOCK : Ids::HORN_CORAL_BLOCK,
CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_BLOCK : Ids::TUBE_CORAL_BLOCK,
}
));
}
private function registerCauldronSerializers() : void{
@ -772,6 +784,8 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSimple(Blocks::CHISELED_DEEPSLATE(), Ids::CHISELED_DEEPSLATE);
$this->mapSimple(Blocks::CHISELED_NETHER_BRICKS(), Ids::CHISELED_NETHER_BRICKS);
$this->mapSimple(Blocks::CHISELED_POLISHED_BLACKSTONE(), Ids::CHISELED_POLISHED_BLACKSTONE);
$this->mapSimple(Blocks::CHISELED_TUFF(), Ids::CHISELED_TUFF);
$this->mapSimple(Blocks::CHISELED_TUFF_BRICKS(), Ids::CHISELED_TUFF_BRICKS);
$this->mapSimple(Blocks::CHORUS_PLANT(), Ids::CHORUS_PLANT);
$this->mapSimple(Blocks::CLAY(), Ids::CLAY);
$this->mapSimple(Blocks::COAL(), Ids::COAL_BLOCK);
@ -927,6 +941,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSimple(Blocks::ENCHANTING_TABLE(), Ids::ENCHANTING_TABLE);
$this->mapSimple(Blocks::END_STONE(), Ids::END_STONE);
$this->mapSimple(Blocks::END_STONE_BRICKS(), Ids::END_BRICKS);
$this->mapSimple(Blocks::FERN(), Ids::FERN);
$this->mapSimple(Blocks::FLETCHING_TABLE(), Ids::FLETCHING_TABLE);
$this->mapSimple(Blocks::GILDED_BLACKSTONE(), Ids::GILDED_BLACKSTONE);
$this->mapSimple(Blocks::GLASS(), Ids::GLASS);
@ -983,6 +998,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSimple(Blocks::POLISHED_DEEPSLATE(), Ids::POLISHED_DEEPSLATE);
$this->mapSimple(Blocks::POLISHED_DIORITE(), Ids::POLISHED_DIORITE);
$this->mapSimple(Blocks::POLISHED_GRANITE(), Ids::POLISHED_GRANITE);
$this->mapSimple(Blocks::POLISHED_TUFF(), Ids::POLISHED_TUFF);
$this->mapSimple(Blocks::QUARTZ_BRICKS(), Ids::QUARTZ_BRICKS);
$this->mapSimple(Blocks::RAW_COPPER(), Ids::RAW_COPPER_BLOCK);
$this->mapSimple(Blocks::RAW_GOLD(), Ids::RAW_GOLD_BLOCK);
@ -1005,9 +1021,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSimple(Blocks::SOUL_SOIL(), Ids::SOUL_SOIL);
$this->mapSimple(Blocks::SPORE_BLOSSOM(), Ids::SPORE_BLOSSOM);
$this->mapSimple(Blocks::STONE(), Ids::STONE);
$this->mapSimple(Blocks::TALL_GRASS(), Ids::SHORT_GRASS); //no, this is not a typo - tall_grass is now the double block, just to be confusing :(
$this->mapSimple(Blocks::TINTED_GLASS(), Ids::TINTED_GLASS);
$this->mapSimple(Blocks::TORCHFLOWER(), Ids::TORCHFLOWER);
$this->mapSimple(Blocks::TUFF(), Ids::TUFF);
$this->mapSimple(Blocks::TUFF_BRICKS(), Ids::TUFF_BRICKS);
$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);
@ -1135,7 +1153,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeBool(StateNames::BREWING_STAND_SLOT_B_BIT, $block->hasSlot(BrewingStandSlot::SOUTHWEST))
->writeBool(StateNames::BREWING_STAND_SLOT_C_BIT, $block->hasSlot(BrewingStandSlot::NORTHWEST));
});
$this->map(Blocks::BRICK_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, StringValues::STONE_SLAB_TYPE_BRICK));
$this->map(Blocks::BRICK_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, Ids::BRICK_SLAB, StringValues::STONE_SLAB_TYPE_BRICK));
$this->mapStairs(Blocks::BRICK_STAIRS(), Ids::BRICK_STAIRS);
$this->map(Blocks::BRICK_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_BRICK));
$this->map(Blocks::BROWN_MUSHROOM_BLOCK(), fn(BrownMushroomBlock $block) => Helper::encodeMushroomBlock($block, new Writer(Ids::BROWN_MUSHROOM_BLOCK)));
@ -1147,6 +1165,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create(Ids::CAKE)
->writeInt(StateNames::BITE_COUNTER, $block->getBites());
});
$this->map(Blocks::CAMPFIRE(), function(Campfire $block) : Writer{
return Writer::create(Ids::CAMPFIRE)
->writeCardinalHorizontalFacing($block->getFacing())
->writeBool(StateNames::EXTINGUISHED, !$block->isLit());
});
$this->map(Blocks::CARROTS(), fn(Carrot $block) => Helper::encodeCrops($block, new Writer(Ids::CARROTS)));
$this->map(Blocks::CARVED_PUMPKIN(), function(CarvedPumpkin $block) : Writer{
return Writer::create(Ids::CARVED_PUMPKIN)
@ -1191,7 +1214,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSlab(Blocks::COBBLED_DEEPSLATE_SLAB(), Ids::COBBLED_DEEPSLATE_SLAB, Ids::COBBLED_DEEPSLATE_DOUBLE_SLAB);
$this->mapStairs(Blocks::COBBLED_DEEPSLATE_STAIRS(), Ids::COBBLED_DEEPSLATE_STAIRS);
$this->map(Blocks::COBBLED_DEEPSLATE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::COBBLED_DEEPSLATE_WALL)));
$this->map(Blocks::COBBLESTONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, StringValues::STONE_SLAB_TYPE_COBBLESTONE));
$this->map(Blocks::COBBLESTONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, Ids::COBBLESTONE_SLAB, StringValues::STONE_SLAB_TYPE_COBBLESTONE));
$this->mapStairs(Blocks::COBBLESTONE_STAIRS(), Ids::STONE_STAIRS);
$this->map(Blocks::COBBLESTONE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_COBBLESTONE));
$this->map(Blocks::COPPER(), function(Copper $block) : Writer{
@ -1274,11 +1297,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeLegacyHorizontalFacing(Facing::opposite($block->getFacing()));
});
$this->map(Blocks::COMPOUND_CREATOR(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, StringValues::CHEMISTRY_TABLE_TYPE_COMPOUND_CREATOR, new Writer(Ids::CHEMISTRY_TABLE)));
$this->map(Blocks::CORAL_BLOCK(), function(CoralBlock $block) : Writer{
return Writer::create(Ids::CORAL_BLOCK)
->writeBool(StateNames::DEAD_BIT, $block->isDead())
->writeCoralType($block->getCoralType());
});
$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));
@ -1323,7 +1341,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
//ROOTED was already checked above
});
});
$this->map(Blocks::DOUBLE_TALLGRASS(), fn(DoubleTallGrass $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_GRASS, Writer::create(Ids::DOUBLE_PLANT)));
$this->map(Blocks::DOUBLE_TALLGRASS(), fn(DoubleTallGrass $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::TALL_GRASS)));
$this->map(Blocks::ELEMENT_CONSTRUCTOR(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, StringValues::CHEMISTRY_TABLE_TYPE_ELEMENT_CONSTRUCTOR, new Writer(Ids::CHEMISTRY_TABLE)));
$this->map(Blocks::ENDER_CHEST(), function(EnderChest $block) : Writer{
return Writer::create(Ids::ENDER_CHEST)
@ -1341,13 +1359,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::END_STONE_BRICK_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_END_STONE_BRICK));
$this->mapStairs(Blocks::END_STONE_BRICK_STAIRS(), Ids::END_BRICK_STAIRS);
$this->map(Blocks::END_STONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_END_BRICK));
$this->map(Blocks::FAKE_WOODEN_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, StringValues::STONE_SLAB_TYPE_WOOD));
$this->map(Blocks::FAKE_WOODEN_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, Ids::PETRIFIED_OAK_SLAB, StringValues::STONE_SLAB_TYPE_WOOD));
$this->map(Blocks::FARMLAND(), function(Farmland $block) : Writer{
return Writer::create(Ids::FARMLAND)
->writeInt(StateNames::MOISTURIZED_AMOUNT, $block->getWetness());
});
$this->map(Blocks::FERN(), fn() => Writer::create(Ids::TALLGRASS)
->writeString(StateNames::TALL_GRASS_TYPE, StringValues::TALL_GRASS_TYPE_FERN));
$this->map(Blocks::FIRE(), function(Fire $block) : Writer{
return Writer::create(Ids::FIRE)
->writeInt(StateNames::AGE, $block->getAge());
@ -1412,7 +1428,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create(Ids::LANTERN)
->writeBool(StateNames::HANGING, $block->isHanging());
});
$this->map(Blocks::LARGE_FERN(), fn(DoubleTallGrass $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_FERN, Writer::create(Ids::DOUBLE_PLANT)));
$this->map(Blocks::LARGE_FERN(), fn(DoubleTallGrass $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::LARGE_FERN)));
$this->map(Blocks::LAVA(), fn(Lava $block) => Helper::encodeLiquid($block, Ids::LAVA, Ids::FLOWING_LAVA));
$this->map(Blocks::LECTERN(), function(Lectern $block) : Writer{
return Writer::create(Ids::LECTERN)
@ -1441,7 +1457,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create(Ids::LIGHTNING_ROD)
->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::LILAC(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::LILAC)));
$this->map(Blocks::LIT_PUMPKIN(), function(LitPumpkin $block) : Writer{
return Writer::create(Ids::LIT_PUMPKIN)
->writeCardinalHorizontalFacing($block->getFacing());
@ -1470,7 +1486,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writePillarAxis($block->getAxis()));
$this->map(Blocks::MUSHROOM_STEM(), fn() => Writer::create(Ids::BROWN_MUSHROOM_BLOCK)
->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_STEM));
$this->map(Blocks::NETHER_BRICK_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, StringValues::STONE_SLAB_TYPE_NETHER_BRICK));
$this->map(Blocks::NETHER_BRICK_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, Ids::NETHER_BRICK_SLAB, StringValues::STONE_SLAB_TYPE_NETHER_BRICK));
$this->mapStairs(Blocks::NETHER_BRICK_STAIRS(), Ids::NETHER_BRICK_STAIRS);
$this->map(Blocks::NETHER_BRICK_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_NETHER_BRICK));
$this->map(Blocks::NETHER_PORTAL(), function(NetherPortal $block) : Writer{
@ -1485,7 +1501,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create(Ids::NETHER_WART)
->writeInt(StateNames::AGE, $block->getAge());
});
$this->map(Blocks::PEONY(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_PAEONIA, Writer::create(Ids::DOUBLE_PLANT)));
$this->map(Blocks::PEONY(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::PEONY)));
$this->map(Blocks::PINK_PETALS(), function(PinkPetals $block) : Writer{
return Writer::create(Ids::PINK_PETALS)
->writeCardinalHorizontalFacing($block->getFacing())
@ -1526,6 +1542,9 @@ 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->mapSlab(Blocks::POLISHED_TUFF_SLAB(), Ids::POLISHED_TUFF_SLAB, Ids::POLISHED_TUFF_DOUBLE_SLAB);
$this->mapStairs(Blocks::POLISHED_TUFF_STAIRS(), Ids::POLISHED_TUFF_STAIRS);
$this->map(Blocks::POLISHED_TUFF_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_TUFF_WALL)));
$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)
@ -1561,7 +1580,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapStairs(Blocks::PURPUR_STAIRS(), Ids::PURPUR_STAIRS);
$this->map(Blocks::QUARTZ(), fn() => Helper::encodeQuartz(StringValues::CHISEL_TYPE_DEFAULT, Axis::Y));
$this->map(Blocks::QUARTZ_PILLAR(), fn(SimplePillar $block) => Helper::encodeQuartz(StringValues::CHISEL_TYPE_LINES, $block->getAxis()));
$this->map(Blocks::QUARTZ_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, StringValues::STONE_SLAB_TYPE_QUARTZ));
$this->map(Blocks::QUARTZ_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, Ids::QUARTZ_SLAB, StringValues::STONE_SLAB_TYPE_QUARTZ));
$this->mapStairs(Blocks::QUARTZ_STAIRS(), Ids::QUARTZ_STAIRS);
$this->map(Blocks::RAIL(), function(Rail $block) : Writer{
return Writer::create(Ids::RAIL)
@ -1599,11 +1618,11 @@ 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::ROSE_BUSH(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_ROSE, Writer::create(Ids::DOUBLE_PLANT)));
$this->map(Blocks::ROSE_BUSH(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::ROSE_BUSH)));
$this->map(Blocks::SAND(), fn() => Writer::create(Ids::SAND)
->writeString(StateNames::SAND_TYPE, StringValues::SAND_TYPE_NORMAL));
$this->map(Blocks::SANDSTONE(), fn() => Helper::encodeSandstone(Ids::SANDSTONE, StringValues::SAND_STONE_TYPE_DEFAULT));
$this->map(Blocks::SANDSTONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, StringValues::STONE_SLAB_TYPE_SANDSTONE));
$this->map(Blocks::SANDSTONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, Ids::SANDSTONE_SLAB, StringValues::STONE_SLAB_TYPE_SANDSTONE));
$this->mapStairs(Blocks::SANDSTONE_STAIRS(), Ids::SANDSTONE_STAIRS);
$this->map(Blocks::SANDSTONE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_SANDSTONE));
$this->map(Blocks::SEA_PICKLE(), function(SeaPickle $block) : Writer{
@ -1626,12 +1645,17 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::SMOOTH_SANDSTONE(), fn() => Helper::encodeSandstone(Ids::SANDSTONE, StringValues::SAND_STONE_TYPE_SMOOTH));
$this->map(Blocks::SMOOTH_SANDSTONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab2($block, StringValues::STONE_SLAB_TYPE_2_SMOOTH_SANDSTONE));
$this->mapStairs(Blocks::SMOOTH_SANDSTONE_STAIRS(), Ids::SMOOTH_SANDSTONE_STAIRS);
$this->map(Blocks::SMOOTH_STONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, StringValues::STONE_SLAB_TYPE_SMOOTH_STONE));
$this->map(Blocks::SMOOTH_STONE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, Ids::SMOOTH_STONE_SLAB, StringValues::STONE_SLAB_TYPE_SMOOTH_STONE));
$this->map(Blocks::SNOW_LAYER(), function(SnowLayer $block) : Writer{
return Writer::create(Ids::SNOW_LAYER)
->writeBool(StateNames::COVERED_BIT, false)
->writeInt(StateNames::HEIGHT, $block->getLayers() - 1);
});
$this->map(Blocks::SOUL_CAMPFIRE(), function(SoulCampfire $block) : Writer{
return Writer::create(Ids::SOUL_CAMPFIRE)
->writeCardinalHorizontalFacing($block->getFacing())
->writeBool(StateNames::EXTINGUISHED, !$block->isLit());
});
$this->map(Blocks::SOUL_FIRE(), function() : Writer{
return Writer::create(Ids::SOUL_FIRE)
->writeInt(StateNames::AGE, 0); //useless for soul fire, we don't track it
@ -1651,7 +1675,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$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));
$this->map(Blocks::STONE_BRICK_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, StringValues::STONE_SLAB_TYPE_STONE_BRICK));
$this->map(Blocks::STONE_BRICK_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, Ids::STONE_BRICK_SLAB, StringValues::STONE_SLAB_TYPE_STONE_BRICK));
$this->mapStairs(Blocks::STONE_BRICK_STAIRS(), Ids::STONE_BRICK_STAIRS);
$this->map(Blocks::STONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_STONE_BRICK));
$this->map(Blocks::STONE_BUTTON(), fn(StoneButton $block) => Helper::encodeButton($block, new Writer(Ids::STONE_BUTTON)));
@ -1662,13 +1686,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create(Ids::REEDS)
->writeInt(StateNames::AGE, $block->getAge());
});
$this->map(Blocks::SUNFLOWER(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_SUNFLOWER, Writer::create(Ids::DOUBLE_PLANT)));
$this->map(Blocks::SUNFLOWER(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::SUNFLOWER)));
$this->map(Blocks::SWEET_BERRY_BUSH(), function(SweetBerryBush $block) : Writer{
return Writer::create(Ids::SWEET_BERRY_BUSH)
->writeInt(StateNames::GROWTH, $block->getAge());
});
$this->map(Blocks::TALL_GRASS(), fn() => Writer::create(Ids::TALLGRASS)
->writeString(StateNames::TALL_GRASS_TYPE, StringValues::TALL_GRASS_TYPE_TALL));
$this->map(Blocks::TNT(), function(TNT $block) : Writer{
return Writer::create(Ids::TNT)
->writeBool(StateNames::ALLOW_UNDERWATER_BIT, $block->worksUnderwater())
@ -1699,6 +1721,12 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeBool(StateNames::POWERED_BIT, $block->isPowered())
->writeLegacyHorizontalFacing($block->getFacing());
});
$this->mapSlab(Blocks::TUFF_BRICK_SLAB(), Ids::TUFF_BRICK_SLAB, Ids::TUFF_BRICK_DOUBLE_SLAB);
$this->mapStairs(Blocks::TUFF_BRICK_STAIRS(), Ids::TUFF_BRICK_STAIRS);
$this->map(Blocks::TUFF_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::TUFF_BRICK_WALL)));
$this->mapSlab(Blocks::TUFF_SLAB(), Ids::TUFF_SLAB, Ids::TUFF_DOUBLE_SLAB);
$this->mapStairs(Blocks::TUFF_STAIRS(), Ids::TUFF_STAIRS);
$this->map(Blocks::TUFF_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::TUFF_WALL)));
$this->map(Blocks::TWISTING_VINES(), function(NetherVines $block) : Writer{
return Writer::create(Ids::TWISTING_VINES)
->writeInt(StateNames::TWISTING_VINES_AGE, $block->getAge());

View File

@ -26,12 +26,10 @@ namespace pocketmine\data\bedrock\block\convert;
use pocketmine\block\Block;
use pocketmine\block\Button;
use pocketmine\block\Candle;
use pocketmine\block\Copper;
use pocketmine\block\CopperSlab;
use pocketmine\block\CopperStairs;
use pocketmine\block\Crops;
use pocketmine\block\DaylightSensor;
use pocketmine\block\Door;
use pocketmine\block\DoublePlant;
use pocketmine\block\FenceGate;
use pocketmine\block\FloorCoralFan;
use pocketmine\block\FloorSign;
@ -48,6 +46,8 @@ use pocketmine\block\Stair;
use pocketmine\block\Stem;
use pocketmine\block\Trapdoor;
use pocketmine\block\utils\CopperOxidation;
use pocketmine\block\utils\ICopper;
use pocketmine\block\utils\SlabType;
use pocketmine\block\VanillaBlocks;
use pocketmine\block\Wall;
use pocketmine\block\WallCoralFan;
@ -100,24 +100,24 @@ final class BlockStateDeserializerHelper{
}
/**
* @phpstan-template TBlock of Copper|CopperSlab|CopperStairs
* @phpstan-template TBlock of ICopper
*
* @phpstan-param TBlock $block
* @phpstan-return TBlock
*/
public static function decodeCopper(Copper|CopperSlab|CopperStairs $block, CopperOxidation $oxidation) : Copper|CopperSlab|CopperStairs{
public static function decodeCopper(ICopper $block, CopperOxidation $oxidation) : ICopper{
$block->setOxidation($oxidation);
$block->setWaxed(false);
return $block;
}
/**
* @phpstan-template TBlock of Copper|CopperSlab|CopperStairs
* @phpstan-template TBlock of ICopper
*
* @phpstan-param TBlock $block
* @phpstan-return TBlock
*/
public static function decodeWaxedCopper(Copper|CopperSlab|CopperStairs $block, CopperOxidation $oxidation) : Copper|CopperSlab|CopperStairs{
public static function decodeWaxedCopper(ICopper $block, CopperOxidation $oxidation) : ICopper{
$block->setOxidation($oxidation);
$block->setWaxed(true);
return $block;
@ -139,6 +139,12 @@ final class BlockStateDeserializerHelper{
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
}
/** @throws BlockStateDeserializeException */
public static function decodeDoublePlant(DoublePlant $block, BlockStateReader $in) : DoublePlant{
return $block
->setTop($in->readBool(BlockStateNames::UPPER_BLOCK_BIT));
}
/** @throws BlockStateDeserializeException */
public static function decodeFenceGate(FenceGate $block, BlockStateReader $in) : FenceGate{
return $block
@ -233,6 +239,17 @@ final class BlockStateDeserializerHelper{
return $block->setPressed($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15) !== 0);
}
/** @throws BlockStateDeserializeException */
public static function decodeSingleSlab(Slab $block, BlockStateReader $in) : Slab{
return $block->setSlabType($in->readSlabPosition());
}
/** @throws BlockStateDeserializeException */
public static function decodeDoubleSlab(Slab $block, BlockStateReader $in) : Slab{
$in->ignored(StateNames::MC_VERTICAL_HALF);
return $block->setSlabType(SlabType::DOUBLE);
}
/** @throws BlockStateDeserializeException */
public static function decodeStairs(Stair $block, BlockStateReader $in) : Stair{
return $block

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\SlabType;
use pocketmine\block\utils\WallConnectionType;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
@ -309,18 +308,6 @@ final class BlockStateReader{
};
}
/** @throws BlockStateDeserializeException */
public function readCoralType() : CoralType{
return match($type = $this->readString(BlockStateNames::CORAL_COLOR)){
StringValues::CORAL_COLOR_BLUE => CoralType::TUBE,
StringValues::CORAL_COLOR_PINK => CoralType::BRAIN,
StringValues::CORAL_COLOR_PURPLE => CoralType::BUBBLE,
StringValues::CORAL_COLOR_RED => CoralType::FIRE,
StringValues::CORAL_COLOR_YELLOW => CoralType::HORN,
default => throw $this->badValueException(BlockStateNames::CORAL_COLOR, $type),
};
}
/** @throws BlockStateDeserializeException */
public function readBellAttachmentType() : BellAttachmentType{
return match($type = $this->readString(BlockStateNames::ATTACHMENT)){

View File

@ -107,10 +107,9 @@ final class BlockStateSerializerHelper{
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
}
public static function encodeDoublePlant(DoublePlant $block, string $doublePlantType, Writer $out) : Writer{
public static function encodeDoublePlant(DoublePlant $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
->writeString(BlockStateNames::DOUBLE_PLANT_TYPE, $doublePlantType);
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop());
}
public static function encodeFenceGate(FenceGate $block, Writer $out) : Writer{
@ -183,11 +182,21 @@ final class BlockStateSerializerHelper{
->writeInt(BlockStateNames::REDSTONE_SIGNAL, $block->isPressed() ? 15 : 0);
}
public static function encodeSlab(Slab $block, string $singleId, string $doubleId) : Writer{
$slabType = $block->getSlabType();
return Writer::create($slabType === SlabType::DOUBLE ? $doubleId : $singleId)
private static function encodeSingleSlab(Slab $block, string $id) : Writer{
return Writer::create($id)
->writeSlabPosition($block->getSlabType());
}
private static function encodeDoubleSlab(Slab $block, string $id) : Writer{
return Writer::create($id)
//this is (intentionally) also written for double slabs (as zero) to maintain bug parity with MCPE
->writeSlabPosition($slabType === SlabType::DOUBLE ? SlabType::BOTTOM : $slabType);
->writeSlabPosition(SlabType::BOTTOM);
}
public static function encodeSlab(Slab $block, string $singleId, string $doubleId) : Writer{
return $block->getSlabType() === SlabType::DOUBLE ?
self::encodeDoubleSlab($block, $doubleId) :
self::encodeSingleSlab($block, $singleId);
}
public static function encodeStairs(Stair $block, Writer $out) : Writer{
@ -215,8 +224,12 @@ final class BlockStateSerializerHelper{
->writeString($typeKey, $typeValue);
}
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 encodeStoneSlab1(Slab $block, string $singleId, string $doubleTypeValue) : Writer{
//1.21 made this a mess by flattening single slab IDs but not double ones
return $block->getSlabType() === SlabType::DOUBLE ?
self::encodeDoubleSlab($block, Ids::DOUBLE_STONE_BLOCK_SLAB)
->writeString(BlockStateNames::STONE_SLAB_TYPE, $doubleTypeValue) :
self::encodeSingleSlab($block, $singleId);
}
public static function encodeStoneSlab2(Slab $block, string $typeValue) : Writer{

View File

@ -44,7 +44,6 @@ use pocketmine\block\utils\DripleafState;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\FroglightType;
use pocketmine\block\utils\LeverFacing;
use pocketmine\block\utils\SlabType;
use pocketmine\block\VanillaBlocks as Blocks;
use pocketmine\block\Wood;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
@ -115,11 +114,8 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
* @phpstan-param \Closure(Reader) : Slab $getBlock
*/
public function mapSlab(string $singleId, string $doubleId, \Closure $getBlock) : void{
$this->map($singleId, fn(Reader $in) : Slab => $getBlock($in)->setSlabType($in->readSlabPosition()));
$this->map($doubleId, function(Reader $in) use ($getBlock) : Slab{
$in->ignored(StateNames::MC_VERTICAL_HALF);
return $getBlock($in)->setSlabType(SlabType::DOUBLE);
});
$this->map($singleId, fn(Reader $in) => Helper::decodeSingleSlab($getBlock($in), $in));
$this->map($doubleId, fn(Reader $in) => Helper::decodeDoubleSlab($getBlock($in), $in));
}
/**
@ -450,6 +446,17 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$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));
}
foreach([
[CoralType::BRAIN, Ids::BRAIN_CORAL_BLOCK, Ids::DEAD_BRAIN_CORAL_BLOCK],
[CoralType::BUBBLE, Ids::BUBBLE_CORAL_BLOCK, Ids::DEAD_BUBBLE_CORAL_BLOCK],
[CoralType::FIRE, Ids::FIRE_CORAL_BLOCK, Ids::DEAD_FIRE_CORAL_BLOCK],
[CoralType::HORN, Ids::HORN_CORAL_BLOCK, Ids::DEAD_HORN_CORAL_BLOCK],
[CoralType::TUBE, Ids::TUBE_CORAL_BLOCK, Ids::DEAD_TUBE_CORAL_BLOCK],
] as [$coralType, $aliveId, $deadId]){
$this->map($aliveId, fn(Reader $in) => Blocks::CORAL_BLOCK()->setCoralType($coralType)->setDead(false));
$this->map($deadId, fn(Reader $in) => Blocks::CORAL_BLOCK()->setCoralType($coralType)->setDead(true));
}
}
private function registerCauldronDeserializers() : void{
@ -666,6 +673,8 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::CHISELED_DEEPSLATE, fn() => Blocks::CHISELED_DEEPSLATE());
$this->mapSimple(Ids::CHISELED_NETHER_BRICKS, fn() => Blocks::CHISELED_NETHER_BRICKS());
$this->mapSimple(Ids::CHISELED_POLISHED_BLACKSTONE, fn() => Blocks::CHISELED_POLISHED_BLACKSTONE());
$this->mapSimple(Ids::CHISELED_TUFF, fn() => Blocks::CHISELED_TUFF());
$this->mapSimple(Ids::CHISELED_TUFF_BRICKS, fn() => Blocks::CHISELED_TUFF_BRICKS());
$this->mapSimple(Ids::CHORUS_PLANT, fn() => Blocks::CHORUS_PLANT());
$this->mapSimple(Ids::CLAY, fn() => Blocks::CLAY());
$this->mapSimple(Ids::COAL_BLOCK, fn() => Blocks::COAL());
@ -819,6 +828,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::ENCHANTING_TABLE, fn() => Blocks::ENCHANTING_TABLE());
$this->mapSimple(Ids::END_BRICKS, fn() => Blocks::END_STONE_BRICKS());
$this->mapSimple(Ids::END_STONE, fn() => Blocks::END_STONE());
$this->mapSimple(Ids::FERN, fn() => Blocks::FERN());
$this->mapSimple(Ids::FLETCHING_TABLE, fn() => Blocks::FLETCHING_TABLE());
$this->mapSimple(Ids::GILDED_BLACKSTONE, fn() => Blocks::GILDED_BLACKSTONE());
$this->mapSimple(Ids::GLASS, fn() => Blocks::GLASS());
@ -872,6 +882,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::POLISHED_DEEPSLATE, fn() => Blocks::POLISHED_DEEPSLATE());
$this->mapSimple(Ids::POLISHED_DIORITE, fn() => Blocks::POLISHED_DIORITE());
$this->mapSimple(Ids::POLISHED_GRANITE, fn() => Blocks::POLISHED_GRANITE());
$this->mapSimple(Ids::POLISHED_TUFF, fn() => Blocks::POLISHED_TUFF());
$this->mapSimple(Ids::QUARTZ_BRICKS, fn() => Blocks::QUARTZ_BRICKS());
$this->mapSimple(Ids::QUARTZ_ORE, fn() => Blocks::NETHER_QUARTZ_ORE());
$this->mapSimple(Ids::RAW_COPPER_BLOCK, fn() => Blocks::RAW_COPPER());
@ -884,6 +895,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::RESERVED6, fn() => Blocks::RESERVED6());
$this->mapSimple(Ids::SCULK, fn() => Blocks::SCULK());
$this->mapSimple(Ids::SEA_LANTERN, fn() => Blocks::SEA_LANTERN());
$this->mapSimple(Ids::SHORT_GRASS, fn() => Blocks::TALL_GRASS()); //no, this is not a typo - tall_grass is now the double block, just to be confusing :(
$this->mapSimple(Ids::SHROOMLIGHT, fn() => Blocks::SHROOMLIGHT());
$this->mapSimple(Ids::SLIME, fn() => Blocks::SLIME());
$this->mapSimple(Ids::SMITHING_TABLE, fn() => Blocks::SMITHING_TABLE());
@ -898,6 +910,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::TINTED_GLASS, fn() => Blocks::TINTED_GLASS());
$this->mapSimple(Ids::TORCHFLOWER, fn() => Blocks::TORCHFLOWER());
$this->mapSimple(Ids::TUFF, fn() => Blocks::TUFF());
$this->mapSimple(Ids::TUFF_BRICKS, fn() => Blocks::TUFF_BRICKS());
$this->mapSimple(Ids::UNDYED_SHULKER_BOX, fn() => Blocks::SHULKER_BOX());
$this->mapSimple(Ids::WARPED_WART_BLOCK, fn() => Blocks::WARPED_WART_BLOCK());
$this->mapSimple(Ids::WARPED_ROOTS, fn() => Blocks::WARPED_ROOTS());
@ -1030,6 +1043,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
return Blocks::CAKE()
->setBites($in->readBoundedInt(StateNames::BITE_COUNTER, 0, 6));
});
$this->map(Ids::CAMPFIRE, function(Reader $in) : Block{
return Blocks::CAMPFIRE()
->setFacing($in->readCardinalHorizontalFacing())
->setLit(!$in->readBool(StateNames::EXTINGUISHED));
});
$this->map(Ids::CARROTS, fn(Reader $in) => Helper::decodeCrops(Blocks::CARROTS(), $in));
$this->map(Ids::CARVED_PUMPKIN, function(Reader $in) : Block{
return Blocks::CARVED_PUMPKIN()
@ -1109,11 +1127,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map(Ids::CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::NONE));
$this->mapSlab(Ids::CUT_COPPER_SLAB, Ids::DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::NONE));
$this->mapStairs(Ids::CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::NONE));
$this->map(Ids::CORAL_BLOCK, function(Reader $in) : Block{
return Blocks::CORAL_BLOCK()
->setCoralType($in->readCoralType())
->setDead($in->readBool(StateNames::DEAD_BIT));
});
$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)
@ -1154,17 +1167,12 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
});
});
$this->map(Ids::DIRT_WITH_ROOTS, fn() => Blocks::DIRT()->setDirtType(DirtType::ROOTED));
$this->map(Ids::DOUBLE_PLANT, function(Reader $in) : Block{
return (match($type = $in->readString(StateNames::DOUBLE_PLANT_TYPE)){
StringValues::DOUBLE_PLANT_TYPE_FERN => Blocks::LARGE_FERN(),
StringValues::DOUBLE_PLANT_TYPE_GRASS => Blocks::DOUBLE_TALLGRASS(),
StringValues::DOUBLE_PLANT_TYPE_PAEONIA => Blocks::PEONY(),
StringValues::DOUBLE_PLANT_TYPE_ROSE => Blocks::ROSE_BUSH(),
StringValues::DOUBLE_PLANT_TYPE_SUNFLOWER => Blocks::SUNFLOWER(),
StringValues::DOUBLE_PLANT_TYPE_SYRINGA => Blocks::LILAC(),
default => throw $in->badValueException(StateNames::DOUBLE_PLANT_TYPE, $type),
})->setTop($in->readBool(StateNames::UPPER_BLOCK_BIT));
});
$this->map(Ids::LARGE_FERN, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::LARGE_FERN(), $in));
$this->map(Ids::TALL_GRASS, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::DOUBLE_TALLGRASS(), $in));
$this->map(Ids::PEONY, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::PEONY(), $in));
$this->map(Ids::ROSE_BUSH, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::ROSE_BUSH(), $in));
$this->map(Ids::SUNFLOWER, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::SUNFLOWER(), $in));
$this->map(Ids::LILAC, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::LILAC(), $in));
$this->mapStairs(Ids::END_BRICK_STAIRS, fn() => Blocks::END_STONE_BRICK_STAIRS());
$this->map(Ids::END_PORTAL_FRAME, function(Reader $in) : Block{
return Blocks::END_PORTAL_FRAME()
@ -1381,6 +1389,9 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map(Ids::POLISHED_DEEPSLATE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_DEEPSLATE_WALL(), $in));
$this->mapStairs(Ids::POLISHED_DIORITE_STAIRS, fn() => Blocks::POLISHED_DIORITE_STAIRS());
$this->mapStairs(Ids::POLISHED_GRANITE_STAIRS, fn() => Blocks::POLISHED_GRANITE_STAIRS());
$this->mapSlab(Ids::POLISHED_TUFF_SLAB, Ids::POLISHED_TUFF_DOUBLE_SLAB, fn() => Blocks::POLISHED_TUFF_SLAB());
$this->mapStairs(Ids::POLISHED_TUFF_STAIRS, fn() => Blocks::POLISHED_TUFF_STAIRS());
$this->map(Ids::POLISHED_TUFF_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_TUFF_WALL(), $in));
$this->map(Ids::PORTAL, function(Reader $in) : Block{
return Blocks::NETHER_PORTAL()
->setAxis(match($value = $in->readString(StateNames::PORTAL_AXIS)){
@ -1437,7 +1448,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$in->ignored(StateNames::PILLAR_AXIS);
return Blocks::SMOOTH_QUARTZ();
default:
return throw $in->badValueException(StateNames::CHISEL_TYPE, $type);
throw $in->badValueException(StateNames::CHISEL_TYPE, $type);
}
});
$this->mapStairs(Ids::QUARTZ_STAIRS, fn() => Blocks::QUARTZ_STAIRS());
@ -1526,6 +1537,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$in->ignored(StateNames::COVERED_BIT); //seems to be useless
return Blocks::SNOW_LAYER()->setLayers($in->readBoundedInt(StateNames::HEIGHT, 0, 7) + 1);
});
$this->map(Ids::SOUL_CAMPFIRE, function(Reader $in) : Block{
return Blocks::SOUL_CAMPFIRE()
->setFacing($in->readCardinalHorizontalFacing())
->setLit(!$in->readBool(StateNames::EXTINGUISHED));
});
$this->map(Ids::SOUL_FIRE, function(Reader $in) : Block{
$in->ignored(StateNames::AGE); //this is useless for soul fire, since it doesn't have the logic associated
return Blocks::SOUL_FIRE();
@ -1552,7 +1568,18 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapStairs(Ids::STONE_BRICK_STAIRS, fn() => Blocks::STONE_BRICK_STAIRS());
$this->map(Ids::STONE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::STONE_BUTTON(), $in));
$this->map(Ids::STONE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::STONE_PRESSURE_PLATE(), $in));
$this->mapSlab(Ids::STONE_BLOCK_SLAB, Ids::DOUBLE_STONE_BLOCK_SLAB, fn(Reader $in) => Helper::mapStoneSlab1Type($in));
//mess for partially flattened slabs - the single IDs were flattened but not the double ones
$this->map(Ids::DOUBLE_STONE_BLOCK_SLAB, fn(Reader $in) => Helper::decodeDoubleSlab(Helper::mapStoneSlab1Type($in), $in));
$this->map(Ids::BRICK_SLAB, fn(Reader $in) => Helper::decodeSingleSlab(Blocks::BRICK_SLAB(), $in));
$this->map(Ids::COBBLESTONE_SLAB, fn(Reader $in) => Helper::decodeSingleSlab(Blocks::COBBLESTONE_SLAB(), $in));
$this->map(Ids::NETHER_BRICK_SLAB, fn(Reader $in) => Helper::decodeSingleSlab(Blocks::NETHER_BRICK_SLAB(), $in));
$this->map(Ids::PETRIFIED_OAK_SLAB, fn(Reader $in) => Helper::decodeSingleSlab(Blocks::FAKE_WOODEN_SLAB(), $in));
$this->map(Ids::QUARTZ_SLAB, fn(Reader $in) => Helper::decodeSingleSlab(Blocks::QUARTZ_SLAB(), $in));
$this->map(Ids::SANDSTONE_SLAB, fn(Reader $in) => Helper::decodeSingleSlab(Blocks::SANDSTONE_SLAB(), $in));
$this->map(Ids::SMOOTH_STONE_SLAB, fn(Reader $in) => Helper::decodeSingleSlab(Blocks::SMOOTH_STONE_SLAB(), $in));
$this->map(Ids::STONE_BRICK_SLAB, fn(Reader $in) => Helper::decodeSingleSlab(Blocks::STONE_BRICK_SLAB(), $in));
$this->mapSlab(Ids::STONE_BLOCK_SLAB2, Ids::DOUBLE_STONE_BLOCK_SLAB2, fn(Reader $in) => Helper::mapStoneSlab2Type($in));
$this->mapSlab(Ids::STONE_BLOCK_SLAB3, Ids::DOUBLE_STONE_BLOCK_SLAB3, fn(Reader $in) => Helper::mapStoneSlab3Type($in));
$this->mapSlab(Ids::STONE_BLOCK_SLAB4, Ids::DOUBLE_STONE_BLOCK_SLAB4, fn(Reader $in) => Helper::mapStoneSlab4Type($in));
@ -1577,13 +1604,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
return Blocks::SWEET_BERRY_BUSH()
->setAge(min($growth, SweetBerryBush::STAGE_MATURE));
});
$this->map(Ids::TALLGRASS, function(Reader $in) : Block{
return match($type = $in->readString(StateNames::TALL_GRASS_TYPE)){
StringValues::TALL_GRASS_TYPE_DEFAULT, StringValues::TALL_GRASS_TYPE_SNOW, StringValues::TALL_GRASS_TYPE_TALL => Blocks::TALL_GRASS(),
StringValues::TALL_GRASS_TYPE_FERN => Blocks::FERN(),
default => throw $in->badValueException(StateNames::TALL_GRASS_TYPE, $type),
};
});
$this->map(Ids::TNT, function(Reader $in) : Block{
return Blocks::TNT()
->setUnstable($in->readBool(StateNames::EXPLODE_BIT))
@ -1615,6 +1635,12 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
->setFacing($in->readLegacyHorizontalFacing())
->setPowered($in->readBool(StateNames::POWERED_BIT));
});
$this->mapSlab(Ids::TUFF_BRICK_SLAB, Ids::TUFF_BRICK_DOUBLE_SLAB, fn() => Blocks::TUFF_BRICK_SLAB());
$this->mapStairs(Ids::TUFF_BRICK_STAIRS, fn() => Blocks::TUFF_BRICK_STAIRS());
$this->map(Ids::TUFF_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::TUFF_BRICK_WALL(), $in));
$this->mapSlab(Ids::TUFF_SLAB, Ids::TUFF_DOUBLE_SLAB, fn() => Blocks::TUFF_SLAB());
$this->mapStairs(Ids::TUFF_STAIRS, fn() => Blocks::TUFF_STAIRS());
$this->map(Ids::TUFF_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::TUFF_WALL(), $in));
$this->map(Ids::TWISTING_VINES, function(Reader $in) : Block{
return Blocks::TWISTING_VINES()
->setAge($in->readBoundedInt(StateNames::TWISTING_VINES_AGE, 0, 25));

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\SlabType;
use pocketmine\block\utils\WallConnectionType;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
@ -256,18 +255,6 @@ final class BlockStateWriter{
return $this;
}
/** @return $this */
public function writeCoralType(CoralType $coralType) : self{
$this->writeString(BlockStateNames::CORAL_COLOR, match($coralType){
CoralType::TUBE => StringValues::CORAL_COLOR_BLUE,
CoralType::BRAIN => StringValues::CORAL_COLOR_PINK,
CoralType::BUBBLE => StringValues::CORAL_COLOR_PURPLE,
CoralType::FIRE => StringValues::CORAL_COLOR_RED,
CoralType::HORN => StringValues::CORAL_COLOR_YELLOW,
});
return $this;
}
/** @return $this */
public function writeBellAttachmentType(BellAttachmentType $attachmentType) : self{
$this->writeString(BlockStateNames::ATTACHMENT, match($attachmentType){

View File

@ -133,6 +133,7 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Block(Ids::BIRCH_DOOR, Blocks::BIRCH_DOOR());
$this->map1to1Block(Ids::BREWING_STAND, Blocks::BREWING_STAND());
$this->map1to1Block(Ids::CAKE, Blocks::CAKE());
$this->map1to1Block(Ids::CAMPFIRE, Blocks::CAMPFIRE());
$this->map1to1Block(Ids::CAULDRON, Blocks::CAULDRON());
$this->map1to1Block(Ids::CHAIN, Blocks::CHAIN());
$this->map1to1Block(Ids::CHERRY_DOOR, Blocks::CHERRY_DOOR());
@ -148,6 +149,7 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Block(Ids::MANGROVE_DOOR, Blocks::MANGROVE_DOOR());
$this->map1to1Block(Ids::NETHER_WART, Blocks::NETHER_WART());
$this->map1to1Block(Ids::REPEATER, Blocks::REDSTONE_REPEATER());
$this->map1to1Block(Ids::SOUL_CAMPFIRE, Blocks::SOUL_CAMPFIRE());
$this->map1to1Block(Ids::SPRUCE_DOOR, Blocks::SPRUCE_DOOR());
$this->map1to1Block(Ids::SUGAR_CANE, Blocks::SUGARCANE());
$this->map1to1Block(Ids::WARPED_DOOR, Blocks::WARPED_DOOR());

View File

@ -143,6 +143,7 @@ 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_BLOCK = "minecraft:coral_block";
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";
@ -173,6 +174,7 @@ final class ItemTypeNames{
public const DISC_FRAGMENT_5 = "minecraft:disc_fragment_5";
public const DOLPHIN_SPAWN_EGG = "minecraft:dolphin_spawn_egg";
public const DONKEY_SPAWN_EGG = "minecraft:donkey_spawn_egg";
public const DOUBLE_PLANT = "minecraft:double_plant";
public const DRAGON_BREATH = "minecraft:dragon_breath";
public const DRIED_KELP = "minecraft:dried_kelp";
public const DROWNED_SPAWN_EGG = "minecraft:drowned_spawn_egg";
@ -331,11 +333,14 @@ final class ItemTypeNames{
public const MUSIC_DISC_BLOCKS = "minecraft:music_disc_blocks";
public const MUSIC_DISC_CAT = "minecraft:music_disc_cat";
public const MUSIC_DISC_CHIRP = "minecraft:music_disc_chirp";
public const MUSIC_DISC_CREATOR = "minecraft:music_disc_creator";
public const MUSIC_DISC_CREATOR_MUSIC_BOX = "minecraft:music_disc_creator_music_box";
public const MUSIC_DISC_FAR = "minecraft:music_disc_far";
public const MUSIC_DISC_MALL = "minecraft:music_disc_mall";
public const MUSIC_DISC_MELLOHI = "minecraft:music_disc_mellohi";
public const MUSIC_DISC_OTHERSIDE = "minecraft:music_disc_otherside";
public const MUSIC_DISC_PIGSTEP = "minecraft:music_disc_pigstep";
public const MUSIC_DISC_PRECIPICE = "minecraft:music_disc_precipice";
public const MUSIC_DISC_RELIC = "minecraft:music_disc_relic";
public const MUSIC_DISC_STAL = "minecraft:music_disc_stal";
public const MUSIC_DISC_STRAD = "minecraft:music_disc_strad";
@ -366,6 +371,8 @@ final class ItemTypeNames{
public const OAK_HANGING_SIGN = "minecraft:oak_hanging_sign";
public const OAK_SIGN = "minecraft:oak_sign";
public const OCELOT_SPAWN_EGG = "minecraft:ocelot_spawn_egg";
public const OMINOUS_BOTTLE = "minecraft:ominous_bottle";
public const OMINOUS_TRIAL_KEY = "minecraft:ominous_trial_key";
public const ORANGE_DYE = "minecraft:orange_dye";
public const OXIDIZED_COPPER_DOOR = "minecraft:oxidized_copper_door";
public const PAINTING = "minecraft:painting";
@ -467,6 +474,7 @@ final class ItemTypeNames{
public const STAINED_HARDENED_CLAY = "minecraft:stained_hardened_clay";
public const STICK = "minecraft:stick";
public const STONE_AXE = "minecraft:stone_axe";
public const STONE_BLOCK_SLAB = "minecraft:stone_block_slab";
public const STONE_HOE = "minecraft:stone_hoe";
public const STONE_PICKAXE = "minecraft:stone_pickaxe";
public const STONE_SHOVEL = "minecraft:stone_shovel";
@ -480,6 +488,7 @@ final class ItemTypeNames{
public const SWEET_BERRIES = "minecraft:sweet_berries";
public const TADPOLE_BUCKET = "minecraft:tadpole_bucket";
public const TADPOLE_SPAWN_EGG = "minecraft:tadpole_spawn_egg";
public const TALLGRASS = "minecraft:tallgrass";
public const TIDE_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:tide_armor_trim_smithing_template";
public const TNT_MINECART = "minecraft:tnt_minecart";
public const TORCHFLOWER_SEEDS = "minecraft:torchflower_seeds";

View File

@ -37,9 +37,11 @@ class PaintingMotive{
new PaintingMotive(1, 1, "Aztec2"),
new PaintingMotive(1, 1, "Bomb"),
new PaintingMotive(1, 1, "Kebab"),
new PaintingMotive(1, 1, "meditative"),
new PaintingMotive(1, 1, "Plant"),
new PaintingMotive(1, 1, "Wasteland"),
new PaintingMotive(1, 2, "Graham"),
new PaintingMotive(1, 2, "prairie_ride"),
new PaintingMotive(1, 2, "Wanderer"),
new PaintingMotive(2, 1, "Courbet"),
new PaintingMotive(2, 1, "Creebet"),
@ -47,8 +49,10 @@ class PaintingMotive{
new PaintingMotive(2, 1, "Sea"),
new PaintingMotive(2, 1, "Sunset"),
new PaintingMotive(2, 2, "Bust"),
new PaintingMotive(2, 2, "baroque"),
new PaintingMotive(2, 2, "Earth"),
new PaintingMotive(2, 2, "Fire"),
new PaintingMotive(2, 2, "humble"),
new PaintingMotive(2, 2, "Match"),
new PaintingMotive(2, 2, "SkullAndRoses"),
new PaintingMotive(2, 2, "Stage"),
@ -56,12 +60,28 @@ class PaintingMotive{
new PaintingMotive(2, 2, "Water"),
new PaintingMotive(2, 2, "Wind"),
new PaintingMotive(2, 2, "Wither"),
new PaintingMotive(3, 3, "bouquet"),
new PaintingMotive(3, 3, "cavebird"),
new PaintingMotive(3, 3, "cotan"),
new PaintingMotive(3, 3, "endboss"),
new PaintingMotive(3, 3, "fern"),
new PaintingMotive(3, 3, "owlemons"),
new PaintingMotive(3, 3, "sunflowers"),
new PaintingMotive(3, 3, "tides"),
new PaintingMotive(3, 4, "backyard"),
new PaintingMotive(3, 4, "pond"),
new PaintingMotive(4, 2, "changing"),
new PaintingMotive(4, 2, "Fighters"),
new PaintingMotive(4, 2, "finding"),
new PaintingMotive(4, 2, "lowmist"),
new PaintingMotive(4, 2, "passage"),
new PaintingMotive(4, 3, "DonkeyKong"),
new PaintingMotive(4, 3, "Skeleton"),
new PaintingMotive(4, 4, "BurningSkull"),
new PaintingMotive(4, 4, "orb"),
new PaintingMotive(4, 4, "Pigscene"),
new PaintingMotive(4, 4, "Pointer")
new PaintingMotive(4, 4, "Pointer"),
new PaintingMotive(4, 4, "unpacked")
] as $motive){
self::registerMotive($motive);
}

View File

@ -0,0 +1,63 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\event\block;
use pocketmine\block\Campfire;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
use pocketmine\item\Item;
class CampfireCookEvent extends BlockEvent implements Cancellable{
use CancellableTrait;
public function __construct(
private Campfire $campfire,
private int $slot,
private Item $input,
private Item $result
){
parent::__construct($campfire);
$this->input = clone $input;
}
public function getCampfire() : Campfire{
return $this->campfire;
}
public function getSlot() : int{
return $this->slot;
}
public function getInput() : Item{
return $this->input;
}
public function getResult() : Item{
return $this->result;
}
public function setResult(Item $result) : void{
$this->result = $result;
}
}

View File

@ -25,5 +25,7 @@ namespace pocketmine\item;
class Bowl extends Item{
//TODO: check fuel
public function getFuelTime() : int{
return 200;
}
}

View File

@ -205,6 +205,7 @@ final class StringToItemParser extends StringToTParser{
$result->registerBlock("cake", fn() => Blocks::CAKE());
$result->registerBlock("cake_block", fn() => Blocks::CAKE());
$result->registerBlock("calcite", fn() => Blocks::CALCITE());
$result->registerBlock("campfire", fn() => Blocks::CAMPFIRE());
$result->registerBlock("candle", fn() => Blocks::CANDLE());
$result->registerBlock("carpet", fn() => Blocks::CARPET());
$result->registerBlock("carrot_block", fn() => Blocks::CARROTS());
@ -239,6 +240,8 @@ final class StringToItemParser extends StringToTParser{
$result->registerBlock("chiseled_red_sandstone", fn() => Blocks::CHISELED_RED_SANDSTONE());
$result->registerBlock("chiseled_sandstone", fn() => Blocks::CHISELED_SANDSTONE());
$result->registerBlock("chiseled_stone_bricks", fn() => Blocks::CHISELED_STONE_BRICKS());
$result->registerBlock("chiseled_tuff", fn() => Blocks::CHISELED_TUFF());
$result->registerBlock("chiseled_tuff_bricks", fn() => Blocks::CHISELED_TUFF_BRICKS());
$result->registerBlock("chorus_flower", fn() => Blocks::CHORUS_FLOWER());
$result->registerBlock("chorus_plant", fn() => Blocks::CHORUS_PLANT());
$result->registerBlock("clay_block", fn() => Blocks::CLAY());
@ -897,6 +900,10 @@ final class StringToItemParser extends StringToTParser{
$result->registerBlock("polished_granite", fn() => Blocks::POLISHED_GRANITE());
$result->registerBlock("polished_granite_slab", fn() => Blocks::POLISHED_GRANITE_SLAB());
$result->registerBlock("polished_granite_stairs", fn() => Blocks::POLISHED_GRANITE_STAIRS());
$result->registerBlock("polished_tuff", fn() => Blocks::POLISHED_TUFF());
$result->registerBlock("polished_tuff_slab", fn() => Blocks::POLISHED_TUFF_SLAB());
$result->registerBlock("polished_tuff_stairs", fn() => Blocks::POLISHED_TUFF_STAIRS());
$result->registerBlock("polished_tuff_wall", fn() => Blocks::POLISHED_TUFF_WALL());
$result->registerBlock("poppy", fn() => Blocks::POPPY());
$result->registerBlock("portal", fn() => Blocks::NETHER_PORTAL());
$result->registerBlock("portal_block", fn() => Blocks::NETHER_PORTAL());
@ -1003,6 +1010,7 @@ final class StringToItemParser extends StringToTParser{
$result->registerBlock("snow", fn() => Blocks::SNOW());
$result->registerBlock("snow_block", fn() => Blocks::SNOW());
$result->registerBlock("snow_layer", fn() => Blocks::SNOW_LAYER());
$result->registerBlock("soul_campfire", fn() => Blocks::SOUL_CAMPFIRE());
$result->registerBlock("soul_lantern", fn() => Blocks::SOUL_LANTERN());
$result->registerBlock("soul_sand", fn() => Blocks::SOUL_SAND());
$result->registerBlock("soul_soil", fn() => Blocks::SOUL_SOIL());
@ -1096,6 +1104,13 @@ final class StringToItemParser extends StringToTParser{
$result->registerBlock("trunk", fn() => Blocks::OAK_PLANKS());
$result->registerBlock("trunk2", fn() => Blocks::ACACIA_LOG()->setStripped(false));
$result->registerBlock("tuff", fn() => Blocks::TUFF());
$result->registerBlock("tuff_bricks", fn() => Blocks::TUFF_BRICKS());
$result->registerBlock("tuff_brick_slab", fn() => Blocks::TUFF_BRICK_SLAB());
$result->registerBlock("tuff_brick_stairs", fn() => Blocks::TUFF_BRICK_STAIRS());
$result->registerBlock("tuff_brick_wall", fn() => Blocks::TUFF_BRICK_WALL());
$result->registerBlock("tuff_slab", fn() => Blocks::TUFF_SLAB());
$result->registerBlock("tuff_stairs", fn() => Blocks::TUFF_STAIRS());
$result->registerBlock("tuff_wall", fn() => Blocks::TUFF_WALL());
$result->registerBlock("twisting_vines", fn() => Blocks::TWISTING_VINES());
$result->registerBlock("underwater_tnt", fn() => Blocks::TNT()->setWorksUnderwater(true));
$result->registerBlock("underwater_torch", fn() => Blocks::UNDERWATER_TORCH());

View File

@ -591,12 +591,12 @@ final class VanillaItems{
}
});
self::register("squid_spawn_egg", new class(new IID(Ids::SQUID_SPAWN_EGG), "Squid Spawn Egg") extends SpawnEgg{
public function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
protected function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
return new Squid(Location::fromObject($pos, $world, $yaw, $pitch));
}
});
self::register("villager_spawn_egg", new class(new IID(Ids::VILLAGER_SPAWN_EGG), "Villager Spawn Egg") extends SpawnEgg{
public function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
protected function createEntity(World $world, Vector3 $pos, float $yaw, float $pitch) : Entity{
return new Villager(Location::fromObject($pos, $world, $yaw, $pitch));
}
});

View File

@ -56,6 +56,7 @@ final class AvailableEnchantmentRegistry{
$this->register(Enchantments::PROJECTILE_PROTECTION(), [Tags::ARMOR], []);
$this->register(Enchantments::THORNS(), [Tags::CHESTPLATE], [Tags::HELMET, Tags::LEGGINGS, Tags::BOOTS]);
$this->register(Enchantments::RESPIRATION(), [Tags::HELMET], []);
$this->register(Enchantments::AQUA_AFFINITY(), [Tags::HELMET], []);
$this->register(Enchantments::SHARPNESS(), [Tags::SWORD, Tags::AXE], []);
$this->register(Enchantments::KNOCKBACK(), [Tags::SWORD], []);
$this->register(Enchantments::FIRE_ASPECT(), [Tags::SWORD], []);

View File

@ -52,6 +52,7 @@ final class StringToEnchantmentParser extends StringToTParser{
$result->register("protection", fn() => VanillaEnchantments::PROTECTION());
$result->register("punch", fn() => VanillaEnchantments::PUNCH());
$result->register("respiration", fn() => VanillaEnchantments::RESPIRATION());
$result->register("aqua_affinity", fn() => VanillaEnchantments::AQUA_AFFINITY());
$result->register("sharpness", fn() => VanillaEnchantments::SHARPNESS());
$result->register("silk_touch", fn() => VanillaEnchantments::SILK_TOUCH());
$result->register("swift_sneak", fn() => VanillaEnchantments::SWIFT_SNEAK());

View File

@ -33,6 +33,7 @@ use pocketmine\utils\RegistryTrait;
* @see build/generate-registry-annotations.php
* @generate-registry-docblock
*
* @method static Enchantment AQUA_AFFINITY()
* @method static ProtectionEnchantment BLAST_PROTECTION()
* @method static Enchantment EFFICIENCY()
* @method static ProtectionEnchantment FEATHER_FALLING()
@ -130,6 +131,15 @@ final class VanillaEnchantments{
fn(int $level) : int => 10 * $level,
30
));
self::register("AQUA_AFFINITY", new Enchantment(
KnownTranslationFactory::enchantment_waterWorker(),
Rarity::RARE,
0,
0,
1,
null,
40
));
self::register("SHARPNESS", new SharpnessEnchantment(
KnownTranslationFactory::enchantment_damage_all(),

View File

@ -96,6 +96,7 @@ class InventoryManager{
private array $complexSlotToInventoryMap = [];
private int $lastInventoryNetworkId = ContainerIds::FIRST;
private int $currentWindowType = WindowTypes::CONTAINER;
private int $clientSelectedHotbarSlot = -1;
@ -327,9 +328,15 @@ class InventoryManager{
foreach($this->containerOpenCallbacks as $callback){
$pks = $callback($windowId, $inventory);
if($pks !== null){
$windowType = null;
foreach($pks as $pk){
if($pk instanceof ContainerOpenPacket){
//workaround useless bullshit in 1.21 - ContainerClose requires a type now for some reason
$windowType = $pk->windowType;
}
$this->session->sendDataPacket($pk);
}
$this->currentWindowType = $windowType ?? WindowTypes::CONTAINER;
$this->syncContents($inventory);
return;
}
@ -378,10 +385,11 @@ class InventoryManager{
$this->openWindowDeferred(function() : void{
$windowId = $this->getNewWindowId();
$this->associateIdWithInventory($windowId, $this->player->getInventory());
$this->currentWindowType = WindowTypes::INVENTORY;
$this->session->sendDataPacket(ContainerOpenPacket::entityInv(
$windowId,
WindowTypes::INVENTORY,
$this->currentWindowType,
$this->player->getId()
));
});
@ -390,7 +398,7 @@ class InventoryManager{
public function onCurrentWindowRemove() : void{
if(isset($this->networkIdToInventoryMap[$this->lastInventoryNetworkId])){
$this->remove($this->lastInventoryNetworkId);
$this->session->sendDataPacket(ContainerClosePacket::create($this->lastInventoryNetworkId, true));
$this->session->sendDataPacket(ContainerClosePacket::create($this->lastInventoryNetworkId, $this->currentWindowType, true));
if($this->pendingCloseWindowId !== null){
throw new AssumptionFailedError("We should not have opened a new window while a window was waiting to be closed");
}
@ -411,7 +419,7 @@ class InventoryManager{
//Always send this, even if no window matches. If we told the client to close a window, it will behave as if it
//initiated the close and expect an ack.
$this->session->sendDataPacket(ContainerClosePacket::create($id, false));
$this->session->sendDataPacket(ContainerClosePacket::create($id, $this->currentWindowType, false));
if($this->pendingCloseWindowId === $id){
$this->pendingCloseWindowId = null;

View File

@ -54,6 +54,7 @@ use pocketmine\network\mcpe\handler\SessionStartPacketHandler;
use pocketmine\network\mcpe\handler\SpawnResponsePacketHandler;
use pocketmine\network\mcpe\protocol\AvailableCommandsPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
use pocketmine\network\mcpe\protocol\ClientboundCloseFormPacket;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\ModalFormRequestPacket;
@ -1170,6 +1171,10 @@ class NetworkSession{
return $this->sendDataPacket(ModalFormRequestPacket::create($id, json_encode($form, JSON_THROW_ON_ERROR)));
}
public function onCloseAllForms() : void{
$this->sendDataPacket(ClientboundCloseFormPacket::create());
}
/**
* Instructs the networksession to start using the chunk at the given coordinates. This may occur asynchronously.
* @param \Closure $onCompletion To be called when chunk sending has completed.

View File

@ -36,6 +36,7 @@ use pocketmine\network\mcpe\protocol\types\recipe\FurnaceRecipeBlockName;
use pocketmine\network\mcpe\protocol\types\recipe\IntIdMetaItemDescriptor;
use pocketmine\network\mcpe\protocol\types\recipe\PotionContainerChangeRecipe as ProtocolPotionContainerChangeRecipe;
use pocketmine\network\mcpe\protocol\types\recipe\PotionTypeRecipe as ProtocolPotionTypeRecipe;
use pocketmine\network\mcpe\protocol\types\recipe\RecipeUnlockingRequirement;
use pocketmine\network\mcpe\protocol\types\recipe\ShapedRecipe as ProtocolShapedRecipe;
use pocketmine\network\mcpe\protocol\types\recipe\ShapelessRecipe as ProtocolShapelessRecipe;
use pocketmine\timings\Timings;
@ -79,6 +80,7 @@ final class CraftingDataCache{
$converter = TypeConverter::getInstance();
$recipesWithTypeIds = [];
$noUnlockingRequirement = new RecipeUnlockingRequirement(null);
foreach($manager->getCraftingRecipeIndex() as $index => $recipe){
if($recipe instanceof ShapelessRecipe){
$typeTag = match($recipe->getType()){
@ -95,6 +97,7 @@ final class CraftingDataCache{
$nullUUID,
$typeTag,
50,
$noUnlockingRequirement,
$index
);
}elseif($recipe instanceof ShapedRecipe){
@ -114,6 +117,7 @@ final class CraftingDataCache{
CraftingRecipeBlockName::CRAFTING_TABLE,
50,
true,
$noUnlockingRequirement,
$index,
);
}else{
@ -126,6 +130,8 @@ final class CraftingDataCache{
FurnaceType::FURNACE => FurnaceRecipeBlockName::FURNACE,
FurnaceType::BLAST_FURNACE => FurnaceRecipeBlockName::BLAST_FURNACE,
FurnaceType::SMOKER => FurnaceRecipeBlockName::SMOKER,
FurnaceType::CAMPFIRE => FurnaceRecipeBlockName::CAMPFIRE,
FurnaceType::SOUL_CAMPFIRE => FurnaceRecipeBlockName::SOUL_CAMPFIRE
};
foreach($manager->getFurnaceRecipeManager($furnaceType)->getAll() as $recipe){
$input = $converter->coreRecipeIngredientToNet($recipe->getInput())->getDescriptor();

View File

@ -83,7 +83,7 @@ abstract class DefaultPermissions{
self::registerPermission(new Permission(Names::COMMAND_PLUGINS, l10n::pocketmine_permission_command_plugins()), [$operatorRoot]);
self::registerPermission(new Permission(Names::COMMAND_SAVE_DISABLE, l10n::pocketmine_permission_command_save_disable()), [$operatorRoot]);
self::registerPermission(new Permission(Names::COMMAND_SAVE_ENABLE, l10n::pocketmine_permission_command_save_enable()), [$operatorRoot]);
self::registerPermission(new Permission(Names::COMMAND_SAVE_PERFORM, l10n::pocketmine_permission_command_save_enable()), [$operatorRoot]);
self::registerPermission(new Permission(Names::COMMAND_SAVE_PERFORM, l10n::pocketmine_permission_command_save_perform()), [$operatorRoot]);
self::registerPermission(new Permission(Names::COMMAND_SAY, l10n::pocketmine_permission_command_say()), [$operatorRoot]);
self::registerPermission(new Permission(Names::COMMAND_SEED, l10n::pocketmine_permission_command_seed()), [$operatorRoot]);
self::registerPermission(new Permission(Names::COMMAND_SETWORLDSPAWN, l10n::pocketmine_permission_command_setworldspawn()), [$operatorRoot]);

View File

@ -2156,6 +2156,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
return true;
}
/**
* Closes the current viewing form and forms in queue.
*/
public function closeAllForms() : void{
$this->getNetworkSession()->onCloseAllForms();
}
/**
* Transfers a player to another server.
*

View File

@ -60,6 +60,8 @@ interface ResourcePack{
* @param int $start Offset to start reading the chunk from
* @param int $length Maximum length of data to return.
*
* @phpstan-param positive-int $length
*
* @return string byte-array
* @throws \InvalidArgumentException if the chunk does not exist
*/

View File

@ -154,6 +154,9 @@ class ZippedResourcePack implements ResourcePack{
}
public function getPackChunk(int $start, int $length) : string{
if($length < 1){
throw new \InvalidArgumentException("Pack length must be positive");
}
fseek($this->fileResource, $start);
if(feof($this->fileResource)){
throw new \InvalidArgumentException("Requested a resource pack chunk with invalid start offset");

View File

@ -51,12 +51,12 @@ use function time;
class BedrockWorldData extends BaseNbtWorldData{
public const CURRENT_STORAGE_VERSION = 10;
public const CURRENT_STORAGE_NETWORK_VERSION = 671;
public const CURRENT_STORAGE_NETWORK_VERSION = 686;
public const CURRENT_CLIENT_VERSION_TARGET = [
1, //major
20, //minor
80, //patch
5, //revision
21, //minor
2, //patch
2, //revision
0 //is beta
];

View File

@ -27,6 +27,7 @@ use function range;
class RegionLocationTableEntry{
private int $firstSector;
/** @phpstan-var positive-int */
private int $sectorCount;
private int $timestamp;
@ -61,6 +62,9 @@ class RegionLocationTableEntry{
return range($this->getFirstSector(), $this->getLastSector());
}
/**
* @phpstan-return positive-int
*/
public function getSectorCount() : int{
return $this->sectorCount;
}

View File

@ -0,0 +1,35 @@
<?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\world\sound;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
final class CampfireSound implements Sound{
public function encode(Vector3 $pos) : array{
return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::BLOCK_CAMPFIRE_CRACKLE, $pos, false)];
}
}

View File

@ -580,6 +580,11 @@ parameters:
count: 1
path: ../../../src/network/mcpe/ChunkRequestTask.php
-
message: "#^Match expression does not handle remaining values\\: pocketmine\\\\crafting\\\\FurnaceType\\:\\:CAMPFIRE\\|pocketmine\\\\crafting\\\\FurnaceType\\:\\:SOUL_CAMPFIRE$#"
count: 1
path: ../../../src/network/mcpe/InventoryManager.php
-
message: "#^Cannot call method doFirstSpawn\\(\\) on pocketmine\\\\player\\\\Player\\|null\\.$#"
count: 1

View File

@ -79,6 +79,7 @@
"CAKE_WITH_CANDLE": 2,
"CAKE_WITH_DYED_CANDLE": 32,
"CALCITE": 1,
"CAMPFIRE": 8,
"CANDLE": 8,
"CARPET": 16,
"CARROTS": 8,
@ -111,6 +112,8 @@
"CHISELED_RED_SANDSTONE": 1,
"CHISELED_SANDSTONE": 1,
"CHISELED_STONE_BRICKS": 1,
"CHISELED_TUFF": 1,
"CHISELED_TUFF_BRICKS": 1,
"CHORUS_FLOWER": 6,
"CHORUS_PLANT": 1,
"CLAY": 1,
@ -532,6 +535,10 @@
"POLISHED_GRANITE": 1,
"POLISHED_GRANITE_SLAB": 3,
"POLISHED_GRANITE_STAIRS": 8,
"POLISHED_TUFF": 1,
"POLISHED_TUFF_SLAB": 3,
"POLISHED_TUFF_STAIRS": 8,
"POLISHED_TUFF_WALL": 162,
"POPPY": 1,
"POTATOES": 8,
"POTION_CAULDRON": 6,
@ -610,6 +617,7 @@
"SMOOTH_STONE_SLAB": 3,
"SNOW": 1,
"SNOW_LAYER": 8,
"SOUL_CAMPFIRE": 8,
"SOUL_FIRE": 1,
"SOUL_LANTERN": 2,
"SOUL_SAND": 1,
@ -660,6 +668,13 @@
"TRIPWIRE": 16,
"TRIPWIRE_HOOK": 16,
"TUFF": 1,
"TUFF_BRICKS": 1,
"TUFF_BRICK_SLAB": 3,
"TUFF_BRICK_STAIRS": 8,
"TUFF_BRICK_WALL": 162,
"TUFF_SLAB": 3,
"TUFF_STAIRS": 8,
"TUFF_WALL": 162,
"TWISTING_VINES": 26,
"UNDERWATER_TORCH": 5,
"VINES": 16,

View File

@ -27,6 +27,7 @@ use PHPUnit\Framework\TestCase;
use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\upgrade\BlockStateUpgradeSchemaUtils;
use Symfony\Component\Filesystem\Path;
use function sprintf;
use const PHP_INT_MAX;
use const pocketmine\BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH;
@ -39,7 +40,19 @@ final class BlockStateDataTest extends TestCase{
) as $schema){
$expected = BlockStateData::CURRENT_VERSION;
$actual = $schema->getVersionId();
self::assertLessThanOrEqual($expected, $actual, "Schema version $actual is newer than the current version $expected");
self::assertLessThanOrEqual($expected, $actual, sprintf(
"Schema version %d (%d.%d.%d.%d) is newer than the current version %d (%d.%d.%d.%d)",
$actual,
($actual >> 24) & 0xff,
($actual >> 16) & 0xff,
($actual >> 8) & 0xff,
$actual & 0xff,
$expected,
($expected >> 24) & 0xff,
($expected >> 16) & 0xff,
($expected >> 8) & 0xff,
$expected & 0xff
));
}
}
}

View File

@ -195,7 +195,7 @@ class ParserPacketHandler extends PacketHandler{
* @return mixed[]
*/
private static function objectToOrderedArray(object $object) : array{
$result = (array) $object;
$result = (array) ($object instanceof \JsonSerializable ? $object->jsonSerialize() : $object);
ksort($result, SORT_STRING);
foreach($result as $property => $value){
@ -335,21 +335,25 @@ class ParserPacketHandler extends PacketHandler{
}
}
}
$unlockingIngredients = $entry->getUnlockingRequirement()->getUnlockingIngredients();
return new ShapedRecipeData(
array_map(fn(array $array) => implode('', $array), $shape),
$outputsByKey,
array_map(fn(ItemStack $output) => $this->itemStackToJson($output), $entry->getOutput()),
$entry->getBlockName(),
$entry->getPriority()
$entry->getPriority(),
$unlockingIngredients !== null ? array_map(fn(RecipeIngredient $input) => $this->recipeIngredientToJson($input), $unlockingIngredients) : []
);
}
private function shapelessRecipeToJson(ShapelessRecipe $recipe) : ShapelessRecipeData{
$unlockingIngredients = $recipe->getUnlockingRequirement()->getUnlockingIngredients();
return new ShapelessRecipeData(
array_map(fn(RecipeIngredient $input) => $this->recipeIngredientToJson($input), $recipe->getInputs()),
array_map(fn(ItemStack $output) => $this->itemStackToJson($output), $recipe->getOutputs()),
$recipe->getBlockName(),
$recipe->getPriority()
$recipe->getPriority(),
$unlockingIngredients !== null ? array_map(fn(RecipeIngredient $input) => $this->recipeIngredientToJson($input), $unlockingIngredients) : []
);
}