Merge branch 'minor-next' into major-next

This commit is contained in:
Dylan K. Taylor 2023-12-14 14:03:09 +00:00
commit 4d337add7c
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
72 changed files with 659 additions and 402 deletions

View File

@ -53,7 +53,7 @@ jobs:
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
- name: Build image for tag - name: Build image for tag
uses: docker/build-push-action@v5.0.0 uses: docker/build-push-action@v5.1.0
with: with:
push: true push: true
context: ./pocketmine-mp context: ./pocketmine-mp
@ -66,7 +66,7 @@ jobs:
- name: Build image for major tag - name: Build image for major tag
if: steps.channel.outputs.CHANNEL == 'stable' if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v5.0.0 uses: docker/build-push-action@v5.1.0
with: with:
push: true push: true
context: ./pocketmine-mp context: ./pocketmine-mp
@ -79,7 +79,7 @@ jobs:
- name: Build image for minor tag - name: Build image for minor tag
if: steps.channel.outputs.CHANNEL == 'stable' if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v5.0.0 uses: docker/build-push-action@v5.1.0
with: with:
push: true push: true
context: ./pocketmine-mp context: ./pocketmine-mp
@ -92,7 +92,7 @@ jobs:
- name: Build image for latest tag - name: Build image for latest tag
if: steps.channel.outputs.CHANNEL == 'stable' if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v5.0.0 uses: docker/build-push-action@v5.1.0
with: with:
push: true push: true
context: ./pocketmine-mp context: ./pocketmine-mp

View File

@ -13,9 +13,9 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Setup PHP and tools - name: Setup PHP and tools
uses: shivammathur/setup-php@2.27.1 uses: shivammathur/setup-php@2.28.0
with: with:
php-version: 8.1 php-version: 8.2
- name: Restore Composer package cache - name: Restore Composer package cache
uses: actions/cache@v3 uses: actions/cache@v3

View File

@ -12,7 +12,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
php-version: [8.1] php-version: [8.2]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -20,7 +20,7 @@ jobs:
submodules: true submodules: true
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@2.27.1 uses: shivammathur/setup-php@2.28.0
with: with:
php-version: ${{ matrix.php-version }} php-version: ${{ matrix.php-version }}

View File

@ -14,7 +14,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
image: [ubuntu-20.04] image: [ubuntu-20.04]
php: ["8.1", "8.2"] php: ["8.1", "8.2", "8.3"]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -49,7 +49,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
image: [ubuntu-20.04] image: [ubuntu-20.04]
php: ["8.1", "8.2"] php: ["8.1", "8.2", "8.3"]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -84,7 +84,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
image: [ubuntu-20.04] image: [ubuntu-20.04]
php: ["8.1", "8.2"] php: ["8.1", "8.2", "8.3"]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -121,7 +121,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
image: [ubuntu-20.04] image: [ubuntu-20.04]
php: ["8.1", "8.2"] php: ["8.1", "8.2", "8.3"]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -173,10 +173,10 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Setup PHP and tools - name: Setup PHP and tools
uses: shivammathur/setup-php@2.27.1 uses: shivammathur/setup-php@2.28.0
with: with:
php-version: 8.1 php-version: 8.2
tools: php-cs-fixer:3.17 tools: php-cs-fixer:3.38
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -8,7 +8,7 @@ jobs:
support: support:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: dessant/support-requests@v3 - uses: dessant/support-requests@v4
with: with:
github-token: ${{ github.token }} github-token: ${{ github.token }}
support-label: "Support request" support-label: "Support request"

View File

