mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-06 11:57:10 +00:00
Merge branch 'minor-next' into major-next
This commit is contained in:
commit
4d337add7c
8
.github/workflows/build-docker-image.yml
vendored
8
.github/workflows/build-docker-image.yml
vendored
@ -53,7 +53,7 @@ jobs:
|
||||
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
4
.github/workflows/discord-release-notify.yml
vendored
4
.github/workflows/discord-release-notify.yml
vendored
@ -13,9 +13,9 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.27.1
|
||||
uses: shivammathur/setup-php@2.28.0
|
||||
with:
|
||||
php-version: 8.1
|
||||
php-version: 8.2
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v3
|
||||
|
4
.github/workflows/draft-release.yml
vendored
4
.github/workflows/draft-release.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-version: [8.1]
|
||||
php-version: [8.2]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -20,7 +20,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.27.1
|
||||
uses: shivammathur/setup-php@2.28.0
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
|
||||
|
14
.github/workflows/main.yml
vendored
14
.github/workflows/main.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: ["8.1", "8.2"]
|
||||
php: ["8.1", "8.2", "8.3"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -49,7 +49,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: ["8.1", "8.2"]
|
||||
php: ["8.1", "8.2", "8.3"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -84,7 +84,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: ["8.1", "8.2"]
|
||||
php: ["8.1", "8.2", "8.3"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -121,7 +121,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [ubuntu-20.04]
|
||||
php: ["8.1", "8.2"]
|
||||
php: ["8.1", "8.2", "8.3"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -173,10 +173,10 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.27.1
|
||||
uses: shivammathur/setup-php@2.28.0
|
||||
with:
|
||||
php-version: 8.1
|
||||
tools: php-cs-fixer:3.17
|
||||
php-version: 8.2
|
||||
tools: php-cs-fixer:3.38
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
2
.github/workflows/support.yml
vendored
2
.github/workflows/support.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
||||
support:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/support-requests@v3
|
||||
- uses: dessant/support-requests@v4
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
support-label: "Support request"
|
||||
|
@ -2,7 +2,7 @@
|
||||
## Pre-requisites
|
||||
- A bash shell (git bash is sufficient for Windows)
|
||||
- [`git`](https://git-scm.com) available in your shell
|
||||
- PHP 8.1 or newer available in your shell
|
||||
- PHP 8.2 or newer available in your shell
|
||||
- [`composer`](https://getcomposer.org) available in your shell
|
||||
|
||||
## Custom PHP binaries
|
||||
|
46
README.md
46
README.md
@ -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>
|
||||
</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/)
|
||||
- [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html)
|
||||
- [Docker image](https://github.com/pmmp/PocketMine-MP/pkgs/container/pocketmine-mp)
|
||||
- [Plugin repository](https://poggit.pmmp.io/plugins)
|
||||
|
||||
## Community & Support
|
||||
- [Forums](https://forums.pmmp.io/)
|
||||
- [Discord](https://discord.gg/bmSAZBG)
|
||||
- [StackOverflow](https://stackoverflow.com/tags/pocketmine)
|
||||
Join our [Discord](https://discord.gg/bmSAZBG) server to chat with other users and developers.
|
||||
|
||||
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
|
||||
* [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
|
||||
* [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
|
||||
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
|
||||
|
||||
## Contributing 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)
|
||||
|
||||
## 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`
|
||||
- Stellar Lumens (XLM): `GAAC5WZ33HCTE3BFJFZJXONMEIBNHFLBXM2HJVAZHXXPYA3HP5XPPS7T`
|
||||
- [Patreon](https://www.patreon.com/pocketminemp)
|
||||
|
||||
Thanks for your support!
|
||||
|
||||
## Licensing information
|
||||
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
16
changelogs/4.26.md
Normal 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.
|
@ -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()`.
|
||||
- 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.
|
||||
|
||||
# 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
30
changelogs/5.9.md
Normal 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.
|
@ -33,10 +33,10 @@
|
||||
"composer-runtime-api": "^2.0",
|
||||
"adhocore/json-comment": "~1.2.0",
|
||||
"pocketmine/netresearch-jsonmapper": "~v4.2.1000",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~3.3.0+bedrock-1.20.40",
|
||||
"pocketmine/bedrock-data": "~2.6.0+bedrock-1.20.40",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.5.0+bedrock-1.20.30",
|
||||
"pocketmine/bedrock-protocol": "~25.0.0+bedrock-1.20.40",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~3.4.0+bedrock-1.20.50",
|
||||
"pocketmine/bedrock-data": "~2.7.0+bedrock-1.20.50",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.6.0+bedrock-1.20.50",
|
||||
"pocketmine/bedrock-protocol": "~26.0.0+bedrock-1.20.50",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
@ -52,7 +52,7 @@
|
||||
"symfony/filesystem": "~6.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.10.41",
|
||||
"phpstan/phpstan": "1.10.47",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "~10.3.0 || ~10.2.0 || ~10.1.0"
|
||||
|
100
composer.lock
generated
100
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "5c19f4766fd04be0cbd38d9f4681864e",
|
||||
"content-hash": "828ee775e4e3548ef3fb0d9690ca2f44",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -122,16 +122,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-block-upgrade-schema",
|
||||
"version": "3.3.0",
|
||||
"version": "3.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
|
||||
"reference": "ee46b9367af262bbddd9f122d4d5b5b495b892e7"
|
||||
"reference": "9872eb37f15080b19c2b7861085e549c48dda92d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/ee46b9367af262bbddd9f122d4d5b5b495b892e7",
|
||||
"reference": "ee46b9367af262bbddd9f122d4d5b5b495b892e7",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/9872eb37f15080b19c2b7861085e549c48dda92d",
|
||||
"reference": "9872eb37f15080b19c2b7861085e549c48dda92d",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -142,22 +142,22 @@
|
||||
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
|
||||
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/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",
|
||||
"version": "2.6.0+bedrock-1.20.40",
|
||||
"version": "2.7.0+bedrock-1.20.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "37e780d28b470230bda3579b04cb50d406e3fbe6"
|
||||
"reference": "36f975dfca7520b7d36b0b39429f274464c9bc13"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/37e780d28b470230bda3579b04cb50d406e3fbe6",
|
||||
"reference": "37e780d28b470230bda3579b04cb50d406e3fbe6",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/36f975dfca7520b7d36b0b39429f274464c9bc13",
|
||||
"reference": "36f975dfca7520b7d36b0b39429f274464c9bc13",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -168,22 +168,22 @@
|
||||
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockData/issues",
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.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",
|
||||
"version": "1.5.0",
|
||||
"version": "1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
|
||||
"reference": "3edc9ebbad9a4f2d9c8f53b3a5ba44d4a792ad93"
|
||||
"reference": "d374e5fd8302977675dcd2a42733abd3ee476ca1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/3edc9ebbad9a4f2d9c8f53b3a5ba44d4a792ad93",
|
||||
"reference": "3edc9ebbad9a4f2d9c8f53b3a5ba44d4a792ad93",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/d374e5fd8302977675dcd2a42733abd3ee476ca1",
|
||||
"reference": "d374e5fd8302977675dcd2a42733abd3ee476ca1",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -194,22 +194,22 @@
|
||||
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
|
||||
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.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",
|
||||
"version": "25.0.0+bedrock-1.20.40",
|
||||
"version": "26.0.0+bedrock-1.20.50",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "69c36c96f6835e93fc278071aa2bb9829abe5cf8"
|
||||
"reference": "f278a0b6d4fa1e2e0408a125f323a3118b1968df"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/69c36c96f6835e93fc278071aa2bb9829abe5cf8",
|
||||
"reference": "69c36c96f6835e93fc278071aa2bb9829abe5cf8",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/f278a0b6d4fa1e2e0408a125f323a3118b1968df",
|
||||
"reference": "f278a0b6d4fa1e2e0408a125f323a3118b1968df",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -223,10 +223,10 @@
|
||||
"ramsey/uuid": "^4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.10.33",
|
||||
"phpstan/phpstan": "1.10.39",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
"phpunit/phpunit": "^9.5 || ^10.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -241,9 +241,9 @@
|
||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/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",
|
||||
@ -830,16 +830,16 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "4.7.4",
|
||||
"version": "4.7.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "60a4c63ab724854332900504274f6150ff26d286"
|
||||
"reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/60a4c63ab724854332900504274f6150ff26d286",
|
||||
"reference": "60a4c63ab724854332900504274f6150ff26d286",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e",
|
||||
"reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -906,7 +906,7 @@
|
||||
],
|
||||
"support": {
|
||||
"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": [
|
||||
{
|
||||
@ -918,7 +918,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-04-15T23:01:58+00:00"
|
||||
"time": "2023-11-08T05:53:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
@ -1378,16 +1378,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.41",
|
||||
"version": "1.10.47",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "c6174523c2a69231df55bdc65b61655e72876d76"
|
||||
"reference": "84dbb33b520ea28b6cf5676a3941f4bae1c1ff39"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6174523c2a69231df55bdc65b61655e72876d76",
|
||||
"reference": "c6174523c2a69231df55bdc65b61655e72876d76",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/84dbb33b520ea28b6cf5676a3941f4bae1c1ff39",
|
||||
"reference": "84dbb33b520ea28b6cf5676a3941f4bae1c1ff39",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1436,7 +1436,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-11-05T12:57:57+00:00"
|
||||
"time": "2023-12-01T15:19:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
@ -1541,16 +1541,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "10.1.7",
|
||||
"version": "10.1.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e"
|
||||
"reference": "a56a9ab2f680246adcf3db43f38ddf1765774735"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/355324ca4980b8916c18b9db29f3ef484078f26e",
|
||||
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/a56a9ab2f680246adcf3db43f38ddf1765774735",
|
||||
"reference": "a56a9ab2f680246adcf3db43f38ddf1765774735",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1607,7 +1607,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.7"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.9"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1615,7 +1615,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-10-04T15:34:17+00:00"
|
||||
"time": "2023-11-23T12:23:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -2878,16 +2878,16 @@
|
||||
},
|
||||
{
|
||||
"name": "theseer/tokenizer",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/theseer/tokenizer.git",
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e"
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"reference": "34a41e998c2183e22995f158c581e7b5e755ab9e",
|
||||
"url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2916,7 +2916,7 @@
|
||||
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
|
||||
"support": {
|
||||
"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": [
|
||||
{
|
||||
@ -2924,7 +2924,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2021-07-28T10:34:58+00:00"
|
||||
"time": "2023-11-20T00:12:19+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
@ -524,7 +524,7 @@ class Server{
|
||||
return $this->playerDataProvider->loadData($name);
|
||||
}catch(PlayerDataLoadException $e){
|
||||
$this->logger->debug("Failed to load player data for $name: " . $e->getMessage());
|
||||
$this->logger->error($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||
$this->logger->error($this->language->translate(KnownTranslationFactory::pocketmine_data_playerCorrupted($name)));
|
||||
return null;
|
||||
}
|
||||
});
|
||||
@ -543,7 +543,7 @@ class Server{
|
||||
try{
|
||||
$this->playerDataProvider->saveData($name, $ev->getSaveData());
|
||||
}catch(PlayerDataSaveException $e){
|
||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
||||
$this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_data_saveError($name, $e->getMessage())));
|
||||
$this->logger->logException($e);
|
||||
}
|
||||
});
|
||||
@ -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(!$this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_DEV_BUILDS, false)){
|
||||
@ -878,7 +878,7 @@ class Server{
|
||||
|
||||
$this->memoryManager = new MemoryManager($this);
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
|
||||
|
||||
if(($poolSize = $this->configGroup->getPropertyString(Yml::SETTINGS_ASYNC_WORKERS, "auto")) === "auto"){
|
||||
$poolSize = 2;
|
||||
@ -938,11 +938,11 @@ class Server{
|
||||
|
||||
$this->onlineMode = $this->configGroup->getConfigBool(ServerProperties::XBOX_AUTH, true);
|
||||
if($this->onlineMode){
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
|
||||
}else{
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_disabled()));
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authWarning()));
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_auth_disabled()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authWarning()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||
}
|
||||
|
||||
if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||
@ -953,17 +953,17 @@ class Server{
|
||||
|
||||
$this->serverID = Utils::getMachineUniqueId($this->getIp() . $this->getPort());
|
||||
|
||||
$this->getLogger()->debug("Server unique id: " . $this->getServerUniqueId());
|
||||
$this->getLogger()->debug("Machine unique id: " . Utils::getMachineUniqueId());
|
||||
$this->logger->debug("Server unique id: " . $this->getServerUniqueId());
|
||||
$this->logger->debug("Machine unique id: " . Utils::getMachineUniqueId());
|
||||
|
||||
$this->network = new Network($this->logger);
|
||||
$this->network->setName($this->getMotd());
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_info(
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_info(
|
||||
$this->getName(),
|
||||
(VersionInfo::IS_DEVELOPMENT_BUILD ? TextFormat::YELLOW : "") . $this->getPocketMineVersion() . TextFormat::RESET
|
||||
)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
|
||||
@ -974,7 +974,7 @@ class Server{
|
||||
|
||||
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes"));
|
||||
|
||||
$this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger);
|
||||
$this->resourceManager = new ResourcePackManager(Path::join($this->dataPath, "resource_packs"), $this->logger);
|
||||
|
||||
$pluginGraylist = null;
|
||||
$graylistFile = Path::join($this->dataPath, "plugin_list.yml");
|
||||
@ -988,7 +988,7 @@ class Server{
|
||||
$this->forceShutdownExit();
|
||||
return;
|
||||
}
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->dataPath, "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||
$this->pluginManager->registerInterface(new FolderPluginLoader($this->autoloader));
|
||||
@ -1051,9 +1051,9 @@ class Server{
|
||||
|
||||
$this->configGroup->save();
|
||||
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
|
||||
|
||||
$forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language);
|
||||
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $forwarder);
|
||||
@ -1141,13 +1141,13 @@ class Server{
|
||||
if($this->worldManager->getDefaultWorld() === null){
|
||||
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
if(trim($default) == ""){
|
||||
$this->getLogger()->warning("level-name cannot be null, using default");
|
||||
$this->logger->warning("level-name cannot be null, using default");
|
||||
$default = "world";
|
||||
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
}
|
||||
if(!$this->worldManager->loadWorld($default, true)){
|
||||
if($this->worldManager->isWorldGenerated($default)){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1156,7 +1156,7 @@ class Server{
|
||||
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
|
||||
|
||||
if($generatorClass === null){
|
||||
$this->getLogger()->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_level_defaultError()));
|
||||
return false;
|
||||
}
|
||||
$creationOptions = WorldCreationOptions::create()
|
||||
@ -1202,7 +1202,7 @@ class Server{
|
||||
return false;
|
||||
}
|
||||
if($rakLibRegistered){
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStart($prettyIp, (string) $port)));
|
||||
}
|
||||
if($useQuery){
|
||||
if(!$rakLibRegistered){
|
||||
@ -1210,7 +1210,7 @@ class Server{
|
||||
//if it's not registered we need to make sure Query still works
|
||||
$this->network->registerInterface(new DedicatedQueryNetworkInterface($ip, $port, $ipV6, new \PrefixedLogger($this->logger, "Dedicated Query Interface")));
|
||||
}
|
||||
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_query_running($prettyIp, (string) $port)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -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).
|
||||
*/
|
||||
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise{
|
||||
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise|string{
|
||||
$timings ??= Timings::$playerNetworkSendCompress;
|
||||
try{
|
||||
$timings->startTiming();
|
||||
@ -1372,15 +1380,14 @@ class Server{
|
||||
$sync = !$this->networkCompressionAsync || $threshold === null || strlen($buffer) < $threshold;
|
||||
}
|
||||
|
||||
$promise = new CompressBatchPromise();
|
||||
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
|
||||
$promise = new CompressBatchPromise();
|
||||
$task = new CompressBatchTask($buffer, $promise, $compressor);
|
||||
$this->asyncPool->submitTask($task);
|
||||
}else{
|
||||
$promise->resolve($compressor->compress($buffer));
|
||||
return $promise;
|
||||
}
|
||||
|
||||
return $promise;
|
||||
return $compressor->compress($buffer);
|
||||
}finally{
|
||||
$timings->stopTiming();
|
||||
}
|
||||
@ -1457,7 +1464,7 @@ class Server{
|
||||
$this->shutdown();
|
||||
|
||||
if(isset($this->pluginManager)){
|
||||
$this->getLogger()->debug("Disabling all plugins");
|
||||
$this->logger->debug("Disabling all plugins");
|
||||
$this->pluginManager->disablePlugins();
|
||||
}
|
||||
|
||||
@ -1466,34 +1473,34 @@ class Server{
|
||||
}
|
||||
|
||||
if(isset($this->worldManager)){
|
||||
$this->getLogger()->debug("Unloading all worlds");
|
||||
$this->logger->debug("Unloading all worlds");
|
||||
foreach($this->worldManager->getWorlds() as $world){
|
||||
$this->worldManager->unloadWorld($world, true);
|
||||
}
|
||||
}
|
||||
|
||||
$this->getLogger()->debug("Removing event handlers");
|
||||
$this->logger->debug("Removing event handlers");
|
||||
HandlerListManager::global()->unregisterAll();
|
||||
|
||||
if(isset($this->asyncPool)){
|
||||
$this->getLogger()->debug("Shutting down async task worker pool");
|
||||
$this->logger->debug("Shutting down async task worker pool");
|
||||
$this->asyncPool->shutdown();
|
||||
}
|
||||
|
||||
if(isset($this->configGroup)){
|
||||
$this->getLogger()->debug("Saving properties");
|
||||
$this->logger->debug("Saving properties");
|
||||
$this->configGroup->save();
|
||||
}
|
||||
|
||||
if($this->console !== null){
|
||||
$this->getLogger()->debug("Closing console");
|
||||
$this->logger->debug("Closing console");
|
||||
$this->console->quit();
|
||||
}
|
||||
|
||||
if(isset($this->network)){
|
||||
$this->getLogger()->debug("Stopping network interfaces");
|
||||
$this->logger->debug("Stopping network interfaces");
|
||||
foreach($this->network->getInterfaces() as $interface){
|
||||
$this->getLogger()->debug("Stopping network interface " . get_class($interface));
|
||||
$this->logger->debug("Stopping network interface " . get_class($interface));
|
||||
$this->network->unregisterInterface($interface);
|
||||
}
|
||||
}
|
||||
@ -1561,7 +1568,7 @@ class Server{
|
||||
}
|
||||
|
||||
private function writeCrashDumpFile(CrashDump $dump) : string{
|
||||
$crashFolder = Path::join($this->getDataPath(), "crashdumps");
|
||||
$crashFolder = Path::join($this->dataPath, "crashdumps");
|
||||
if(!is_dir($crashFolder)){
|
||||
mkdir($crashFolder);
|
||||
}
|
||||
@ -1592,17 +1599,17 @@ class Server{
|
||||
ini_set("error_reporting", '0');
|
||||
ini_set("memory_limit", '-1'); //Fix error dump not dumped on memory problems
|
||||
try{
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_create()));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_create()));
|
||||
$dump = new CrashDump($this, $this->pluginManager ?? null);
|
||||
|
||||
$crashDumpPath = $this->writeCrashDumpFile($dump);
|
||||
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
|
||||
|
||||
if($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_ENABLED, true)){
|
||||
$report = true;
|
||||
|
||||
$stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash");
|
||||
$stamp = Path::join($this->dataPath, "crashdumps", ".last_crash");
|
||||
$crashInterval = 120; //2 minutes
|
||||
if(($lastReportTime = @filemtime($stamp)) !== false && $lastReportTime + $crashInterval >= time()){
|
||||
$report = false;
|
||||
@ -1633,7 +1640,7 @@ class Server{
|
||||
if(isset($data->crashId) && is_int($data->crashId) && isset($data->crashUrl) && is_string($data->crashUrl)){
|
||||
$reportId = $data->crashId;
|
||||
$reportUrl = $data->crashUrl;
|
||||
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
|
||||
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_crash_archive($reportUrl, (string) $reportId)));
|
||||
}elseif(isset($data->error) && is_string($data->error)){
|
||||
$this->logger->emergency("Automatic crash report submission failed: $data->error");
|
||||
}else{
|
||||
@ -1647,7 +1654,7 @@ class Server{
|
||||
}catch(\Throwable $e){
|
||||
$this->logger->logException($e);
|
||||
try{
|
||||
$this->logger->critical($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage())));
|
||||
$this->logger->critical($this->language->translate(KnownTranslationFactory::pocketmine_crash_error($e->getMessage())));
|
||||
}catch(\Throwable $e){}
|
||||
}
|
||||
|
||||
@ -1765,7 +1772,7 @@ class Server{
|
||||
|
||||
echo "\x1b]0;" . $this->getName() . " " .
|
||||
$this->getPocketMineVersion() .
|
||||
" | Online $online/" . $this->getMaxPlayers() .
|
||||
" | Online $online/" . $this->maxPlayers .
|
||||
($connecting > 0 ? " (+$connecting connecting)" : "") .
|
||||
" | Memory " . $usage .
|
||||
" | U " . round($bandwidthStats->getSend()->getAverageBytes() / 1024, 2) .
|
||||
@ -1830,10 +1837,10 @@ class Server{
|
||||
}
|
||||
|
||||
if(($this->tickCounter % self::TICKS_PER_TPS_OVERLOAD_WARNING) === 0 && $this->getTicksPerSecondAverage() < self::TPS_OVERLOAD_WARNING_THRESHOLD){
|
||||
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_tickOverload()));
|
||||
}
|
||||
|
||||
$this->getMemoryManager()->check();
|
||||
$this->memoryManager->check();
|
||||
|
||||
if($this->console !== null){
|
||||
Timings::$serverCommand->startTiming();
|
||||
|
@ -24,7 +24,9 @@ declare(strict_types=1);
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\snooze\SleeperHandlerEntry;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use pocketmine\utils\Utils;
|
||||
use function hrtime;
|
||||
|
||||
/**
|
||||
@ -35,12 +37,29 @@ final class TimeTrackingSleeperHandler extends SleeperHandler{
|
||||
|
||||
private int $notificationProcessingTimeNs = 0;
|
||||
|
||||
/**
|
||||
* @var TimingsHandler[]
|
||||
* @phpstan-var array<string, TimingsHandler>
|
||||
*/
|
||||
private static array $handlerTimings = [];
|
||||
|
||||
public function __construct(
|
||||
private TimingsHandler $timings
|
||||
){
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function addNotifier(\Closure $handler) : SleeperHandlerEntry{
|
||||
$name = Utils::getNiceClosureName($handler);
|
||||
$timings = self::$handlerTimings[$name] ??= new TimingsHandler("Snooze Handler: " . $name, $this->timings);
|
||||
|
||||
return parent::addNotifier(function() use ($timings, $handler) : void{
|
||||
$timings->startTiming();
|
||||
$handler();
|
||||
$timings->stopTiming();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in nanoseconds spent processing notifications since the last reset.
|
||||
*/
|
||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.8.2";
|
||||
public const BASE_VERSION = "5.9.1";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
@ -173,7 +173,7 @@ class Bamboo extends Transparent{
|
||||
$newHeight = $height + $growAmount;
|
||||
|
||||
$stemBlock = (clone $this)->setReady(false)->setLeafSize(self::NO_LEAVES);
|
||||
if($newHeight >= 4 && !$stemBlock->isThick()){ //don't change it to false if height is less, because it might have been chopped
|
||||
if($newHeight >= 4 && !$stemBlock->thick){ //don't change it to false if height is less, because it might have been chopped
|
||||
$stemBlock = $stemBlock->setThick(true);
|
||||
}
|
||||
$smallLeavesBlock = (clone $stemBlock)->setLeafSize(self::SMALL_LEAVES);
|
||||
|
@ -55,12 +55,12 @@ class Barrel extends Opaque{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
if(abs($player->getPosition()->getX() - $this->position->getX()) < 2 && abs($player->getPosition()->getZ() - $this->position->getZ()) < 2){
|
||||
$y = $player->getEyePos()->getY();
|
||||
if(abs($player->getPosition()->x - $this->position->x) < 2 && abs($player->getPosition()->z - $this->position->z) < 2){
|
||||
$y = $player->getEyePos()->y;
|
||||
|
||||
if($y - $this->position->getY() > 2){
|
||||
if($y - $this->position->y > 2){
|
||||
$this->facing = Facing::UP;
|
||||
}elseif($this->position->getY() - $y > 0){
|
||||
}elseif($this->position->y - $y > 0){
|
||||
$this->facing = Facing::DOWN;
|
||||
}else{
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
|
@ -65,8 +65,8 @@ abstract class BaseBigDripleaf extends Transparent{
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
}
|
||||
if($block instanceof BaseBigDripleaf){
|
||||
$this->facing = $block->getFacing();
|
||||
$tx->addBlock($block->getPosition(), VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($this->facing));
|
||||
$this->facing = $block->facing;
|
||||
$tx->addBlock($block->position, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($this->facing));
|
||||
}
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
@ -98,7 +98,7 @@ abstract class BaseBigDripleaf extends Transparent{
|
||||
if($head === null){
|
||||
return false;
|
||||
}
|
||||
$pos = $head->getPosition();
|
||||
$pos = $head->position;
|
||||
$up = $pos->up();
|
||||
$world = $pos->getWorld();
|
||||
if(
|
||||
@ -110,8 +110,8 @@ abstract class BaseBigDripleaf extends Transparent{
|
||||
|
||||
$tx = new BlockTransaction($world);
|
||||
|
||||
$tx->addBlock($pos, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($head->getFacing()));
|
||||
$tx->addBlock($up, VanillaBlocks::BIG_DRIPLEAF_HEAD()->setFacing($head->getFacing()));
|
||||
$tx->addBlock($pos, VanillaBlocks::BIG_DRIPLEAF_STEM()->setFacing($head->facing));
|
||||
$tx->addBlock($up, VanillaBlocks::BIG_DRIPLEAF_HEAD()->setFacing($head->facing));
|
||||
|
||||
$ev = new StructureGrowEvent($head, $tx, $player);
|
||||
$ev->call();
|
||||
|
@ -145,7 +145,7 @@ class Bed extends Transparent{
|
||||
|
||||
$b = ($this->isHeadPart() ? $this : $other);
|
||||
|
||||
if($b->isOccupied()){
|
||||
if($b->occupied){
|
||||
$player->sendMessage(KnownTranslationFactory::tile_bed_occupied()->prefix(TextFormat::GRAY));
|
||||
|
||||
return true;
|
||||
|
@ -97,7 +97,7 @@ class ChiseledBookshelf extends Opaque{
|
||||
return false;
|
||||
}
|
||||
|
||||
$x = Facing::axis($face) === Axis::X ? $clickVector->getZ() : $clickVector->getX();
|
||||
$x = Facing::axis($face) === Axis::X ? $clickVector->z : $clickVector->x;
|
||||
$slot = ChiseledBookshelfSlot::fromBlockFaceCoordinates(
|
||||
Facing::isPositive(Facing::rotateY($face, true)) ? 1 - $x : $x,
|
||||
$clickVector->y
|
||||
|
@ -54,7 +54,7 @@ final class ChorusFlower extends Flowable{
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
$position = $block->getPosition();
|
||||
$position = $block->position;
|
||||
$world = $position->getWorld();
|
||||
$down = $world->getBlock($position->down());
|
||||
|
||||
@ -152,7 +152,7 @@ final class ChorusFlower extends Flowable{
|
||||
if($tx === null){
|
||||
$tx = new BlockTransaction($this->position->getWorld());
|
||||
}
|
||||
$tx->addBlock($this->position->getSide($facing), (clone $this)->setAge(min(self::MAX_AGE, $this->getAge() + $ageChange)));
|
||||
$tx->addBlock($this->position->getSide($facing), (clone $this)->setAge(min(self::MAX_AGE, $this->age + $ageChange)));
|
||||
|
||||
return $tx;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ final class ChorusPlant extends Flowable{
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
$position = $block->getPosition();
|
||||
$position = $block->position;
|
||||
$world = $position->getWorld();
|
||||
|
||||
$down = $world->getBlock($position->down());
|
||||
|
@ -29,6 +29,7 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
@ -106,4 +107,14 @@ final class DoublePitcherCrop extends DoublePlant{
|
||||
$this->grow(null);
|
||||
}
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
$this->age >= self::MAX_AGE ? VanillaBlocks::PITCHER_PLANT()->asItem() : VanillaItems::PITCHER_POD()
|
||||
];
|
||||
}
|
||||
|
||||
public function asItem() : Item{
|
||||
return VanillaItems::PITCHER_POD();
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ class Farmland extends Transparent{
|
||||
$ev = new EntityTrampleFarmlandEvent($entity, $this);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
$this->getPosition()->getWorld()->setBlock($this->getPosition(), VanillaBlocks::DIRT());
|
||||
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::DIRT());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -140,7 +140,7 @@ class Fire extends BaseFire{
|
||||
$block->onIncinerate();
|
||||
|
||||
$world = $this->position->getWorld();
|
||||
if($world->getBlock($block->getPosition())->isSameState($block)){
|
||||
if($world->getBlock($block->position)->isSameState($block)){
|
||||
$spreadedFire = false;
|
||||
if(mt_rand(0, $this->age + 9) < 5){ //TODO: check rain
|
||||
$fire = clone $this;
|
||||
|
@ -58,7 +58,7 @@ final class FloorCoralFan extends BaseCoral{
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player !== null){
|
||||
$playerBlockPos = $player->getPosition()->floor();
|
||||
$directionVector = $blockReplace->getPosition()->subtractVector($playerBlockPos)->normalize();
|
||||
$directionVector = $blockReplace->position->subtractVector($playerBlockPos)->normalize();
|
||||
$angle = rad2deg(atan2($directionVector->getZ(), $directionVector->getX()));
|
||||
|
||||
if($angle <= 45 || 315 <= $angle || (135 <= $angle && $angle <= 225)){
|
||||
|
@ -61,7 +61,7 @@ class Jukebox extends Opaque{
|
||||
|
||||
public function ejectRecord() : void{
|
||||
if($this->record !== null){
|
||||
$this->getPosition()->getWorld()->dropItem($this->getPosition()->add(0.5, 1, 0.5), $this->record);
|
||||
$this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $this->record);
|
||||
$this->record = null;
|
||||
$this->stopSound();
|
||||
}
|
||||
@ -76,12 +76,12 @@ class Jukebox extends Opaque{
|
||||
|
||||
public function startSound() : void{
|
||||
if($this->record !== null){
|
||||
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordSound($this->record->getRecordType()));
|
||||
$this->position->getWorld()->addSound($this->position, new RecordSound($this->record->getRecordType()));
|
||||
}
|
||||
}
|
||||
|
||||
public function stopSound() : void{
|
||||
$this->getPosition()->getWorld()->addSound($this->getPosition(), new RecordStopSound());
|
||||
$this->position->getWorld()->addSound($this->position, new RecordStopSound());
|
||||
}
|
||||
|
||||
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
|
@ -108,8 +108,8 @@ class NetherVines extends Flowable{
|
||||
|
||||
private function grow(?Player $player, int $growthAmount = 1) : bool{
|
||||
$top = $this->seekToTip();
|
||||
$age = $top->getAge();
|
||||
$pos = $top->getPosition();
|
||||
$age = $top->age;
|
||||
$pos = $top->position;
|
||||
$world = $pos->getWorld();
|
||||
$changedBlocks = 0;
|
||||
|
||||
|
@ -70,13 +70,13 @@ class PinkPetals extends Flowable{
|
||||
}
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return ($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT) || $this->supportedWhenPlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
return ($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT) || $this->supportedWhenPlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT){
|
||||
$this->count = $blockReplace->getCount() + 1;
|
||||
$this->facing = $blockReplace->getFacing();
|
||||
if($blockReplace instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT){
|
||||
$this->count = $blockReplace->count + 1;
|
||||
$this->facing = $blockReplace->facing;
|
||||
}elseif($player !== null){
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\block\utils\StaticSupportTrait;
|
||||
use pocketmine\event\block\StructureGrowEvent;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
@ -101,4 +102,8 @@ final class PitcherCrop extends Flowable{
|
||||
$this->grow(null);
|
||||
}
|
||||
}
|
||||
|
||||
public function asItem() : Item{
|
||||
return VanillaItems::PITCHER_POD();
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ class RedMushroom extends Flowable{
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$down = $this->getSide(Facing::DOWN);
|
||||
$position = $this->getPosition();
|
||||
$position = $this->position;
|
||||
$lightLevel = $position->getWorld()->getFullLightAt($position->x, $position->y, $position->z);
|
||||
$downId = $down->getTypeId();
|
||||
//TODO: nylium support
|
||||
|
@ -83,7 +83,7 @@ class SmallDripleaf extends Transparent{
|
||||
$this->facing = Facing::opposite($player->getHorizontalFacing());
|
||||
}
|
||||
|
||||
$tx->addBlock($block->getPosition(), VanillaBlocks::SMALL_DRIPLEAF()
|
||||
$tx->addBlock($block->position, VanillaBlocks::SMALL_DRIPLEAF()
|
||||
->setFacing($this->facing)
|
||||
->setTop(true)
|
||||
);
|
||||
@ -117,7 +117,7 @@ class SmallDripleaf extends Transparent{
|
||||
$height = mt_rand(2, 5);
|
||||
$grown = 0;
|
||||
for($i = 0; $i < $height; $i++){
|
||||
$pos = $bottomBlock->getSide(Facing::UP, $i)->getPosition();
|
||||
$pos = $bottomBlock->getSide(Facing::UP, $i)->position;
|
||||
if(!$this->canGrowTo($pos)){
|
||||
break;
|
||||
}
|
||||
|
@ -106,8 +106,8 @@ class Stair extends Transparent{
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
if(
|
||||
$facing === Facing::UP && $this->isUpsideDown() ||
|
||||
$facing === Facing::DOWN && !$this->isUpsideDown() ||
|
||||
$facing === Facing::UP && $this->upsideDown ||
|
||||
$facing === Facing::DOWN && !$this->upsideDown ||
|
||||
($facing === $this->facing && $this->shape !== StairShape::OUTER_LEFT && $this->shape !== StairShape::OUTER_RIGHT) ||
|
||||
($facing === Facing::rotate($this->facing, Axis::Y, false) && $this->shape === StairShape::INNER_LEFT) ||
|
||||
($facing === Facing::rotate($this->facing, Axis::Y, true) && $this->shape === StairShape::INNER_RIGHT)
|
||||
|
@ -47,20 +47,20 @@ trait AnimatedBlockInventoryTrait{
|
||||
public function onOpen(Player $who) : void{
|
||||
parent::onOpen($who);
|
||||
|
||||
if($this->getHolder()->isValid() && $this->getViewerCount() === 1){
|
||||
if($this->holder->isValid() && $this->getViewerCount() === 1){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->animateBlock(true);
|
||||
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
||||
$this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getOpenSound());
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected function animateBlock(bool $isOpen) : void;
|
||||
|
||||
public function onClose(Player $who) : void{
|
||||
if($this->getHolder()->isValid() && $this->getViewerCount() === 1){
|
||||
if($this->holder->isValid() && $this->getViewerCount() === 1){
|
||||
//TODO: this crap really shouldn't be managed by the inventory
|
||||
$this->animateBlock(false);
|
||||
$this->getHolder()->getWorld()->addSound($this->getHolder()->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
||||
$this->holder->getWorld()->addSound($this->holder->add(0.5, 0.5, 0.5), $this->getCloseSound());
|
||||
}
|
||||
parent::onClose($who);
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ class Chest extends Spawnable implements Container, Nameable{
|
||||
if($pair->doubleInventory !== null){
|
||||
$this->doubleInventory = $pair->doubleInventory;
|
||||
}else{
|
||||
if(($pair->getPosition()->x + ($pair->getPosition()->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly
|
||||
if(($pair->position->x + ($pair->position->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly
|
||||
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($pair->inventory, $this->inventory);
|
||||
}else{
|
||||
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($this->inventory, $pair->inventory);
|
||||
|
@ -27,6 +27,7 @@ use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\network\mcpe\convert\TypeConverter;
|
||||
use pocketmine\world\World;
|
||||
|
||||
@ -52,13 +53,17 @@ class ItemFrame extends Spawnable{
|
||||
if(($itemTag = $nbt->getCompoundTag(self::TAG_ITEM)) !== null){
|
||||
$this->item = Item::nbtDeserialize($itemTag);
|
||||
}
|
||||
$this->itemRotation = $nbt->getByte(self::TAG_ITEM_ROTATION, $this->itemRotation);
|
||||
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->itemDropChance = $nbt->getFloat(self::TAG_ITEM_DROP_CHANCE, $this->itemDropChance);
|
||||
}
|
||||
|
||||
protected function writeSaveData(CompoundTag $nbt) : void{
|
||||
$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()){
|
||||
$nbt->setTag(self::TAG_ITEM, $this->item->nbtSerialize());
|
||||
}
|
||||
@ -98,7 +103,7 @@ class ItemFrame extends Spawnable{
|
||||
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
$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()){
|
||||
$nbt->setTag(self::TAG_ITEM, TypeConverter::getInstance()->getItemTranslator()->toNetworkNbt($this->item));
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ final class BlockStateData{
|
||||
public const CURRENT_VERSION =
|
||||
(1 << 24) | //major
|
||||
(20 << 16) | //minor
|
||||
(40 << 8) | //patch
|
||||
(3); //revision
|
||||
(50 << 8) | //patch
|
||||
(1); //revision
|
||||
|
||||
public const TAG_NAME = "name";
|
||||
public const TAG_STATES = "states";
|
||||
|
@ -66,6 +66,7 @@ final class BlockStateNames{
|
||||
public const CORAL_HANG_TYPE_BIT = "coral_hang_type_bit";
|
||||
public const COVERED_BIT = "covered_bit";
|
||||
public const CRACKED_STATE = "cracked_state";
|
||||
public const CRAFTING = "crafting";
|
||||
public const DAMAGE = "damage";
|
||||
public const DEAD_BIT = "dead_bit";
|
||||
public const DEPRECATED = "deprecated";
|
||||
@ -109,6 +110,7 @@ final class BlockStateNames{
|
||||
public const OCCUPIED_BIT = "occupied_bit";
|
||||
public const OLD_LEAF_TYPE = "old_leaf_type";
|
||||
public const OPEN_BIT = "open_bit";
|
||||
public const ORIENTATION = "orientation";
|
||||
public const OUTPUT_LIT_BIT = "output_lit_bit";
|
||||
public const OUTPUT_SUBTRACT_BIT = "output_subtract_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_3 = "stone_slab_type_3";
|
||||
public const STONE_SLAB_TYPE_4 = "stone_slab_type_4";
|
||||
public const STONE_TYPE = "stone_type";
|
||||
public const STRIPPED_BIT = "stripped_bit";
|
||||
public const STRUCTURE_BLOCK_TYPE = "structure_block_type";
|
||||
public const STRUCTURE_VOID_TYPE = "structure_void_type";
|
||||
|
@ -168,6 +168,19 @@ final class BlockStateStringValues{
|
||||
public const OLD_LEAF_TYPE_OAK = "oak";
|
||||
public const OLD_LEAF_TYPE_SPRUCE = "spruce";
|
||||
|
||||
public const ORIENTATION_DOWN_EAST = "down_east";
|
||||
public const ORIENTATION_DOWN_NORTH = "down_north";
|
||||
public const ORIENTATION_DOWN_SOUTH = "down_south";
|
||||
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_Y = "y";
|
||||
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_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_DATA = "data";
|
||||
public const STRUCTURE_BLOCK_TYPE_EXPORT = "export";
|
||||
|
@ -37,6 +37,7 @@ final class BlockTypeNames{
|
||||
public const ACACIA_FENCE_GATE = "minecraft:acacia_fence_gate";
|
||||
public const ACACIA_HANGING_SIGN = "minecraft:acacia_hanging_sign";
|
||||
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_STAIRS = "minecraft:acacia_stairs";
|
||||
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_CLUSTER = "minecraft:amethyst_cluster";
|
||||
public const ANCIENT_DEBRIS = "minecraft:ancient_debris";
|
||||
public const ANDESITE = "minecraft:andesite";
|
||||
public const ANDESITE_STAIRS = "minecraft:andesite_stairs";
|
||||
public const ANVIL = "minecraft:anvil";
|
||||
public const AZALEA = "minecraft:azalea";
|
||||
@ -90,6 +92,7 @@ final class BlockTypeNames{
|
||||
public const BIRCH_FENCE_GATE = "minecraft:birch_fence_gate";
|
||||
public const BIRCH_HANGING_SIGN = "minecraft:birch_hanging_sign";
|
||||
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_STAIRS = "minecraft:birch_stairs";
|
||||
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 CHEST = "minecraft:chest";
|
||||
public const CHISELED_BOOKSHELF = "minecraft:chiseled_bookshelf";
|
||||
public const CHISELED_COPPER = "minecraft:chiseled_copper";
|
||||
public const CHISELED_DEEPSLATE = "minecraft:chiseled_deepslate";
|
||||
public const CHISELED_NETHER_BRICKS = "minecraft:chiseled_nether_bricks";
|
||||
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_PLANT = "minecraft:chorus_plant";
|
||||
public const CLAY = "minecraft:clay";
|
||||
@ -208,7 +214,11 @@ final class BlockTypeNames{
|
||||
public const COMPOSTER = "minecraft:composter";
|
||||
public const CONDUIT = "minecraft:conduit";
|
||||
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_TRAPDOOR = "minecraft:copper_trapdoor";
|
||||
public const CORAL_BLOCK = "minecraft:coral_block";
|
||||
public const CORAL_FAN = "minecraft:coral_fan";
|
||||
public const CORAL_FAN_DEAD = "minecraft:coral_fan_dead";
|
||||
@ -219,6 +229,7 @@ final class BlockTypeNames{
|
||||
public const CRACKED_DEEPSLATE_TILES = "minecraft:cracked_deepslate_tiles";
|
||||
public const CRACKED_NETHER_BRICKS = "minecraft:cracked_nether_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 CRIMSON_BUTTON = "minecraft:crimson_button";
|
||||
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_HANGING_SIGN = "minecraft:dark_oak_hanging_sign";
|
||||
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_STAIRS = "minecraft:dark_oak_stairs";
|
||||
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 DIAMOND_BLOCK = "minecraft:diamond_block";
|
||||
public const DIAMOND_ORE = "minecraft:diamond_ore";
|
||||
public const DIORITE = "minecraft:diorite";
|
||||
public const DIORITE_STAIRS = "minecraft:diorite_stairs";
|
||||
public const DIRT = "minecraft:dirt";
|
||||
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_STONE = "minecraft:end_stone";
|
||||
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_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_SLAB = "minecraft:exposed_cut_copper_slab";
|
||||
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_ORE = "minecraft:gold_ore";
|
||||
public const GOLDEN_RAIL = "minecraft:golden_rail";
|
||||
public const GRANITE = "minecraft:granite";
|
||||
public const GRANITE_STAIRS = "minecraft:granite_stairs";
|
||||
public const GRASS = "minecraft:grass";
|
||||
public const GRASS_PATH = "minecraft:grass_path";
|
||||
@ -527,6 +546,7 @@ final class BlockTypeNames{
|
||||
public const JUNGLE_FENCE_GATE = "minecraft:jungle_fence_gate";
|
||||
public const JUNGLE_HANGING_SIGN = "minecraft:jungle_hanging_sign";
|
||||
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_STAIRS = "minecraft:jungle_stairs";
|
||||
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_HANGING_SIGN = "minecraft:oak_hanging_sign";
|
||||
public const OAK_LOG = "minecraft:oak_log";
|
||||
public const OAK_PLANKS = "minecraft:oak_planks";
|
||||
public const OAK_STAIRS = "minecraft:oak_stairs";
|
||||
public const OBSERVER = "minecraft:observer";
|
||||
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_TERRACOTTA = "minecraft:orange_terracotta";
|
||||
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_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_SLAB = "minecraft:oxidized_cut_copper_slab";
|
||||
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 PITCHER_CROP = "minecraft:pitcher_crop";
|
||||
public const PITCHER_PLANT = "minecraft:pitcher_plant";
|
||||
public const PLANKS = "minecraft:planks";
|
||||
public const PODZOL = "minecraft:podzol";
|
||||
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_BASALT = "minecraft:polished_basalt";
|
||||
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_STAIRS = "minecraft:polished_deepslate_stairs";
|
||||
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_GRANITE = "minecraft:polished_granite";
|
||||
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 POTATOES = "minecraft:potatoes";
|
||||
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_HANGING_SIGN = "minecraft:spruce_hanging_sign";
|
||||
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_STAIRS = "minecraft:spruce_stairs";
|
||||
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 TUBE_CORAL = "minecraft:tube_coral";
|
||||
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 TWISTING_VINES = "minecraft:twisting_vines";
|
||||
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 WATER = "minecraft:water";
|
||||
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_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_SLAB = "minecraft:waxed_cut_copper_slab";
|
||||
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_EXPOSED_CHISELED_COPPER = "minecraft:waxed_exposed_chiseled_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_SLAB = "minecraft:waxed_exposed_cut_copper_slab";
|
||||
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_OXIDIZED_CHISELED_COPPER = "minecraft:waxed_oxidized_chiseled_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_SLAB = "minecraft:waxed_oxidized_cut_copper_slab";
|
||||
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_WEATHERED_CHISELED_COPPER = "minecraft:waxed_weathered_chiseled_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_SLAB = "minecraft:waxed_weathered_cut_copper_slab";
|
||||
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 WEATHERED_CHISELED_COPPER = "minecraft:weathered_chiseled_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_SLAB = "minecraft:weathered_cut_copper_slab";
|
||||
public const WEATHERED_CUT_COPPER_STAIRS = "minecraft:weathered_cut_copper_stairs";
|
||||
|
@ -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->mapLog(Blocks::ACACIA_LOG(), Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG);
|
||||
$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_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->mapLog(Blocks::BIRCH_LOG(), Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG);
|
||||
$this->mapSimple(Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE);
|
||||
$this->mapSimple(Blocks::BIRCH_PLANKS(), Ids::BIRCH_PLANKS);
|
||||
$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_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->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_PLANKS(), Ids::DARK_OAK_PLANKS);
|
||||
$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_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->mapLog(Blocks::JUNGLE_LOG(), Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG);
|
||||
$this->mapSimple(Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE);
|
||||
$this->mapSimple(Blocks::JUNGLE_PLANKS(), Ids::JUNGLE_PLANKS);
|
||||
$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_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->mapLog(Blocks::OAK_LOG(), Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG);
|
||||
$this->mapSimple(Blocks::OAK_FENCE(), Ids::OAK_FENCE);
|
||||
$this->mapSimple(Blocks::OAK_PLANKS(), Ids::OAK_PLANKS);
|
||||
$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_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_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->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_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_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{
|
||||
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([
|
||||
StringValues::WOOD_TYPE_ACACIA => Blocks::ACACIA_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::AMETHYST(), Ids::AMETHYST_BLOCK);
|
||||
$this->mapSimple(Blocks::ANCIENT_DEBRIS(), Ids::ANCIENT_DEBRIS);
|
||||
$this->mapSimple(Blocks::ANDESITE(), Ids::ANDESITE);
|
||||
$this->mapSimple(Blocks::BARRIER(), Ids::BARRIER);
|
||||
$this->mapSimple(Blocks::BEACON(), Ids::BEACON);
|
||||
$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::DIAMOND(), Ids::DIAMOND_BLOCK);
|
||||
$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::DRIED_KELP(), Ids::DRIED_KELP_BLOCK);
|
||||
$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::GOLD(), Ids::GOLD_BLOCK);
|
||||
$this->mapSimple(Blocks::GOLD_ORE(), Ids::GOLD_ORE);
|
||||
$this->mapSimple(Blocks::GRANITE(), Ids::GRANITE);
|
||||
$this->mapSimple(Blocks::GRASS(), Ids::GRASS);
|
||||
$this->mapSimple(Blocks::GRASS_PATH(), Ids::GRASS_PATH);
|
||||
$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_MUD(), Ids::PACKED_MUD);
|
||||
$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_BRICKS(), Ids::POLISHED_BLACKSTONE_BRICKS);
|
||||
$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::RAW_COPPER(), Ids::RAW_COPPER_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_SOIL(), Ids::SOUL_SOIL);
|
||||
$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::TORCHFLOWER(), Ids::TORCHFLOWER);
|
||||
$this->mapSimple(Blocks::TUFF(), Ids::TUFF);
|
||||
@ -984,7 +985,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
})
|
||||
->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_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));
|
||||
@ -1267,7 +1267,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
->writeBool(StateNames::RAIL_DATA_BIT, $block->isActivated())
|
||||
->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->mapStairs(Blocks::DIORITE_STAIRS(), Ids::DIORITE_STAIRS);
|
||||
$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());
|
||||
});
|
||||
$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->mapStairs(Blocks::GRANITE_STAIRS(), Ids::GRANITE_STAIRS);
|
||||
$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)
|
||||
->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->mapStairs(Blocks::POLISHED_ANDESITE_STAIRS(), Ids::POLISHED_ANDESITE_STAIRS);
|
||||
$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->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_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->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->mapStairs(Blocks::POLISHED_GRANITE_STAIRS(), Ids::POLISHED_GRANITE_STAIRS);
|
||||
$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)
|
||||
->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)
|
||||
->writeCardinalHorizontalFacing($block->getFacing()));
|
||||
$this->map(Blocks::STONE_BRICKS(), fn() => Helper::encodeStoneBricks(StringValues::STONE_BRICK_TYPE_DEFAULT));
|
||||
|
@ -228,11 +228,6 @@ final class BlockStateSerializerHelper{
|
||||
->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{
|
||||
return BlockStateWriter::create(Ids::STONEBRICK)
|
||||
->writeString(BlockStateNames::STONE_BRICK_TYPE, $type);
|
||||
|
@ -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->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_PLANKS, fn() => Blocks::ACACIA_PLANKS());
|
||||
$this->mapStairs(Ids::ACACIA_STAIRS, fn() => Blocks::ACACIA_STAIRS());
|
||||
//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->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_PLANKS, fn() => Blocks::BIRCH_PLANKS());
|
||||
$this->mapStairs(Ids::BIRCH_STAIRS, fn() => Blocks::BIRCH_STAIRS());
|
||||
//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->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_PLANKS, fn() => Blocks::DARK_OAK_PLANKS());
|
||||
$this->mapStairs(Ids::DARK_OAK_STAIRS, fn() => Blocks::DARK_OAK_STAIRS());
|
||||
//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->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_PLANKS, fn() => Blocks::JUNGLE_PLANKS());
|
||||
$this->mapStairs(Ids::JUNGLE_STAIRS, fn() => Blocks::JUNGLE_STAIRS());
|
||||
//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->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_PLANKS, fn() => Blocks::OAK_PLANKS());
|
||||
$this->mapStairs(Ids::OAK_STAIRS, fn() => Blocks::OAK_STAIRS());
|
||||
//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->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_PLANKS, fn() => Blocks::SPRUCE_PLANKS());
|
||||
$this->mapStairs(Ids::SPRUCE_STAIRS, fn() => Blocks::SPRUCE_STAIRS());
|
||||
//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{
|
||||
|
||||
$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->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::AMETHYST_BLOCK, fn() => Blocks::AMETHYST());
|
||||
$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::BEACON, fn() => Blocks::BEACON());
|
||||
$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::DIAMOND_BLOCK, fn() => Blocks::DIAMOND());
|
||||
$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::DRIED_KELP_BLOCK, fn() => Blocks::DRIED_KELP());
|
||||
$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::GOLD_BLOCK, fn() => Blocks::GOLD());
|
||||
$this->mapSimple(Ids::GOLD_ORE, fn() => Blocks::GOLD_ORE());
|
||||
$this->mapSimple(Ids::GRANITE, fn() => Blocks::GRANITE());
|
||||
$this->mapSimple(Ids::GRASS, fn() => Blocks::GRASS());
|
||||
$this->mapSimple(Ids::GRASS_PATH, fn() => Blocks::GRASS_PATH());
|
||||
$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_MUD, fn() => Blocks::PACKED_MUD());
|
||||
$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_BRICKS, fn() => Blocks::POLISHED_BLACKSTONE_BRICKS());
|
||||
$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_ORE, fn() => Blocks::NETHER_QUARTZ_ORE());
|
||||
$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_SOIL, fn() => Blocks::SOUL_SOIL());
|
||||
$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::TINTED_GLASS, fn() => Blocks::TINTED_GLASS());
|
||||
$this->mapSimple(Ids::TORCHFLOWER, fn() => Blocks::TORCHFLOWER());
|
||||
@ -1528,18 +1529,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::BANNER()
|
||||
->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->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));
|
||||
|
@ -147,7 +147,6 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Block(Ids::JUNGLE_DOOR, Blocks::JUNGLE_DOOR());
|
||||
$this->map1to1Block(Ids::MANGROVE_DOOR, Blocks::MANGROVE_DOOR());
|
||||
$this->map1to1Block(Ids::NETHER_WART, Blocks::NETHER_WART());
|
||||
$this->map1to1Block(Ids::PITCHER_POD, Blocks::PITCHER_CROP());
|
||||
$this->map1to1Block(Ids::REPEATER, Blocks::REDSTONE_REPEATER());
|
||||
$this->map1to1Block(Ids::SPRUCE_DOOR, Blocks::SPRUCE_DOOR());
|
||||
$this->map1to1Block(Ids::SUGAR_CANE, Blocks::SUGARCANE());
|
||||
@ -326,6 +325,7 @@ final class ItemSerializerDeserializerRegistrar{
|
||||
$this->map1to1Item(Ids::PAINTING, Items::PAINTING());
|
||||
$this->map1to1Item(Ids::PAPER, Items::PAPER());
|
||||
$this->map1to1Item(Ids::PHANTOM_MEMBRANE, Items::PHANTOM_MEMBRANE());
|
||||
$this->map1to1Item(Ids::PITCHER_POD, Items::PITCHER_POD());
|
||||
$this->map1to1Item(Ids::POISONOUS_POTATO, Items::POISONOUS_POTATO());
|
||||
$this->map1to1Item(Ids::POPPED_CHORUS_FRUIT, Items::POPPED_CHORUS_FRUIT());
|
||||
$this->map1to1Item(Ids::PORKCHOP, Items::RAW_PORKCHOP());
|
||||
|
@ -134,6 +134,7 @@ final class ItemTypeNames{
|
||||
public const COOKED_RABBIT = "minecraft:cooked_rabbit";
|
||||
public const COOKED_SALMON = "minecraft:cooked_salmon";
|
||||
public const COOKIE = "minecraft:cookie";
|
||||
public const COPPER_DOOR = "minecraft:copper_door";
|
||||
public const COPPER_INGOT = "minecraft:copper_ingot";
|
||||
public const CORAL = "minecraft:coral";
|
||||
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_HANGING_SIGN = "minecraft:dark_oak_hanging_sign";
|
||||
public const DARK_OAK_SIGN = "minecraft:dark_oak_sign";
|
||||
public const DEBUG_STICK = "minecraft:debug_stick";
|
||||
public const DIAMOND = "minecraft:diamond";
|
||||
public const DIAMOND_AXE = "minecraft:diamond_axe";
|
||||
public const DIAMOND_BOOTS = "minecraft:diamond_boots";
|
||||
@ -186,6 +188,7 @@ final class ItemTypeNames{
|
||||
public const EVOKER_SPAWN_EGG = "minecraft:evoker_spawn_egg";
|
||||
public const EXPERIENCE_BOTTLE = "minecraft:experience_bottle";
|
||||
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 FEATHER = "minecraft:feather";
|
||||
public const FENCE = "minecraft:fence";
|
||||
@ -347,6 +350,7 @@ final class ItemTypeNames{
|
||||
public const OAK_SIGN = "minecraft:oak_sign";
|
||||
public const OCELOT_SPAWN_EGG = "minecraft:ocelot_spawn_egg";
|
||||
public const ORANGE_DYE = "minecraft:orange_dye";
|
||||
public const OXIDIZED_COPPER_DOOR = "minecraft:oxidized_copper_door";
|
||||
public const PAINTING = "minecraft:painting";
|
||||
public const PANDA_SPAWN_EGG = "minecraft:panda_spawn_egg";
|
||||
public const PAPER = "minecraft:paper";
|
||||
@ -360,6 +364,7 @@ final class ItemTypeNames{
|
||||
public const PILLAGER_SPAWN_EGG = "minecraft:pillager_spawn_egg";
|
||||
public const PINK_DYE = "minecraft:pink_dye";
|
||||
public const PITCHER_POD = "minecraft:pitcher_pod";
|
||||
public const PLANKS = "minecraft:planks";
|
||||
public const PLENTY_POTTERY_SHERD = "minecraft:plenty_pottery_sherd";
|
||||
public const POISONOUS_POTATO = "minecraft:poisonous_potato";
|
||||
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_SIGN = "minecraft:warped_sign";
|
||||
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 WEATHERED_COPPER_DOOR = "minecraft:weathered_copper_door";
|
||||
public const WHEAT = "minecraft:wheat";
|
||||
public const WHEAT_SEEDS = "minecraft:wheat_seeds";
|
||||
public const WHITE_DYE = "minecraft:white_dye";
|
||||
|
@ -173,8 +173,9 @@ abstract class Projectile extends Entity{
|
||||
$entityHit = null;
|
||||
$hitResult = null;
|
||||
|
||||
$world = $this->getWorld();
|
||||
foreach(VoxelRayTrace::betweenPoints($start, $end) as $vector3){
|
||||
$block = $this->getWorld()->getBlockAt($vector3->x, $vector3->y, $vector3->z);
|
||||
$block = $world->getBlockAt($vector3->x, $vector3->y, $vector3->z);
|
||||
|
||||
$blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end);
|
||||
if($blockHitResult !== null){
|
||||
@ -188,7 +189,7 @@ abstract class Projectile extends Entity{
|
||||
$entityDistance = PHP_INT_MAX;
|
||||
|
||||
$newDiff = $end->subtractVector($start);
|
||||
foreach($this->getWorld()->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){
|
||||
foreach($world->getCollidingEntities($this->boundingBox->addCoord($newDiff->x, $newDiff->y, $newDiff->z)->expand(1, 1, 1), $this) as $entity){
|
||||
if($entity->getId() === $this->getOwningEntityId() && $this->ticksLived < 5){
|
||||
continue;
|
||||
}
|
||||
@ -256,7 +257,7 @@ abstract class Projectile extends Entity{
|
||||
);
|
||||
}
|
||||
|
||||
$this->getWorld()->onEntityMoved($this);
|
||||
$world->onEntityMoved($this);
|
||||
$this->checkBlockIntersections();
|
||||
|
||||
Timings::$projectileMove->stopTiming();
|
||||
|
@ -31,8 +31,9 @@ class Snowball extends Throwable{
|
||||
public function getNetworkTypeId() : string{ return EntityIds::SNOWBALL; }
|
||||
|
||||
protected function onHit(ProjectileHitEvent $event) : void{
|
||||
$world = $this->getWorld();
|
||||
for($i = 0; $i < 6; ++$i){
|
||||
$this->getWorld()->addParticle($this->location, new SnowballPoofParticle());
|
||||
$world->addParticle($this->location, new SnowballPoofParticle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -322,8 +322,9 @@ final class ItemTypeIds{
|
||||
public const RIB_ARMOR_TRIM_SMITHING_TEMPLATE = 20283;
|
||||
public const EYE_ARMOR_TRIM_SMITHING_TEMPLATE = 20284;
|
||||
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;
|
||||
|
||||
|
34
src/item/PitcherPod.php
Normal file
34
src/item/PitcherPod.php
Normal 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();
|
||||
}
|
||||
}
|
@ -868,6 +868,7 @@ final class StringToItemParser extends StringToTParser{
|
||||
$result->registerBlock("pink_petals", fn() => Blocks::PINK_PETALS());
|
||||
$result->registerBlock("pink_tulip", fn() => Blocks::PINK_TULIP());
|
||||
$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("planks", fn() => Blocks::OAK_PLANKS());
|
||||
$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("paper", fn() => Items::PAPER());
|
||||
$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("popped_chorus_fruit", fn() => Items::POPPED_CHORUS_FRUIT());
|
||||
$result->register("porkchop", fn() => Items::RAW_PORKCHOP());
|
||||
|
@ -240,6 +240,7 @@ use function strtolower;
|
||||
* @method static PaintingItem PAINTING()
|
||||
* @method static Item PAPER()
|
||||
* @method static Item PHANTOM_MEMBRANE()
|
||||
* @method static PitcherPod PITCHER_POD()
|
||||
* @method static PoisonousPotato POISONOUS_POTATO()
|
||||
* @method static Item POPPED_CHORUS_FRUIT()
|
||||
* @method static Potato POTATO()
|
||||
@ -503,6 +504,7 @@ final class VanillaItems{
|
||||
self::register("painting", new PaintingItem(new IID(Ids::PAINTING), "Painting"));
|
||||
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("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("popped_chorus_fruit", new Item(new IID(Ids::POPPED_CHORUS_FRUIT), "Popped Chorus Fruit"));
|
||||
self::register("potato", new Potato(new IID(Ids::POTATO), "Potato"));
|
||||
|
@ -117,6 +117,7 @@ use function count;
|
||||
use function get_class;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function is_string;
|
||||
use function json_encode;
|
||||
use function random_bytes;
|
||||
use function str_split;
|
||||
@ -158,8 +159,8 @@ class NetworkSession{
|
||||
private array $sendBuffer = [];
|
||||
|
||||
/**
|
||||
* @var \SplQueue|CompressBatchPromise[]
|
||||
* @phpstan-var \SplQueue<CompressBatchPromise>
|
||||
* @var \SplQueue|CompressBatchPromise[]|string[]
|
||||
* @phpstan-var \SplQueue<CompressBatchPromise|string>
|
||||
*/
|
||||
private \SplQueue $compressedQueue;
|
||||
private bool $forceAsyncCompression = true;
|
||||
@ -235,8 +236,10 @@ class NetworkSession{
|
||||
$this->onPlayerCreated(...),
|
||||
function() : void{
|
||||
//TODO: this should never actually occur... right?
|
||||
$this->logger->error("Failed to create player");
|
||||
$this->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_error_internal());
|
||||
$this->disconnectWithError(
|
||||
reason: "Failed to create player",
|
||||
disconnectScreenMessage: KnownTranslationFactory::pocketmine_disconnect_error_internal()
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -525,13 +528,12 @@ class NetworkSession{
|
||||
PacketBatch::encodeRaw($stream, $this->sendBuffer);
|
||||
|
||||
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{
|
||||
$promise = new CompressBatchPromise();
|
||||
$promise->resolve($stream->getBuffer());
|
||||
$batch = $stream->getBuffer();
|
||||
}
|
||||
$this->sendBuffer = [];
|
||||
$this->queueCompressedNoBufferFlush($promise, $immediate);
|
||||
$this->queueCompressedNoBufferFlush($batch, $immediate);
|
||||
}finally{
|
||||
Timings::$playerNetworkSend->stopTiming();
|
||||
}
|
||||
@ -550,7 +552,7 @@ class NetworkSession{
|
||||
|
||||
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();
|
||||
try{
|
||||
$this->flushSendBuffer($immediate); //Maintain ordering if possible
|
||||
@ -560,36 +562,25 @@ class NetworkSession{
|
||||
}
|
||||
}
|
||||
|
||||
private function queueCompressedNoBufferFlush(CompressBatchPromise $payload, bool $immediate = false) : void{
|
||||
private function queueCompressedNoBufferFlush(CompressBatchPromise|string $batch, bool $immediate = false) : void{
|
||||
Timings::$playerNetworkSend->startTiming();
|
||||
try{
|
||||
if($immediate){
|
||||
if(is_string($batch)){
|
||||
if($immediate){
|
||||
//Skips all queues
|
||||
$this->sendEncoded($batch, true);
|
||||
}else{
|
||||
$this->compressedQueue->enqueue($batch);
|
||||
$this->flushCompressedQueue();
|
||||
}
|
||||
}elseif($immediate){
|
||||
//Skips all queues
|
||||
$this->sendEncoded($payload->getResult(), true);
|
||||
$this->sendEncoded($batch->getResult(), true);
|
||||
}else{
|
||||
$this->compressedQueue->enqueue($payload);
|
||||
$payload->onResolve(function(CompressBatchPromise $payload) : void{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}finally{
|
||||
Timings::$playerNetworkSend->stopTiming();
|
||||
}
|
||||
$this->compressedQueue->enqueue($batch);
|
||||
$batch->onResolve(function() : void{
|
||||
if($this->connected){
|
||||
$this->flushCompressedQueue();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -598,6 +589,30 @@ class NetworkSession{
|
||||
}
|
||||
}
|
||||
|
||||
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{
|
||||
Timings::$playerNetworkSend->stopTiming();
|
||||
}
|
||||
}
|
||||
|
||||
private function sendEncoded(string $payload, bool $immediate = false) : void{
|
||||
if($this->cipher !== null){
|
||||
Timings::$playerNetworkSendEncrypt->startTiming();
|
||||
@ -662,8 +677,13 @@ class NetworkSession{
|
||||
}, $reason);
|
||||
}
|
||||
|
||||
public function disconnectWithError(Translatable|string $reason) : void{
|
||||
$this->disconnect(KnownTranslationFactory::pocketmine_disconnect_error($reason, implode("-", str_split(bin2hex(random_bytes(6)), 4))));
|
||||
public function disconnectWithError(Translatable|string $reason, Translatable|string|null $disconnectScreenMessage = null) : void{
|
||||
$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{
|
||||
@ -722,7 +742,10 @@ class NetworkSession{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -1118,12 +1141,12 @@ class NetworkSession{
|
||||
*/
|
||||
public function syncPlayerList(array $players) : void{
|
||||
$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)));
|
||||
}
|
||||
|
||||
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{
|
||||
|
@ -88,9 +88,9 @@ final class StandardPacketBroadcaster implements PacketBroadcaster{
|
||||
PacketBatch::encodeRaw($stream, $packetBuffers);
|
||||
$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){
|
||||
$target->queueCompressed($promise);
|
||||
$target->queueCompressed($batch);
|
||||
}
|
||||
}else{
|
||||
foreach($compressorTargets as $target){
|
||||
|
25
src/network/mcpe/cache/ChunkCache.php
vendored
25
src/network/mcpe/cache/ChunkCache.php
vendored
@ -136,32 +136,19 @@ class ChunkCache implements ChunkListener{
|
||||
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
|
||||
*/
|
||||
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->hasResult()){
|
||||
//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{
|
||||
//dump the cache, it'll be regenerated the next time it's requested
|
||||
$this->destroy($chunkX, $chunkZ);
|
||||
|
2
src/network/mcpe/cache/CraftingDataCache.php
vendored
2
src/network/mcpe/cache/CraftingDataCache.php
vendored
@ -160,7 +160,7 @@ final class CraftingDataCache{
|
||||
}
|
||||
|
||||
$potionContainerChangeRecipes = [];
|
||||
$itemTypeDictionary = TypeConverter::getInstance()->getItemTypeDictionary();
|
||||
$itemTypeDictionary = $converter->getItemTypeDictionary();
|
||||
foreach($manager->getPotionContainerChangeRecipes() as $recipe){
|
||||
$input = $itemTypeDictionary->fromStringId($recipe->getInputItemId());
|
||||
$ingredient = $converter->coreRecipeIngredientToNet($recipe->getIngredient())->getDescriptor();
|
||||
|
@ -57,7 +57,6 @@ use pocketmine\network\mcpe\protocol\BossEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket;
|
||||
use pocketmine\network\mcpe\protocol\CommandRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
|
||||
use pocketmine\network\mcpe\protocol\CraftingEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\EmotePacket;
|
||||
use pocketmine\network\mcpe\protocol\InteractPacket;
|
||||
use pocketmine\network\mcpe\protocol\InventoryTransactionPacket;
|
||||
@ -731,10 +730,6 @@ class InGamePacketHandler extends PacketHandler{
|
||||
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{
|
||||
$pos = new Vector3($packet->blockPosition->getX(), $packet->blockPosition->getY(), $packet->blockPosition->getZ());
|
||||
if($pos->distanceSquared($this->player->getLocation()) > 10000){
|
||||
|
@ -73,8 +73,10 @@ class LoginPacketHandler extends PacketHandler{
|
||||
try{
|
||||
$skin = $this->session->getTypeConverter()->getSkinAdapter()->fromSkinData(ClientDataToSkinDataHelper::fromClientData($clientData));
|
||||
}catch(\InvalidArgumentException | InvalidSkinException $e){
|
||||
$this->session->getLogger()->debug("Invalid skin: " . $e->getMessage());
|
||||
$this->session->disconnectWithError(KnownTranslationFactory::disconnectionScreen_invalidSkin());
|
||||
$this->session->disconnectWithError(
|
||||
reason: "Invalid skin: " . $e->getMessage(),
|
||||
disconnectScreenMessage: KnownTranslationFactory::disconnectionScreen_invalidSkin()
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -85,8 +85,10 @@ class ResourcePacksPacketHandler extends PacketHandler{
|
||||
}
|
||||
|
||||
private function disconnectWithError(string $error) : void{
|
||||
$this->session->getLogger()->error("Error downloading resource packs: " . $error);
|
||||
$this->session->disconnectWithError(KnownTranslationFactory::disconnectionScreen_resourcePack());
|
||||
$this->session->disconnectWithError(
|
||||
reason: "Error downloading resource packs: " . $error,
|
||||
disconnectScreenMessage: KnownTranslationFactory::disconnectionScreen_resourcePack()
|
||||
);
|
||||
}
|
||||
|
||||
public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{
|
||||
|
@ -219,11 +219,14 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{
|
||||
$session->handleEncoded($buf);
|
||||
}catch(PacketHandlingException $e){
|
||||
$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
|
||||
$logger->debug(implode("\n", Utils::printableExceptionInfo($e)));
|
||||
$session->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_error_badPacket());
|
||||
|
||||
$this->interface->blockAddress($address, 5);
|
||||
}catch(\Throwable $e){
|
||||
//record the name of the player who caused the crash, to make it easier to find the reproducing steps
|
||||
|
@ -818,13 +818,13 @@ class Player extends Human implements CommandSender, ChunkListener, IPlayer{
|
||||
$this->usedChunks[$index] = UsedChunkStatus::REQUESTED_GENERATION;
|
||||
$this->activeChunkGenerationRequests[$index] = true;
|
||||
unset($this->loadQueue[$index]);
|
||||
$this->getWorld()->registerChunkLoader($this->chunkLoader, $X, $Z, true);
|
||||
$this->getWorld()->registerChunkListener($this, $X, $Z);
|
||||
$world->registerChunkLoader($this->chunkLoader, $X, $Z, true);
|
||||
$world->registerChunkListener($this, $X, $Z);
|
||||
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{
|
||||
if(!$this->isConnected() || !isset($this->usedChunks[$index]) || $world !== $this->getWorld()){
|
||||
return;
|
||||
|
@ -73,7 +73,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
|
||||
|
||||
$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->scheduler = new TaskScheduler($this->getFullName());
|
||||
|
||||
@ -148,9 +148,9 @@ abstract class PluginBase implements Plugin, CommandExecutor{
|
||||
private function registerYamlCommands() : void{
|
||||
$pluginCmds = [];
|
||||
|
||||
foreach(Utils::stringifyKeys($this->getDescription()->getCommands()) as $key => $data){
|
||||
foreach(Utils::stringifyKeys($this->description->getCommands()) as $key => $data){
|
||||
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;
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
|
||||
$aliasList = [];
|
||||
foreach($data->getAliases() as $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;
|
||||
}
|
||||
$aliasList[] = $alias;
|
||||
@ -184,7 +184,7 @@ abstract class PluginBase implements Plugin, CommandExecutor{
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
public function getCommand(string $name){
|
||||
$command = $this->getServer()->getPluginCommand($name);
|
||||
$command = $this->server->getPluginCommand($name);
|
||||
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){
|
||||
|
@ -28,6 +28,7 @@ use pmmp\thread\Thread as NativeThread;
|
||||
use pmmp\thread\ThreadSafe;
|
||||
use pmmp\thread\ThreadSafeArray;
|
||||
use pocketmine\thread\NonThreadSafeValue;
|
||||
use function array_key_exists;
|
||||
use function assert;
|
||||
use function igbinary_serialize;
|
||||
use function igbinary_unserialize;
|
||||
@ -202,7 +203,7 @@ abstract class AsyncTask extends Runnable{
|
||||
*/
|
||||
protected function fetchLocal(string $key){
|
||||
$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");
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ use function get_class;
|
||||
use function str_starts_with;
|
||||
|
||||
abstract class Timings{
|
||||
public const GROUP_MINECRAFT = "Minecraft";
|
||||
public const GROUP_BREAKDOWN = "Minecraft - Breakdown";
|
||||
|
||||
private static bool $initialized = false;
|
||||
@ -134,8 +135,8 @@ abstract class Timings{
|
||||
self::$initialized = true;
|
||||
|
||||
self::$fullTick = new TimingsHandler("Full Server Tick");
|
||||
self::$serverTick = new TimingsHandler("Server Tick Update Cycle", self::$fullTick, group: self::GROUP_BREAKDOWN);
|
||||
self::$serverInterrupts = new TimingsHandler("Server Mid-Tick Processing", 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);
|
||||
self::$memoryManager = new TimingsHandler("Memory Manager");
|
||||
self::$garbageCollector = new TimingsHandler("Garbage Collector", self::$memoryManager);
|
||||
self::$titleTick = new TimingsHandler("Console Title Tick");
|
||||
@ -143,51 +144,51 @@ abstract class Timings{
|
||||
self::$connection = new TimingsHandler("Connection Handler");
|
||||
|
||||
self::$playerNetworkSend = new TimingsHandler("Player Network Send", self::$connection);
|
||||
self::$playerNetworkSendCompress = new TimingsHandler("Player Network Send - Compression", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||
self::$playerNetworkSendCompressBroadcast = new TimingsHandler("Player Network Send - Compression (Broadcast)", self::$playerNetworkSendCompress, group: self::GROUP_BREAKDOWN);
|
||||
self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler("Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress, group: self::GROUP_BREAKDOWN);
|
||||
self::$playerNetworkSendEncrypt = new TimingsHandler("Player Network Send - Encryption", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||
self::$playerNetworkSendInventorySync = new TimingsHandler("Player Network Send - Inventory Sync", self::$playerNetworkSend, group: self::GROUP_BREAKDOWN);
|
||||
self::$playerNetworkSendPreSpawnGameData = new TimingsHandler("Player Network Send - Pre-Spawn Game Data", 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);
|
||||
self::$playerNetworkSendCompressSessionBuffer = new TimingsHandler("Player Network Send - Compression (Session Buffer)", self::$playerNetworkSendCompress);
|
||||
self::$playerNetworkSendEncrypt = new TimingsHandler("Player Network Send - Encryption", self::$playerNetworkSend);
|
||||
self::$playerNetworkSendInventorySync = new TimingsHandler("Player Network Send - Inventory Sync", self::$playerNetworkSend);
|
||||
self::$playerNetworkSendPreSpawnGameData = new TimingsHandler("Player Network Send - Pre-Spawn Game Data", self::$playerNetworkSend);
|
||||
|
||||
self::$playerNetworkReceive = new TimingsHandler("Player Network Receive", self::$connection);
|
||||
self::$playerNetworkReceiveDecompress = new TimingsHandler("Player Network Receive - Decompression", self::$playerNetworkReceive, group: self::GROUP_BREAKDOWN);
|
||||
self::$playerNetworkReceiveDecrypt = new TimingsHandler("Player Network Receive - Decryption", 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);
|
||||
|
||||
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::$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::$serverCommand = new TimingsHandler("Server Command");
|
||||
self::$permissibleCalculation = new TimingsHandler("Permissible Calculation");
|
||||
self::$permissibleCalculationDiff = new TimingsHandler("Permissible Calculation - Diff", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN);
|
||||
self::$permissibleCalculationCallback = new TimingsHandler("Permissible Calculation - Callbacks", self::$permissibleCalculation, group: self::GROUP_BREAKDOWN);
|
||||
self::$permissibleCalculationDiff = new TimingsHandler("Permissible Calculation - Diff", self::$permissibleCalculation);
|
||||
self::$permissibleCalculationCallback = new TimingsHandler("Permissible Calculation - Callbacks", self::$permissibleCalculation);
|
||||
|
||||
self::$syncPlayerDataLoad = new TimingsHandler("Player Data Load");
|
||||
self::$syncPlayerDataSave = new TimingsHandler("Player Data Save");
|
||||
|
||||
self::$entityMove = new TimingsHandler("Entity Movement", group: self::GROUP_BREAKDOWN);
|
||||
self::$entityMoveCollision = new TimingsHandler("Entity Movement - Collision Checks", self::$entityMove, group: self::GROUP_BREAKDOWN);
|
||||
self::$entityMove = new TimingsHandler("Entity Movement");
|
||||
self::$entityMoveCollision = new TimingsHandler("Entity Movement - Collision Checks", self::$entityMove);
|
||||
|
||||
self::$projectileMove = new TimingsHandler("Projectile Movement", self::$entityMove, group: self::GROUP_BREAKDOWN);
|
||||
self::$projectileMoveRayTrace = new TimingsHandler("Projectile Movement - Ray Tracing", self::$projectileMove, group: self::GROUP_BREAKDOWN);
|
||||
self::$projectileMove = new TimingsHandler("Projectile Movement", self::$entityMove);
|
||||
self::$projectileMoveRayTrace = new TimingsHandler("Projectile Movement - Ray Tracing", self::$projectileMove);
|
||||
|
||||
self::$playerCheckNearEntities = new TimingsHandler("checkNearEntities", group: self::GROUP_BREAKDOWN);
|
||||
self::$entityBaseTick = new TimingsHandler("Entity Base Tick", group: self::GROUP_BREAKDOWN);
|
||||
self::$livingEntityBaseTick = new TimingsHandler("Entity Base Tick - Living", group: self::GROUP_BREAKDOWN);
|
||||
self::$itemEntityBaseTick = new TimingsHandler("Entity Base Tick - ItemEntity", group: self::GROUP_BREAKDOWN);
|
||||
self::$playerCheckNearEntities = new TimingsHandler("checkNearEntities");
|
||||
self::$entityBaseTick = new TimingsHandler("Entity Base Tick");
|
||||
self::$livingEntityBaseTick = new TimingsHandler("Entity Base Tick - Living");
|
||||
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::$asyncTaskProgressUpdateParent = new TimingsHandler("Async Tasks - Progress Updates", self::$schedulerAsync, group: self::GROUP_BREAKDOWN);
|
||||
self::$asyncTaskCompletionParent = new TimingsHandler("Async Tasks - Completion Handlers", self::$schedulerAsync, group: self::GROUP_BREAKDOWN);
|
||||
self::$asyncTaskErrorParent = new TimingsHandler("Async Tasks - Error Handlers", self::$schedulerAsync, group: self::GROUP_BREAKDOWN);
|
||||
self::$schedulerAsync = new TimingsHandler("Scheduler - Async Tasks");
|
||||
self::$asyncTaskProgressUpdateParent = new TimingsHandler("Async Tasks - Progress Updates", self::$schedulerAsync);
|
||||
self::$asyncTaskCompletionParent = new TimingsHandler("Async Tasks - Completion Handlers", self::$schedulerAsync);
|
||||
self::$asyncTaskErrorParent = new TimingsHandler("Async Tasks - Error Handlers", self::$schedulerAsync);
|
||||
|
||||
self::$playerCommand = new TimingsHandler("Player Command", group: self::GROUP_BREAKDOWN);
|
||||
self::$craftingDataCacheRebuild = new TimingsHandler("Build CraftingDataPacket Cache", group: self::GROUP_BREAKDOWN);
|
||||
self::$playerCommand = new TimingsHandler("Player Command");
|
||||
self::$craftingDataCacheRebuild = new TimingsHandler("Build CraftingDataPacket Cache");
|
||||
|
||||
}
|
||||
|
||||
@ -229,7 +230,7 @@ abstract class Timings{
|
||||
}else{
|
||||
$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];
|
||||
@ -239,8 +240,7 @@ abstract class Timings{
|
||||
self::init();
|
||||
if(!isset(self::$tileEntityTypeTimingMap[$tile::class])){
|
||||
self::$tileEntityTypeTimingMap[$tile::class] = new TimingsHandler(
|
||||
"Block Entity Tick - " . self::shortenCoreClassName($tile::class, "pocketmine\\block\\tile\\"),
|
||||
group: self::GROUP_BREAKDOWN
|
||||
"Block Entity Tick - " . self::shortenCoreClassName($tile::class, "pocketmine\\block\\tile\\")
|
||||
);
|
||||
}
|
||||
|
||||
@ -250,7 +250,7 @@ abstract class Timings{
|
||||
public static function getReceiveDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
||||
self::init();
|
||||
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];
|
||||
@ -259,31 +259,28 @@ abstract class Timings{
|
||||
public static function getDecodeDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
||||
return self::$packetDecodeTimingMap[$pk::class] ??= new TimingsHandler(
|
||||
"Decode - " . $pk->getName(),
|
||||
self::getReceiveDataPacketTimings($pk),
|
||||
group: self::GROUP_BREAKDOWN
|
||||
self::getReceiveDataPacketTimings($pk)
|
||||
);
|
||||
}
|
||||
|
||||
public static function getHandleDataPacketTimings(ServerboundPacket $pk) : TimingsHandler{
|
||||
return self::$packetHandleTimingMap[$pk::class] ??= new TimingsHandler(
|
||||
"Handler - " . $pk->getName(),
|
||||
self::getReceiveDataPacketTimings($pk),
|
||||
group: self::GROUP_BREAKDOWN
|
||||
self::getReceiveDataPacketTimings($pk)
|
||||
);
|
||||
}
|
||||
|
||||
public static function getEncodeDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
||||
return self::$packetEncodeTimingMap[$pk::class] ??= new TimingsHandler(
|
||||
"Encode - " . $pk->getName(),
|
||||
self::getSendDataPacketTimings($pk),
|
||||
group: self::GROUP_BREAKDOWN
|
||||
self::getSendDataPacketTimings($pk)
|
||||
);
|
||||
}
|
||||
|
||||
public static function getSendDataPacketTimings(ClientboundPacket $pk) : TimingsHandler{
|
||||
self::init();
|
||||
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];
|
||||
@ -292,7 +289,7 @@ abstract class Timings{
|
||||
public static function getCommandDispatchTimings(string $commandName) : TimingsHandler{
|
||||
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{
|
||||
@ -316,7 +313,7 @@ abstract class Timings{
|
||||
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;
|
||||
if(!isset(self::$asyncTaskProgressUpdate[$taskClass])){
|
||||
self::init();
|
||||
@ -330,7 +327,7 @@ abstract class Timings{
|
||||
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;
|
||||
if(!isset(self::$asyncTaskCompletion[$taskClass])){
|
||||
self::init();
|
||||
@ -344,7 +341,7 @@ abstract class Timings{
|
||||
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;
|
||||
if(!isset(self::$asyncTaskError[$taskClass])){
|
||||
self::init();
|
||||
|
@ -120,7 +120,7 @@ class TimingsHandler{
|
||||
public function __construct(
|
||||
private string $name,
|
||||
private ?TimingsHandler $parent = null,
|
||||
private string $group = "Minecraft"
|
||||
private string $group = Timings::GROUP_MINECRAFT
|
||||
){}
|
||||
|
||||
public function getName() : string{ return $this->name; }
|
||||
|
@ -33,7 +33,7 @@ use function preg_match;
|
||||
* 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.
|
||||
* 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{
|
||||
/**
|
||||
|
@ -1016,8 +1016,12 @@ class World implements ChunkManager{
|
||||
continue;
|
||||
}
|
||||
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){
|
||||
$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){
|
||||
$p->onChunkChanged($chunkX, $chunkZ, $chunk);
|
||||
}
|
||||
@ -2623,7 +2627,7 @@ class World implements ChunkManager{
|
||||
|
||||
public function isChunkPopulated(int $x, int $z) : bool{
|
||||
$chunk = $this->loadChunk($x, $z);
|
||||
return $chunk !== null ? $chunk->isPopulated() : false;
|
||||
return $chunk !== null && $chunk->isPopulated();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\world;
|
||||
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
|
||||
class WorldTimings{
|
||||
@ -66,7 +65,7 @@ class WorldTimings{
|
||||
private static function newTimer(string $worldName, string $timerName) : TimingsHandler{
|
||||
$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){
|
||||
|
@ -51,12 +51,12 @@ use function time;
|
||||
class BedrockWorldData extends BaseNbtWorldData{
|
||||
|
||||
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 = [
|
||||
1, //major
|
||||
20, //minor
|
||||
40, //patch
|
||||
1, //revision
|
||||
50, //patch
|
||||
3, //revision
|
||||
0 //is beta
|
||||
];
|
||||
|
||||
|
@ -32,7 +32,7 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'git' on mixed\\.$#"
|
||||
count: 2
|
||||
count: 1
|
||||
path: ../../../src/VersionInfo.php
|
||||
|
||||
-
|
||||
@ -807,7 +807,7 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset string on mixed\\.$#"
|
||||
count: 3
|
||||
count: 2
|
||||
path: ../../../src/utils/Config.php
|
||||
|
||||
-
|
||||
@ -965,11 +965,6 @@ parameters:
|
||||
count: 2
|
||||
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\\.$#"
|
||||
count: 2
|
||||
|
@ -20,21 +20,6 @@ parameters:
|
||||
count: 1
|
||||
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\\.$#"
|
||||
count: 1
|
||||
|
@ -121,4 +121,23 @@ class AsyncPoolTest extends TestCase{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user