@ -2,7 +2,7 @@
## Pre-requisites ## Pre-requisites
- A bash shell (git bash is sufficient for Windows) - A bash shell (git bash is sufficient for Windows)
- [`git`](https://git-scm.com) available in your shell - [`git`](https://git-scm.com) available in your shell
- PHP 8.1 or newer available in your shell - PHP 8.2 or newer available in your shell
- [`composer`](https://getcomposer.org) available in your shell - [`composer`](https://getcomposer.org) available in your shell
## Custom PHP binaries ## Custom PHP binaries

View File

@ -20,31 +20,61 @@
<a href="https://github.com/pmmp/PocketMine-MP/releases/latest"><img alt="GitHub release (latest by SemVer)" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/latest/total?sort=semver"></a> <a href="https://github.com/pmmp/PocketMine-MP/releases/latest"><img alt="GitHub release (latest by SemVer)" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/latest/total?sort=semver"></a>
</p> </p>
## Getting started ## What is this?
PocketMine-MP is a highly customisable server software for Minecraft: Bedrock Edition, built from scratch in PHP, with over 10 years of history.
If you're looking to create a Minecraft: Bedrock server with **custom functionality**, look no further.
- 🧩 **Powerful plugin API** - extend and customise gameplay as you see fit
- 🗺️ **Rich ecosystem** and **large developer community** - find plugins easily and learn to develop your own
- 🌐 **Multi-world support** - offer a more varied game experience to players without transferring them to other server nodes
- 🏎️ **Performance** - get 100+ players onto one server (depending on hardware and plugins)
- ⤴️ **Continuously updated** - new Minecraft versions are usually supported within days
## :x: PocketMine-MP is NOT a vanilla Minecraft server software.
**It is poorly suited to hosting vanilla survival servers.**
It doesn't have many features from the vanilla game, such as vanilla world generation, redstone, mob AI, and various other things.
If you just want to play **vanilla survival multiplayer**, consider using the [official Minecraft: Bedrock server software](https://minecraft.net/download/server/bedrock) instead of PocketMine-MP.
If that's not an option for you, you may be able to add some of PocketMine-MP's missing features using plugins from [Poggit](https://poggit.pmmp.io/plugins), or write plugins to implement them yourself.
## Getting Started
- [Documentation](http://pmmp.readthedocs.org/) - [Documentation](http://pmmp.readthedocs.org/)
- [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html) - [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html)
- [Docker image](https://github.com/pmmp/PocketMine-MP/pkgs/container/pocketmine-mp) - [Docker image](https://github.com/pmmp/PocketMine-MP/pkgs/container/pocketmine-mp)
- [Plugin repository](https://poggit.pmmp.io/plugins) - [Plugin repository](https://poggit.pmmp.io/plugins)
## Community & Support ## Community & Support
- [Forums](https://forums.pmmp.io/) Join our [Discord](https://discord.gg/bmSAZBG) server to chat with other users and developers.
- [Discord](https://discord.gg/bmSAZBG)
- [StackOverflow](https://stackoverflow.com/tags/pocketmine) You can also post questions on [StackOverflow](https://stackoverflow.com/tags/pocketmine) under the tag `pocketmine`.
## Developing Plugins
If you want to write your own plugins, the following resources may be useful.
Don't forget you can always ask our community if you need help.
## For developers
* [Building and running from source](BUILDING.md)
* [Developer documentation](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers * [Developer documentation](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers
* [Latest release API documentation](https://apidoc.pmmp.io) - Doxygen API documentation generated for each release * [Latest release API documentation](https://apidoc.pmmp.io) - Doxygen API documentation generated for each release
* [Latest bleeding-edge API documentation](https://apidoc-dev.pmmp.io) - Doxygen API documentation generated weekly from `major-next` branch * [Latest bleeding-edge API documentation](https://apidoc-dev.pmmp.io) - Doxygen API documentation generated weekly from `major-next` branch
* [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins * [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features * [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
## Contributing to PocketMine-MP
PocketMine-MP accepts community contributions! The following resources will be useful if you want to contribute to PocketMine-MP.
* [Building and running PocketMine-MP from source](BUILDING.md)
* [Contributing Guidelines](CONTRIBUTING.md) * [Contributing Guidelines](CONTRIBUTING.md)
## Donate ## Donate
- Bitcoin Cash (BCH): `qq3r46hn6ljnhnqnfwxt5pg3g447eq9jhvw5ddfear` PocketMine-MP is free, but it requires a lot of time and effort from unpaid volunteers to develop. Donations enable us to keep delivering support for new versions and adding features your players love.
You can support development using the following methods:
- [Patreon](https://www.patreon.com/pocketminemp)
- Bitcoin (BTC): `171u8K9e4FtU6j3e5sqNoxKUgEw9qWQdRV` - Bitcoin (BTC): `171u8K9e4FtU6j3e5sqNoxKUgEw9qWQdRV`
- Stellar Lumens (XLM): `GAAC5WZ33HCTE3BFJFZJXONMEIBNHFLBXM2HJVAZHXXPYA3HP5XPPS7T` - Stellar Lumens (XLM): `GAAC5WZ33HCTE3BFJFZJXONMEIBNHFLBXM2HJVAZHXXPYA3HP5XPPS7T`
- [Patreon](https://www.patreon.com/pocketminemp)
Thanks for your support!
## Licensing information ## Licensing information
This project is licensed under LGPL-3.0. Please see the [LICENSE](/LICENSE) file for details. This project is licensed under LGPL-3.0. Please see the [LICENSE](/LICENSE) file for details.

@ -1 +1 @@
Subproject commit a34e48e7da753b633ffaa4a4f9516eae4bb97baa Subproject commit 6dc09c57eb2a044b3c71e65fa3760dfcaed7fa5e

16
changelogs/4.26.md Normal file
View File

@ -0,0 +1,16 @@
# 4.26.0
Released 6th December 2023.
**For Minecraft: Bedrock Edition 1.20.50**
This is a support release for Minecraft: Bedrock Edition 1.20.50.
**Plugin compatibility:** Plugins for previous 4.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.20.50.
- Removed support for older versions.

View File

@ -117,3 +117,22 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
- Removed code generation step for `RuntimeDataDescriber` enum serialization. All described enums now use PHP 8.1 native enums, which can be described without codegen using `RuntimeDataDescriber->enum()`. - Removed code generation step for `RuntimeDataDescriber` enum serialization. All described enums now use PHP 8.1 native enums, which can be described without codegen using `RuntimeDataDescriber->enum()`.
- Added `DeprecatedLegacyEnumAccessRule` custom PHPStan rule to flag legacy `EnumTrait` case accessors. - Added `DeprecatedLegacyEnumAccessRule` custom PHPStan rule to flag legacy `EnumTrait` case accessors.
- Cleaned up remaining hardcoded `Config` keys in `SetupWizard`. These usages now use auto-generated constants like the rest of the codebase. - Cleaned up remaining hardcoded `Config` keys in `SetupWizard`. These usages now use auto-generated constants like the rest of the codebase.
# 5.8.2
Released 9th November 2023.
## Performance
- Improved performance of small packet zero-compression (unintended use of slow zlib compressor instead of fast libdeflate one).
- This affected the majority of outbound packets, as most packets are below the 256-byte threshold for compression.
- This faster method is over 20x faster than the old method, producing noticeable performance gains for large servers.
## Fixes
- Fixed melons and pumpkins not growing.
- Fixed melon and pumpkin stems not attaching to the grown melon/pumpkin.
- Fixed iron and gold ores not being affected by the Fortune enchantment.
- Fixed ancient debris burning in lava.
- Fixed sign (front) text loading from vanilla world saves (back text is not yet supported).
## Internals
- Removed bogus optimization from `tools/generate-blockstate-upgrade-schema.php` that could cause incorrect `remappedStates` generation when some of the states stayed under the old ID.
- Fixed possible crash in `BlockStateUpgrader` name flattening rule handling with invalid blockstate NBT data.

30
changelogs/5.9.md Normal file
View File

@ -0,0 +1,30 @@
# 5.9.0
Released 6th December 2023.
**For Minecraft: Bedrock Edition 1.20.50**
This is a support release for Minecraft: Bedrock Edition 1.20.50.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.20.50.
- Removed support for older versions.
## Fixes
- Fixed `pitcher_plant` and `pitcher_pod` not being accepted by `StringToItemParser` (and therefore not being usable in commands).
- Rotation of items in item frames in worlds from newer versions of Bedrock is now correctly loaded.
- Fixed possible crash in block update sending if a chunk was unloaded during a previous chunk's block update syncing.
- Fixed `AsyncTask::fetchLocal()` throwing an exception if `null` was stored in the local storage.
## Documentation
- `Server::prepareBatch()` is now correctly marked as `@internal`.
- Updated documentation for `Server::prepareBatch()` to accurately reflect its behaviour.
- Fixed incorrect path in doc comments of `EnumTrait` and `RegistryTrait`.
## Internals
- Added PHP 8.3 to the test matrix. This has not been thoroughly tested yet, so it should only be used for testing purposes.

View File

@ -33,10 +33,10 @@
"composer-runtime-api": "^2.0", "composer-runtime-api": "^2.0",
"adhocore/json-comment": "~1.2.0", "adhocore/json-comment": "~1.2.0",
"pocketmine/netresearch-jsonmapper": "~v4.2.1000", "pocketmine/netresearch-jsonmapper": "~v4.2.1000",
"pocketmine/bedrock-block-upgrade-schema": "~3.3.0+bedrock-1.20.40", "pocketmine/bedrock-block-upgrade-schema": "~3.4.0+bedrock-1.20.50",
"pocketmine/bedrock-data": "~2.6.0+bedrock-1.20.40", "pocketmine/bedrock-data": "~2.7.0+bedrock-1.20.50",
"pocketmine/bedrock-item-upgrade-schema": "~1.5.0+bedrock-1.20.30", "pocketmine/bedrock-item-upgrade-schema": "~1.6.0+bedrock-1.20.50",
"pocketmine/bedrock-protocol": "~25.0.0+bedrock-1.20.40", "pocketmine/bedrock-protocol": "~26.0.0+bedrock-1.20.50",
"pocketmine/binaryutils": "^0.2.1", "pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2", "pocketmine/callback-validator": "^1.0.2",
"pocketmine/color": "^0.3.0", "pocketmine/color": "^0.3.0",
@ -52,7 +52,7 @@
"symfony/filesystem": "~6.3.0" "symfony/filesystem": "~6.3.0"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "1.10.41", "phpstan/phpstan": "1.10.47",
"phpstan/phpstan-phpunit": "^1.1.0", "phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0", "phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "~10.3.0 || ~10.2.0 || ~10.1.0" "phpunit/phpunit": "~10.3.0 || ~10.2.0 || ~10.1.0"

100
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "5c19f4766fd04be0cbd38d9f4681864e", "content-hash": "828ee775e4e3548ef3fb0d9690ca2f44",
"packages": [ "packages": [
{ {
"name": "adhocore/json-comment", "name": "adhocore/json-comment",
@ -122,16 +122,16 @@
}, },
{ {
"name": "pocketmine/bedrock-block-upgrade-schema", "name": "pocketmine/bedrock-block-upgrade-schema",
"version": "3.3.0", "version": "3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git", "url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
"reference": "ee46b9367af262bbddd9f122d4d5b5b495b892e7" "reference": "9872eb37f15080b19c2b7861085e549c48dda92d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/ee46b9367af262bbddd9f122d4d5b5b495b892e7", "url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/9872eb37f15080b19c2b7861085e549c48dda92d",
"reference": "ee46b9367af262bbddd9f122d4d5b5b495b892e7", "reference": "9872eb37f15080b19c2b7861085e549c48dda92d",
"shasum": "" "shasum": ""
}, },
"type": "library", "type": "library",
@ -142,22 +142,22 @@
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves", "description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
"support": { "support": {
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues", "issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/3.3.0" "source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/3.4.0"
}, },
"time": "2023-10-16T16:11:02+00:00" "time": "2023-11-08T15:22:06+00:00"
}, },
{ {
"name": "pocketmine/bedrock-data", "name": "pocketmine/bedrock-data",
"version": "2.6.0+bedrock-1.20.40", "version": "2.7.0+bedrock-1.20.50",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/BedrockData.git", "url": "https://github.com/pmmp/BedrockData.git",
"reference": "37e780d28b470230bda3579b04cb50d406e3fbe6" "reference": "36f975dfca7520b7d36b0b39429f274464c9bc13"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/37e780d28b470230bda3579b04cb50d406e3fbe6", "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/36f975dfca7520b7d36b0b39429f274464c9bc13",
"reference": "37e780d28b470230bda3579b04cb50d406e3fbe6", "reference": "36f975dfca7520b7d36b0b39429f274464c9bc13",
"shasum": "" "shasum": ""
}, },
"type": "library", "type": "library",
@ -168,22 +168,22 @@
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP", "description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
"support": { "support": {
"issues": "https://github.com/pmmp/BedrockData/issues", "issues": "https://github.com/pmmp/BedrockData/issues",
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.40" "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.50"
}, },
"time": "2023-10-26T10:39:13+00:00" "time": "2023-12-06T13:59:08+00:00"
}, },
{ {
"name": "pocketmine/bedrock-item-upgrade-schema", "name": "pocketmine/bedrock-item-upgrade-schema",
"version": "1.5.0", "version": "1.6.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git", "url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
"reference": "3edc9ebbad9a4f2d9c8f53b3a5ba44d4a792ad93" "reference": "d374e5fd8302977675dcd2a42733abd3ee476ca1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/3edc9ebbad9a4f2d9c8f53b3a5ba44d4a792ad93", "url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/d374e5fd8302977675dcd2a42733abd3ee476ca1",
"reference": "3edc9ebbad9a4f2d9c8f53b3a5ba44d4a792ad93", "reference": "d374e5fd8302977675dcd2a42733abd3ee476ca1",
"shasum": "" "shasum": ""
}, },
"type": "library", "type": "library",
@ -194,22 +194,22 @@
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves", "description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
"support": { "support": {
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues", "issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.5.0" "source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.6.0"
}, },
"time": "2023-09-01T19:58:57+00:00" "time": "2023-11-08T18:12:14+00:00"
}, },
{ {
"name": "pocketmine/bedrock-protocol", "name": "pocketmine/bedrock-protocol",
"version": "25.0.0+bedrock-1.20.40", "version": "26.0.0+bedrock-1.20.50",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git", "url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "69c36c96f6835e93fc278071aa2bb9829abe5cf8" "reference": "f278a0b6d4fa1e2e0408a125f323a3118b1968df"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/69c36c96f6835e93fc278071aa2bb9829abe5cf8", "url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/f278a0b6d4fa1e2e0408a125f323a3118b1968df",
"reference": "69c36c96f6835e93fc278071aa2bb9829abe5cf8", "reference": "f278a0b6d4fa1e2e0408a125f323a3118b1968df",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -223,10 +223,10 @@
"ramsey/uuid": "^4.1" "ramsey/uuid": "^4.1"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "1.10.33", "phpstan/phpstan": "1.10.39",
"phpstan/phpstan-phpunit": "^1.0.0", "phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0", "phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5" "phpunit/phpunit": "^9.5 || ^10.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -241,9 +241,9 @@
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP", "description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
"support": { "support": {
"issues": "https://github.com/pmmp/BedrockProtocol/issues", "issues": "https://github.com/pmmp/BedrockProtocol/issues",
"source": "https://github.com/pmmp/BedrockProtocol/tree/25.0.0+bedrock-1.20.40" "source": "https://github.com/pmmp/BedrockProtocol/tree/26.0.0+bedrock-1.20.50"
}, },
"time": "2023-10-26T11:03:10+00:00" "time": "2023-12-06T14:08:37+00:00"
}, },
{ {
"name": "pocketmine/binaryutils", "name": "pocketmine/binaryutils",
@ -830,16 +830,16 @@
}, },
{ {
"name": "ramsey/uuid", "name": "ramsey/uuid",
"version": "4.7.4", "version": "4.7.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/ramsey/uuid.git", "url": "https://github.com/ramsey/uuid.git",
"reference": "60a4c63ab724854332900504274f6150ff26d286" "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/60a4c63ab724854332900504274f6150ff26d286", "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e",
"reference": "60a4c63ab724854332900504274f6150ff26d286", "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -906,7 +906,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/ramsey/uuid/issues", "issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.7.4" "source": "https://github.com/ramsey/uuid/tree/4.7.5"
}, },
"funding": [ "funding": [
{ {
@ -918,7 +918,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-04-15T23:01:58+00:00" "time": "2023-11-08T05:53:05+00:00"
}, },
{ {
"name": "symfony/filesystem", "name": "symfony/filesystem",
@ -1378,16 +1378,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.41", "version": "1.10.47",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "c6174523c2a69231df55bdc65b61655e72876d76" "reference": "84dbb33b520ea28b6cf5676a3941f4bae1c1ff39"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6174523c2a69231df55bdc65b61655e72876d76", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/84dbb33b520ea28b6cf5676a3941f4bae1c1ff39",
"reference": "c6174523c2a69231df55bdc65b61655e72876d76", "reference": "84dbb33b520ea28b6cf5676a3941f4bae1c1ff39",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1436,7 +1436,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-11-05T12:57:57+00:00" "time": "2023-12-01T15:19:17+00:00"
}, },
{ {
"name": "phpstan/phpstan-phpunit", "name": "phpstan/phpstan-phpunit",
@ -1541,16 +1541,16 @@
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "10.1.7", "version": "10.1.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e" "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/355324ca4980b8916c18b9db29f3ef484078f26e", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/a56a9ab2f680246adcf3db43f38ddf1765774735",
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e", "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1607,7 +1607,7 @@
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.7" "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.9"
}, },
"funding": [ "funding": [
{ {
@ -1615,7 +1615,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-10-04T15:34:17+00:00" "time": "2023-11-23T12:23:20+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@ -2878,16 +2878,16 @@
}, },
{ {
"name": "theseer/tokenizer", "name": "theseer/tokenizer",
"version": "1.2.1", "version": "1.2.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/theseer/tokenizer.git", "url": "https://github.com/theseer/tokenizer.git",
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2916,7 +2916,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": { "support": {
"issues": "https://github.com/theseer/tokenizer/issues", "issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/1.2.1" "source": "https://github.com/theseer/tokenizer/tree/1.2.2"
}, },
"funding": [ "funding": [
{ {
@ -2924,7 +2924,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2021-07-28T10:34:58+00:00" "time": "2023-11-20T00:12:19+00:00"
} }
], ],
"aliases": [], "aliases": [],

View File

@ -524,7 +524,7 @@ class Server{
return $this->playerDataProvider->loadData($name); return $this->playerDataProvider->loadData($name);
}catch(PlayerDataLoadException $e){ }catch(PlayerDataLoadException $e){
$this->logger->debug("Failed to load player data for $name: " . $e->getMessage()); $this->logger->debug("Failed to load player data for $name: " . $e->getMessage());
$this->logger->error($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name))); $this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
return null; return null;
} }
}); });
@ -543,7 +543,7 @@ class Server{
try{ try{
$this->playerDataProvider->saveData($name, $ev->getSaveData()); $this->playerDataProvider->saveData($name, $ev->getSaveData());
}catch(PlayerDataSaveException $e){ }catch(PlayerDataSaveException $e){
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage()))); $this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
$this->logger->logException($e); $this->logger->logException($e);
} }
}); });
@ -855,7 +855,7 @@ class Server{
} }
} }
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::language_selected($this->getLanguage()->getName(), $this->getLanguage()->getLang()))); $this->logger->info($this->language->translate(KnownTranslationFactory::language_selected($this->language->getName(), $this->language->getLang())));
if(VersionInfo::IS_DEVELOPMENT_BUILD){ if(VersionInfo::IS_DEVELOPMENT_BUILD){
if(!$this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_DEV_BUILDS, false)){ if(!$this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_DEV_BUILDS, false)){
@ -878,7 +878,7 @@ class Server{
$this->memoryManager = new MemoryManager($this); $this->memoryManager = new MemoryManager($this);
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET))); $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
if(($poolSize = $this->configGroup->getPropertyString(Yml::SETTINGS_ASYNC_WORKERS, "auto")) === "auto"){ if(($poolSize = $this->configGroup->getPropertyString(Yml::SETTINGS_ASYNC_WORKERS, "auto")) === "auto"){
$poolSize = 2; $poolSize = 2;
@ -938,11 +938,11 @@ class Server{
$this->onlineMode = $this->configGroup->getConfigBool(ServerProperties::XBOX_AUTH, true); $this->onlineMode = $this->configGroup->getConfigBool(ServerProperties::XBOX_AUTH, true);
if($this->onlineMode){ if($this->onlineMode){
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_enabled())); $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
}else{ }else{
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_disabled())); $this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_disabled()));
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authWarning())); $this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authWarning()));
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled())); $this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
} }
if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){ if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
@ -953,17 +953,17 @@ class Server{
$this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort()); $this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort());
$this->getLogger()->debug("Server unique id: " . $this->getServerUniqueId()); $this->logger->debug("Server unique id: " . $this->getServerUniqueId());
$this->getLogger()->debug("Machine unique id: " . Utils::getMachineUniqueId()); $this->logger->debug("Machine unique id: " . Utils::getMachineUniqueId());
$this->network = new Network($this->logger); $this->network = new Network($this->logger);
$this->network->setName($this->getMotd()); $this->network->setName($this->getMotd());
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_info( $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_info(
$this->getName(), $this->getName(),
(VersionInfo::IS_DEVELOPMENT_BUILD ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET (VersionInfo::IS_DEVELOPMENT_BUILD ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET
))); )));
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName()))); $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false)); TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND); $this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
@ -974,7 +974,7 @@ class Server{
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes")); $this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes"));
$this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger); $this->resourceManager = new ResourcePackManager(Path::join($this->dataPath, "resource_packs"), $this->logger);
$pluginGraylist = null; $pluginGraylist = null;
$graylistFile = Path::join($this->dataPath, "plugin_list.yml"); $graylistFile = Path::join($this->dataPath, "plugin_list.yml");
@ -988,7 +988,7 @@ class Server{
$this->forceShutdownExit(); $this->forceShutdownExit();
return; return;
} }
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist); $this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->dataPath, "plugin_data"), $pluginGraylist);
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader)); $this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
$this->pluginManager->registerInterface(new ScriptPluginLoader()); $this->pluginManager->registerInterface(new ScriptPluginLoader());
$this->pluginManager->registerInterface(new FolderPluginLoader($this->autoloader)); $this->pluginManager->registerInterface(new FolderPluginLoader($this->autoloader));
@ -1051,9 +1051,9 @@ class Server{
$this->configGroup->save(); $this->configGroup->save();
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName()))); $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET))); $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3))))); $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
$forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language); $forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language);
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $forwarder); $this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $forwarder);
@ -1141,13 +1141,13 @@ class Server{
if($this->worldManager->getDefaultWorld() === null){ if($this->worldManager->getDefaultWorld() === null){
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world"); $default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
if(trim($default) == ""){ if(trim($default) == ""){
$this->getLogger()->warning("level-name cannot be null, using default"); $this->logger->warning("level-name cannot be null, using default");
$default = "world"; $default = "world";
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world"); $this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
} }
if(!$this->worldManager->loadWorld($default, true)){ if(!$this->worldManager->loadWorld($default, true)){
if($this->worldManager->isWorldGenerated($default)){ if($this->worldManager->isWorldGenerated($default)){
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError())); $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
return false; return false;
} }
@ -1156,7 +1156,7 @@ class Server{
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default); $generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
if($generatorClass === null){ if($generatorClass === null){
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError())); $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
return false; return false;
} }
$creationOptions = WorldCreationOptions::create() $creationOptions = WorldCreationOptions::create()
@ -1202,7 +1202,7 @@ class Server{
return false; return false;
} }
if($rakLibRegistered){ if($rakLibRegistered){
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port))); $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
} }
if($useQuery){ if($useQuery){
if(!$rakLibRegistered){ if(!$rakLibRegistered){
@ -1210,7 +1210,7 @@ class Server{
//if it's not registered we need to make sure Query still works //if it's not registered we need to make sure Query still works
$this->network->registerInterface(new DedicatedQueryNetworkInterface($ip, $port, $ipV6, new \PrefixedLogger($this->logger, "Dedicated Query Interface"))); $this->network->registerInterface(new DedicatedQueryNetworkInterface($ip, $port, $ipV6, new \PrefixedLogger($this->logger, "Dedicated Query Interface")));
} }
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port))); $this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
} }
return true; return true;
} }
@ -1358,11 +1358,19 @@ class Server{
} }
/** /**
* Broadcasts a list of packets in a batch to a list of players * @internal
* Promises to compress the given batch buffer using the selected compressor, optionally on a separate thread.
*
* If the buffer is smaller than the batch-threshold (usually 256), the buffer will be compressed at level 0 if supported
* by the compressor. This means that the payload will be wrapped with the appropriate header and footer, but not
* actually compressed.
*
* If the buffer is larger than the async-compression-threshold (usually 10,000), the buffer may be compressed in
* a separate thread (if available).
* *
* @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null). * @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null).
*/ */
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise{ public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise|string{
$timings ??= Timings::$playerNetworkSendCompress; $timings ??= Timings::$playerNetworkSendCompress;
try{ try{
$timings->startTiming(); $timings->startTiming();
@ -1372,15 +1380,14 @@ class Server{
$sync = !$this->networkCompressionAsync || $threshold === null || strlen($buffer) < $threshold; $sync = !$this->networkCompressionAsync || $threshold === null || strlen($buffer) < $threshold;
} }
$promise = new CompressBatchPromise();
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){ if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
$promise = new CompressBatchPromise();
$task = new CompressBatchTask($buffer, $promise, $compressor); $task = new CompressBatchTask($buffer, $promise, $compressor);
$this->asyncPool->submitTask($task); $this->asyncPool->submitTask($task);
}else{ return $promise;
$promise->resolve($compressor->compress($buffer));
} }
return $promise; return $compressor->compress($buffer);
}finally{ }finally{
$timings->stopTiming(); $timings->stopTiming();
} }
@ -1457,7 +1464,7 @@ class Server{
$this->shutdown(); $this->shutdown();
if(isset($this->pluginManager)){ if(isset($this->pluginManager)){
$this->getLogger()->debug("Disabling all plugins"); $this->logger->debug("Disabling all plugins");
$this->pluginManager->disablePlugins(); $this->pluginManager->disablePlugins();
} }
@ -1466,34 +1473,34 @@ class Server{
} }
if(isset($this->worldManager)){ if(isset($this->worldManager)){
$this->getLogger()->debug("Unloading all worlds"); $this->logger->debug("Unloading all worlds");
foreach($this->worldManager->getWorlds() as $world){ foreach($this->worldManager->getWorlds() as $world){
$this->worldManager->unloadWorld($world, true); $this->worldManager->unloadWorld($world, true);
} }
} }
$this->getLogger()->debug("Removing event handlers"); $this->logger->debug("Removing event handlers");
HandlerListManager::global()->unregisterAll(); HandlerListManager::global()->unregisterAll();
if(isset($this->asyncPool)){ if(isset($this->asyncPool)){
$this->getLogger()->debug("Shutting down async task worker pool"); $this->logger->debug("Shutting down async task worker pool");
$this->asyncPool->shutdown(); $this->asyncPool->shutdown();
} }
if(isset($this->configGroup)){ if(isset($this->configGroup)){
$this->getLogger()->debug("Saving properties"); $this->logger->debug("Saving properties");
$this->configGroup->save(); $this->configGroup->save();
} }
if($this->console !== null){ if($this->console !== null){
$this->getLogger()->debug("Closing console"); $this->logger->debug("Closing console");
$this->console->quit(); $this->console->quit();
} }
if(isset($this->network)){ if(isset($this->network)){
$this->getLogger()->debug("Stopping network interfaces"); $this->logger->debug("Stopping network interfaces");
foreach($this->network->getInterfaces() as $interface){ foreach($this->network->getInterfaces() as $interface){
$this->getLogger()->debug("Stopping network interface " . get_class($interface)); $this->logger->debug("Stopping network interface " . get_class($interface));
$this->network->unregisterInterface($interface); $this->network->unregisterInterface($interface);
} }
} }
@ -1561,7 +1568,7 @@ class Server{
} }
private function writeCrashDumpFile(CrashDump $dump) : string{ private function writeCrashDumpFile(CrashDump $dump) : string{
$crashFolder = Path::join($this->getDataPath(), "crashdumps"); $crashFolder = Path::join($this->dataPath, "crashdumps");
if(!is_dir($crashFolder)){ if(!is_dir($crashFolder)){
mkdir($crashFolder); mkdir($crashFolder);
} }
@ -1592,17 +1599,17 @@ class Server{
ini_set("error_reporting", '0'); ini_set("error_reporting", '0');
ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems
try{ try{
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_create())); $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_create()));
$dump = new CrashDump($this, $this->pluginManager ?? null); $dump = new CrashDump($this, $this->pluginManager ?? null);
$crashDumpPath = $this->writeCrashDumpFile($dump); $crashDumpPath = $this->writeCrashDumpFile($dump);
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath))); $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
if($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_ENABLED, true)){ if($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_ENABLED, true)){
$report = true; $report = true;
$stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash"); $stamp = Path::join($this->dataPath, "crashdumps", ".last_crash");
$crashInterval = 120; //2 minutes $crashInterval = 120; //2 minutes
if(($lastReportTime = @filemtime($stamp)) !== false && $lastReportTime + $crashInterval >= time()){ if(($lastReportTime = @filemtime($stamp)) !== false && $lastReportTime + $crashInterval >= time()){
$report = false; $report = false;
@ -1633,7 +1640,7 @@ class Server{
if(isset($data->crashId) && is_int($data->crashId) && isset($data->crashUrl) && is_string($data->crashUrl)){ if(isset($data->crashId) && is_int($data->crashId) && isset($data->crashUrl) && is_string($data->crashUrl)){
$reportId = $data->crashId; $reportId = $data->crashId;
$reportUrl = $data->crashUrl; $reportUrl = $data->crashUrl;
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId))); $this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
}elseif(isset($data->error) && is_string($data->error)){ }elseif(isset($data->error) && is_string($data->error)){
$this->logger->emergency("Automatic crash report submission failed: $data->error"); $this->logger->emergency("Automatic crash report submission failed: $data->error");
}else{ }else{
@ -1647,7 +1654,7 @@ class Server{
}catch(\Throwable $e){ }catch(\Throwable $e){
$this->logger->logException($e); $this->logger->logException($e);
try{ try{
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage()))); $this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage())));
}catch(\Throwable $e){} }catch(\Throwable $e){}
} }
@ -1765,7 +1772,7 @@ class Server{
echo "\x1b]0;" . $this->getName() . " " . echo "\x1b]0;" . $this->getName() . " " .
$this->getPocketMineVersion() . $this->getPocketMineVersion() .
" | Online $online/" . $this->getMaxPlayers() . " | Online $online/" . $this->maxPlayers .
($connecting > 0 ? " (+$connecting connecting)" : "") . ($connecting > 0 ? " (+$connecting connecting)" : "") .
" | Memory " . $usage . " | Memory " . $usage .
" | U " . round($bandwidthStats->getSend()->getAverageBytes() / 1024, 2) . " | U " . round($bandwidthStats->getSend()->getAverageBytes() / 1024, 2) .
@ -1830,10 +1837,10 @@ class Server{
} }
if(($this->tickCounter % self::TICKS_PER_TPS_OVERLOAD_WARNING) === 0 && $this->getTicksPerSecondAverage() < self::TPS_OVERLOAD_WARNING_THRESHOLD){ if(($this->tickCounter % self::TICKS_PER_TPS_OVERLOAD_WARNING) === 0 && $this->getTicksPerSecondAverage() < self::TPS_OVERLOAD_WARNING_THRESHOLD){
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload())); $this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
} }
$this->getMemoryManager()->check(); $this->memoryManager->check();
if($this->console !== null){ if($this->console !== null){
Timings::$serverCommand->startTiming(); Timings::$serverCommand->startTiming();

View File

@ -24,7 +24,9 @@ declare(strict_types=1);
namespace pocketmine; namespace pocketmine;
use pocketmine\snooze\SleeperHandler; use pocketmine\snooze\SleeperHandler;
use pocketmine\snooze\SleeperHandlerEntry;
use pocketmine\timings\TimingsHandler; use pocketmine\timings\TimingsHandler;
use pocketmine\utils\Utils;
use function hrtime; use function hrtime;
/** /**
@ -35,12 +37,29 @@ final class TimeTrackingSleeperHandler extends SleeperHandler{
private int $notificationProcessingTimeNs = 0; private int $notificationProcessingTimeNs = 0;
/**
* @var TimingsHandler[]
* @phpstan-var array<string, TimingsHandler>
*/
private static array $handlerTimings = [];
public function __construct( public function __construct(
private TimingsHandler $timings private TimingsHandler $timings
){ ){
parent::__construct(); parent::__construct();
} }
public function addNotifier(\Closure $handler) : SleeperHandlerEntry{
$name = Utils::getNiceClosureName($handler);
$timings = self::$handlerTimings[$name] ??= new TimingsHandler("Snooze Handler: " . $name, $this->timings);
return parent::addNotifier(function() use ($timings, $handler) : void{
$timings->startTiming();
$handler();
$timings->stopTiming();
});
}
/** /**
* Returns the time in nanoseconds spent processing notifications since the last reset. * Returns the time in nanoseconds spent processing notifications since the last reset.
*/ */

View File

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

View File

@ -173,7 +173,7 @@ class Bamboo extends Transparent{
$newHeight = $height + $growAmount; $newHeight = $height + $growAmount;
$stemBlock = (clone $this)->setReady(false)->setLeafSize(self::NO_LEAVES); $stemBlock = (clone $this)->setReady(false)->setLeafSize(self::NO_LEAVES);
if($newHeight >= 4 && !$stemBlock->isThick()){ //don't change it to false if height is less, because it might have been chopped if($newHeight >= 4 && !$stemBlock->thick){ //don't change it to false if height is less, because it might have been chopped
$stemBlock = $stemBlock->setThick(true); $stemBlock = $stemBlock->setThick(true);
} }
$smallLeavesBlock = (clone $stemBlock)->setLeafSize(self::SMALL_LEAVES); $smallLeavesBlock = (clone $stemBlock)->setLeafSize(self::SMALL_LEAVES);

View File

@ -55,12 +55,12 @@ class Barrel extends Opaque{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){ if($player !== null){
if(abs($player->getPosition()->getX() - $this->position->getX()) < 2 && abs($player->getPosition()->getZ() - $this->position->getZ()) < 2){ if(abs($player->getPosition()->x - $this->position->x) < 2 && abs($player->getPosition()->z - $this->position->z) < 2){
$y = $player->getEyePos()->getY(); $y = $player->getEyePos()->y;
if($y - $this->position->getY() > 2){ if($y - $this->position->y > 2){
$this->facing = Facing::UP; $this->facing = Facing::UP;
}elseif($this->position->getY() - $y > 0){ }elseif($this->position->y - $y > 0){
$this->facing = Facing::DOWN; $this->facing = Facing::DOWN;
}else{ }else{
$this->facing = Facing::opposite($player->getHorizontalFacing()); $this->facing = Facing::opposite($player->getHorizontalFacing());

View File

@ -65,8 +65,8 @@ abstract class BaseBigDripleaf extends Transparent{
$this->facing = Facing::opposite($player->getHorizontalFacing()); $this->facing = Facing::opposite($player->getHorizontalFacing());
} }
if($block instanceof BaseBigDripleaf){ if($block instanceof BaseBigDripleaf){
$this->facing = $block->getFacing(); $this->facing = $block->facing;
$tx->addBlock($block->getPosition(), VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($this->facing)); $tx->addBlock($block->position, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($this->facing));
} }
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
@ -98,7 +98,7 @@ abstract class BaseBigDripleaf extends Transparent{
if($head === null){ if($head === null){
return false; return false;
} }
$pos = $head->getPosition(); $pos = $head->position;
$up = $pos->up(); $up = $pos->up();
$world = $pos->getWorld(); $world = $pos->getWorld();
if( if(
@ -110,8 +110,8 @@ abstract class BaseBigDripleaf extends Transparent{
$tx = new BlockTransaction($world); $tx = new BlockTransaction($world);
$tx->addBlock($pos, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($head->getFacing())); $tx->addBlock($pos, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($head->facing));
$tx->addBlock($up, VanillaBlocks::BIG_DRIPLEAF_HEAD()->setFacing($head->getFacing())); $tx->addBlock($up, VanillaBlocks::BIG_DRIPLEAF_HEAD()->setFacing($head->facing));
$ev = new StructureGrowEvent($head, $tx, $player); $ev = new StructureGrowEvent($head, $tx, $player);
$ev->call(); $ev->call();

View File

@ -145,7 +145,7 @@ class Bed extends Transparent{
$b = ($this->isHeadPart() ? $this : $other); $b = ($this->isHeadPart() ? $this : $other);
if($b->isOccupied()){ if($b->occupied){
$player->sendMessage(KnownTranslationFactory::tile_bed_occupied()->prefix(TextFormat::GRAY)); $player->sendMessage(KnownTranslationFactory::tile_bed_occupied()->prefix(TextFormat::GRAY));
return true; return true;

View File

@ -97,7 +97,7 @@ class ChiseledBookshelf extends Opaque{
return false; return false;
} }
$x = Facing::axis($face) === Axis::X ? $clickVector->getZ() : $clickVector->getX(); $x = Facing::axis($face) === Axis::X ? $clickVector->z : $clickVector->x;
$slot = ChiseledBookshelfSlot::fromBlockFaceCoordinates( $slot = ChiseledBookshelfSlot::fromBlockFaceCoordinates(
Facing::isPositive(Facing::rotateY($face, true)) ? 1 - $x : $x, Facing::isPositive(Facing::rotateY($face, true)) ? 1 - $x : $x,
$clickVector->y $clickVector->y

View File

@ -54,7 +54,7 @@ final class ChorusFlower extends Flowable{
} }
private function canBeSupportedAt(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
$position = $block->getPosition(); $position = $block->position;
$world = $position->getWorld(); $world = $position->getWorld();
$down = $world->getBlock($position->down()); $down = $world->getBlock($position->down());
@ -152,7 +152,7 @@ final class ChorusFlower extends Flowable{
if($tx === null){ if($tx === null){
$tx = new BlockTransaction($this->position->getWorld()); $tx = new BlockTransaction($this->position->getWorld());
} }
$tx->addBlock($this->position->getSide($facing), (clone $this)->setAge(min(self::MAX_AGE, $this->getAge() + $ageChange))); $tx->addBlock($this->position->getSide($facing), (clone $this)->setAge(min(self::MAX_AGE, $this->age + $ageChange)));
return $tx; return $tx;
} }

View File

@ -51,7 +51,7 @@ final class ChorusPlant extends Flowable{
} }
private function canBeSupportedAt(Block $block) : bool{ private function canBeSupportedAt(Block $block) : bool{
$position = $block->getPosition(); $position = $block->position;
$world = $position->getWorld(); $world = $position->getWorld();
$down = $world->getBlock($position->down()); $down = $world->getBlock($position->down());

View File

@ -29,6 +29,7 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\StructureGrowEvent; use pocketmine\event\block\StructureGrowEvent;
use pocketmine\item\Fertilizer; use pocketmine\item\Fertilizer;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Axis; use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
@ -106,4 +107,14 @@ final class DoublePitcherCrop extends DoublePlant{
$this->grow(null); $this->grow(null);
} }
} }
public function getDropsForCompatibleTool(Item $item) : array{
return [
$this->age >= self::MAX_AGE ? VanillaBlocks::PITCHER_PLANT()->asItem() : VanillaItems::PITCHER_POD()
];
}
public function asItem() : Item{
return VanillaItems::PITCHER_POD();
}
} }

View File

@ -152,7 +152,7 @@ class Farmland extends Transparent{
$ev = new EntityTrampleFarmlandEvent($entity, $this); $ev = new EntityTrampleFarmlandEvent($entity, $this);
$ev->call(); $ev->call();
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$this->getPosition()->getWorld()->setBlock($this->getPosition(), VanillaBlocks::DIRT()); $this->position->getWorld()->setBlock($this->position, VanillaBlocks::DIRT());
} }
} }
return null; return null;

View File

@ -140,7 +140,7 @@ class Fire extends BaseFire{
$block->onIncinerate(); $block->onIncinerate();
$world = $this->position->getWorld(); $world = $this->position->getWorld();
if($world->getBlock($block->getPosition())->isSameState($block)){ if($world->getBlock($block->position)->isSameState($block)){
$spreadedFire = false; $spreadedFire = false;
if(mt_rand(0, $this->age + 9) < 5){ //TODO: check rain if(mt_rand(0, $this->age + 9) < 5){ //TODO: check rain
$fire = clone $this; $fire = clone $this;

View File

@ -58,7 +58,7 @@ final class FloorCoralFan extends BaseCoral{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){ if($player !== null){
$playerBlockPos = $player->getPosition()->floor(); $playerBlockPos = $player->getPosition()->floor();
$directionVector = $blockReplace->getPosition()->subtractVector($playerBlockPos)->normalize(); $directionVector = $blockReplace->position->subtractVector($playerBlockPos)->normalize();
$angle = rad2deg(atan2($directionVector->getZ(), $directionVector->getX())); $angle = rad2deg(atan2($directionVector->getZ(), $directionVector->getX()));
if($angle <= 45 || 315 <= $angle || (135 <= $angle && $angle <= 225)){ if($angle <= 45 || 315 <= $angle || (135 <= $angle && $angle <= 225)){

View File

@ -61,7 +61,7 @@ class Jukebox extends Opaque{
public function ejectRecord() : void{ public function ejectRecord() : void{
if($this->record !== null){ if($this->record !== null){
$this->getPosition()->getWorld()->dropItem($this->getPosition()->add(0.5, 1, 0.5), $this->record); $this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $this->record);
$this->record = null; $this->record = null;
$this->stopSound(); $this->stopSound();
} }
@ -76,12 +76,12 @@ class Jukebox extends Opaque{
public function startSound() : void{ public function startSound() : void{
if($this->record !== null){ if($this->record !== null){
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordSound($this->record->getRecordType())); $this->position->getWorld()->addSound($this->position, new RecordSound($this->record->getRecordType()));
} }
} }
public function stopSound() : void{ public function stopSound() : void{
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordStopSound()); $this->position->getWorld()->addSound($this->position, new RecordStopSound());
} }
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{ public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{

View File

@ -108,8 +108,8 @@ class NetherVines extends Flowable{
private function grow(?Player $player, int $growthAmount = 1) : bool{ private function grow(?Player $player, int $growthAmount = 1) : bool{
$top = $this->seekToTip(); $top = $this->seekToTip();
$age = $top->getAge(); $age = $top->age;
$pos = $top->getPosition(); $pos = $top->position;
$world = $pos->getWorld(); $world = $pos->getWorld();
$changedBlocks = 0; $changedBlocks = 0;

View File

@ -70,13 +70,13 @@ class PinkPetals extends Flowable{
} }
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{ public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
return ($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT) || $this->supportedWhenPlacedAt($blockReplace, $clickVector, $face, $isClickedBlock); return ($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT) || $this->supportedWhenPlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
} }
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT){ if($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT){
$this->count = $blockReplace->getCount() + 1; $this->count = $blockReplace->count + 1;
$this->facing = $blockReplace->getFacing(); $this->facing = $blockReplace->facing;
}elseif($player !== null){ }elseif($player !== null){
$this->facing = Facing::opposite($player->getHorizontalFacing()); $this->facing = Facing::opposite($player->getHorizontalFacing());
} }

View File

@ -30,6 +30,7 @@ use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\event\block\StructureGrowEvent; use pocketmine\event\block\StructureGrowEvent;
use pocketmine\item\Fertilizer; use pocketmine\item\Fertilizer;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Axis; use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
@ -101,4 +102,8 @@ final class PitcherCrop extends Flowable{
$this->grow(null); $this->grow(null);
} }
} }
public function asItem() : Item{
return VanillaItems::PITCHER_POD();
}
} }

View File

@ -43,7 +43,7 @@ class RedMushroom extends Flowable{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $this->getSide(Facing::DOWN); $down = $this->getSide(Facing::DOWN);
$position = $this->getPosition(); $position = $this->position;
$lightLevel = $position->getWorld()->getFullLightAt($position->x, $position->y, $position->z); $lightLevel = $position->getWorld()->getFullLightAt($position->x, $position->y, $position->z);
$downId = $down->getTypeId(); $downId = $down->getTypeId();
//TODO: nylium support //TODO: nylium support

View File

@ -83,7 +83,7 @@ class SmallDripleaf extends Transparent{
$this->facing = Facing::opposite($player->getHorizontalFacing()); $this->facing = Facing::opposite($player->getHorizontalFacing());
} }
$tx->addBlock($block->getPosition(), VanillaBlocks::SMALL_DRIPLEAF() $tx->addBlock($block->position, VanillaBlocks::SMALL_DRIPLEAF()
->setFacing($this->facing) ->setFacing($this->facing)
->setTop(true) ->setTop(true)
); );
@ -117,7 +117,7 @@ class SmallDripleaf extends Transparent{
$height = mt_rand(2, 5); $height = mt_rand(2, 5);
$grown = 0; $grown = 0;
for($i = 0; $i < $height; $i++){ for($i = 0; $i < $height; $i++){
$pos = $bottomBlock->getSide(Facing::UP, $i)->getPosition(); $pos = $bottomBlock->getSide(Facing::UP, $i)->position;
if(!$this->canGrowTo($pos)){ if(!$this->canGrowTo($pos)){
break; break;
} }

View File

@ -106,8 +106,8 @@ class Stair extends Transparent{
public function getSupportType(int $facing) : SupportType{ public function getSupportType(int $facing) : SupportType{
if( if(
$facing === Facing::UP && $this->isUpsideDown() || $facing === Facing::UP && $this->upsideDown ||
$facing === Facing::DOWN && !$this->isUpsideDown() || $facing === Facing::DOWN && !$this->upsideDown ||
($facing === $this->facing && $this->shape !== StairShape::OUTER_LEFT && $this->shape !== StairShape::OUTER_RIGHT) || ($facing === $this->facing && $this->shape !== StairShape::OUTER_LEFT && $this->shape !== StairShape::OUTER_RIGHT) ||
($facing === Facing::rotate($this->facing, Axis::Y, false) && $this->shape === StairShape::INNER_LEFT) || ($facing === Facing::rotate($this->facing, Axis::Y, false) && $this->shape === StairShape::INNER_LEFT) ||
($facing === Facing::rotate($this->facing, Axis::Y, true) && $this->shape === StairShape::INNER_RIGHT) ($facing === Facing::rotate($this->facing, Axis::Y, true) && $this->shape === StairShape::INNER_RIGHT)

View File

@ -47,20 +47,20 @@ trait AnimatedBlockInventoryTrait{
public function onOpen(Player $who) : void{ public function onOpen(Player $who) : void{
parent::onOpen($who); parent::onOpen($who);
if($this->getHolder()->isValid() && $this->getViewerCount() === 1){ if($this->holder->isValid() && $this->getViewerCount() === 1){
//TODO: this crap really shouldn't be managed by the inventory //TODO: this crap really shouldn't be managed by the inventory
$this->animateBlock(true); $this->animateBlock(true);
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound()); $this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getOpenSound());
} }
} }
abstract protected function animateBlock(bool $isOpen) : void; abstract protected function animateBlock(bool $isOpen) : void;
public function onClose(Player $who) : void{ public function onClose(Player $who) : void{
if($this->getHolder()->isValid() && $this->getViewerCount() === 1){ if($this->holder->isValid() && $this->getViewerCount() === 1){
//TODO: this crap really shouldn't be managed by the inventory //TODO: this crap really shouldn't be managed by the inventory
$this->animateBlock(false); $this->animateBlock(false);
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound()); $this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getCloseSound());
} }
parent::onClose($who); parent::onClose($who);
} }

View File

@ -139,7 +139,7 @@ class Chest extends Spawnable implements Container, Nameable{
if($pair->doubleInventory !== null){ if($pair->doubleInventory !== null){
$this->doubleInventory = $pair->doubleInventory; $this->doubleInventory = $pair->doubleInventory;
}else{ }else{
if(($pair->getPosition()->x + ($pair->getPosition()->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly if(($pair->position->x + ($pair->position->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($pair->inventory, $this->inventory); $this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($pair->inventory, $this->inventory);
}else{ }else{
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($this->inventory, $pair->inventory); $this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($this->inventory, $pair->inventory);

View File

@ -27,6 +27,7 @@ use pocketmine\item\Item;
use pocketmine\item\VanillaItems; use pocketmine\item\VanillaItems;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\network\mcpe\convert\TypeConverter; use pocketmine\network\mcpe\convert\TypeConverter;
use pocketmine\world\World; use pocketmine\world\World;
@ -52,13 +53,17 @@ class ItemFrame extends Spawnable{
if(($itemTag = $nbt->getCompoundTag(self::TAG_ITEM)) !== null){ if(($itemTag = $nbt->getCompoundTag(self::TAG_ITEM)) !== null){
$this->item = Item::nbtDeserialize($itemTag); $this->item = Item::nbtDeserialize($itemTag);
} }
if($nbt->getTag(self::TAG_ITEM_ROTATION) instanceof FloatTag){
$this->itemRotation = (int) ($nbt->getFloat(self::TAG_ITEM_ROTATION, $this->itemRotation * 45) / 45);
} else {
$this->itemRotation = $nbt->getByte(self::TAG_ITEM_ROTATION, $this->itemRotation); $this->itemRotation = $nbt->getByte(self::TAG_ITEM_ROTATION, $this->itemRotation);
}
$this->itemDropChance = $nbt->getFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance); $this->itemDropChance = $nbt->getFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance);
} }
protected function writeSaveData(CompoundTag $nbt) : void{ protected function writeSaveData(CompoundTag $nbt) : void{
$nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance); $nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance);
$nbt->setByte(self::TAG_ITEM_ROTATION, $this->itemRotation); $nbt->setFloat(self::TAG_ITEM_ROTATION, $this->itemRotation * 45);
if(!$this->item->isNull()){ if(!$this->item->isNull()){
$nbt->setTag(self::TAG_ITEM, $this->item->nbtSerialize()); $nbt->setTag(self::TAG_ITEM, $this->item->nbtSerialize());
} }
@ -98,7 +103,7 @@ class ItemFrame extends Spawnable{
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{ protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
$nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance); $nbt->setFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance);
$nbt->setByte(self::TAG_ITEM_ROTATION, $this->itemRotation); $nbt->setFloat(self::TAG_ITEM_ROTATION, $this->itemRotation * 45);
if(!$this->item->isNull()){ if(!$this->item->isNull()){
$nbt->setTag(self::TAG_ITEM, TypeConverter::getInstance()->getItemTranslator()->toNetworkNbt($this->item)); $nbt->setTag(self::TAG_ITEM, TypeConverter::getInstance()->getItemTranslator()->toNetworkNbt($this->item));
} }

View File

@ -42,8 +42,8 @@ final class BlockStateData{
public const CURRENT_VERSION = public const CURRENT_VERSION =
(1 << 24) | //major (1 << 24) | //major
(20 << 16) | //minor (20 << 16) | //minor
(40 << 8) | //patch (50 << 8) | //patch
(3); //revision (1); //revision
public const TAG_NAME = "name"; public const TAG_NAME = "name";
public const TAG_STATES = "states"; public const TAG_STATES = "states";

View File

@ -66,6 +66,7 @@ final class BlockStateNames{
public const CORAL_HANG_TYPE_BIT = "coral_hang_type_bit"; public const CORAL_HANG_TYPE_BIT = "coral_hang_type_bit";
public const COVERED_BIT = "covered_bit"; public const COVERED_BIT = "covered_bit";
public const CRACKED_STATE = "cracked_state"; public const CRACKED_STATE = "cracked_state";
public const CRAFTING = "crafting";
public const DAMAGE = "damage"; public const DAMAGE = "damage";
public const DEAD_BIT = "dead_bit"; public const DEAD_BIT = "dead_bit";
public const DEPRECATED = "deprecated"; public const DEPRECATED = "deprecated";
@ -109,6 +110,7 @@ final class BlockStateNames{
public const OCCUPIED_BIT = "occupied_bit"; public const OCCUPIED_BIT = "occupied_bit";
public const OLD_LEAF_TYPE = "old_leaf_type"; public const OLD_LEAF_TYPE = "old_leaf_type";
public const OPEN_BIT = "open_bit"; public const OPEN_BIT = "open_bit";
public const ORIENTATION = "orientation";
public const OUTPUT_LIT_BIT = "output_lit_bit"; public const OUTPUT_LIT_BIT = "output_lit_bit";
public const OUTPUT_SUBTRACT_BIT = "output_subtract_bit"; public const OUTPUT_SUBTRACT_BIT = "output_subtract_bit";
public const PERSISTENT_BIT = "persistent_bit"; public const PERSISTENT_BIT = "persistent_bit";
@ -136,7 +138,6 @@ final class BlockStateNames{
public const STONE_SLAB_TYPE_2 = "stone_slab_type_2"; public const STONE_SLAB_TYPE_2 = "stone_slab_type_2";
public const STONE_SLAB_TYPE_3 = "stone_slab_type_3"; public const STONE_SLAB_TYPE_3 = "stone_slab_type_3";
public const STONE_SLAB_TYPE_4 = "stone_slab_type_4"; public const STONE_SLAB_TYPE_4 = "stone_slab_type_4";
public const STONE_TYPE = "stone_type";
public const STRIPPED_BIT = "stripped_bit"; public const STRIPPED_BIT = "stripped_bit";
public const STRUCTURE_BLOCK_TYPE = "structure_block_type"; public const STRUCTURE_BLOCK_TYPE = "structure_block_type";
public const STRUCTURE_VOID_TYPE = "structure_void_type"; public const STRUCTURE_VOID_TYPE = "structure_void_type";

View File

@ -168,6 +168,19 @@ final class BlockStateStringValues{
public const OLD_LEAF_TYPE_OAK = "oak"; public const OLD_LEAF_TYPE_OAK = "oak";
public const OLD_LEAF_TYPE_SPRUCE = "spruce"; public const OLD_LEAF_TYPE_SPRUCE = "spruce";
public const ORIENTATION_DOWN_EAST = "down_east";
public const ORIENTATION_DOWN_NORTH = "down_north";
public const ORIENTATION_DOWN_SOUTH = "down_south";
public const ORIENTATION_DOWN_WEST = "down_west";
public const ORIENTATION_EAST_UP = "east_up";
public const ORIENTATION_NORTH_UP = "north_up";
public const ORIENTATION_SOUTH_UP = "south_up";
public const ORIENTATION_UP_EAST = "up_east";
public const ORIENTATION_UP_NORTH = "up_north";
public const ORIENTATION_UP_SOUTH = "up_south";
public const ORIENTATION_UP_WEST = "up_west";
public const ORIENTATION_WEST_UP = "west_up";
public const PILLAR_AXIS_X = "x"; public const PILLAR_AXIS_X = "x";
public const PILLAR_AXIS_Y = "y"; public const PILLAR_AXIS_Y = "y";
public const PILLAR_AXIS_Z = "z"; public const PILLAR_AXIS_Z = "z";
@ -241,14 +254,6 @@ final class BlockStateStringValues{
public const STONE_SLAB_TYPE_4_SMOOTH_QUARTZ = "smooth_quartz"; public const STONE_SLAB_TYPE_4_SMOOTH_QUARTZ = "smooth_quartz";
public const STONE_SLAB_TYPE_4_STONE = "stone"; public const STONE_SLAB_TYPE_4_STONE = "stone";
public const STONE_TYPE_ANDESITE = "andesite";
public const STONE_TYPE_ANDESITE_SMOOTH = "andesite_smooth";
public const STONE_TYPE_DIORITE = "diorite";
public const STONE_TYPE_DIORITE_SMOOTH = "diorite_smooth";
public const STONE_TYPE_GRANITE = "granite";
public const STONE_TYPE_GRANITE_SMOOTH = "granite_smooth";
public const STONE_TYPE_STONE = "stone";
public const STRUCTURE_BLOCK_TYPE_CORNER = "corner"; public const STRUCTURE_BLOCK_TYPE_CORNER = "corner";
public const STRUCTURE_BLOCK_TYPE_DATA = "data"; public const STRUCTURE_BLOCK_TYPE_DATA = "data";
public const STRUCTURE_BLOCK_TYPE_EXPORT = "export"; public const STRUCTURE_BLOCK_TYPE_EXPORT = "export";

View File

@ -37,6 +37,7 @@ final class BlockTypeNames{
public const ACACIA_FENCE_GATE = "minecraft:acacia_fence_gate"; public const ACACIA_FENCE_GATE = "minecraft:acacia_fence_gate";
public const ACACIA_HANGING_SIGN = "minecraft:acacia_hanging_sign"; public const ACACIA_HANGING_SIGN = "minecraft:acacia_hanging_sign";
public const ACACIA_LOG = "minecraft:acacia_log"; public const ACACIA_LOG = "minecraft:acacia_log";
public const ACACIA_PLANKS = "minecraft:acacia_planks";
public const ACACIA_PRESSURE_PLATE = "minecraft:acacia_pressure_plate"; public const ACACIA_PRESSURE_PLATE = "minecraft:acacia_pressure_plate";
public const ACACIA_STAIRS = "minecraft:acacia_stairs"; public const ACACIA_STAIRS = "minecraft:acacia_stairs";
public const ACACIA_STANDING_SIGN = "minecraft:acacia_standing_sign"; public const ACACIA_STANDING_SIGN = "minecraft:acacia_standing_sign";
@ -48,6 +49,7 @@ final class BlockTypeNames{
public const AMETHYST_BLOCK = "minecraft:amethyst_block"; public const AMETHYST_BLOCK = "minecraft:amethyst_block";
public const AMETHYST_CLUSTER = "minecraft:amethyst_cluster"; public const AMETHYST_CLUSTER = "minecraft:amethyst_cluster";
public const ANCIENT_DEBRIS = "minecraft:ancient_debris"; public const ANCIENT_DEBRIS = "minecraft:ancient_debris";
public const ANDESITE = "minecraft:andesite";
public const ANDESITE_STAIRS = "minecraft:andesite_stairs"; public const ANDESITE_STAIRS = "minecraft:andesite_stairs";
public const ANVIL = "minecraft:anvil"; public const ANVIL = "minecraft:anvil";
public const AZALEA = "minecraft:azalea"; public const AZALEA = "minecraft:azalea";
@ -90,6 +92,7 @@ final class BlockTypeNames{
public const BIRCH_FENCE_GATE = "minecraft:birch_fence_gate"; public const BIRCH_FENCE_GATE = "minecraft:birch_fence_gate";
public const BIRCH_HANGING_SIGN = "minecraft:birch_hanging_sign"; public const BIRCH_HANGING_SIGN = "minecraft:birch_hanging_sign";
public const BIRCH_LOG = "minecraft:birch_log"; public const BIRCH_LOG = "minecraft:birch_log";
public const BIRCH_PLANKS = "minecraft:birch_planks";
public const BIRCH_PRESSURE_PLATE = "minecraft:birch_pressure_plate"; public const BIRCH_PRESSURE_PLATE = "minecraft:birch_pressure_plate";
public const BIRCH_STAIRS = "minecraft:birch_stairs"; public const BIRCH_STAIRS = "minecraft:birch_stairs";
public const BIRCH_STANDING_SIGN = "minecraft:birch_standing_sign"; public const BIRCH_STANDING_SIGN = "minecraft:birch_standing_sign";
@ -185,9 +188,12 @@ final class BlockTypeNames{
public const CHERRY_WOOD = "minecraft:cherry_wood"; public const CHERRY_WOOD = "minecraft:cherry_wood";
public const CHEST = "minecraft:chest"; public const CHEST = "minecraft:chest";
public const CHISELED_BOOKSHELF = "minecraft:chiseled_bookshelf"; public const CHISELED_BOOKSHELF = "minecraft:chiseled_bookshelf";
public const CHISELED_COPPER = "minecraft:chiseled_copper";
public const CHISELED_DEEPSLATE = "minecraft:chiseled_deepslate"; public const CHISELED_DEEPSLATE = "minecraft:chiseled_deepslate";
public const CHISELED_NETHER_BRICKS = "minecraft:chiseled_nether_bricks"; public const CHISELED_NETHER_BRICKS = "minecraft:chiseled_nether_bricks";
public const CHISELED_POLISHED_BLACKSTONE = "minecraft:chiseled_polished_blackstone"; public const CHISELED_POLISHED_BLACKSTONE = "minecraft:chiseled_polished_blackstone";
public const CHISELED_TUFF = "minecraft:chiseled_tuff";
public const CHISELED_TUFF_BRICKS = "minecraft:chiseled_tuff_bricks";
public const CHORUS_FLOWER = "minecraft:chorus_flower"; public const CHORUS_FLOWER = "minecraft:chorus_flower";
public const CHORUS_PLANT = "minecraft:chorus_plant"; public const CHORUS_PLANT = "minecraft:chorus_plant";
public const CLAY = "minecraft:clay"; public const CLAY = "minecraft:clay";
@ -208,7 +214,11 @@ final class BlockTypeNames{
public const COMPOSTER = "minecraft:composter"; public const COMPOSTER = "minecraft:composter";
public const CONDUIT = "minecraft:conduit"; public const CONDUIT = "minecraft:conduit";
public const COPPER_BLOCK = "minecraft:copper_block"; public const COPPER_BLOCK = "minecraft:copper_block";
public const COPPER_BULB = "minecraft:copper_bulb";
public const COPPER_DOOR = "minecraft:copper_door";
public const COPPER_GRATE = "minecraft:copper_grate";
public const COPPER_ORE = "minecraft:copper_ore"; public const COPPER_ORE = "minecraft:copper_ore";
public const COPPER_TRAPDOOR = "minecraft:copper_trapdoor";
public const CORAL_BLOCK = "minecraft:coral_block"; public const CORAL_BLOCK = "minecraft:coral_block";
public const CORAL_FAN = "minecraft:coral_fan"; public const CORAL_FAN = "minecraft:coral_fan";
public const CORAL_FAN_DEAD = "minecraft:coral_fan_dead"; public const CORAL_FAN_DEAD = "minecraft:coral_fan_dead";
@ -219,6 +229,7 @@ final class BlockTypeNames{
public const CRACKED_DEEPSLATE_TILES = "minecraft:cracked_deepslate_tiles"; public const CRACKED_DEEPSLATE_TILES = "minecraft:cracked_deepslate_tiles";
public const CRACKED_NETHER_BRICKS = "minecraft:cracked_nether_bricks"; public const CRACKED_NETHER_BRICKS = "minecraft:cracked_nether_bricks";
public const CRACKED_POLISHED_BLACKSTONE_BRICKS = "minecraft:cracked_polished_blackstone_bricks"; public const CRACKED_POLISHED_BLACKSTONE_BRICKS = "minecraft:cracked_polished_blackstone_bricks";
public const CRAFTER = "minecraft:crafter";
public const CRAFTING_TABLE = "minecraft:crafting_table"; public const CRAFTING_TABLE = "minecraft:crafting_table";
public const CRIMSON_BUTTON = "minecraft:crimson_button"; public const CRIMSON_BUTTON = "minecraft:crimson_button";
public const CRIMSON_DOOR = "minecraft:crimson_door"; public const CRIMSON_DOOR = "minecraft:crimson_door";
@ -259,6 +270,7 @@ final class BlockTypeNames{
public const DARK_OAK_FENCE_GATE = "minecraft:dark_oak_fence_gate"; public const DARK_OAK_FENCE_GATE = "minecraft:dark_oak_fence_gate";
public const DARK_OAK_HANGING_SIGN = "minecraft:dark_oak_hanging_sign"; public const DARK_OAK_HANGING_SIGN = "minecraft:dark_oak_hanging_sign";
public const DARK_OAK_LOG = "minecraft:dark_oak_log"; public const DARK_OAK_LOG = "minecraft:dark_oak_log";
public const DARK_OAK_PLANKS = "minecraft:dark_oak_planks";
public const DARK_OAK_PRESSURE_PLATE = "minecraft:dark_oak_pressure_plate"; public const DARK_OAK_PRESSURE_PLATE = "minecraft:dark_oak_pressure_plate";
public const DARK_OAK_STAIRS = "minecraft:dark_oak_stairs"; public const DARK_OAK_STAIRS = "minecraft:dark_oak_stairs";
public const DARK_OAK_TRAPDOOR = "minecraft:dark_oak_trapdoor"; public const DARK_OAK_TRAPDOOR = "minecraft:dark_oak_trapdoor";
@ -297,6 +309,7 @@ final class BlockTypeNames{
public const DETECTOR_RAIL = "minecraft:detector_rail"; public const DETECTOR_RAIL = "minecraft:detector_rail";
public const DIAMOND_BLOCK = "minecraft:diamond_block"; public const DIAMOND_BLOCK = "minecraft:diamond_block";
public const DIAMOND_ORE = "minecraft:diamond_ore"; public const DIAMOND_ORE = "minecraft:diamond_ore";
public const DIORITE = "minecraft:diorite";
public const DIORITE_STAIRS = "minecraft:diorite_stairs"; public const DIORITE_STAIRS = "minecraft:diorite_stairs";
public const DIRT = "minecraft:dirt"; public const DIRT = "minecraft:dirt";
public const DIRT_WITH_ROOTS = "minecraft:dirt_with_roots"; public const DIRT_WITH_ROOTS = "minecraft:dirt_with_roots";
@ -442,7 +455,12 @@ final class BlockTypeNames{
public const END_ROD = "minecraft:end_rod"; public const END_ROD = "minecraft:end_rod";
public const END_STONE = "minecraft:end_stone"; public const END_STONE = "minecraft:end_stone";
public const ENDER_CHEST = "minecraft:ender_chest"; public const ENDER_CHEST = "minecraft:ender_chest";
public const EXPOSED_CHISELED_COPPER = "minecraft:exposed_chiseled_copper";
public const EXPOSED_COPPER = "minecraft:exposed_copper"; public const EXPOSED_COPPER = "minecraft:exposed_copper";
public const EXPOSED_COPPER_BULB = "minecraft:exposed_copper_bulb";
public const EXPOSED_COPPER_DOOR = "minecraft:exposed_copper_door";
public const EXPOSED_COPPER_GRATE = "minecraft:exposed_copper_grate";
public const EXPOSED_COPPER_TRAPDOOR = "minecraft:exposed_copper_trapdoor";
public const EXPOSED_CUT_COPPER = "minecraft:exposed_cut_copper"; public const EXPOSED_CUT_COPPER = "minecraft:exposed_cut_copper";
public const EXPOSED_CUT_COPPER_SLAB = "minecraft:exposed_cut_copper_slab"; public const EXPOSED_CUT_COPPER_SLAB = "minecraft:exposed_cut_copper_slab";
public const EXPOSED_CUT_COPPER_STAIRS = "minecraft:exposed_cut_copper_stairs"; public const EXPOSED_CUT_COPPER_STAIRS = "minecraft:exposed_cut_copper_stairs";
@ -470,6 +488,7 @@ final class BlockTypeNames{
public const GOLD_BLOCK = "minecraft:gold_block"; public const GOLD_BLOCK = "minecraft:gold_block";
public const GOLD_ORE = "minecraft:gold_ore"; public const GOLD_ORE = "minecraft:gold_ore";
public const GOLDEN_RAIL = "minecraft:golden_rail"; public const GOLDEN_RAIL = "minecraft:golden_rail";
public const GRANITE = "minecraft:granite";
public const GRANITE_STAIRS = "minecraft:granite_stairs"; public const GRANITE_STAIRS = "minecraft:granite_stairs";
public const GRASS = "minecraft:grass"; public const GRASS = "minecraft:grass";
public const GRASS_PATH = "minecraft:grass_path"; public const GRASS_PATH = "minecraft:grass_path";
@ -527,6 +546,7 @@ final class BlockTypeNames{
public const JUNGLE_FENCE_GATE = "minecraft:jungle_fence_gate"; public const JUNGLE_FENCE_GATE = "minecraft:jungle_fence_gate";
public const JUNGLE_HANGING_SIGN = "minecraft:jungle_hanging_sign"; public const JUNGLE_HANGING_SIGN = "minecraft:jungle_hanging_sign";
public const JUNGLE_LOG = "minecraft:jungle_log"; public const JUNGLE_LOG = "minecraft:jungle_log";
public const JUNGLE_PLANKS = "minecraft:jungle_planks";
public const JUNGLE_PRESSURE_PLATE = "minecraft:jungle_pressure_plate"; public const JUNGLE_PRESSURE_PLATE = "minecraft:jungle_pressure_plate";
public const JUNGLE_STAIRS = "minecraft:jungle_stairs"; public const JUNGLE_STAIRS = "minecraft:jungle_stairs";
public const JUNGLE_STANDING_SIGN = "minecraft:jungle_standing_sign"; public const JUNGLE_STANDING_SIGN = "minecraft:jungle_standing_sign";
@ -651,6 +671,7 @@ final class BlockTypeNames{
public const OAK_FENCE = "minecraft:oak_fence"; public const OAK_FENCE = "minecraft:oak_fence";
public const OAK_HANGING_SIGN = "minecraft:oak_hanging_sign"; public const OAK_HANGING_SIGN = "minecraft:oak_hanging_sign";
public const OAK_LOG = "minecraft:oak_log"; public const OAK_LOG = "minecraft:oak_log";
public const OAK_PLANKS = "minecraft:oak_planks";
public const OAK_STAIRS = "minecraft:oak_stairs"; public const OAK_STAIRS = "minecraft:oak_stairs";
public const OBSERVER = "minecraft:observer"; public const OBSERVER = "minecraft:observer";
public const OBSIDIAN = "minecraft:obsidian"; public const OBSIDIAN = "minecraft:obsidian";
@ -666,7 +687,12 @@ final class BlockTypeNames{
public const ORANGE_STAINED_GLASS_PANE = "minecraft:orange_stained_glass_pane"; public const ORANGE_STAINED_GLASS_PANE = "minecraft:orange_stained_glass_pane";
public const ORANGE_TERRACOTTA = "minecraft:orange_terracotta"; public const ORANGE_TERRACOTTA = "minecraft:orange_terracotta";
public const ORANGE_WOOL = "minecraft:orange_wool"; public const ORANGE_WOOL = "minecraft:orange_wool";
public const OXIDIZED_CHISELED_COPPER = "minecraft:oxidized_chiseled_copper";
public const OXIDIZED_COPPER = "minecraft:oxidized_copper"; public const OXIDIZED_COPPER = "minecraft:oxidized_copper";
public const OXIDIZED_COPPER_BULB = "minecraft:oxidized_copper_bulb";
public const OXIDIZED_COPPER_DOOR = "minecraft:oxidized_copper_door";
public const OXIDIZED_COPPER_GRATE = "minecraft:oxidized_copper_grate";
public const OXIDIZED_COPPER_TRAPDOOR = "minecraft:oxidized_copper_trapdoor";
public const OXIDIZED_CUT_COPPER = "minecraft:oxidized_cut_copper"; public const OXIDIZED_CUT_COPPER = "minecraft:oxidized_cut_copper";
public const OXIDIZED_CUT_COPPER_SLAB = "minecraft:oxidized_cut_copper_slab"; public const OXIDIZED_CUT_COPPER_SLAB = "minecraft:oxidized_cut_copper_slab";
public const OXIDIZED_CUT_COPPER_STAIRS = "minecraft:oxidized_cut_copper_stairs"; public const OXIDIZED_CUT_COPPER_STAIRS = "minecraft:oxidized_cut_copper_stairs";
@ -690,9 +716,9 @@ final class BlockTypeNames{
public const PISTON_ARM_COLLISION = "minecraft:piston_arm_collision"; public const PISTON_ARM_COLLISION = "minecraft:piston_arm_collision";
public const PITCHER_CROP = "minecraft:pitcher_crop"; public const PITCHER_CROP = "minecraft:pitcher_crop";
public const PITCHER_PLANT = "minecraft:pitcher_plant"; public const PITCHER_PLANT = "minecraft:pitcher_plant";
public const PLANKS = "minecraft:planks";
public const PODZOL = "minecraft:podzol"; public const PODZOL = "minecraft:podzol";
public const POINTED_DRIPSTONE = "minecraft:pointed_dripstone"; public const POINTED_DRIPSTONE = "minecraft:pointed_dripstone";
public const POLISHED_ANDESITE = "minecraft:polished_andesite";
public const POLISHED_ANDESITE_STAIRS = "minecraft:polished_andesite_stairs"; public const POLISHED_ANDESITE_STAIRS = "minecraft:polished_andesite_stairs";
public const POLISHED_BASALT = "minecraft:polished_basalt"; public const POLISHED_BASALT = "minecraft:polished_basalt";
public const POLISHED_BLACKSTONE = "minecraft:polished_blackstone"; public const POLISHED_BLACKSTONE = "minecraft:polished_blackstone";
@ -712,8 +738,15 @@ final class BlockTypeNames{
public const POLISHED_DEEPSLATE_SLAB = "minecraft:polished_deepslate_slab"; public const POLISHED_DEEPSLATE_SLAB = "minecraft:polished_deepslate_slab";
public const POLISHED_DEEPSLATE_STAIRS = "minecraft:polished_deepslate_stairs"; public const POLISHED_DEEPSLATE_STAIRS = "minecraft:polished_deepslate_stairs";
public const POLISHED_DEEPSLATE_WALL = "minecraft:polished_deepslate_wall"; public const POLISHED_DEEPSLATE_WALL = "minecraft:polished_deepslate_wall";
public const POLISHED_DIORITE = "minecraft:polished_diorite";
public const POLISHED_DIORITE_STAIRS = "minecraft:polished_diorite_stairs"; public const POLISHED_DIORITE_STAIRS = "minecraft:polished_diorite_stairs";
public const POLISHED_GRANITE = "minecraft:polished_granite";
public const POLISHED_GRANITE_STAIRS = "minecraft:polished_granite_stairs"; public const POLISHED_GRANITE_STAIRS = "minecraft:polished_granite_stairs";
public const POLISHED_TUFF = "minecraft:polished_tuff";
public const POLISHED_TUFF_DOUBLE_SLAB = "minecraft:polished_tuff_double_slab";
public const POLISHED_TUFF_SLAB = "minecraft:polished_tuff_slab";
public const POLISHED_TUFF_STAIRS = "minecraft:polished_tuff_stairs";
public const POLISHED_TUFF_WALL = "minecraft:polished_tuff_wall";
public const PORTAL = "minecraft:portal"; public const PORTAL = "minecraft:portal";
public const POTATOES = "minecraft:potatoes"; public const POTATOES = "minecraft:potatoes";
public const POWDER_SNOW = "minecraft:powder_snow"; public const POWDER_SNOW = "minecraft:powder_snow";
@ -816,6 +849,7 @@ final class BlockTypeNames{
public const SPRUCE_FENCE_GATE = "minecraft:spruce_fence_gate"; public const SPRUCE_FENCE_GATE = "minecraft:spruce_fence_gate";
public const SPRUCE_HANGING_SIGN = "minecraft:spruce_hanging_sign"; public const SPRUCE_HANGING_SIGN = "minecraft:spruce_hanging_sign";
public const SPRUCE_LOG = "minecraft:spruce_log"; public const SPRUCE_LOG = "minecraft:spruce_log";
public const SPRUCE_PLANKS = "minecraft:spruce_planks";
public const SPRUCE_PRESSURE_PLATE = "minecraft:spruce_pressure_plate"; public const SPRUCE_PRESSURE_PLATE = "minecraft:spruce_pressure_plate";
public const SPRUCE_STAIRS = "minecraft:spruce_stairs"; public const SPRUCE_STAIRS = "minecraft:spruce_stairs";
public const SPRUCE_STANDING_SIGN = "minecraft:spruce_standing_sign"; public const SPRUCE_STANDING_SIGN = "minecraft:spruce_standing_sign";
@ -870,6 +904,15 @@ final class BlockTypeNames{
public const TRIPWIRE_HOOK = "minecraft:tripwire_hook"; public const TRIPWIRE_HOOK = "minecraft:tripwire_hook";
public const TUBE_CORAL = "minecraft:tube_coral"; public const TUBE_CORAL = "minecraft:tube_coral";
public const TUFF = "minecraft:tuff"; public const TUFF = "minecraft:tuff";
public const TUFF_BRICK_DOUBLE_SLAB = "minecraft:tuff_brick_double_slab";
public const TUFF_BRICK_SLAB = "minecraft:tuff_brick_slab";
public const TUFF_BRICK_STAIRS = "minecraft:tuff_brick_stairs";
public const TUFF_BRICK_WALL = "minecraft:tuff_brick_wall";
public const TUFF_BRICKS = "minecraft:tuff_bricks";
public const TUFF_DOUBLE_SLAB = "minecraft:tuff_double_slab";
public const TUFF_SLAB = "minecraft:tuff_slab";
public const TUFF_STAIRS = "minecraft:tuff_stairs";
public const TUFF_WALL = "minecraft:tuff_wall";
public const TURTLE_EGG = "minecraft:turtle_egg"; public const TURTLE_EGG = "minecraft:turtle_egg";
public const TWISTING_VINES = "minecraft:twisting_vines"; public const TWISTING_VINES = "minecraft:twisting_vines";
public const UNDERWATER_TORCH = "minecraft:underwater_torch"; public const UNDERWATER_TORCH = "minecraft:underwater_torch";
@ -903,27 +946,52 @@ final class BlockTypeNames{
public const WARPED_WART_BLOCK = "minecraft:warped_wart_block"; public const WARPED_WART_BLOCK = "minecraft:warped_wart_block";
public const WATER = "minecraft:water"; public const WATER = "minecraft:water";
public const WATERLILY = "minecraft:waterlily"; public const WATERLILY = "minecraft:waterlily";
public const WAXED_CHISELED_COPPER = "minecraft:waxed_chiseled_copper";
public const WAXED_COPPER = "minecraft:waxed_copper"; public const WAXED_COPPER = "minecraft:waxed_copper";
public const WAXED_COPPER_BULB = "minecraft:waxed_copper_bulb";
public const WAXED_COPPER_DOOR = "minecraft:waxed_copper_door";
public const WAXED_COPPER_GRATE = "minecraft:waxed_copper_grate";
public const WAXED_COPPER_TRAPDOOR = "minecraft:waxed_copper_trapdoor";
public const WAXED_CUT_COPPER = "minecraft:waxed_cut_copper"; public const WAXED_CUT_COPPER = "minecraft:waxed_cut_copper";
public const WAXED_CUT_COPPER_SLAB = "minecraft:waxed_cut_copper_slab"; public const WAXED_CUT_COPPER_SLAB = "minecraft:waxed_cut_copper_slab";
public const WAXED_CUT_COPPER_STAIRS = "minecraft:waxed_cut_copper_stairs"; public const WAXED_CUT_COPPER_STAIRS = "minecraft:waxed_cut_copper_stairs";
public const WAXED_DOUBLE_CUT_COPPER_SLAB = "minecraft:waxed_double_cut_copper_slab"; public const WAXED_DOUBLE_CUT_COPPER_SLAB = "minecraft:waxed_double_cut_copper_slab";
public const WAXED_EXPOSED_CHISELED_COPPER = "minecraft:waxed_exposed_chiseled_copper";
public const WAXED_EXPOSED_COPPER = "minecraft:waxed_exposed_copper"; public const WAXED_EXPOSED_COPPER = "minecraft:waxed_exposed_copper";
public const WAXED_EXPOSED_COPPER_BULB = "minecraft:waxed_exposed_copper_bulb";
public const WAXED_EXPOSED_COPPER_DOOR = "minecraft:waxed_exposed_copper_door";
public const WAXED_EXPOSED_COPPER_GRATE = "minecraft:waxed_exposed_copper_grate";
public const WAXED_EXPOSED_COPPER_TRAPDOOR = "minecraft:waxed_exposed_copper_trapdoor";
public const WAXED_EXPOSED_CUT_COPPER = "minecraft:waxed_exposed_cut_copper"; public const WAXED_EXPOSED_CUT_COPPER = "minecraft:waxed_exposed_cut_copper";
public const WAXED_EXPOSED_CUT_COPPER_SLAB = "minecraft:waxed_exposed_cut_copper_slab"; public const WAXED_EXPOSED_CUT_COPPER_SLAB = "minecraft:waxed_exposed_cut_copper_slab";
public const WAXED_EXPOSED_CUT_COPPER_STAIRS = "minecraft:waxed_exposed_cut_copper_stairs"; public const WAXED_EXPOSED_CUT_COPPER_STAIRS = "minecraft:waxed_exposed_cut_copper_stairs";
public const WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB = "minecraft:waxed_exposed_double_cut_copper_slab"; public const WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB = "minecraft:waxed_exposed_double_cut_copper_slab";
public const WAXED_OXIDIZED_CHISELED_COPPER = "minecraft:waxed_oxidized_chiseled_copper";
public const WAXED_OXIDIZED_COPPER = "minecraft:waxed_oxidized_copper"; public const WAXED_OXIDIZED_COPPER = "minecraft:waxed_oxidized_copper";
public const WAXED_OXIDIZED_COPPER_BULB = "minecraft:waxed_oxidized_copper_bulb";
public const WAXED_OXIDIZED_COPPER_DOOR = "minecraft:waxed_oxidized_copper_door";
public const WAXED_OXIDIZED_COPPER_GRATE = "minecraft:waxed_oxidized_copper_grate";
public const WAXED_OXIDIZED_COPPER_TRAPDOOR = "minecraft:waxed_oxidized_copper_trapdoor";
public const WAXED_OXIDIZED_CUT_COPPER = "minecraft:waxed_oxidized_cut_copper"; public const WAXED_OXIDIZED_CUT_COPPER = "minecraft:waxed_oxidized_cut_copper";
public const WAXED_OXIDIZED_CUT_COPPER_SLAB = "minecraft:waxed_oxidized_cut_copper_slab"; public const WAXED_OXIDIZED_CUT_COPPER_SLAB = "minecraft:waxed_oxidized_cut_copper_slab";
public const WAXED_OXIDIZED_CUT_COPPER_STAIRS = "minecraft:waxed_oxidized_cut_copper_stairs"; public const WAXED_OXIDIZED_CUT_COPPER_STAIRS = "minecraft:waxed_oxidized_cut_copper_stairs";
public const WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB = "minecraft:waxed_oxidized_double_cut_copper_slab"; public const WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB = "minecraft:waxed_oxidized_double_cut_copper_slab";
public const WAXED_WEATHERED_CHISELED_COPPER = "minecraft:waxed_weathered_chiseled_copper";
public const WAXED_WEATHERED_COPPER = "minecraft:waxed_weathered_copper"; public const WAXED_WEATHERED_COPPER = "minecraft:waxed_weathered_copper";
public const WAXED_WEATHERED_COPPER_BULB = "minecraft:waxed_weathered_copper_bulb";
public const WAXED_WEATHERED_COPPER_DOOR = "minecraft:waxed_weathered_copper_door";
public const WAXED_WEATHERED_COPPER_GRATE = "minecraft:waxed_weathered_copper_grate";
public const WAXED_WEATHERED_COPPER_TRAPDOOR = "minecraft:waxed_weathered_copper_trapdoor";
public const WAXED_WEATHERED_CUT_COPPER = "minecraft:waxed_weathered_cut_copper"; public const WAXED_WEATHERED_CUT_COPPER = "minecraft:waxed_weathered_cut_copper";
public const WAXED_WEATHERED_CUT_COPPER_SLAB = "minecraft:waxed_weathered_cut_copper_slab"; public const WAXED_WEATHERED_CUT_COPPER_SLAB = "minecraft:waxed_weathered_cut_copper_slab";
public const WAXED_WEATHERED_CUT_COPPER_STAIRS = "minecraft:waxed_weathered_cut_copper_stairs"; public const WAXED_WEATHERED_CUT_COPPER_STAIRS = "minecraft:waxed_weathered_cut_copper_stairs";
public const WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB = "minecraft:waxed_weathered_double_cut_copper_slab"; public const WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB = "minecraft:waxed_weathered_double_cut_copper_slab";
public const WEATHERED_CHISELED_COPPER = "minecraft:weathered_chiseled_copper";
public const WEATHERED_COPPER = "minecraft:weathered_copper"; public const WEATHERED_COPPER = "minecraft:weathered_copper";
public const WEATHERED_COPPER_BULB = "minecraft:weathered_copper_bulb";
public const WEATHERED_COPPER_DOOR = "minecraft:weathered_copper_door";
public const WEATHERED_COPPER_GRATE = "minecraft:weathered_copper_grate";
public const WEATHERED_COPPER_TRAPDOOR = "minecraft:weathered_copper_trapdoor";
public const WEATHERED_CUT_COPPER = "minecraft:weathered_cut_copper"; public const WEATHERED_CUT_COPPER = "minecraft:weathered_cut_copper";
public const WEATHERED_CUT_COPPER_SLAB = "minecraft:weathered_cut_copper_slab"; public const WEATHERED_CUT_COPPER_SLAB = "minecraft:weathered_cut_copper_slab";
public const WEATHERED_CUT_COPPER_STAIRS = "minecraft:weathered_cut_copper_stairs"; public const WEATHERED_CUT_COPPER_STAIRS = "minecraft:weathered_cut_copper_stairs";

View File

@ -520,7 +520,8 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::ACACIA_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::ACACIA_WALL_SIGN))); $this->map(Blocks::ACACIA_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::ACACIA_WALL_SIGN)));
$this->mapLog(Blocks::ACACIA_LOG(), Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG); $this->mapLog(Blocks::ACACIA_LOG(), Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG);
$this->mapSimple(Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE); $this->mapSimple(Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE);
//wood, planks and slabs still use the old way of storing wood type $this->mapSimple(Blocks::ACACIA_PLANKS(), Ids::ACACIA_PLANKS);
//wood and slabs still use the old way of storing wood type
$this->map(Blocks::BIRCH_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::BIRCH_BUTTON))); $this->map(Blocks::BIRCH_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::BIRCH_BUTTON)));
$this->map(Blocks::BIRCH_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::BIRCH_DOOR))); $this->map(Blocks::BIRCH_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::BIRCH_DOOR)));
@ -531,8 +532,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::BIRCH_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::BIRCH_WALL_SIGN))); $this->map(Blocks::BIRCH_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::BIRCH_WALL_SIGN)));
$this->mapLog(Blocks::BIRCH_LOG(), Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG); $this->mapLog(Blocks::BIRCH_LOG(), Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG);
$this->mapSimple(Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE); $this->mapSimple(Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE);
$this->mapSimple(Blocks::BIRCH_PLANKS(), Ids::BIRCH_PLANKS);
$this->mapStairs(Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS); $this->mapStairs(Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS);
//wood, planks and slabs still use the old way of storing wood type //wood and slabs still use the old way of storing wood type
$this->map(Blocks::CHERRY_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::CHERRY_BUTTON))); $this->map(Blocks::CHERRY_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::CHERRY_BUTTON)));
$this->map(Blocks::CHERRY_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::CHERRY_DOOR))); $this->map(Blocks::CHERRY_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::CHERRY_DOOR)));
@ -581,8 +583,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::DARK_OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::DARKOAK_WALL_SIGN))); $this->map(Blocks::DARK_OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::DARKOAK_WALL_SIGN)));
$this->mapLog(Blocks::DARK_OAK_LOG(), Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG); $this->mapLog(Blocks::DARK_OAK_LOG(), Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG);
$this->mapSimple(Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE); $this->mapSimple(Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE);
$this->mapSimple(Blocks::DARK_OAK_PLANKS(), Ids::DARK_OAK_PLANKS);
$this->mapStairs(Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS); $this->mapStairs(Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS);
//wood, planks and slabs still use the old way of storing wood type //wood and slabs still use the old way of storing wood type
$this->map(Blocks::JUNGLE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::JUNGLE_BUTTON))); $this->map(Blocks::JUNGLE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::JUNGLE_BUTTON)));
$this->map(Blocks::JUNGLE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::JUNGLE_DOOR))); $this->map(Blocks::JUNGLE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::JUNGLE_DOOR)));
@ -593,8 +596,9 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::JUNGLE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::JUNGLE_WALL_SIGN))); $this->map(Blocks::JUNGLE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::JUNGLE_WALL_SIGN)));
$this->mapLog(Blocks::JUNGLE_LOG(), Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG); $this->mapLog(Blocks::JUNGLE_LOG(), Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG);
$this->mapSimple(Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE); $this->mapSimple(Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE);
$this->mapSimple(Blocks::JUNGLE_PLANKS(), Ids::JUNGLE_PLANKS);
$this->mapStairs(Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS); $this->mapStairs(Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS);
//wood, planks and slabs still use the old way of storing wood type //wood and slabs still use the old way of storing wood type
$this->map(Blocks::MANGROVE_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::MANGROVE_BUTTON))); $this->map(Blocks::MANGROVE_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::MANGROVE_BUTTON)));
$this->map(Blocks::MANGROVE_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::MANGROVE_DOOR))); $this->map(Blocks::MANGROVE_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::MANGROVE_DOOR)));
@ -629,20 +633,22 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::WALL_SIGN))); $this->map(Blocks::OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::WALL_SIGN)));
$this->mapLog(Blocks::OAK_LOG(), Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG); $this->mapLog(Blocks::OAK_LOG(), Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG);
$this->mapSimple(Blocks::OAK_FENCE(), Ids::OAK_FENCE); $this->mapSimple(Blocks::OAK_FENCE(), Ids::OAK_FENCE);
$this->mapSimple(Blocks::OAK_PLANKS(), Ids::OAK_PLANKS);
$this->mapStairs(Blocks::OAK_STAIRS(), Ids::OAK_STAIRS); $this->mapStairs(Blocks::OAK_STAIRS(), Ids::OAK_STAIRS);
//wood, planks and slabs still use the old way of storing wood type //wood and slabs still use the old way of storing wood type
$this->mapSimple(Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE);
$this->mapLog(Blocks::SPRUCE_LOG(), Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG);
$this->map(Blocks::SPRUCE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::SPRUCE_BUTTON))); $this->map(Blocks::SPRUCE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::SPRUCE_BUTTON)));
$this->map(Blocks::SPRUCE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::SPRUCE_DOOR))); $this->map(Blocks::SPRUCE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::SPRUCE_DOOR)));
$this->map(Blocks::SPRUCE_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::SPRUCE_FENCE_GATE))); $this->map(Blocks::SPRUCE_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::SPRUCE_FENCE_GATE)));
$this->map(Blocks::SPRUCE_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::SPRUCE_PRESSURE_PLATE))); $this->map(Blocks::SPRUCE_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::SPRUCE_PRESSURE_PLATE)));
$this->map(Blocks::SPRUCE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::SPRUCE_STANDING_SIGN))); $this->map(Blocks::SPRUCE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::SPRUCE_STANDING_SIGN)));
$this->mapStairs(Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS);
$this->map(Blocks::SPRUCE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::SPRUCE_TRAPDOOR))); $this->map(Blocks::SPRUCE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::SPRUCE_TRAPDOOR)));
$this->map(Blocks::SPRUCE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::SPRUCE_WALL_SIGN))); $this->map(Blocks::SPRUCE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::SPRUCE_WALL_SIGN)));
//wood, planks and slabs still use the old way of storing wood type $this->mapLog(Blocks::SPRUCE_LOG(), Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG);
$this->mapSimple(Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE);
$this->mapSimple(Blocks::SPRUCE_PLANKS(), Ids::SPRUCE_PLANKS);
$this->mapStairs(Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS);
//wood and slabs still use the old way of storing wood type
$this->map(Blocks::WARPED_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::WARPED_BUTTON))); $this->map(Blocks::WARPED_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::WARPED_BUTTON)));
$this->map(Blocks::WARPED_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::WARPED_DOOR))); $this->map(Blocks::WARPED_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::WARPED_DOOR)));
@ -660,18 +666,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
} }
private function registerLegacyWoodBlockSerializers() : void{ private function registerLegacyWoodBlockSerializers() : void{
foreach([
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_PLANKS(),
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_PLANKS(),
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_PLANKS(),
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_PLANKS(),
StringValues::WOOD_TYPE_OAK => Blocks::OAK_PLANKS(),
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_PLANKS(),
] as $woodType => $block){
$this->map($block, fn() => Writer::create(Ids::PLANKS)
->writeString(StateNames::WOOD_TYPE, $woodType));
}
foreach([ foreach([
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_SLAB(), StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_SLAB(),
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_SLAB(), StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_SLAB(),
@ -715,6 +709,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSimple(Blocks::AIR(), Ids::AIR); $this->mapSimple(Blocks::AIR(), Ids::AIR);
$this->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK); $this->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK);
$this->mapSimple(Blocks::ANCIENT_DEBRIS(), Ids::ANCIENT_DEBRIS); $this->mapSimple(Blocks::ANCIENT_DEBRIS(), Ids::ANCIENT_DEBRIS);
$this->mapSimple(Blocks::ANDESITE(), Ids::ANDESITE);
$this->mapSimple(Blocks::BARRIER(), Ids::BARRIER); $this->mapSimple(Blocks::BARRIER(), Ids::BARRIER);
$this->mapSimple(Blocks::BEACON(), Ids::BEACON); $this->mapSimple(Blocks::BEACON(), Ids::BEACON);
$this->mapSimple(Blocks::BLACKSTONE(), Ids::BLACKSTONE); $this->mapSimple(Blocks::BLACKSTONE(), Ids::BLACKSTONE);
@ -757,6 +752,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSimple(Blocks::DEEPSLATE_TILES(), Ids::DEEPSLATE_TILES); $this->mapSimple(Blocks::DEEPSLATE_TILES(), Ids::DEEPSLATE_TILES);
$this->mapSimple(Blocks::DIAMOND(), Ids::DIAMOND_BLOCK); $this->mapSimple(Blocks::DIAMOND(), Ids::DIAMOND_BLOCK);
$this->mapSimple(Blocks::DIAMOND_ORE(), Ids::DIAMOND_ORE); $this->mapSimple(Blocks::DIAMOND_ORE(), Ids::DIAMOND_ORE);
$this->mapSimple(Blocks::DIORITE(), Ids::DIORITE);
$this->mapSimple(Blocks::DRAGON_EGG(), Ids::DRAGON_EGG); $this->mapSimple(Blocks::DRAGON_EGG(), Ids::DRAGON_EGG);
$this->mapSimple(Blocks::DRIED_KELP(), Ids::DRIED_KELP_BLOCK); $this->mapSimple(Blocks::DRIED_KELP(), Ids::DRIED_KELP_BLOCK);
$this->mapSimple(Blocks::ELEMENT_ACTINIUM(), Ids::ELEMENT_89); $this->mapSimple(Blocks::ELEMENT_ACTINIUM(), Ids::ELEMENT_89);
@ -891,6 +887,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSimple(Blocks::GLOWSTONE(), Ids::GLOWSTONE); $this->mapSimple(Blocks::GLOWSTONE(), Ids::GLOWSTONE);
$this->mapSimple(Blocks::GOLD(), Ids::GOLD_BLOCK); $this->mapSimple(Blocks::GOLD(), Ids::GOLD_BLOCK);
$this->mapSimple(Blocks::GOLD_ORE(), Ids::GOLD_ORE); $this->mapSimple(Blocks::GOLD_ORE(), Ids::GOLD_ORE);
$this->mapSimple(Blocks::GRANITE(), Ids::GRANITE);
$this->mapSimple(Blocks::GRASS(), Ids::GRASS); $this->mapSimple(Blocks::GRASS(), Ids::GRASS);
$this->mapSimple(Blocks::GRASS_PATH(), Ids::GRASS_PATH); $this->mapSimple(Blocks::GRASS_PATH(), Ids::GRASS_PATH);
$this->mapSimple(Blocks::GRAVEL(), Ids::GRAVEL); $this->mapSimple(Blocks::GRAVEL(), Ids::GRAVEL);
@ -932,9 +929,12 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSimple(Blocks::PACKED_ICE(), Ids::PACKED_ICE); $this->mapSimple(Blocks::PACKED_ICE(), Ids::PACKED_ICE);
$this->mapSimple(Blocks::PACKED_MUD(), Ids::PACKED_MUD); $this->mapSimple(Blocks::PACKED_MUD(), Ids::PACKED_MUD);
$this->mapSimple(Blocks::PODZOL(), Ids::PODZOL); $this->mapSimple(Blocks::PODZOL(), Ids::PODZOL);
$this->mapSimple(Blocks::POLISHED_ANDESITE(), Ids::POLISHED_ANDESITE);
$this->mapSimple(Blocks::POLISHED_BLACKSTONE(), Ids::POLISHED_BLACKSTONE); $this->mapSimple(Blocks::POLISHED_BLACKSTONE(), Ids::POLISHED_BLACKSTONE);
$this->mapSimple(Blocks::POLISHED_BLACKSTONE_BRICKS(), Ids::POLISHED_BLACKSTONE_BRICKS); $this->mapSimple(Blocks::POLISHED_BLACKSTONE_BRICKS(), Ids::POLISHED_BLACKSTONE_BRICKS);
$this->mapSimple(Blocks::POLISHED_DEEPSLATE(), Ids::POLISHED_DEEPSLATE); $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::QUARTZ_BRICKS(), Ids::QUARTZ_BRICKS); $this->mapSimple(Blocks::QUARTZ_BRICKS(), Ids::QUARTZ_BRICKS);
$this->mapSimple(Blocks::RAW_COPPER(), Ids::RAW_COPPER_BLOCK); $this->mapSimple(Blocks::RAW_COPPER(), Ids::RAW_COPPER_BLOCK);
$this->mapSimple(Blocks::RAW_GOLD(), Ids::RAW_GOLD_BLOCK); $this->mapSimple(Blocks::RAW_GOLD(), Ids::RAW_GOLD_BLOCK);
@ -956,6 +956,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSimple(Blocks::SOUL_SAND(), Ids::SOUL_SAND); $this->mapSimple(Blocks::SOUL_SAND(), Ids::SOUL_SAND);
$this->mapSimple(Blocks::SOUL_SOIL(), Ids::SOUL_SOIL); $this->mapSimple(Blocks::SOUL_SOIL(), Ids::SOUL_SOIL);
$this->mapSimple(Blocks::SPORE_BLOSSOM(), Ids::SPORE_BLOSSOM); $this->mapSimple(Blocks::SPORE_BLOSSOM(), Ids::SPORE_BLOSSOM);
$this->mapSimple(Blocks::STONE(), Ids::STONE);
$this->mapSimple(Blocks::TINTED_GLASS(), Ids::TINTED_GLASS); $this->mapSimple(Blocks::TINTED_GLASS(), Ids::TINTED_GLASS);
$this->mapSimple(Blocks::TORCHFLOWER(), Ids::TORCHFLOWER); $this->mapSimple(Blocks::TORCHFLOWER(), Ids::TORCHFLOWER);
$this->mapSimple(Blocks::TUFF(), Ids::TUFF); $this->mapSimple(Blocks::TUFF(), Ids::TUFF);
@ -984,7 +985,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
}) })
->writeBlockFace($block->getFacing()) ->writeBlockFace($block->getFacing())
); );
$this->map(Blocks::ANDESITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_ANDESITE));
$this->map(Blocks::ANDESITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_ANDESITE)); $this->map(Blocks::ANDESITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_ANDESITE));
$this->map(Blocks::ANDESITE_STAIRS(), fn(Stair $block) => Helper::encodeStairs($block, new Writer(Ids::ANDESITE_STAIRS))); $this->map(Blocks::ANDESITE_STAIRS(), fn(Stair $block) => Helper::encodeStairs($block, new Writer(Ids::ANDESITE_STAIRS)));
$this->map(Blocks::ANDESITE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_ANDESITE)); $this->map(Blocks::ANDESITE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_ANDESITE));
@ -1267,7 +1267,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeBool(StateNames::RAIL_DATA_BIT, $block->isActivated()) ->writeBool(StateNames::RAIL_DATA_BIT, $block->isActivated())
->writeInt(StateNames::RAIL_DIRECTION, $block->getShape()); ->writeInt(StateNames::RAIL_DIRECTION, $block->getShape());
}); });
$this->map(Blocks::DIORITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_DIORITE));
$this->map(Blocks::DIORITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_DIORITE)); $this->map(Blocks::DIORITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_DIORITE));
$this->mapStairs(Blocks::DIORITE_STAIRS(), Ids::DIORITE_STAIRS); $this->mapStairs(Blocks::DIORITE_STAIRS(), Ids::DIORITE_STAIRS);
$this->map(Blocks::DIORITE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_DIORITE)); $this->map(Blocks::DIORITE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_DIORITE));
@ -1334,7 +1333,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeFacingFlags($block->getFaces()); ->writeFacingFlags($block->getFaces());
}); });
$this->map(Blocks::GLOWING_ITEM_FRAME(), fn(ItemFrame $block) => Helper::encodeItemFrame($block, Ids::GLOW_FRAME)); $this->map(Blocks::GLOWING_ITEM_FRAME(), fn(ItemFrame $block) => Helper::encodeItemFrame($block, Ids::GLOW_FRAME));
$this->map(Blocks::GRANITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_GRANITE));
$this->map(Blocks::GRANITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_GRANITE)); $this->map(Blocks::GRANITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_GRANITE));
$this->mapStairs(Blocks::GRANITE_STAIRS(), Ids::GRANITE_STAIRS); $this->mapStairs(Blocks::GRANITE_STAIRS(), Ids::GRANITE_STAIRS);
$this->map(Blocks::GRANITE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_GRANITE)); $this->map(Blocks::GRANITE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_GRANITE));
@ -1472,7 +1470,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeInt(StateNames::GROWTH, $block->getAge() + 1 + PitcherCrop::MAX_AGE) ->writeInt(StateNames::GROWTH, $block->getAge() + 1 + PitcherCrop::MAX_AGE)
->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop()); ->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
}); });
$this->map(Blocks::POLISHED_ANDESITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_ANDESITE_SMOOTH));
$this->map(Blocks::POLISHED_ANDESITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_POLISHED_ANDESITE)); $this->map(Blocks::POLISHED_ANDESITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_POLISHED_ANDESITE));
$this->mapStairs(Blocks::POLISHED_ANDESITE_STAIRS(), Ids::POLISHED_ANDESITE_STAIRS); $this->mapStairs(Blocks::POLISHED_ANDESITE_STAIRS(), Ids::POLISHED_ANDESITE_STAIRS);
$this->map(Blocks::POLISHED_BASALT(), function(SimplePillar $block) : Writer{ $this->map(Blocks::POLISHED_BASALT(), function(SimplePillar $block) : Writer{
@ -1490,10 +1487,8 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSlab(Blocks::POLISHED_DEEPSLATE_SLAB(), Ids::POLISHED_DEEPSLATE_SLAB, Ids::POLISHED_DEEPSLATE_DOUBLE_SLAB); $this->mapSlab(Blocks::POLISHED_DEEPSLATE_SLAB(), Ids::POLISHED_DEEPSLATE_SLAB, Ids::POLISHED_DEEPSLATE_DOUBLE_SLAB);
$this->mapStairs(Blocks::POLISHED_DEEPSLATE_STAIRS(), Ids::POLISHED_DEEPSLATE_STAIRS); $this->mapStairs(Blocks::POLISHED_DEEPSLATE_STAIRS(), Ids::POLISHED_DEEPSLATE_STAIRS);
$this->map(Blocks::POLISHED_DEEPSLATE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_DEEPSLATE_WALL))); $this->map(Blocks::POLISHED_DEEPSLATE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_DEEPSLATE_WALL)));
$this->map(Blocks::POLISHED_DIORITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_DIORITE_SMOOTH));
$this->map(Blocks::POLISHED_DIORITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_POLISHED_DIORITE)); $this->map(Blocks::POLISHED_DIORITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_POLISHED_DIORITE));
$this->mapStairs(Blocks::POLISHED_DIORITE_STAIRS(), Ids::POLISHED_DIORITE_STAIRS); $this->mapStairs(Blocks::POLISHED_DIORITE_STAIRS(), Ids::POLISHED_DIORITE_STAIRS);
$this->map(Blocks::POLISHED_GRANITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_GRANITE_SMOOTH));
$this->map(Blocks::POLISHED_GRANITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_POLISHED_GRANITE)); $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->mapStairs(Blocks::POLISHED_GRANITE_STAIRS(), Ids::POLISHED_GRANITE_STAIRS);
$this->map(Blocks::POPPY(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_POPPY)); $this->map(Blocks::POPPY(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_POPPY));
@ -1629,7 +1624,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create(Ids::HARD_STAINED_GLASS_PANE) return Writer::create(Ids::HARD_STAINED_GLASS_PANE)
->writeColor($block->getColor()); ->writeColor($block->getColor());
}); });
$this->map(Blocks::STONE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_STONE));
$this->map(Blocks::STONECUTTER(), fn(Stonecutter $block) => Writer::create(Ids::STONECUTTER_BLOCK) $this->map(Blocks::STONECUTTER(), fn(Stonecutter $block) => Writer::create(Ids::STONECUTTER_BLOCK)
->writeCardinalHorizontalFacing($block->getFacing())); ->writeCardinalHorizontalFacing($block->getFacing()));
$this->map(Blocks::STONE_BRICKS(), fn() => Helper::encodeStoneBricks(StringValues::STONE_BRICK_TYPE_DEFAULT)); $this->map(Blocks::STONE_BRICKS(), fn() => Helper::encodeStoneBricks(StringValues::STONE_BRICK_TYPE_DEFAULT));

View File

@ -228,11 +228,6 @@ final class BlockStateSerializerHelper{
->writeFacingWithoutUp($facing === Facing::UP ? Facing::DOWN : $facing); ->writeFacingWithoutUp($facing === Facing::UP ? Facing::DOWN : $facing);
} }
public static function encodeStone(string $type) : BlockStateWriter{
return BlockStateWriter::create(Ids::STONE)
->writeString(BlockStateNames::STONE_TYPE, $type);
}
public static function encodeStoneBricks(string $type) : BlockStateWriter{ public static function encodeStoneBricks(string $type) : BlockStateWriter{
return BlockStateWriter::create(Ids::STONEBRICK) return BlockStateWriter::create(Ids::STONEBRICK)
->writeString(BlockStateNames::STONE_BRICK_TYPE, $type); ->writeString(BlockStateNames::STONE_BRICK_TYPE, $type);

View File

@ -427,6 +427,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map(Ids::ACACIA_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::ACACIA_WALL_SIGN(), $in)); $this->map(Ids::ACACIA_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::ACACIA_WALL_SIGN(), $in));
$this->mapLog(Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG, fn() => Blocks::ACACIA_LOG()); $this->mapLog(Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG, fn() => Blocks::ACACIA_LOG());
$this->mapSimple(Ids::ACACIA_FENCE, fn() => Blocks::ACACIA_FENCE()); $this->mapSimple(Ids::ACACIA_FENCE, fn() => Blocks::ACACIA_FENCE());
$this->mapSimple(Ids::ACACIA_PLANKS, fn() => Blocks::ACACIA_PLANKS());
$this->mapStairs(Ids::ACACIA_STAIRS, fn() => Blocks::ACACIA_STAIRS()); $this->mapStairs(Ids::ACACIA_STAIRS, fn() => Blocks::ACACIA_STAIRS());
//wood, planks and slabs still use the old way of storing wood type //wood, planks and slabs still use the old way of storing wood type
@ -439,6 +440,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map(Ids::BIRCH_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::BIRCH_WALL_SIGN(), $in)); $this->map(Ids::BIRCH_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::BIRCH_WALL_SIGN(), $in));
$this->mapLog(Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG, fn() => Blocks::BIRCH_LOG()); $this->mapLog(Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG, fn() => Blocks::BIRCH_LOG());
$this->mapSimple(Ids::BIRCH_FENCE, fn() => Blocks::BIRCH_FENCE()); $this->mapSimple(Ids::BIRCH_FENCE, fn() => Blocks::BIRCH_FENCE());
$this->mapSimple(Ids::BIRCH_PLANKS, fn() => Blocks::BIRCH_PLANKS());
$this->mapStairs(Ids::BIRCH_STAIRS, fn() => Blocks::BIRCH_STAIRS()); $this->mapStairs(Ids::BIRCH_STAIRS, fn() => Blocks::BIRCH_STAIRS());
//wood, planks and slabs still use the old way of storing wood type //wood, planks and slabs still use the old way of storing wood type
@ -483,6 +485,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map(Ids::DARK_OAK_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::DARK_OAK_TRAPDOOR(), $in)); $this->map(Ids::DARK_OAK_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::DARK_OAK_TRAPDOOR(), $in));
$this->mapLog(Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG, fn() => Blocks::DARK_OAK_LOG()); $this->mapLog(Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG, fn() => Blocks::DARK_OAK_LOG());
$this->mapSimple(Ids::DARK_OAK_FENCE, fn() => Blocks::DARK_OAK_FENCE()); $this->mapSimple(Ids::DARK_OAK_FENCE, fn() => Blocks::DARK_OAK_FENCE());
$this->mapSimple(Ids::DARK_OAK_PLANKS, fn() => Blocks::DARK_OAK_PLANKS());
$this->mapStairs(Ids::DARK_OAK_STAIRS, fn() => Blocks::DARK_OAK_STAIRS()); $this->mapStairs(Ids::DARK_OAK_STAIRS, fn() => Blocks::DARK_OAK_STAIRS());
//wood, planks and slabs still use the old way of storing wood type //wood, planks and slabs still use the old way of storing wood type
@ -495,6 +498,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map(Ids::JUNGLE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::JUNGLE_WALL_SIGN(), $in)); $this->map(Ids::JUNGLE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::JUNGLE_WALL_SIGN(), $in));
$this->mapLog(Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG, fn() => Blocks::JUNGLE_LOG()); $this->mapLog(Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG, fn() => Blocks::JUNGLE_LOG());
$this->mapSimple(Ids::JUNGLE_FENCE, fn() => Blocks::JUNGLE_FENCE()); $this->mapSimple(Ids::JUNGLE_FENCE, fn() => Blocks::JUNGLE_FENCE());
$this->mapSimple(Ids::JUNGLE_PLANKS, fn() => Blocks::JUNGLE_PLANKS());
$this->mapStairs(Ids::JUNGLE_STAIRS, fn() => Blocks::JUNGLE_STAIRS()); $this->mapStairs(Ids::JUNGLE_STAIRS, fn() => Blocks::JUNGLE_STAIRS());
//wood, planks and slabs still use the old way of storing wood type //wood, planks and slabs still use the old way of storing wood type
@ -526,6 +530,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map(Ids::WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::OAK_WALL_SIGN(), $in)); $this->map(Ids::WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::OAK_WALL_SIGN(), $in));
$this->mapLog(Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG, fn() => Blocks::OAK_LOG()); $this->mapLog(Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG, fn() => Blocks::OAK_LOG());
$this->mapSimple(Ids::OAK_FENCE, fn() => Blocks::OAK_FENCE()); $this->mapSimple(Ids::OAK_FENCE, fn() => Blocks::OAK_FENCE());
$this->mapSimple(Ids::OAK_PLANKS, fn() => Blocks::OAK_PLANKS());
$this->mapStairs(Ids::OAK_STAIRS, fn() => Blocks::OAK_STAIRS()); $this->mapStairs(Ids::OAK_STAIRS, fn() => Blocks::OAK_STAIRS());
//wood, planks and slabs still use the old way of storing wood type //wood, planks and slabs still use the old way of storing wood type
@ -538,6 +543,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map(Ids::SPRUCE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::SPRUCE_WALL_SIGN(), $in)); $this->map(Ids::SPRUCE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::SPRUCE_WALL_SIGN(), $in));
$this->mapLog(Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG, fn() => Blocks::SPRUCE_LOG()); $this->mapLog(Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG, fn() => Blocks::SPRUCE_LOG());
$this->mapSimple(Ids::SPRUCE_FENCE, fn() => Blocks::SPRUCE_FENCE()); $this->mapSimple(Ids::SPRUCE_FENCE, fn() => Blocks::SPRUCE_FENCE());
$this->mapSimple(Ids::SPRUCE_PLANKS, fn() => Blocks::SPRUCE_PLANKS());
$this->mapStairs(Ids::SPRUCE_STAIRS, fn() => Blocks::SPRUCE_STAIRS()); $this->mapStairs(Ids::SPRUCE_STAIRS, fn() => Blocks::SPRUCE_STAIRS());
//wood, planks and slabs still use the old way of storing wood type //wood, planks and slabs still use the old way of storing wood type
@ -557,18 +563,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
} }
private function registerLegacyWoodBlockDeserializers() : void{ private function registerLegacyWoodBlockDeserializers() : void{
$this->map(Ids::PLANKS, function(Reader $in) : Block{
return match($woodName = $in->readString(StateNames::WOOD_TYPE)){
StringValues::WOOD_TYPE_OAK => Blocks::OAK_PLANKS(),
StringValues::WOOD_TYPE_SPRUCE => Blocks::SPRUCE_PLANKS(),
StringValues::WOOD_TYPE_BIRCH => Blocks::BIRCH_PLANKS(),
StringValues::WOOD_TYPE_JUNGLE => Blocks::JUNGLE_PLANKS(),
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_PLANKS(),
StringValues::WOOD_TYPE_DARK_OAK => Blocks::DARK_OAK_PLANKS(),
default => throw $in->badValueException(StateNames::WOOD_TYPE, $woodName),
};
});
$this->mapSlab(Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB, fn(Reader $in) => Helper::mapWoodenSlabType($in)); $this->mapSlab(Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB, fn(Reader $in) => Helper::mapWoodenSlabType($in));
$this->map(Ids::WOOD, fn(Reader $in) : Block => Helper::decodeLog(match($woodType = $in->readString(StateNames::WOOD_TYPE)){ $this->map(Ids::WOOD, fn(Reader $in) : Block => Helper::decodeLog(match($woodType = $in->readString(StateNames::WOOD_TYPE)){
@ -608,6 +602,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::AIR, fn() => Blocks::AIR()); $this->mapSimple(Ids::AIR, fn() => Blocks::AIR());
$this->mapSimple(Ids::AMETHYST_BLOCK, fn() => Blocks::AMETHYST()); $this->mapSimple(Ids::AMETHYST_BLOCK, fn() => Blocks::AMETHYST());
$this->mapSimple(Ids::ANCIENT_DEBRIS, fn() => Blocks::ANCIENT_DEBRIS()); $this->mapSimple(Ids::ANCIENT_DEBRIS, fn() => Blocks::ANCIENT_DEBRIS());
$this->mapSimple(Ids::ANDESITE, fn() => Blocks::ANDESITE());
$this->mapSimple(Ids::BARRIER, fn() => Blocks::BARRIER()); $this->mapSimple(Ids::BARRIER, fn() => Blocks::BARRIER());
$this->mapSimple(Ids::BEACON, fn() => Blocks::BEACON()); $this->mapSimple(Ids::BEACON, fn() => Blocks::BEACON());
$this->mapSimple(Ids::BLACKSTONE, fn() => Blocks::BLACKSTONE()); $this->mapSimple(Ids::BLACKSTONE, fn() => Blocks::BLACKSTONE());
@ -648,6 +643,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::DEEPSLATE_TILES, fn() => Blocks::DEEPSLATE_TILES()); $this->mapSimple(Ids::DEEPSLATE_TILES, fn() => Blocks::DEEPSLATE_TILES());
$this->mapSimple(Ids::DIAMOND_BLOCK, fn() => Blocks::DIAMOND()); $this->mapSimple(Ids::DIAMOND_BLOCK, fn() => Blocks::DIAMOND());
$this->mapSimple(Ids::DIAMOND_ORE, fn() => Blocks::DIAMOND_ORE()); $this->mapSimple(Ids::DIAMOND_ORE, fn() => Blocks::DIAMOND_ORE());
$this->mapSimple(Ids::DIORITE, fn() => Blocks::DIORITE());
$this->mapSimple(Ids::DRAGON_EGG, fn() => Blocks::DRAGON_EGG()); $this->mapSimple(Ids::DRAGON_EGG, fn() => Blocks::DRAGON_EGG());
$this->mapSimple(Ids::DRIED_KELP_BLOCK, fn() => Blocks::DRIED_KELP()); $this->mapSimple(Ids::DRIED_KELP_BLOCK, fn() => Blocks::DRIED_KELP());
$this->mapSimple(Ids::ELEMENT_0, fn() => Blocks::ELEMENT_ZERO()); $this->mapSimple(Ids::ELEMENT_0, fn() => Blocks::ELEMENT_ZERO());
@ -782,6 +778,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::GLOWSTONE, fn() => Blocks::GLOWSTONE()); $this->mapSimple(Ids::GLOWSTONE, fn() => Blocks::GLOWSTONE());
$this->mapSimple(Ids::GOLD_BLOCK, fn() => Blocks::GOLD()); $this->mapSimple(Ids::GOLD_BLOCK, fn() => Blocks::GOLD());
$this->mapSimple(Ids::GOLD_ORE, fn() => Blocks::GOLD_ORE()); $this->mapSimple(Ids::GOLD_ORE, fn() => Blocks::GOLD_ORE());
$this->mapSimple(Ids::GRANITE, fn() => Blocks::GRANITE());
$this->mapSimple(Ids::GRASS, fn() => Blocks::GRASS()); $this->mapSimple(Ids::GRASS, fn() => Blocks::GRASS());
$this->mapSimple(Ids::GRASS_PATH, fn() => Blocks::GRASS_PATH()); $this->mapSimple(Ids::GRASS_PATH, fn() => Blocks::GRASS_PATH());
$this->mapSimple(Ids::GRAVEL, fn() => Blocks::GRAVEL()); $this->mapSimple(Ids::GRAVEL, fn() => Blocks::GRAVEL());
@ -820,9 +817,12 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::PACKED_ICE, fn() => Blocks::PACKED_ICE()); $this->mapSimple(Ids::PACKED_ICE, fn() => Blocks::PACKED_ICE());
$this->mapSimple(Ids::PACKED_MUD, fn() => Blocks::PACKED_MUD()); $this->mapSimple(Ids::PACKED_MUD, fn() => Blocks::PACKED_MUD());
$this->mapSimple(Ids::PODZOL, fn() => Blocks::PODZOL()); $this->mapSimple(Ids::PODZOL, fn() => Blocks::PODZOL());
$this->mapSimple(Ids::POLISHED_ANDESITE, fn() => Blocks::POLISHED_ANDESITE());
$this->mapSimple(Ids::POLISHED_BLACKSTONE, fn() => Blocks::POLISHED_BLACKSTONE()); $this->mapSimple(Ids::POLISHED_BLACKSTONE, fn() => Blocks::POLISHED_BLACKSTONE());
$this->mapSimple(Ids::POLISHED_BLACKSTONE_BRICKS, fn() => Blocks::POLISHED_BLACKSTONE_BRICKS()); $this->mapSimple(Ids::POLISHED_BLACKSTONE_BRICKS, fn() => Blocks::POLISHED_BLACKSTONE_BRICKS());
$this->mapSimple(Ids::POLISHED_DEEPSLATE, fn() => Blocks::POLISHED_DEEPSLATE()); $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::QUARTZ_BRICKS, fn() => Blocks::QUARTZ_BRICKS()); $this->mapSimple(Ids::QUARTZ_BRICKS, fn() => Blocks::QUARTZ_BRICKS());
$this->mapSimple(Ids::QUARTZ_ORE, fn() => Blocks::NETHER_QUARTZ_ORE()); $this->mapSimple(Ids::QUARTZ_ORE, fn() => Blocks::NETHER_QUARTZ_ORE());
$this->mapSimple(Ids::RAW_COPPER_BLOCK, fn() => Blocks::RAW_COPPER()); $this->mapSimple(Ids::RAW_COPPER_BLOCK, fn() => Blocks::RAW_COPPER());
@ -844,6 +844,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSimple(Ids::SOUL_SAND, fn() => Blocks::SOUL_SAND()); $this->mapSimple(Ids::SOUL_SAND, fn() => Blocks::SOUL_SAND());
$this->mapSimple(Ids::SOUL_SOIL, fn() => Blocks::SOUL_SOIL()); $this->mapSimple(Ids::SOUL_SOIL, fn() => Blocks::SOUL_SOIL());
$this->mapSimple(Ids::SPORE_BLOSSOM, fn() => Blocks::SPORE_BLOSSOM()); $this->mapSimple(Ids::SPORE_BLOSSOM, fn() => Blocks::SPORE_BLOSSOM());
$this->mapSimple(Ids::STONE, fn() => Blocks::STONE());
$this->mapSimple(Ids::STONECUTTER, fn() => Blocks::LEGACY_STONECUTTER()); $this->mapSimple(Ids::STONECUTTER, fn() => Blocks::LEGACY_STONECUTTER());
$this->mapSimple(Ids::TINTED_GLASS, fn() => Blocks::TINTED_GLASS()); $this->mapSimple(Ids::TINTED_GLASS, fn() => Blocks::TINTED_GLASS());
$this->mapSimple(Ids::TORCHFLOWER, fn() => Blocks::TORCHFLOWER()); $this->mapSimple(Ids::TORCHFLOWER, fn() => Blocks::TORCHFLOWER());
@ -1528,18 +1529,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
return Blocks::BANNER() return Blocks::BANNER()
->setRotation($in->readBoundedInt(StateNames::GROUND_SIGN_DIRECTION, 0, 15)); ->setRotation($in->readBoundedInt(StateNames::GROUND_SIGN_DIRECTION, 0, 15));
}); });
$this->map(Ids::STONE, function(Reader $in) : Block{
return match($type = $in->readString(StateNames::STONE_TYPE)){
StringValues::STONE_TYPE_ANDESITE => Blocks::ANDESITE(),
StringValues::STONE_TYPE_ANDESITE_SMOOTH => Blocks::POLISHED_ANDESITE(),
StringValues::STONE_TYPE_DIORITE => Blocks::DIORITE(),
StringValues::STONE_TYPE_DIORITE_SMOOTH => Blocks::POLISHED_DIORITE(),
StringValues::STONE_TYPE_GRANITE => Blocks::GRANITE(),
StringValues::STONE_TYPE_GRANITE_SMOOTH => Blocks::POLISHED_GRANITE(),
StringValues::STONE_TYPE_STONE => Blocks::STONE(),
default => throw $in->badValueException(StateNames::STONE_TYPE, $type),
};
});
$this->mapStairs(Ids::STONE_BRICK_STAIRS, fn() => Blocks::STONE_BRICK_STAIRS()); $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_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->map(Ids::STONE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::STONE_PRESSURE_PLATE(), $in));

View File

@ -147,7 +147,6 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Block(Ids::JUNGLE_DOOR, Blocks::JUNGLE_DOOR()); $this->map1to1Block(Ids::JUNGLE_DOOR, Blocks::JUNGLE_DOOR());
$this->map1to1Block(Ids::MANGROVE_DOOR, Blocks::MANGROVE_DOOR()); $this->map1to1Block(Ids::MANGROVE_DOOR, Blocks::MANGROVE_DOOR());
$this->map1to1Block(Ids::NETHER_WART, Blocks::NETHER_WART()); $this->map1to1Block(Ids::NETHER_WART, Blocks::NETHER_WART());
$this->map1to1Block(Ids::PITCHER_POD, Blocks::PITCHER_CROP());
$this->map1to1Block(Ids::REPEATER, Blocks::REDSTONE_REPEATER()); $this->map1to1Block(Ids::REPEATER, Blocks::REDSTONE_REPEATER());
$this->map1to1Block(Ids::SPRUCE_DOOR, Blocks::SPRUCE_DOOR()); $this->map1to1Block(Ids::SPRUCE_DOOR, Blocks::SPRUCE_DOOR());
$this->map1to1Block(Ids::SUGAR_CANE, Blocks::SUGARCANE()); $this->map1to1Block(Ids::SUGAR_CANE, Blocks::SUGARCANE());
@ -326,6 +325,7 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Item(Ids::PAINTING, Items::PAINTING()); $this->map1to1Item(Ids::PAINTING, Items::PAINTING());
$this->map1to1Item(Ids::PAPER, Items::PAPER()); $this->map1to1Item(Ids::PAPER, Items::PAPER());
$this->map1to1Item(Ids::PHANTOM_MEMBRANE, Items::PHANTOM_MEMBRANE()); $this->map1to1Item(Ids::PHANTOM_MEMBRANE, Items::PHANTOM_MEMBRANE());
$this->map1to1Item(Ids::PITCHER_POD, Items::PITCHER_POD());
$this->map1to1Item(Ids::POISONOUS_POTATO, Items::POISONOUS_POTATO()); $this->map1to1Item(Ids::POISONOUS_POTATO, Items::POISONOUS_POTATO());
$this->map1to1Item(Ids::POPPED_CHORUS_FRUIT, Items::POPPED_CHORUS_FRUIT()); $this->map1to1Item(Ids::POPPED_CHORUS_FRUIT, Items::POPPED_CHORUS_FRUIT());
$this->map1to1Item(Ids::PORKCHOP, Items::RAW_PORKCHOP()); $this->map1to1Item(Ids::PORKCHOP, Items::RAW_PORKCHOP());

View File

@ -134,6 +134,7 @@ final class ItemTypeNames{
public const COOKED_RABBIT = "minecraft:cooked_rabbit"; public const COOKED_RABBIT = "minecraft:cooked_rabbit";
public const COOKED_SALMON = "minecraft:cooked_salmon"; public const COOKED_SALMON = "minecraft:cooked_salmon";
public const COOKIE = "minecraft:cookie"; public const COOKIE = "minecraft:cookie";
public const COPPER_DOOR = "minecraft:copper_door";
public const COPPER_INGOT = "minecraft:copper_ingot"; public const COPPER_INGOT = "minecraft:copper_ingot";
public const CORAL = "minecraft:coral"; public const CORAL = "minecraft:coral";
public const COW_SPAWN_EGG = "minecraft:cow_spawn_egg"; public const COW_SPAWN_EGG = "minecraft:cow_spawn_egg";
@ -150,6 +151,7 @@ final class ItemTypeNames{
public const DARK_OAK_DOOR = "minecraft:dark_oak_door"; public const DARK_OAK_DOOR = "minecraft:dark_oak_door";
public const DARK_OAK_HANGING_SIGN = "minecraft:dark_oak_hanging_sign"; public const DARK_OAK_HANGING_SIGN = "minecraft:dark_oak_hanging_sign";
public const DARK_OAK_SIGN = "minecraft:dark_oak_sign"; public const DARK_OAK_SIGN = "minecraft:dark_oak_sign";
public const DEBUG_STICK = "minecraft:debug_stick";
public const DIAMOND = "minecraft:diamond"; public const DIAMOND = "minecraft:diamond";
public const DIAMOND_AXE = "minecraft:diamond_axe"; public const DIAMOND_AXE = "minecraft:diamond_axe";
public const DIAMOND_BOOTS = "minecraft:diamond_boots"; public const DIAMOND_BOOTS = "minecraft:diamond_boots";
@ -186,6 +188,7 @@ final class ItemTypeNames{
public const EVOKER_SPAWN_EGG = "minecraft:evoker_spawn_egg"; public const EVOKER_SPAWN_EGG = "minecraft:evoker_spawn_egg";
public const EXPERIENCE_BOTTLE = "minecraft:experience_bottle"; public const EXPERIENCE_BOTTLE = "minecraft:experience_bottle";
public const EXPLORER_POTTERY_SHERD = "minecraft:explorer_pottery_sherd"; public const EXPLORER_POTTERY_SHERD = "minecraft:explorer_pottery_sherd";
public const EXPOSED_COPPER_DOOR = "minecraft:exposed_copper_door";
public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:eye_armor_trim_smithing_template"; public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:eye_armor_trim_smithing_template";
public const FEATHER = "minecraft:feather"; public const FEATHER = "minecraft:feather";
public const FENCE = "minecraft:fence"; public const FENCE = "minecraft:fence";
@ -347,6 +350,7 @@ final class ItemTypeNames{
public const OAK_SIGN = "minecraft:oak_sign"; public const OAK_SIGN = "minecraft:oak_sign";
public const OCELOT_SPAWN_EGG = "minecraft:ocelot_spawn_egg"; public const OCELOT_SPAWN_EGG = "minecraft:ocelot_spawn_egg";
public const ORANGE_DYE = "minecraft:orange_dye"; public const ORANGE_DYE = "minecraft:orange_dye";
public const OXIDIZED_COPPER_DOOR = "minecraft:oxidized_copper_door";
public const PAINTING = "minecraft:painting"; public const PAINTING = "minecraft:painting";
public const PANDA_SPAWN_EGG = "minecraft:panda_spawn_egg"; public const PANDA_SPAWN_EGG = "minecraft:panda_spawn_egg";
public const PAPER = "minecraft:paper"; public const PAPER = "minecraft:paper";
@ -360,6 +364,7 @@ final class ItemTypeNames{
public const PILLAGER_SPAWN_EGG = "minecraft:pillager_spawn_egg"; public const PILLAGER_SPAWN_EGG = "minecraft:pillager_spawn_egg";
public const PINK_DYE = "minecraft:pink_dye"; public const PINK_DYE = "minecraft:pink_dye";
public const PITCHER_POD = "minecraft:pitcher_pod"; public const PITCHER_POD = "minecraft:pitcher_pod";
public const PLANKS = "minecraft:planks";
public const PLENTY_POTTERY_SHERD = "minecraft:plenty_pottery_sherd"; public const PLENTY_POTTERY_SHERD = "minecraft:plenty_pottery_sherd";
public const POISONOUS_POTATO = "minecraft:poisonous_potato"; public const POISONOUS_POTATO = "minecraft:poisonous_potato";
public const POLAR_BEAR_SPAWN_EGG = "minecraft:polar_bear_spawn_egg"; public const POLAR_BEAR_SPAWN_EGG = "minecraft:polar_bear_spawn_egg";
@ -479,7 +484,12 @@ final class ItemTypeNames{
public const WARPED_HANGING_SIGN = "minecraft:warped_hanging_sign"; public const WARPED_HANGING_SIGN = "minecraft:warped_hanging_sign";
public const WARPED_SIGN = "minecraft:warped_sign"; public const WARPED_SIGN = "minecraft:warped_sign";
public const WATER_BUCKET = "minecraft:water_bucket"; public const WATER_BUCKET = "minecraft:water_bucket";
public const WAXED_COPPER_DOOR = "minecraft:waxed_copper_door";
public const WAXED_EXPOSED_COPPER_DOOR = "minecraft:waxed_exposed_copper_door";
public const WAXED_OXIDIZED_COPPER_DOOR = "minecraft:waxed_oxidized_copper_door";
public const WAXED_WEATHERED_COPPER_DOOR = "minecraft:waxed_weathered_copper_door";
public const WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:wayfinder_armor_trim_smithing_template"; public const WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:wayfinder_armor_trim_smithing_template";
public const WEATHERED_COPPER_DOOR = "minecraft:weathered_copper_door";
public const WHEAT = "minecraft:wheat"; public const WHEAT = "minecraft:wheat";
public const WHEAT_SEEDS = "minecraft:wheat_seeds"; public const WHEAT_SEEDS = "minecraft:wheat_seeds";
public const WHITE_DYE = "minecraft:white_dye"; public const WHITE_DYE = "minecraft:white_dye";

View File

@ -173,8 +173,9 @@ abstract class Projectile extends Entity{
$entityHit = null; $entityHit = null;
$hitResult = null; $hitResult = null;
$world = $this->getWorld();
foreach(VoxelRayTrace::betweenPoints($start, $end) as $vector3){ foreach(VoxelRayTrace::betweenPoints($start, $end) as $vector3){
$block = $this->getWorld()->getBlockAt($vector3->x, $vector3->y, $vector3->z); $block = $world->getBlockAt($vector3->x, $vector3->y, $vector3->z);
$blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end); $blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end);
if($blockHitResult !== null){ if($blockHitResult !== null){
@ -188,7 +189,7 @@ abstract class Projectile extends Entity{
$entityDistance = PHP_INT_MAX; $entityDistance = PHP_INT_MAX;
$newDiff = $end->subtractVector($start); $newDiff = $end->subtractVector($start);
foreach($this->getWorld()->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){ foreach($world->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){
if($entity->getId() === $this->getOwningEntityId() && $this->ticksLived < 5){ if($entity->getId() === $this->getOwningEntityId() && $this->ticksLived < 5){
continue; continue;
} }
@ -256,7 +257,7 @@ abstract class Projectile extends Entity{
); );
} }
$this->getWorld()->onEntityMoved($this); $world->onEntityMoved($this);
$this->checkBlockIntersections(); $this->checkBlockIntersections();
Timings::$projectileMove->stopTiming(); Timings::$projectileMove->stopTiming();

View File

@ -31,8 +31,9 @@ class Snowball extends Throwable{
public function getNetworkTypeId() : string{ return EntityIds::SNOWBALL; } public function getNetworkTypeId() : string{ return EntityIds::SNOWBALL; }
protected function onHit(ProjectileHitEvent $event) : void{ protected function onHit(ProjectileHitEvent $event) : void{
$world = $this->getWorld();
for($i = 0; $i < 6; ++$i){ for($i = 0; $i < 6; ++$i){
$this->getWorld()->addParticle($this->location, new SnowballPoofParticle()); $world->addParticle($this->location, new SnowballPoofParticle());
} }
} }
} }

View File

@ -322,8 +322,9 @@ final class ItemTypeIds{
public const RIB_ARMOR_TRIM_SMITHING_TEMPLATE = 20283; public const RIB_ARMOR_TRIM_SMITHING_TEMPLATE = 20283;
public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = 20284; public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = 20284;
public const SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = 20285; public const SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = 20285;
public const PITCHER_POD = 20286;
public const FIRST_UNUSED_ITEM_ID = 20286; public const FIRST_UNUSED_ITEM_ID = 20287;
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID; private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;

34
src/item/PitcherPod.php Normal file
View File

@ -0,0 +1,34 @@
<?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\item;
use pocketmine\block\Block;
use pocketmine\block\VanillaBlocks;
final class PitcherPod extends Item{
public function getBlock(?int $clickedFace = null) : Block{
return VanillaBlocks::PITCHER_CROP();
}
}

View File

@ -868,6 +868,7 @@ final class StringToItemParser extends StringToTParser{
$result->registerBlock("pink_petals", fn() => Blocks::PINK_PETALS()); $result->registerBlock("pink_petals", fn() => Blocks::PINK_PETALS());
$result->registerBlock("pink_tulip", fn() => Blocks::PINK_TULIP()); $result->registerBlock("pink_tulip", fn() => Blocks::PINK_TULIP());
$result->registerBlock("piglin_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PIGLIN)); $result->registerBlock("piglin_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PIGLIN));
$result->registerBlock("pitcher_plant", fn() => Blocks::PITCHER_PLANT());
$result->registerBlock("plank", fn() => Blocks::OAK_PLANKS()); $result->registerBlock("plank", fn() => Blocks::OAK_PLANKS());
$result->registerBlock("planks", fn() => Blocks::OAK_PLANKS()); $result->registerBlock("planks", fn() => Blocks::OAK_PLANKS());
$result->registerBlock("player_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PLAYER)); $result->registerBlock("player_head", fn() => Blocks::MOB_HEAD()->setMobHeadType(MobHeadType::PLAYER));
@ -1405,6 +1406,7 @@ final class StringToItemParser extends StringToTParser{
$result->register("painting", fn() => Items::PAINTING()); $result->register("painting", fn() => Items::PAINTING());
$result->register("paper", fn() => Items::PAPER()); $result->register("paper", fn() => Items::PAPER());
$result->register("phantom_membrane", fn() => Items::PHANTOM_MEMBRANE()); $result->register("phantom_membrane", fn() => Items::PHANTOM_MEMBRANE());
$result->register("pitcher_pod", fn() => Items::PITCHER_POD());
$result->register("poisonous_potato", fn() => Items::POISONOUS_POTATO()); $result->register("poisonous_potato", fn() => Items::POISONOUS_POTATO());
$result->register("popped_chorus_fruit", fn() => Items::POPPED_CHORUS_FRUIT()); $result->register("popped_chorus_fruit", fn() => Items::POPPED_CHORUS_FRUIT());
$result->register("porkchop", fn() => Items::RAW_PORKCHOP()); $result->register("porkchop", fn() => Items::RAW_PORKCHOP());

View File

@ -240,6 +240,7 @@ use function strtolower;
* @method static PaintingItem PAINTING() * @method static PaintingItem PAINTING()
* @method static Item PAPER() * @method static Item PAPER()
* @method static Item PHANTOM_MEMBRANE() * @method static Item PHANTOM_MEMBRANE()
* @method static PitcherPod PITCHER_POD()
* @method static PoisonousPotato POISONOUS_POTATO() * @method static PoisonousPotato POISONOUS_POTATO()
* @method static Item POPPED_CHORUS_FRUIT() * @method static Item POPPED_CHORUS_FRUIT()
* @method static Potato POTATO() * @method static Potato POTATO()
@ -503,6 +504,7 @@ final class VanillaItems{
self::register("painting", new PaintingItem(new IID(Ids::PAINTING), "Painting")); self::register("painting", new PaintingItem(new IID(Ids::PAINTING), "Painting"));
self::register("paper", new Item(new IID(Ids::PAPER), "Paper")); self::register("paper", new Item(new IID(Ids::PAPER), "Paper"));
self::register("phantom_membrane", new Item(new IID(Ids::PHANTOM_MEMBRANE), "Phantom Membrane")); self::register("phantom_membrane", new Item(new IID(Ids::PHANTOM_MEMBRANE), "Phantom Membrane"));
self::register("pitcher_pod", new PitcherPod(new IID(Ids::PITCHER_POD), "Pitcher Pod"));
self::register("poisonous_potato", new PoisonousPotato(new IID(Ids::POISONOUS_POTATO), "Poisonous Potato")); self::register("poisonous_potato", new PoisonousPotato(new IID(Ids::POISONOUS_POTATO), "Poisonous Potato"));
self::register("popped_chorus_fruit", new Item(new IID(Ids::POPPED_CHORUS_FRUIT), "Popped Chorus Fruit")); self::register("popped_chorus_fruit", new Item(new IID(Ids::POPPED_CHORUS_FRUIT), "Popped Chorus Fruit"));
self::register("potato", new Potato(new IID(Ids::POTATO), "Potato")); self::register("potato", new Potato(new IID(Ids::POTATO), "Potato"));

View File

@ -117,6 +117,7 @@ use function count;
use function get_class; use function get_class;
use function implode; use function implode;
use function in_array; use function in_array;
use function is_string;
use function json_encode; use function json_encode;
use function random_bytes; use function random_bytes;
use function str_split; use function str_split;
@ -158,8 +159,8 @@ class NetworkSession{
private array $sendBuffer = []; private array $sendBuffer = [];
/** /**
* @var \SplQueue|CompressBatchPromise[] * @var \SplQueue|CompressBatchPromise[]|string[]
* @phpstan-var \SplQueue<CompressBatchPromise> * @phpstan-var \SplQueue<CompressBatchPromise|string>
*/ */
private \SplQueue $compressedQueue; private \SplQueue $compressedQueue;
private bool $forceAsyncCompression = true; private bool $forceAsyncCompression = true;
@ -235,8 +236,10 @@ class NetworkSession{
$this->onPlayerCreated(...), $this->onPlayerCreated(...),
function() : void{ function() : void{
//TODO: this should never actually occur... right? //TODO: this should never actually occur... right?
$this->logger->error("Failed to create player"); $this->disconnectWithError(
$this->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_error_internal()); reason: "Failed to create player",
disconnectScreenMessage: KnownTranslationFactory::pocketmine_disconnect_error_internal()
);
} }
); );
} }
@ -525,13 +528,12 @@ class NetworkSession{
PacketBatch::encodeRaw($stream, $this->sendBuffer); PacketBatch::encodeRaw($stream, $this->sendBuffer);
if($this->enableCompression){ if($this->enableCompression){
$promise = $this->server->prepareBatch($stream->getBuffer(), $this->compressor, $syncMode, Timings::$playerNetworkSendCompressSessionBuffer); $batch = $this->server->prepareBatch($stream->getBuffer(), $this->compressor, $syncMode, Timings::$playerNetworkSendCompressSessionBuffer);
}else{ }else{
$promise = new CompressBatchPromise(); $batch = $stream->getBuffer();
$promise->resolve($stream->getBuffer());
} }
$this->sendBuffer = []; $this->sendBuffer = [];
$this->queueCompressedNoBufferFlush($promise, $immediate); $this->queueCompressedNoBufferFlush($batch, $immediate);
}finally{ }finally{
Timings::$playerNetworkSend->stopTiming(); Timings::$playerNetworkSend->stopTiming();
} }
@ -550,7 +552,7 @@ class NetworkSession{
public function getTypeConverter() : TypeConverter{ return $this->typeConverter; } public function getTypeConverter() : TypeConverter{ return $this->typeConverter; }
public function queueCompressed(CompressBatchPromise $payload, bool $immediate = false) : void{ public function queueCompressed(CompressBatchPromise|string $payload, bool $immediate = false) : void{
Timings::$playerNetworkSend->startTiming(); Timings::$playerNetworkSend->startTiming();
try{ try{
$this->flushSendBuffer($immediate); //Maintain ordering if possible $this->flushSendBuffer($immediate); //Maintain ordering if possible
@ -560,38 +562,51 @@ class NetworkSession{
} }
} }
private function queueCompressedNoBufferFlush(CompressBatchPromise $payload, bool $immediate = false) : void{ private function queueCompressedNoBufferFlush(CompressBatchPromise|string $batch, bool $immediate = false) : void{
Timings::$playerNetworkSend->startTiming(); Timings::$playerNetworkSend->startTiming();
try{ try{
if(is_string($batch)){
if($immediate){ if($immediate){
//Skips all queues //Skips all queues
$this->sendEncoded($payload->getResult(), true); $this->sendEncoded($batch, true);
}else{ }else{
$this->compressedQueue->enqueue($payload); $this->compressedQueue->enqueue($batch);
$payload->onResolve(function(CompressBatchPromise $payload) : void{ $this->flushCompressedQueue();
if($this->connected && $this->compressedQueue->bottom() === $payload){
Timings::$playerNetworkSend->startTiming();
try{
$this->compressedQueue->dequeue(); //result unused
$this->sendEncoded($payload->getResult());
while(!$this->compressedQueue->isEmpty()){
/** @var CompressBatchPromise $current */
$current = $this->compressedQueue->bottom();
if($current->hasResult()){
$this->compressedQueue->dequeue();
$this->sendEncoded($current->getResult());
}else{
//can't send any more queued until this one is ready
break;
} }
}elseif($immediate){
//Skips all queues
$this->sendEncoded($batch->getResult(), true);
}else{
$this->compressedQueue->enqueue($batch);
$batch->onResolve(function() : void{
if($this->connected){
$this->flushCompressedQueue();
}
});
} }
}finally{ }finally{
Timings::$playerNetworkSend->stopTiming(); Timings::$playerNetworkSend->stopTiming();
} }
} }
});
private function flushCompressedQueue() : void{
Timings::$playerNetworkSend->startTiming();
try{
while(!$this->compressedQueue->isEmpty()){
/** @var CompressBatchPromise|string $current */
$current = $this->compressedQueue->bottom();
if(is_string($current)){
$this->compressedQueue->dequeue();
$this->sendEncoded($current);
}elseif($current->hasResult()){
$this->compressedQueue->dequeue();
$this->sendEncoded($current->getResult());
}else{
//can't send any more queued until this one is ready
break;
}
} }
}finally{ }finally{
Timings::$playerNetworkSend->stopTiming(); Timings::$playerNetworkSend->stopTiming();
@ -662,8 +677,13 @@ class NetworkSession{
}, $reason); }, $reason);
} }
public function disconnectWithError(Translatable|string $reason) : void{ public function disconnectWithError(Translatable|string $reason, Translatable|string|null $disconnectScreenMessage = null) : void{
$this->disconnect(KnownTranslationFactory::pocketmine_disconnect_error($reason, implode("-", str_split(bin2hex(random_bytes(6)), 4)))); $errorId = implode("-", str_split(bin2hex(random_bytes(6)), 4));
$this->disconnect(
reason: KnownTranslationFactory::pocketmine_disconnect_error($reason, $errorId)->prefix(TextFormat::RED),
disconnectScreenMessage: KnownTranslationFactory::pocketmine_disconnect_error($disconnectScreenMessage ?? $reason, $errorId),
);
} }
public function disconnectIncompatibleProtocol(int $protocolVersion) : void{ public function disconnectIncompatibleProtocol(int $protocolVersion) : void{
@ -722,7 +742,10 @@ class NetworkSession{
} }
if($error !== null){ if($error !== null){
$this->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_invalidSession($error)); $this->disconnectWithError(
reason: KnownTranslationFactory::pocketmine_disconnect_invalidSession($error),
disconnectScreenMessage: KnownTranslationFactory::pocketmine_disconnect_error_authentication()
);
return; return;
} }
@ -1118,12 +1141,12 @@ class NetworkSession{
*/ */
public function syncPlayerList(array $players) : void{ public function syncPlayerList(array $players) : void{
$this->sendDataPacket(PlayerListPacket::add(array_map(function(Player $player) : PlayerListEntry{ $this->sendDataPacket(PlayerListPacket::add(array_map(function(Player $player) : PlayerListEntry{
return PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), TypeConverter::getInstance()->getSkinAdapter()->toSkinData($player->getSkin()), $player->getXuid()); return PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $this->typeConverter->getSkinAdapter()->toSkinData($player->getSkin()), $player->getXuid());
}, $players))); }, $players)));
} }
public function onPlayerAdded(Player $p) : void{ public function onPlayerAdded(Player $p) : void{
$this->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($p->getUniqueId(), $p->getId(), $p->getDisplayName(), TypeConverter::getInstance()->getSkinAdapter()->toSkinData($p->getSkin()), $p->getXuid())])); $this->sendDataPacket(PlayerListPacket::add([PlayerListEntry::createAdditionEntry($p->getUniqueId(), $p->getId(), $p->getDisplayName(), $this->typeConverter->getSkinAdapter()->toSkinData($p->getSkin()), $p->getXuid())]));
} }
public function onPlayerRemoved(Player $p) : void{ public function onPlayerRemoved(Player $p) : void{

View File

@ -88,9 +88,9 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
PacketBatch::encodeRaw($stream, $packetBuffers); PacketBatch::encodeRaw($stream, $packetBuffers);
$batchBuffer = $stream->getBuffer(); $batchBuffer = $stream->getBuffer();
$promise = $this->server->prepareBatch($batchBuffer, $compressor, timings: Timings::$playerNetworkSendCompressBroadcast); $batch = $this->server->prepareBatch($batchBuffer, $compressor, timings: Timings::$playerNetworkSendCompressBroadcast);
foreach($compressorTargets as $target){ foreach($compressorTargets as $target){
$target->queueCompressed($promise); $target->queueCompressed($batch);
} }
}else{ }else{
foreach($compressorTargets as $target){ foreach($compressorTargets as $target){

View File

@ -136,32 +136,19 @@ class ChunkCache implements ChunkListener{
return $existing !== null; return $existing !== null;
} }
/**
* Restarts an async request for an unresolved chunk.
*
* @throws \InvalidArgumentException
*/
private function restartPendingRequest(int $chunkX, int $chunkZ) : void{
$chunkHash = World::chunkHash($chunkX, $chunkZ);
$existing = $this->caches[$chunkHash] ?? null;
if($existing === null || $existing->hasResult()){
throw new \InvalidArgumentException("Restart can only be applied to unresolved promises");
}
$existing->cancel();
unset($this->caches[$chunkHash]);
$this->request($chunkX, $chunkZ)->onResolve(...$existing->getResolveCallbacks());
}
/** /**
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
private function destroyOrRestart(int $chunkX, int $chunkZ) : void{ private function destroyOrRestart(int $chunkX, int $chunkZ) : void{
$cache = $this->caches[World::chunkHash($chunkX, $chunkZ)] ?? null; $chunkPosHash = World::chunkHash($chunkX, $chunkZ);
$cache = $this->caches[$chunkPosHash] ?? null;
if($cache !== null){ if($cache !== null){
if(!$cache->hasResult()){ if(!$cache->hasResult()){
//some requesters are waiting for this chunk, so their request needs to be fulfilled //some requesters are waiting for this chunk, so their request needs to be fulfilled
$this->restartPendingRequest($chunkX, $chunkZ); $cache->cancel();
unset($this->caches[$chunkPosHash]);
$this->request($chunkX, $chunkZ)->onResolve(...$cache->getResolveCallbacks());
}else{ }else{
//dump the cache, it'll be regenerated the next time it's requested //dump the cache, it'll be regenerated the next time it's requested
$this->destroy($chunkX, $chunkZ); $this->destroy($chunkX, $chunkZ);

View File

@ -160,7 +160,7 @@ final class CraftingDataCache{
} }
$potionContainerChangeRecipes = []; $potionContainerChangeRecipes = [];
$itemTypeDictionary = TypeConverter::getInstance()->getItemTypeDictionary(); $itemTypeDictionary = $converter->getItemTypeDictionary();
foreach($manager->getPotionContainerChangeRecipes() as $recipe){ foreach($manager->getPotionContainerChangeRecipes() as $recipe){
$input = $itemTypeDictionary->fromStringId($recipe->getInputItemId()); $input = $itemTypeDictionary->fromStringId($recipe->getInputItemId());
$ingredient = $converter->coreRecipeIngredientToNet($recipe->getIngredient())->getDescriptor(); $ingredient = $converter->coreRecipeIngredientToNet($recipe->getIngredient())->getDescriptor();

View File

@ -57,7 +57,6 @@ use pocketmine\network\mcpe\protocol\BossEventPacket;
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket; use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
use pocketmine\network\mcpe\protocol\CommandRequestPacket; use pocketmine\network\mcpe\protocol\CommandRequestPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket; use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
use pocketmine\network\mcpe\protocol\EmotePacket; use pocketmine\network\mcpe\protocol\EmotePacket;
use pocketmine\network\mcpe\protocol\InteractPacket; use pocketmine\network\mcpe\protocol\InteractPacket;
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket; use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
@ -731,10 +730,6 @@ class InGamePacketHandler extends PacketHandler{
return true; //this packet is useless return true; //this packet is useless
} }
public function handleCraftingEvent(CraftingEventPacket $packet) : bool{
return true; //this is a broken useless packet, so we don't use it
}
public function handleBlockActorData(BlockActorDataPacket $packet) : bool{ public function handleBlockActorData(BlockActorDataPacket $packet) : bool{
$pos = new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ()); $pos = new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ());
if($pos->distanceSquared($this->player->getLocation()) > 10000){ if($pos->distanceSquared($this->player->getLocation()) > 10000){

View File

@ -73,8 +73,10 @@ class LoginPacketHandler extends PacketHandler{
try{ try{
$skin = $this->session->getTypeConverter()->getSkinAdapter()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData)); $skin = $this->session->getTypeConverter()->getSkinAdapter()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData));
}catch(\InvalidArgumentException | InvalidSkinException $e){ }catch(\InvalidArgumentException | InvalidSkinException $e){
$this->session->getLogger()->debug("Invalid skin: " . $e->getMessage()); $this->session->disconnectWithError(
$this->session->disconnectWithError(KnownTranslationFactory::disconnectionScreen_invalidSkin()); reason: "Invalid skin: " . $e->getMessage(),
disconnectScreenMessage: KnownTranslationFactory::disconnectionScreen_invalidSkin()
);
return true; return true;
} }

View File

@ -85,8 +85,10 @@ class ResourcePacksPacketHandler extends PacketHandler{
} }
private function disconnectWithError(string $error) : void{ private function disconnectWithError(string $error) : void{
$this->session->getLogger()->error("Error downloading resource packs: " . $error); $this->session->disconnectWithError(
$this->session->disconnectWithError(KnownTranslationFactory::disconnectionScreen_resourcePack()); reason: "Error downloading resource packs: " . $error,
disconnectScreenMessage: KnownTranslationFactory::disconnectionScreen_resourcePack()
);
} }
public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{ public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{

View File

@ -219,11 +219,14 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
$session->handleEncoded($buf); $session->handleEncoded($buf);
}catch(PacketHandlingException $e){ }catch(PacketHandlingException $e){
$logger = $session->getLogger(); $logger = $session->getLogger();
$logger->error("Bad packet: " . $e->getMessage());
$session->disconnectWithError(
reason: "Bad packet: " . $e->getMessage(),
disconnectScreenMessage: KnownTranslationFactory::pocketmine_disconnect_error_badPacket()
);
//intentionally doesn't use logException, we don't want spammy packet error traces to appear in release mode //intentionally doesn't use logException, we don't want spammy packet error traces to appear in release mode
$logger->debug(implode("\n", Utils::printableExceptionInfo($e))); $logger->debug(implode("\n", Utils::printableExceptionInfo($e)));
$session->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_error_badPacket());
$this->interface->blockAddress($address, 5); $this->interface->blockAddress($address, 5);
}catch(\Throwable $e){ }catch(\Throwable $e){
//record the name of the player who caused the crash, to make it easier to find the reproducing steps //record the name of the player who caused the crash, to make it easier to find the reproducing steps

View File

@ -818,13 +818,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
$this->usedChunks[$index] = UsedChunkStatus::REQUESTED_GENERATION; $this->usedChunks[$index] = UsedChunkStatus::REQUESTED_GENERATION;
$this->activeChunkGenerationRequests[$index] = true; $this->activeChunkGenerationRequests[$index] = true;
unset($this->loadQueue[$index]); unset($this->loadQueue[$index]);
$this->getWorld()->registerChunkLoader($this->chunkLoader, $X, $Z, true); $world->registerChunkLoader($this->chunkLoader, $X, $Z, true);
$this->getWorld()->registerChunkListener($this, $X, $Z); $world->registerChunkListener($this, $X, $Z);
if(isset($this->tickingChunks[$index])){ if(isset($this->tickingChunks[$index])){
$this->getWorld()->registerTickingChunk($this->chunkTicker, $X, $Z); $world->registerTickingChunk($this->chunkTicker, $X, $Z);
} }
$this->getWorld()->requestChunkPopulation($X, $Z, $this->chunkLoader)->onCompletion( $world->requestChunkPopulation($X, $Z, $this->chunkLoader)->onCompletion(
function() use ($X, $Z, $index, $world) : void{ function() use ($X, $Z, $index, $world) : void{
if(!$this->isConnected() || !isset($this->usedChunks[$index]) || $world !== $this->getWorld()){ if(!$this->isConnected() || !isset($this->usedChunks[$index]) || $world !== $this->getWorld()){
return; return;

View File

@ -73,7 +73,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
$this->configFile = Path::join($this->dataFolder, "config.yml"); $this->configFile = Path::join($this->dataFolder, "config.yml");
$prefix = $this->getDescription()->getPrefix(); $prefix = $this->description->getPrefix();
$this->logger = new PluginLogger($server->getLogger(), $prefix !== "" ? $prefix : $this->getName()); $this->logger = new PluginLogger($server->getLogger(), $prefix !== "" ? $prefix : $this->getName());
$this->scheduler = new TaskScheduler($this->getFullName()); $this->scheduler = new TaskScheduler($this->getFullName());
@ -148,9 +148,9 @@ abstract class PluginBase implements Plugin, CommandExecutor{
private function registerYamlCommands() : void{ private function registerYamlCommands() : void{
$pluginCmds = []; $pluginCmds = [];
foreach(Utils::stringifyKeys($this->getDescription()->getCommands()) as $key => $data){ foreach(Utils::stringifyKeys($this->description->getCommands()) as $key => $data){
if(str_contains($key, ":")){ if(str_contains($key, ":")){
$this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_commandError($key, $this->getDescription()->getFullName(), ":"))); $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_commandError($key, $this->description->getFullName(), ":")));
continue; continue;
} }
@ -166,7 +166,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
$aliasList = []; $aliasList = [];
foreach($data->getAliases() as $alias){ foreach($data->getAliases() as $alias){
if(str_contains($alias, ":")){ if(str_contains($alias, ":")){
$this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_aliasError($alias, $this->getDescription()->getFullName(), ":"))); $this->logger->error($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_aliasError($alias, $this->description->getFullName(), ":")));
continue; continue;
} }
$aliasList[] = $alias; $aliasList[] = $alias;
@ -184,7 +184,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
} }
if(count($pluginCmds) > 0){ if(count($pluginCmds) > 0){
$this->server->getCommandMap()->registerAll($this->getDescription()->getName(), $pluginCmds); $this->server->getCommandMap()->registerAll($this->description->getName(), $pluginCmds);
} }
} }
@ -193,9 +193,9 @@ abstract class PluginBase implements Plugin, CommandExecutor{
* @phpstan-return (Command&PluginOwned)|null * @phpstan-return (Command&PluginOwned)|null
*/ */
public function getCommand(string $name){ public function getCommand(string $name){
$command = $this->getServer()->getPluginCommand($name); $command = $this->server->getPluginCommand($name);
if($command === null || $command->getOwningPlugin() !== $this){ if($command === null || $command->getOwningPlugin() !== $this){
$command = $this->getServer()->getPluginCommand(strtolower($this->description->getName()) . ":" . $name); $command = $this->server->getPluginCommand(strtolower($this->description->getName()) . ":" . $name);
} }
if($command instanceof PluginOwned && $command->getOwningPlugin() === $this){ if($command instanceof PluginOwned && $command->getOwningPlugin() === $this){

View File

@ -28,6 +28,7 @@ use pmmp\thread\Thread as NativeThread;
use pmmp\thread\ThreadSafe; use pmmp\thread\ThreadSafe;
use pmmp\thread\ThreadSafeArray; use pmmp\thread\ThreadSafeArray;
use pocketmine\thread\NonThreadSafeValue; use pocketmine\thread\NonThreadSafeValue;
use function array_key_exists;
use function assert; use function assert;
use function igbinary_serialize; use function igbinary_serialize;
use function igbinary_unserialize; use function igbinary_unserialize;
@ -202,7 +203,7 @@ abstract class AsyncTask extends Runnable{
*/ */
protected function fetchLocal(string $key){ protected function fetchLocal(string $key){
$id = spl_object_id($this); $id = spl_object_id($this);
if(!isset(self::$threadLocalStorage[$id][$key])){ if(!isset(self::$threadLocalStorage[$id]) || !array_key_exists($key, self::$threadLocalStorage[$id])){
throw new \InvalidArgumentException("No matching thread-local data found on this thread"); throw new \InvalidArgumentException("No matching thread-local data found on this thread");
} }

View File

@ -35,6 +35,7 @@ use function get_class;
use function str_starts_with; use function str_starts_with;
abstract class Timings{ abstract class Timings{
public const GROUP_MINECRAFT = "Minecraft";
public const GROUP_BREAKDOWN = "Minecraft - Breakdown"; public const GROUP_BREAKDOWN = "Minecraft - Breakdown";
private static bool $initialized = false; private static bool $initialized = false;
@ -134,8 +135,8 @@ abstract class Timings{
self::$initialized = true; self::$initialized = true;
self::$fullTick = new TimingsHandler("Full Server Tick"); self::$fullTick = new TimingsHandler("Full Server Tick");
self::$serverTick = new TimingsHandler("Server Tick Update Cycle", self::$fullTick, group: self::GROUP_BREAKDOWN); self::$serverTick = new TimingsHandler("Server Tick Update Cycle", self::$fullTick);
self::$serverInterrupts = new TimingsHandler("Server Mid-Tick Processing", self::$fullTick, group: self::GROUP_BREAKDOWN); self::$serverInterrupts = new TimingsHandler("Server Mid-Tick Processing", self::$fullTick);
self::$memoryManager = new TimingsHandler("Memory Manager"); self::$memoryManager = new TimingsHandler("Memory Manager");
self::$garbageCollector = new TimingsHandler("Garbage Collector", self::$memoryManager); self::$garbageCollector = new TimingsHandler("Garbage Collector", self::$memoryManager);
self::$titleTick = new TimingsHandler("Console Title Tick"); self::$titleTick = new TimingsHandler("Console Title Tick");
@ -143,51 +144,51 @@ abstract class Timings{
self::$connection = new TimingsHandler("Connection Handler"); self::$connection = new TimingsHandler("Connection Handler");
self::$playerNetworkSend = new TimingsHandler("Player Network Send", self::$connection); self::$playerNetworkSend = new TimingsHandler("Player Network Send", self::$connection);
self::$playerNetworkSendCompress = new TimingsHandler("Player Network Send - Compression", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN); self::$playerNetworkSendCompress = new TimingsHandler("Player Network Send - Compression", self::$playerNetworkSend);
self::$playerNetworkSendCompressBroadcast = new TimingsHandler("Player Network Send - Compression (Broadcast)", self::$playerNetworkSendCompress, group: self::GROUP_BREAKDOWN); self::$playerNetworkSendCompressBroadcast = new TimingsHandler("Player Network Send - Compression (Broadcast)", self::$playerNetworkSendCompress);
self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler("Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress, group: self::GROUP_BREAKDOWN); self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler("Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress);
self::$playerNetworkSendEncrypt = new TimingsHandler("Player Network Send - Encryption", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN); self::$playerNetworkSendEncrypt = new TimingsHandler("Player Network Send - Encryption", self::$playerNetworkSend);
self::$playerNetworkSendInventorySync = new TimingsHandler("Player Network Send - Inventory Sync", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN); self::$playerNetworkSendInventorySync = new TimingsHandler("Player Network Send - Inventory Sync", self::$playerNetworkSend);
self::$playerNetworkSendPreSpawnGameData = new TimingsHandler("Player Network Send - Pre-Spawn Game Data", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN); self::$playerNetworkSendPreSpawnGameData = new TimingsHandler("Player Network Send - Pre-Spawn Game Data", self::$playerNetworkSend);
self::$playerNetworkReceive = new TimingsHandler("Player Network Receive", self::$connection); self::$playerNetworkReceive = new TimingsHandler("Player Network Receive", self::$connection);
self::$playerNetworkReceiveDecompress = new TimingsHandler("Player Network Receive - Decompression", self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN); self::$playerNetworkReceiveDecompress = new TimingsHandler("Player Network Receive - Decompression", self::$playerNetworkReceive);
self::$playerNetworkReceiveDecrypt = new TimingsHandler("Player Network Receive - Decryption", self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN); self::$playerNetworkReceiveDecrypt = new TimingsHandler("Player Network Receive - Decryption", self::$playerNetworkReceive);
self::$broadcastPackets = new TimingsHandler("Broadcast Packets", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN); self::$broadcastPackets = new TimingsHandler("Broadcast Packets", self::$playerNetworkSend);
self::$playerMove = new TimingsHandler("Player Movement"); self::$playerMove = new TimingsHandler("Player Movement");
self::$playerChunkOrder = new TimingsHandler("Player Order Chunks"); self::$playerChunkOrder = new TimingsHandler("Player Order Chunks");
self::$playerChunkSend = new TimingsHandler("Player Network Send - Chunks", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN); self::$playerChunkSend = new TimingsHandler("Player Network Send - Chunks", self::$playerNetworkSend);
self::$scheduler = new TimingsHandler("Scheduler"); self::$scheduler = new TimingsHandler("Scheduler");
self::$serverCommand = new TimingsHandler("Server Command"); self::$serverCommand = new TimingsHandler("Server Command");
self::$permissibleCalculation = new TimingsHandler("Permissible Calculation"); self::$permissibleCalculation = new TimingsHandler("Permissible Calculation");
self::$permissibleCalculationDiff = new TimingsHandler("Permissible Calculation - Diff", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN); self::$permissibleCalculationDiff = new TimingsHandler("Permissible Calculation - Diff", self::$permissibleCalculation);
self::$permissibleCalculationCallback = new TimingsHandler("Permissible Calculation - Callbacks", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN); self::$permissibleCalculationCallback = new TimingsHandler("Permissible Calculation - Callbacks", self::$permissibleCalculation);
self::$syncPlayerDataLoad = new TimingsHandler("Player Data Load"); self::$syncPlayerDataLoad = new TimingsHandler("Player Data Load");
self::$syncPlayerDataSave = new TimingsHandler("Player Data Save"); self::$syncPlayerDataSave = new TimingsHandler("Player Data Save");
self::$entityMove = new TimingsHandler("Entity Movement", group: self::GROUP_BREAKDOWN); self::$entityMove = new TimingsHandler("Entity Movement");
self::$entityMoveCollision = new TimingsHandler("Entity Movement - Collision Checks", self::$entityMove, group: self::GROUP_BREAKDOWN); self::$entityMoveCollision = new TimingsHandler("Entity Movement - Collision Checks", self::$entityMove);
self::$projectileMove = new TimingsHandler("Projectile Movement", self::$entityMove, group: self::GROUP_BREAKDOWN); self::$projectileMove = new TimingsHandler("Projectile Movement", self::$entityMove);
self::$projectileMoveRayTrace = new TimingsHandler("Projectile Movement - Ray Tracing", self::$projectileMove, group: self::GROUP_BREAKDOWN); self::$projectileMoveRayTrace = new TimingsHandler("Projectile Movement - Ray Tracing", self::$projectileMove);
self::$playerCheckNearEntities = new TimingsHandler("checkNearEntities", group: self::GROUP_BREAKDOWN); self::$playerCheckNearEntities = new TimingsHandler("checkNearEntities");
self::$entityBaseTick = new TimingsHandler("Entity Base Tick", group: self::GROUP_BREAKDOWN); self::$entityBaseTick = new TimingsHandler("Entity Base Tick");
self::$livingEntityBaseTick = new TimingsHandler("Entity Base Tick - Living", group: self::GROUP_BREAKDOWN); self::$livingEntityBaseTick = new TimingsHandler("Entity Base Tick - Living");
self::$itemEntityBaseTick = new TimingsHandler("Entity Base Tick - ItemEntity", group: self::GROUP_BREAKDOWN); self::$itemEntityBaseTick = new TimingsHandler("Entity Base Tick - ItemEntity");
self::$schedulerSync = new TimingsHandler("Scheduler - Sync Tasks", group: self::GROUP_BREAKDOWN); self::$schedulerSync = new TimingsHandler("Scheduler - Sync Tasks");
self::$schedulerAsync = new TimingsHandler("Scheduler - Async Tasks", group: self::GROUP_BREAKDOWN); self::$schedulerAsync = new TimingsHandler("Scheduler - Async Tasks");
self::$asyncTaskProgressUpdateParent = new TimingsHandler("Async Tasks - Progress Updates", self::$schedulerAsync, group: self::GROUP_BREAKDOWN); self::$asyncTaskProgressUpdateParent = new TimingsHandler("Async Tasks - Progress Updates", self::$schedulerAsync);
self::$asyncTaskCompletionParent = new TimingsHandler("Async Tasks - Completion Handlers", self::$schedulerAsync, group: self::GROUP_BREAKDOWN); self::$asyncTaskCompletionParent = new TimingsHandler("Async Tasks - Completion Handlers", self::$schedulerAsync);
self::$asyncTaskErrorParent = new TimingsHandler("Async Tasks - Error Handlers", self::$schedulerAsync, group: self::GROUP_BREAKDOWN); self::$asyncTaskErrorParent = new TimingsHandler("Async Tasks - Error Handlers", self::$schedulerAsync);
self::$playerCommand = new TimingsHandler("Player Command", group: self::GROUP_BREAKDOWN); self::$playerCommand = new TimingsHandler("Player Command");
self::$craftingDataCacheRebuild = new TimingsHandler("Build CraftingDataPacket Cache", group: self::GROUP_BREAKDOWN); self::$craftingDataCacheRebuild = new TimingsHandler("Build CraftingDataPacket Cache");
} }
@ -229,7 +230,7 @@ abstract class Timings{
}else{ }else{
$displayName = self::shortenCoreClassName($entity::class, "pocketmine\\entity\\"); $displayName = self::shortenCoreClassName($entity::class, "pocketmine\\entity\\");
} }
self::$entityTypeTimingMap[$entity::class] = new TimingsHandler("Entity Tick - " . $displayName, group: self::GROUP_BREAKDOWN); self::$entityTypeTimingMap[$entity::class] = new TimingsHandler("Entity Tick - " . $displayName);
} }
return self::$entityTypeTimingMap[$entity::class]; return self::$entityTypeTimingMap[$entity::class];
@ -239,8 +240,7 @@ abstract class Timings{
self::init(); self::init();
if(!isset(self::$tileEntityTypeTimingMap[$tile::class])){ if(!isset(self::$tileEntityTypeTimingMap[$tile::class])){
self::$tileEntityTypeTimingMap[$tile::class] = new TimingsHandler( self::$tileEntityTypeTimingMap[$tile::class] = new TimingsHandler(
"Block Entity Tick - " . self::shortenCoreClassName($tile::class, "pocketmine\\block\\tile\\"), "Block Entity Tick - " . self::shortenCoreClassName($tile::class, "pocketmine\\block\\tile\\")
group: self::GROUP_BREAKDOWN
); );
} }
@ -250,7 +250,7 @@ abstract class Timings{
public static function getReceiveDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{ public static function getReceiveDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
self::init(); self::init();
if(!isset(self::$packetReceiveTimingMap[$pk::class])){ if(!isset(self::$packetReceiveTimingMap[$pk::class])){
self::$packetReceiveTimingMap[$pk::class] = new TimingsHandler("Receive - " . $pk->getName(), self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN); self::$packetReceiveTimingMap[$pk::class] = new TimingsHandler("Receive - " . $pk->getName(), self::$playerNetworkReceive);
} }
return self::$packetReceiveTimingMap[$pk::class]; return self::$packetReceiveTimingMap[$pk::class];
@ -259,31 +259,28 @@ abstract class Timings{
public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{ public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
return self::$packetDecodeTimingMap[$pk::class] ??= new TimingsHandler( return self::$packetDecodeTimingMap[$pk::class] ??= new TimingsHandler(
"Decode - " . $pk->getName(), "Decode - " . $pk->getName(),
self::getReceiveDataPacketTimings($pk), self::getReceiveDataPacketTimings($pk)
group: self::GROUP_BREAKDOWN
); );
} }
public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{ public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
return self::$packetHandleTimingMap[$pk::class] ??= new TimingsHandler( return self::$packetHandleTimingMap[$pk::class] ??= new TimingsHandler(
"Handler - " . $pk->getName(), "Handler - " . $pk->getName(),
self::getReceiveDataPacketTimings($pk), self::getReceiveDataPacketTimings($pk)
group: self::GROUP_BREAKDOWN
); );
} }
public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{ public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
return self::$packetEncodeTimingMap[$pk::class] ??= new TimingsHandler( return self::$packetEncodeTimingMap[$pk::class] ??= new TimingsHandler(
"Encode - " . $pk->getName(), "Encode - " . $pk->getName(),
self::getSendDataPacketTimings($pk), self::getSendDataPacketTimings($pk)
group: self::GROUP_BREAKDOWN
); );
} }
public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{ public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
self::init(); self::init();
if(!isset(self::$packetSendTimingMap[$pk::class])){ if(!isset(self::$packetSendTimingMap[$pk::class])){
self::$packetSendTimingMap[$pk::class] = new TimingsHandler("Send - " . $pk->getName(), self::$playerNetworkSend, group: self::GROUP_BREAKDOWN); self::$packetSendTimingMap[$pk::class] = new TimingsHandler("Send - " . $pk->getName(), self::$playerNetworkSend);
} }
return self::$packetSendTimingMap[$pk::class]; return self::$packetSendTimingMap[$pk::class];
@ -292,7 +289,7 @@ abstract class Timings{
public static function getCommandDispatchTimings(string $commandName) : TimingsHandler{ public static function getCommandDispatchTimings(string $commandName) : TimingsHandler{
self::init(); self::init();
return self::$commandTimingMap[$commandName] ??= new TimingsHandler("Command - " . $commandName, group: self::GROUP_BREAKDOWN); return self::$commandTimingMap[$commandName] ??= new TimingsHandler("Command - " . $commandName);
} }
public static function getEventTimings(Event $event) : TimingsHandler{ public static function getEventTimings(Event $event) : TimingsHandler{
@ -316,7 +313,7 @@ abstract class Timings{
return self::$eventHandlers[$event][$handlerName]; return self::$eventHandlers[$event][$handlerName];
} }
public static function getAsyncTaskProgressUpdateTimings(AsyncTask $task, string $group = self::GROUP_BREAKDOWN) : TimingsHandler{ public static function getAsyncTaskProgressUpdateTimings(AsyncTask $task, string $group = self::GROUP_MINECRAFT) : TimingsHandler{
$taskClass = $task::class; $taskClass = $task::class;
if(!isset(self::$asyncTaskProgressUpdate[$taskClass])){ if(!isset(self::$asyncTaskProgressUpdate[$taskClass])){
self::init(); self::init();
@ -330,7 +327,7 @@ abstract class Timings{
return self::$asyncTaskProgressUpdate[$taskClass]; return self::$asyncTaskProgressUpdate[$taskClass];
} }
public static function getAsyncTaskCompletionTimings(AsyncTask $task, string $group = self::GROUP_BREAKDOWN) : TimingsHandler{ public static function getAsyncTaskCompletionTimings(AsyncTask $task, string $group = self::GROUP_MINECRAFT) : TimingsHandler{
$taskClass = $task::class; $taskClass = $task::class;
if(!isset(self::$asyncTaskCompletion[$taskClass])){ if(!isset(self::$asyncTaskCompletion[$taskClass])){
self::init(); self::init();
@ -344,7 +341,7 @@ abstract class Timings{
return self::$asyncTaskCompletion[$taskClass]; return self::$asyncTaskCompletion[$taskClass];
} }
public static function getAsyncTaskErrorTimings(AsyncTask $task, string $group = self::GROUP_BREAKDOWN) : TimingsHandler{ public static function getAsyncTaskErrorTimings(AsyncTask $task, string $group = self::GROUP_MINECRAFT) : TimingsHandler{
$taskClass = $task::class; $taskClass = $task::class;
if(!isset(self::$asyncTaskError[$taskClass])){ if(!isset(self::$asyncTaskError[$taskClass])){
self::init(); self::init();

View File

@ -120,7 +120,7 @@ class TimingsHandler{
public function __construct( public function __construct(
private string $name, private string $name,
private ?TimingsHandler $parent = null, private ?TimingsHandler $parent = null,
private string $group = "Minecraft" private string $group = Timings::GROUP_MINECRAFT
){} ){}
public function getName() : string{ return $this->name; } public function getName() : string{ return $this->name; }

View File

@ -33,7 +33,7 @@ use function preg_match;
* These faux constants are exposed in static class methods, which are handled using __callStatic(). * These faux constants are exposed in static class methods, which are handled using __callStatic().
* *
* Classes using this trait need to include \@method tags in their class docblock for every faux constant. * Classes using this trait need to include \@method tags in their class docblock for every faux constant.
* Alternatively, just put \@generate-registry-docblock in the docblock and run tools/generate-registry-annotations.php * Alternatively, just put \@generate-registry-docblock in the docblock and run build/generate-registry-annotations.php
*/ */
trait RegistryTrait{ trait RegistryTrait{
/** /**

View File

@ -1016,8 +1016,12 @@ class World implements ChunkManager{
continue; continue;
} }
World::getXZ($index, $chunkX, $chunkZ); World::getXZ($index, $chunkX, $chunkZ);
if(!$this->isChunkLoaded($chunkX, $chunkZ)){
//a previous chunk may have caused this one to be unloaded by a ChunkListener
continue;
}
if(count($blocks) > 512){ if(count($blocks) > 512){
$chunk = $this->getChunk($chunkX, $chunkZ); $chunk = $this->getChunk($chunkX, $chunkZ) ?? throw new AssumptionFailedError("We already checked that the chunk is loaded");
foreach($this->getChunkPlayers($chunkX, $chunkZ) as $p){ foreach($this->getChunkPlayers($chunkX, $chunkZ) as $p){
$p->onChunkChanged($chunkX, $chunkZ, $chunk); $p->onChunkChanged($chunkX, $chunkZ, $chunk);
} }
@ -2623,7 +2627,7 @@ class World implements ChunkManager{
public function isChunkPopulated(int $x, int $z) : bool{ public function isChunkPopulated(int $x, int $z) : bool{
$chunk = $this->loadChunk($x, $z); $chunk = $this->loadChunk($x, $z);
return $chunk !== null ? $chunk->isPopulated() : false; return $chunk !== null && $chunk->isPopulated();
} }
/** /**

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\world; namespace pocketmine\world;
use pocketmine\timings\Timings;
use pocketmine\timings\TimingsHandler; use pocketmine\timings\TimingsHandler;
class WorldTimings{ class WorldTimings{
@ -66,7 +65,7 @@ class WorldTimings{
private static function newTimer(string $worldName, string $timerName) : TimingsHandler{ private static function newTimer(string $worldName, string $timerName) : TimingsHandler{
$aggregator = self::$aggregators[$timerName] ??= new TimingsHandler("Worlds - $timerName"); //displayed in Minecraft primary table $aggregator = self::$aggregators[$timerName] ??= new TimingsHandler("Worlds - $timerName"); //displayed in Minecraft primary table
return new TimingsHandler("$worldName - $timerName", $aggregator, Timings::GROUP_BREAKDOWN); return new TimingsHandler("$worldName - $timerName", $aggregator);
} }
public function __construct(World $world){ public function __construct(World $world){

View File

@ -51,12 +51,12 @@ use function time;
class BedrockWorldData extends BaseNbtWorldData{ class BedrockWorldData extends BaseNbtWorldData{
public const CURRENT_STORAGE_VERSION = 10; public const CURRENT_STORAGE_VERSION = 10;
public const CURRENT_STORAGE_NETWORK_VERSION = 622; public const CURRENT_STORAGE_NETWORK_VERSION = 630;
public const CURRENT_CLIENT_VERSION_TARGET = [ public const CURRENT_CLIENT_VERSION_TARGET = [
1, //major 1, //major
20, //minor 20, //minor
40, //patch 50, //patch
1, //revision 3, //revision
0 //is beta 0 //is beta
]; ];

View File

@ -32,7 +32,7 @@ parameters:
- -
message: "#^Cannot access offset 'git' on mixed\\.$#" message: "#^Cannot access offset 'git' on mixed\\.$#"
count: 2 count: 1
path: ../../../src/VersionInfo.php path: ../../../src/VersionInfo.php
- -
@ -807,7 +807,7 @@ parameters:
- -
message: "#^Cannot access offset string on mixed\\.$#" message: "#^Cannot access offset string on mixed\\.$#"
count: 3 count: 2
path: ../../../src/utils/Config.php path: ../../../src/utils/Config.php
- -
@ -965,11 +965,6 @@ parameters:
count: 2 count: 2
path: ../../../src/world/World.php path: ../../../src/world/World.php
-
message: "#^Parameter \\#3 \\$chunk of method pocketmine\\\\player\\\\Player\\:\\:onChunkChanged\\(\\) expects pocketmine\\\\world\\\\format\\\\Chunk, pocketmine\\\\world\\\\format\\\\Chunk\\|null given\\.$#"
count: 1
path: ../../../src/world/World.php
- -
message: "#^Parameter \\#3 \\$y of method pocketmine\\\\block\\\\Block\\:\\:position\\(\\) expects int, float\\|int given\\.$#" message: "#^Parameter \\#3 \\$y of method pocketmine\\\\block\\\\Block\\:\\:position\\(\\) expects int, float\\|int given\\.$#"
count: 2 count: 2

View File

@ -20,21 +20,6 @@ parameters:
count: 1 count: 1
path: ../../../src/entity/projectile/Projectile.php path: ../../../src/entity/projectile/Projectile.php
-
message: "#^Match arm comparison between 1\\|2\\|3\\|4 and 0 is always false\\.$#"
count: 1
path: ../../../src/network/mcpe/handler/InGamePacketHandler.php
-
message: "#^Match arm comparison between 4 and 4 is always true\\.$#"
count: 1
path: ../../../src/network/mcpe/handler/InGamePacketHandler.php
-
message: "#^Match arm is unreachable because previous comparison is always true\\.$#"
count: 1
path: ../../../src/network/mcpe/handler/InGamePacketHandler.php
- -
message: "#^Property pocketmine\\\\network\\\\mcpe\\\\raklib\\\\PthreadsChannelWriter\\:\\:\\$buffer is never read, only written\\.$#" message: "#^Property pocketmine\\\\network\\\\mcpe\\\\raklib\\\\PthreadsChannelWriter\\:\\:\\$buffer is never read, only written\\.$#"
count: 1 count: 1

View File

@ -121,4 +121,23 @@ class AsyncPoolTest extends TestCase{
usleep(50 * 1000); usleep(50 * 1000);
} }
} }
public function testNullComplexDataFetch() : void{
$this->pool->submitTask(new class extends AsyncTask{
public function __construct(){
$this->storeLocal("null", null);
}
public function onRun() : void{
//dummy
}
public function onCompletion() : void{
AsyncPoolTest::assertNull($this->fetchLocal("null"));
}
});
while($this->pool->collectTasks()){
usleep(50 * 1000);
}
}
} }