Compare commits

..

6 Commits

Author SHA1 Message Date
016614e714 ... 2025-02-17 02:05:09 +00:00
9e7e76a609 Fix PHPStan 2025-02-17 02:01:52 +00:00
b1e4e44f77 Ensure overloaded members can't conflict with static ones and vice versa 2025-02-17 01:58:08 +00:00
f4f31b654b Generate parameter name 2025-02-17 01:56:13 +00:00
799dfecdd9 typo 2025-02-17 01:13:18 +00:00
1415e2492a First look at enum-overloaded registry members
this allows us to reference registry members with dynamic enum cases, which has a lot of potential applications.

this enables us to keep the blocks as unique types, but with some of the power of dynamic state properties.

this is a rough initial proof of concept; it will need to be improved for further integration.
2025-02-17 00:58:07 +00:00
166 changed files with 2598 additions and 1289 deletions

View File

@ -57,9 +57,6 @@ body:
attributes:
value: |
## Version, OS and game info
> [!WARNING]
> "Latest" is not a valid version.
> Failure to fill these fields with valid information may result in your issue being closed.
- type: input
attributes:

View File

@ -12,10 +12,6 @@ updates:
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
#since we lock this to exact versions, it causes conflicts with minor-next & major-next in composer.lock
#better to just test updates to this locally anyway since almost every version breaks something
- dependency-name: phpstan/phpstan
groups:
production-patch-updates:
dependency-type: production

View File

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

View File

@ -165,7 +165,7 @@ jobs:
${{ github.workspace }}/core-permissions.rst
- name: Create draft release
uses: ncipollo/release-action@v1.16.0
uses: ncipollo/release-action@v1.15.0
id: create-draft
with:
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json,${{ github.workspace }}/core-permissions.rst
@ -182,8 +182,6 @@ jobs:
:information_source: Download the recommended PHP binary [here](${{ steps.php-binary-url.outputs.PHP_BINARY_URL }}).
:warning: Found a bug? Report it on our [issue tracker](${{ github.server_url }}/${{ github.repository }}/issues). **We can't fix bugs if you don't report them.**
- name: Post draft release URL on PR
if: github.event_name == 'pull_request_target'
uses: thollander/actions-comment-pull-request@v3

View File

@ -20,7 +20,10 @@ jobs:
- Check our [Documentation](https://doc.pmmp.io) to see if you can find answers there
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG)
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG) or our [Forums](https://forums.pmmp.io)
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
close-issue: true
lock-issue: false

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "tests/plugins/DevTools"]
path = tests/plugins/DevTools
url = https://github.com/pmmp/DevTools.git
[submodule "build/php"]
path = build/php
url = https://github.com/pmmp/php-build-scripts.git

View File

@ -5,6 +5,7 @@ $finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/build')
->in(__DIR__ . '/tests')
->in(__DIR__ . '/tools')
->notPath('plugins/DevTools')
->notName('PocketMine.php');
return (new PhpCsFixer\Config)

View File

@ -65,8 +65,6 @@ PocketMine-MP accepts community contributions! The following resources will be u
* [Building and running PocketMine-MP from source](BUILDING.md)
* [Contributing Guidelines](CONTRIBUTING.md)
New here? Check out [issues with the "Easy task" label](https://github.com/pmmp/PocketMine-MP/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Easy%20task%22) for things you could work to familiarise yourself with the codebase.
## Donate
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.

View File

@ -36,7 +36,7 @@ require dirname(__DIR__) . '/vendor/autoload.php';
*/
$options = [
"base_version" => VersionInfo::BASE_VERSION,
"major_version" => fn() => explode(".", VersionInfo::BASE_VERSION, limit: 2)[0],
"major_version" => fn() => explode(".", VersionInfo::BASE_VERSION)[0],
"mcpe_version" => ProtocolInfo::MINECRAFT_VERSION_NETWORK,
"is_dev" => VersionInfo::IS_DEVELOPMENT_BUILD,
"changelog_file_name" => function() : string{

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\build\update_registry_annotations;
use pocketmine\utils\OverloadedRegistryMember;
use pocketmine\utils\Utils;
use function basename;
use function class_exists;
@ -34,6 +35,7 @@ use function fwrite;
use function implode;
use function is_dir;
use function ksort;
use function lcfirst;
use function mb_strtoupper;
use function preg_match;
use function sprintf;
@ -47,11 +49,19 @@ if(count($argv) !== 2){
exit(1);
}
/**
* @phpstan-param \ReflectionClass<*> $class
*/
function makeTypehint(string $namespaceName, \ReflectionClass $class) : string{
return $class->getNamespaceName() === $namespaceName ? $class->getShortName() : '\\' . $class->getName();
}
/**
* @param object[] $members
* @phpstan-param array<string, object> $members
* @phpstan-param array<string, OverloadedRegistryMember> $overloadedMembers
*/
function generateMethodAnnotations(string $namespaceName, array $members) : string{
function generateMethodAnnotations(string $namespaceName, array $members, array $overloadedMembers) : string{
$selfName = basename(__FILE__);
$lines = ["/**"];
$lines[] = " * This doc-block is generated automatically, do not modify it manually.";
@ -69,14 +79,20 @@ function generateMethodAnnotations(string $namespaceName, array $members) : stri
}
if($reflect === false){
$typehint = "object";
}elseif($reflect->getNamespaceName() === $namespaceName){
$typehint = $reflect->getShortName();
}else{
$typehint = '\\' . $reflect->getName();
$typehint = makeTypehint($namespaceName, $reflect);
}
$accessor = mb_strtoupper($name);
$memberLines[$accessor] = sprintf($lineTmpl, $accessor, $typehint);
}
foreach(Utils::stringifyKeys($overloadedMembers) as $baseName => $member){
$accessor = mb_strtoupper($baseName);
$returnTypehint = makeTypehint($namespaceName, new \ReflectionClass($member->memberClass));
$enumReflect = new \ReflectionClass($member->enumClass);
$paramTypehint = makeTypehint($namespaceName, $enumReflect);
$memberLines[] = sprintf(" * @method static %s %s(%s \$%s)", $returnTypehint, $accessor, $paramTypehint, lcfirst($enumReflect->getShortName()));
}
ksort($memberLines, SORT_STRING);
foreach($memberLines as $line){
@ -107,7 +123,7 @@ function processFile(string $file) : void{
}
echo "Found registry in $file\n";
$replacement = generateMethodAnnotations($matches[1], $className::getAll());
$replacement = generateMethodAnnotations($matches[1], $className::getAll(), $className::getAllOverloaded());
$newContents = str_replace($docComment, $replacement, $contents);
if($newContents !== $contents){

View File

@ -36,17 +36,3 @@ It also allows creating new collapsible groups of items, and modifying or removi
- `BedrockDataFiles` now includes constants for folders at the top level of `BedrockData` as well as files.
- The structure of creative data in `BedrockData` was changed to accommodate item category and grouping information. `creativeitems.json` has been replaced by `creative/*.json`, which contain information about item grouping and also segregates item lists per category.
- New information was added to `required_item_list.json` in `BedrockData`, as the server is now required to send item component NBT data in some cases.
# 5.25.1
Released 26th February 2025.
## Fixes
- Fixed confusing exception message when a block-breaking tool has an efficiency value of zero.
- Fixed incorrect facing of doors since 1.21.60 (resulted in mismatched AABBs between client & server, rendering glitches etc.)
- Resource pack UUIDs are now validated on load. Previously, invalid UUIDs would be accepted, and potentially cause a server crash on player join.
# 5.25.2
Released 4th March 2025.
## Fixes
- Added limits to various `explode()` calls.

View File

@ -1,71 +0,0 @@
# 5.26.0
Released 22nd March 2025.
This is a minor feature release focused on performance improvements.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## Performance
- Significantly improved performance of entity movement. Load testing with item entities showed a 3x increase in the number of entities supported without lag.
- Significantly improved performance of on-ground checks for player movement. This still needs further work, but optimisations implemented in this version should improve performance substantially.
- Updated `pocketmine/nbt` dependency with performance improvements to `TAG_Compound` and `TAG_List` comparison. This should improve performance of inventory-related actions.
- `InventoryTransaction` now avoids useless item clones when processing transactions, which should improve performance of inventory-related actions.
## Dependencies
- `pocketmine/bedrock-protocol` has been updated to `36.2.0`, which adds new functions to access some packet fields.
- `pocketmine/nbt` has been updated to `1.1.0`, which improves performance when comparing NBT object trees.
## Gameplay
- Block breaking animation speed now takes into account the following: jumping, being in water, haste, mining fatigue
## Tools
- `blockstate-upgrade-schema-utils.php` now has a new `dump-table` command, which turns a `.bin` palette table file into human-readable text for debugging.
## API
### `pocketmine\block`
- The following methods have been added:
- `public RuntimeBlockStateRegistry->hasStateId(int $stateId) : bool` - checks whether the given state ID is registered
### `pocketmine\crafting`
- The following methods have been deprecated:
- `CraftingManager::sort()` - this was implicitly internal anyway
### `pocketmine\utils`
- The following constants have been added:
- `TextFormat::MATERIAL_RESIN`
- The following static properties have been added:
- `Terminal::$COLOR_MATERIAL_RESIN`
### `pocketmine\data\bedrock\block`
- `BlockStateToObjectDeserializer` now permits overriding **deserializers** for Bedrock IDs. This may be useful to implement custom state handling, or to implement missing block variants (such as snow cauldron).
- This was originally prohibited since 5.0.0. However, there is no technical reason to disallow overriding **deserializers**.
- Overriding **serializers** is still **not permitted**. Reusing type IDs doesn't make any sense and would break internal design contracts.
- If you want to make a custom version of a vanilla block, create a custom type ID for it, exactly as you would for a regular custom block.
- The following methods have been added:
- `public BlockStateToObjectDeserializer->getDeserializerForId(string $id) : ?(\Closure(BlockStateReader) : Block)`
### `pocketmine\data\bedrock\item`
- `ItemDeserializer` now permits overriding **deserializers** for Bedrock IDs. As above, this may be useful to implement custom data handling, or to implement missing variants of existing items.
- This was originally prohibited since 5.0.0. However, there is no technical reason to disallow overriding **deserializers**.
- Overriding **serializers** is still **not permitted**. Reusing type IDs doesn't make any sense and would break internal design contracts.
- As above, if you want to make a custom version of a vanilla item, create a custom type ID for it, exactly as you would for a regular custom item.
- The following methods have been added:
- `public ItemDeserializer->getDeserializerForId(string $id) : ?(\Closure(SavedItemData) : Item)`
## Internals
- `new $class` is now banned on new internals code by a PHPStan rule. Closures or factory objects should be used instead for greater flexibility and better static analysis.
- `CraftingManager` now uses a more stable hash function for recipe output filtering.
- `ChunkCache` now accepts `int $dimensionId` in the constructor. This may be useful for plugins which implement the nether.
- `RuntimeBlockStateRegistry` now precomputes basic collision info about known states for fast paths.
- This permits specialization for common shapes like cubes and collisionless blocks, which allows skipping complex logic in entity movement calculation. This vastly improves performance.
- Any block whose class overrides `readStateFromWorld()` or `getModelPositionOffset()` will *not* be optimised.
- `Block->recalculateCollisionBoxes()` now has a hard requirement not to depend on anything other than available properties. It must not use `World` or its position.
- This change was problematic for `ChorusPlant`, which used nearby blocks to calculate its collision boxes.
- Blocks which need nearby blocks should override `readStateFromWorld()` and set dynamic state properties, similar to fences.
- This design flaw will be corrected with a major change to `Block` internals currently in planning for a future major version.
- `Block->getCollisionBoxes()` may not be called at all during gameplay for blocks with shapes determined to be simple, like cubes and collisionless blocks.
- `BlockStateToObjectDeserializer` now checks if the returned blockstate is registered in `RuntimeBlockStateRegistry` to promote earlier error detection (instead of crashing in random code paths).

View File

@ -36,7 +36,7 @@
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
"pocketmine/bedrock-data": "~4.0.0+bedrock-1.21.60",
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
"pocketmine/bedrock-protocol": "~36.2.0+bedrock-1.21.60",
"pocketmine/bedrock-protocol": "~36.0.0+bedrock-1.21.60",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/color": "^0.3.0",
@ -52,7 +52,7 @@
"symfony/filesystem": "~6.4.0"
},
"require-dev": {
"phpstan/phpstan": "2.1.8",
"phpstan/phpstan": "2.1.4",
"phpstan/phpstan-phpunit": "^2.0.0",
"phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^10.5.24"
@ -78,6 +78,7 @@
"sort-packages": true
},
"scripts": {
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make ./ --relative tests/plugins/DevTools --out plugins/DevTools.phar",
"make-server": [
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
"@php -dphar.readonly=0 build/server-phar.php"

141
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "6314ae9a7919042f10bd17f0a3ef6e9d",
"content-hash": "663122b8f03ef5ec6718a419923a0851",
"packages": [
{
"name": "adhocore/json-comment",
@ -67,16 +67,16 @@
},
{
"name": "brick/math",
"version": "0.12.3",
"version": "0.12.1",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
"reference": "f510c0a40911935b77b86859eb5223d58d660df1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
"url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1",
"reference": "f510c0a40911935b77b86859eb5223d58d660df1",
"shasum": ""
},
"require": {
@ -85,7 +85,7 @@
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^10.1",
"vimeo/psalm": "6.8.8"
"vimeo/psalm": "5.16.0"
},
"type": "library",
"autoload": {
@ -115,7 +115,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.12.3"
"source": "https://github.com/brick/math/tree/0.12.1"
},
"funding": [
{
@ -123,7 +123,7 @@
"type": "github"
}
],
"time": "2025-02-28T13:11:00+00:00"
"time": "2023-11-29T23:19:16+00:00"
},
{
"name": "netresearch/jsonmapper",
@ -256,16 +256,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
"version": "36.2.0+bedrock-1.21.60",
"version": "36.0.0+bedrock-1.21.60",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "6830e8a9ee9ecb6984b7b02f412473136ae92d50"
"reference": "2057de319c5c551001c2a544e08d1bc7727d9963"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/6830e8a9ee9ecb6984b7b02f412473136ae92d50",
"reference": "6830e8a9ee9ecb6984b7b02f412473136ae92d50",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/2057de319c5c551001c2a544e08d1bc7727d9963",
"reference": "2057de319c5c551001c2a544e08d1bc7727d9963",
"shasum": ""
},
"require": {
@ -296,9 +296,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/36.2.0+bedrock-1.21.60"
"source": "https://github.com/pmmp/BedrockProtocol/tree/36.0.0+bedrock-1.21.60"
},
"time": "2025-03-14T17:17:21+00:00"
"time": "2025-02-16T15:59:08+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -471,16 +471,16 @@
},
{
"name": "pocketmine/locale-data",
"version": "2.24.1",
"version": "2.24.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Language.git",
"reference": "8f48cbe1fb5835a8bb573bed00ef04c65c26c7e5"
"reference": "6ec5e92c77a2102b2692763733e4763012facae9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Language/zipball/8f48cbe1fb5835a8bb573bed00ef04c65c26c7e5",
"reference": "8f48cbe1fb5835a8bb573bed00ef04c65c26c7e5",
"url": "https://api.github.com/repos/pmmp/Language/zipball/6ec5e92c77a2102b2692763733e4763012facae9",
"reference": "6ec5e92c77a2102b2692763733e4763012facae9",
"shasum": ""
},
"type": "library",
@ -488,9 +488,9 @@
"description": "Language resources used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Language/issues",
"source": "https://github.com/pmmp/Language/tree/2.24.1"
"source": "https://github.com/pmmp/Language/tree/2.24.0"
},
"time": "2025-03-16T19:04:15+00:00"
"time": "2025-02-16T20:46:34+00:00"
},
{
"name": "pocketmine/log",
@ -576,16 +576,16 @@
},
{
"name": "pocketmine/nbt",
"version": "1.1.1",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/NBT.git",
"reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1"
"reference": "cfd53a86166b851786967fc560cdb372e66fde96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/c3c7b0a7295daeaf7873d90fed5c5d10381d12e1",
"reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/cfd53a86166b851786967fc560cdb372e66fde96",
"reference": "cfd53a86166b851786967fc560cdb372e66fde96",
"shasum": ""
},
"require": {
@ -612,9 +612,9 @@
"description": "PHP library for working with Named Binary Tags",
"support": {
"issues": "https://github.com/pmmp/NBT/issues",
"source": "https://github.com/pmmp/NBT/tree/1.1.1"
"source": "https://github.com/pmmp/NBT/tree/1.1.0"
},
"time": "2025-03-09T01:46:03+00:00"
"time": "2025-02-01T21:20:26+00:00"
},
{
"name": "pocketmine/raklib",
@ -742,16 +742,16 @@
},
{
"name": "ramsey/collection",
"version": "2.1.0",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
"reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109"
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/collection/zipball/3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
"reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
"url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
"shasum": ""
},
"require": {
@ -759,22 +759,25 @@
},
"require-dev": {
"captainhook/plugin-composer": "^5.3",
"ergebnis/composer-normalize": "^2.45",
"fakerphp/faker": "^1.24",
"ergebnis/composer-normalize": "^2.28.3",
"fakerphp/faker": "^1.21",
"hamcrest/hamcrest-php": "^2.0",
"jangregor/phpstan-prophecy": "^2.1",
"mockery/mockery": "^1.6",
"jangregor/phpstan-prophecy": "^1.0",
"mockery/mockery": "^1.5",
"php-parallel-lint/php-console-highlighter": "^1.0",
"php-parallel-lint/php-parallel-lint": "^1.4",
"phpspec/prophecy-phpunit": "^2.3",
"phpstan/extension-installer": "^1.4",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-mockery": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^10.5",
"ramsey/coding-standard": "^2.3",
"ramsey/conventional-commits": "^1.6",
"roave/security-advisories": "dev-latest"
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpcsstandards/phpcsutils": "^1.0.0-rc1",
"phpspec/prophecy-phpunit": "^2.0",
"phpstan/extension-installer": "^1.2",
"phpstan/phpstan": "^1.9",
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-phpunit": "^1.3",
"phpunit/phpunit": "^9.5",
"psalm/plugin-mockery": "^1.1",
"psalm/plugin-phpunit": "^0.18.4",
"ramsey/coding-standard": "^2.0.3",
"ramsey/conventional-commits": "^1.3",
"vimeo/psalm": "^5.4"
},
"type": "library",
"extra": {
@ -812,9 +815,19 @@
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
"source": "https://github.com/ramsey/collection/tree/2.1.0"
"source": "https://github.com/ramsey/collection/tree/2.0.0"
},
"time": "2025-03-02T04:48:29+00:00"
"funding": [
{
"url": "https://github.com/ramsey",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/ramsey/collection",
"type": "tidelift"
}
],
"time": "2022-12-31T21:50:55+00:00"
},
{
"name": "ramsey/uuid",
@ -1137,16 +1150,16 @@
"packages-dev": [
{
"name": "myclabs/deep-copy",
"version": "1.13.0",
"version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"shasum": ""
},
"require": {
@ -1185,7 +1198,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
},
"funding": [
{
@ -1193,7 +1206,7 @@
"type": "tidelift"
}
],
"time": "2025-02-12T12:17:51+00:00"
"time": "2024-11-08T17:47:46+00:00"
},
{
"name": "nikic/php-parser",
@ -1373,16 +1386,16 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.8",
"version": "2.1.4",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f"
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/f9adff3b87c03b12cc7e46a30a524648e497758f",
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f99e18eb775dbaf6460c95fa0b65312da9c746a",
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a",
"shasum": ""
},
"require": {
@ -1427,7 +1440,7 @@
"type": "github"
}
],
"time": "2025-03-09T09:30:48+00:00"
"time": "2025-02-10T08:25:21+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
@ -1851,16 +1864,16 @@
},
{
"name": "phpunit/phpunit",
"version": "10.5.45",
"version": "10.5.44",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "bd68a781d8e30348bc297449f5234b3458267ae8"
"reference": "1381c62769be4bb88fa4c5aec1366c7c66ca4f36"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8",
"reference": "bd68a781d8e30348bc297449f5234b3458267ae8",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1381c62769be4bb88fa4c5aec1366c7c66ca4f36",
"reference": "1381c62769be4bb88fa4c5aec1366c7c66ca4f36",
"shasum": ""
},
"require": {
@ -1932,7 +1945,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45"
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.44"
},
"funding": [
{
@ -1948,7 +1961,7 @@
"type": "tidelift"
}
],
"time": "2025-02-06T16:08:12+00:00"
"time": "2025-01-31T07:00:38+00:00"
},
{
"name": "sebastian/cli-parser",
@ -2954,5 +2967,5 @@
"platform-overrides": {
"php": "8.1.0"
},
"plugin-api-version": "2.3.0"
"plugin-api-version": "2.6.0"
}

View File

@ -10,9 +10,9 @@ includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
rules:
- pocketmine\phpstan\rules\DisallowDynamicNewRule
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
- pocketmine\phpstan\rules\ExplodeLimitRule
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule

View File

@ -31,7 +31,6 @@ use function hrtime;
use function max;
use function min;
use function number_format;
use function sprintf;
/**
* Allows threads to manually trigger the cyclic garbage collector using a threshold like PHP's own garbage collector,
@ -49,7 +48,6 @@ final class GarbageCollectorManager{
private int $threshold = self::GC_THRESHOLD_DEFAULT;
private int $collectionTimeTotalNs = 0;
private int $runs = 0;
private \Logger $logger;
private TimingsHandler $timings;
@ -98,16 +96,7 @@ final class GarbageCollectorManager{
$time = $end - $start;
$this->collectionTimeTotalNs += $time;
$this->runs++;
$this->logger->info(sprintf(
"Run #%d took %s ms (%s -> %s roots, %s cycles collected) - cumulative GC time: %s ms",
$this->runs,
number_format($time / 1_000_000, 2),
$rootsBefore,
$rootsAfter,
$cycles,
number_format($this->collectionTimeTotalNs / 1_000_000, 2)
));
$this->logger->debug("gc_collect_cycles: " . number_format($time) . " ns ($rootsBefore -> $rootsAfter roots, $cycles cycles collected) - total GC time: " . number_format($this->collectionTimeTotalNs) . " ns");
return $cycles;
}

View File

@ -123,6 +123,13 @@ class MemoryManager{
return $this->globalMemoryLimit;
}
/**
* @deprecated
*/
public function canUseChunkCache() : bool{
return !$this->lowMemory;
}
/**
* Returns the allowed chunk radius based on the current memory usage.
*/
@ -229,4 +236,13 @@ class MemoryManager{
}
}
}
/**
* Static memory dumper accessible from any thread.
* @deprecated
* @see MemoryDump
*/
public static function dumpMemory(mixed $startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
MemoryDump::dumpMemory($startingObject, $outputFolder, $maxNesting, $maxStringSize, $logger);
}
}

View File

@ -264,7 +264,7 @@ JIT_WARNING
$composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp');
if($composerGitHash !== null){
//we can't verify dependency versions if we were installed without using git
$currentGitHash = explode("-", VersionInfo::GIT_HASH(), 2)[0];
$currentGitHash = explode("-", VersionInfo::GIT_HASH())[0];
if($currentGitHash !== $composerGitHash){
critical_error("Composer dependencies and/or autoloader are out of sync.");
critical_error("- Current revision is $currentGitHash");

View File

@ -80,7 +80,6 @@ use pocketmine\player\PlayerDataLoadException;
use pocketmine\player\PlayerDataProvider;
use pocketmine\player\PlayerDataSaveException;
use pocketmine\player\PlayerInfo;
use pocketmine\plugin\FolderPluginLoader;
use pocketmine\plugin\PharPluginLoader;
use pocketmine\plugin\PluginEnableOrder;
use pocketmine\plugin\PluginGraylist;
@ -347,10 +346,6 @@ class Server{
return $this->maxPlayers;
}
public function setMaxPlayers(int $maxPlayers) : void{
$this->maxPlayers = $maxPlayers;
}
/**
* Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
* are not logged into Xbox Live will be disconnected.
@ -704,7 +699,7 @@ class Server{
public function removeOp(string $name) : void{
$lowercaseName = strtolower($name);
foreach(Utils::promoteKeys($this->operators->getAll()) as $operatorName => $_){
foreach($this->operators->getAll() as $operatorName => $_){
$operatorName = (string) $operatorName;
if($lowercaseName === strtolower($operatorName)){
$this->operators->remove($operatorName);
@ -1034,7 +1029,6 @@ class Server{
$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));
$providerManager = new WorldProviderManager();
if(

View File

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

View File

@ -29,7 +29,6 @@ namespace pocketmine\block;
use pocketmine\block\tile\Spawnable;
use pocketmine\block\tile\Tile;
use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\Waterloggable;
use pocketmine\data\runtime\InvalidSerializedRuntimeDataException;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\data\runtime\RuntimeDataReader;
@ -385,13 +384,7 @@ class Block{
if($chunk === null){
throw new AssumptionFailedError("World::setBlock() should have loaded the chunk before calling this method");
}
$x = $this->position->x & Chunk::COORD_MASK;
$z = $this->position->z & Chunk::COORD_MASK;
$stateId = $this->getStateId();
$chunk->setBlockStateId($x, $this->position->y, $z, $stateId);
if($this instanceof Waterloggable){
$chunk->setWaterStateId($x, $this->position->y, $z, $this->getWaterState()?->getStateId());
}
$chunk->setBlockStateId($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getStateId());
$tileType = $this->idInfo->getTileClass();
$oldTile = $world->getTile($this->position);
@ -628,9 +621,6 @@ class Block{
final public function position(World $world, int $x, int $y, int $z) : void{
$this->position = new Position($x, $y, $z, $world);
$this->collisionBoxes = null;
if($this instanceof Waterloggable){
$this->getWaterState()?->position($world, $x, $y, $z);
}
}
/**

View File

@ -154,7 +154,7 @@ class BlockBreakInfo{
$efficiency = $item->getMiningEfficiency(($this->toolType & $item->getBlockToolType()) !== 0);
if($efficiency <= 0){
throw new \InvalidArgumentException(get_class($item) . " must have a positive mining efficiency, but got $efficiency");
throw new \InvalidArgumentException(get_class($item) . " has invalid mining efficiency: expected >= 0, got $efficiency");
}
$base /= $efficiency;

View File

@ -26,7 +26,6 @@ namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\MinimumCostFlowCalculator;
use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\Waterloggable;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockSpreadEvent;
@ -141,9 +140,6 @@ abstract class Liquid extends Transparent{
}
protected function getEffectiveFlowDecay(Block $block) : int{
if($block instanceof Waterloggable){
$block = $block->getWaterState() ?? $block;
}
if(!($block instanceof Liquid) || !$block->hasSameTypeId($this)){
return -1;
}
@ -181,9 +177,6 @@ abstract class Liquid extends Transparent{
$sideZ = $z + $dz;
$sideBlock = $world->getBlockAt($sideX, $sideY, $sideZ);
if($sideBlock instanceof Waterloggable){
$sideBlock = $sideBlock->getWaterState() ?? $sideBlock;
}
$blockDecay = $this->getEffectiveFlowDecay($sideBlock);
if($blockDecay < 0){
@ -295,25 +288,14 @@ abstract class Liquid extends Transparent{
}
if($falling !== $this->falling || (!$falling && $newDecay !== $this->decay)){
$actualBlock = $world->getBlockAt($x, $y, $z);
if(!$falling && $newDecay < 0){
if($actualBlock instanceof Waterloggable && $this instanceof Water){
$actualBlock->setWaterState(null);
$world->setBlockAt($x, $y, $z, $actualBlock);
}else{
$world->setBlockAt($x, $y, $z, VanillaBlocks::AIR());
}
$world->setBlockAt($x, $y, $z, VanillaBlocks::AIR());
return;
}
$this->falling = $falling;
$this->decay = $falling ? 0 : $newDecay;
if($actualBlock instanceof Waterloggable && $this instanceof Water){
$actualBlock->setWaterState($this);
$world->setBlockAt($x, $y, $z, $actualBlock);
}else{
$world->setBlockAt($x, $y, $z, $this); //local block update will cause an update to be scheduled
}
$world->setBlockAt($x, $y, $z, $this); //local block update will cause an update to be scheduled
}
}
@ -361,9 +343,6 @@ abstract class Liquid extends Transparent{
/** @phpstan-impure */
private function getSmallestFlowDecay(Block $block, int $decay) : int{
if($block instanceof Waterloggable){
$block = $block->getWaterState() ?? $block;
}
if(!($block instanceof Liquid) || !$block->hasSameTypeId($this)){
return $decay;
}
@ -391,9 +370,6 @@ abstract class Liquid extends Transparent{
}
protected function canFlowInto(Block $block) : bool{
if($block instanceof Waterloggable){
$block = $block->getWaterState() ?? $block;
}
return
$this->position->getWorld()->isInWorld($block->position->x, $block->position->y, $block->position->z) &&
$block->canBeFlowedInto() &&

View File

@ -209,10 +209,6 @@ class RuntimeBlockStateRegistry{
return $block;
}
public function hasStateId(int $stateId) : bool{
return isset($this->fullList[$stateId]);
}
/**
* @return Block[]
* @phpstan-return array<int, Block>

View File

@ -26,8 +26,6 @@ namespace pocketmine\block;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\StairShape;
use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\Waterloggable;
use pocketmine\block\utils\WaterloggableTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\Axis;
@ -37,11 +35,8 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class Stair extends Transparent implements Waterloggable{
class Stair extends Transparent{
use HorizontalFacingTrait;
use WaterloggableTrait {
WaterloggableTrait::readStateFromWorld as private readWaterStateFromWorld;
}
protected bool $upsideDown = false;
protected StairShape $shape = StairShape::STRAIGHT;
@ -53,7 +48,6 @@ class Stair extends Transparent implements Waterloggable{
public function readStateFromWorld() : Block{
parent::readStateFromWorld();
$this->readWaterStateFromWorld();
$this->collisionBoxes = null;
@ -137,19 +131,7 @@ class Stair extends Transparent implements Waterloggable{
$this->facing = $player->getHorizontalFacing();
}
$this->upsideDown = (($clickVector->y > 0.5 && $face !== Facing::UP) || $face === Facing::DOWN);
if($blockReplace instanceof Water && $blockReplace->isSource()){
$this->waterState = $blockReplace;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{
$ret = parent::onBreak($item, $player, $returnedItems);
if($this->waterState !== null){
$this->position->getWorld()->setBlock($this->position, $this->waterState);
}
return $ret;
}
}

View File

@ -58,10 +58,17 @@ class SweetBerryBush extends Flowable{
return 0;
}
/**
* @deprecated
*/
protected function canBeSupportedBy(Block $block) : bool{
return $block->getTypeId() !== BlockTypeIds::FARMLAND && //bedrock-specific thing (bug?)
($block->hasTypeTag(BlockTypeTags::DIRT) || $block->hasTypeTag(BlockTypeTags::MUD));
}
private function canBeSupportedAt(Block $block) : bool{
$supportBlock = $block->getSide(Facing::DOWN);
return $supportBlock->getTypeId() !== BlockTypeIds::FARMLAND && //bedrock-specific thing (bug?)
($supportBlock->hasTypeTag(BlockTypeTags::DIRT) || $supportBlock->hasTypeTag(BlockTypeTags::MUD));
return $this->canBeSupportedBy($supportBlock);
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{

View File

@ -79,6 +79,10 @@ use function strtolower;
* @see build/generate-registry-annotations.php
* @generate-registry-docblock
*
* @method static Sapling SAPLING(\pocketmine\block\utils\SaplingType $saplingType)
* @method static Leaves LEAVES(\pocketmine\block\utils\LeavesType $leavesType)
* @method static FloorSign SIGN(\pocketmine\block\utils\WoodType $woodType)
* @method static WallSign WALL_SIGN(\pocketmine\block\utils\WoodType $woodType)
* @method static WoodenButton ACACIA_BUTTON()
* @method static WoodenDoor ACACIA_DOOR()
* @method static WoodenFence ACACIA_FENCE()
@ -804,8 +808,8 @@ use function strtolower;
* @method static Water WATER()
* @method static WaterCauldron WATER_CAULDRON()
* @method static NetherVines WEEPING_VINES()
* @method static WeightedPressurePlate WEIGHTED_PRESSURE_PLATE_HEAVY()
* @method static WeightedPressurePlate WEIGHTED_PRESSURE_PLATE_LIGHT()
* @method static WeightedPressurePlateHeavy WEIGHTED_PRESSURE_PLATE_HEAVY()
* @method static WeightedPressurePlateLight WEIGHTED_PRESSURE_PLATE_LIGHT()
* @method static Wheat WHEAT()
* @method static Flower WHITE_TULIP()
* @method static WitherRose WITHER_ROSE()
@ -1201,14 +1205,14 @@ final class VanillaBlocks{
self::register("lily_pad", fn(BID $id) => new WaterLily($id, "Lily Pad", new Info(BreakInfo::instant())));
$weightedPressurePlateBreakInfo = new Info(BreakInfo::pickaxe(0.5));
self::register("weighted_pressure_plate_heavy", fn(BID $id) => new WeightedPressurePlate(
self::register("weighted_pressure_plate_heavy", fn(BID $id) => new WeightedPressurePlateHeavy(
$id,
"Weighted Pressure Plate Heavy",
$weightedPressurePlateBreakInfo,
deactivationDelayTicks: 10,
signalStrengthFactor: 0.1
));
self::register("weighted_pressure_plate_light", fn(BID $id) => new WeightedPressurePlate(
self::register("weighted_pressure_plate_light", fn(BID $id) => new WeightedPressurePlateLight(
$id,
"Weighted Pressure Plate Light",
$weightedPressurePlateBreakInfo,
@ -1231,10 +1235,12 @@ final class VanillaBlocks{
$name = $saplingType->getDisplayName();
self::register(strtolower($saplingType->name) . "_sapling", fn(BID $id) => new Sapling($id, $name . " Sapling", $saplingTypeInfo, $saplingType));
}
self::registerOverloaded("sapling", SaplingType::class, Sapling::class);
foreach(LeavesType::cases() as $leavesType){
$name = $leavesType->getDisplayName();
self::register(strtolower($leavesType->name) . "_leaves", fn(BID $id) => new Leaves($id, $name . " Leaves", $leavesBreakInfo, $leavesType));
}
self::registerOverloaded("leaves", LeavesType::class, Leaves::class);
$sandstoneBreakInfo = new Info(BreakInfo::pickaxe(0.8, ToolTier::WOOD));
self::register("red_sandstone_stairs", fn(BID $id) => new Stair($id, "Red Sandstone Stairs", $sandstoneBreakInfo));
@ -1370,22 +1376,12 @@ final class VanillaBlocks{
self::register($idName("pressure_plate"), fn(BID $id) => new WoodenPressurePlate($id, $name . " Pressure Plate", $woodenPressurePlateBreakInfo, $woodType, 20));
self::register($idName("trapdoor"), fn(BID $id) => new WoodenTrapdoor($id, $name . " Trapdoor", $woodenDoorBreakInfo, $woodType));
$signAsItem = match($woodType){
WoodType::OAK => VanillaItems::OAK_SIGN(...),
WoodType::SPRUCE => VanillaItems::SPRUCE_SIGN(...),
WoodType::BIRCH => VanillaItems::BIRCH_SIGN(...),
WoodType::JUNGLE => VanillaItems::JUNGLE_SIGN(...),
WoodType::ACACIA => VanillaItems::ACACIA_SIGN(...),
WoodType::DARK_OAK => VanillaItems::DARK_OAK_SIGN(...),
WoodType::MANGROVE => VanillaItems::MANGROVE_SIGN(...),
WoodType::CRIMSON => VanillaItems::CRIMSON_SIGN(...),
WoodType::WARPED => VanillaItems::WARPED_SIGN(...),
WoodType::CHERRY => VanillaItems::CHERRY_SIGN(...),
WoodType::PALE_OAK => VanillaItems::PALE_OAK_SIGN(...),
};
$signAsItem = fn() => VanillaItems::SIGN($woodType);
self::register($idName("sign"), fn(BID $id) => new FloorSign($id, $name . " Sign", $signBreakInfo, $woodType, $signAsItem), TileSign::class);
self::register($idName("wall_sign"), fn(BID $id) => new WallSign($id, $name . " Wall Sign", $signBreakInfo, $woodType, $signAsItem), TileSign::class);
}
self::registerOverloaded("sign", WoodType::class, FloorSign::class);
self::registerOverloaded("wall_sign", WoodType::class, WallSign::class);
}
private static function registerMushroomBlocks() : void{

View File

@ -21,12 +21,11 @@
declare(strict_types=1);
namespace pocketmine\block\utils;
namespace pocketmine\block;
use pocketmine\block\Water;
/**
* @deprecated
*/
class WeightedPressurePlateHeavy extends WeightedPressurePlate{
interface Waterloggable{
public function getWaterState() : ?Water;
public function setWaterState(?Water $state) : Waterloggable;
}

View File

@ -0,0 +1,31 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
/**
* @deprecated
*/
class WeightedPressurePlateLight extends WeightedPressurePlate{
}

View File

@ -62,10 +62,9 @@ class Sign extends Spawnable{
/**
* @return string[]
* @deprecated
*/
public static function fixTextBlob(string $blob) : array{
return array_slice(array_pad(explode("\n", $blob, limit: 5), 4, ""), 0, 4);
return array_slice(array_pad(explode("\n", $blob), 4, ""), 0, 4);
}
protected SignText $text;

View File

@ -35,6 +35,20 @@ abstract class Spawnable extends Tile{
/** @phpstan-var CacheableNbt<\pocketmine\nbt\tag\CompoundTag>|null */
private ?CacheableNbt $spawnCompoundCache = null;
/**
* @deprecated
*/
public function isDirty() : bool{
return $this->spawnCompoundCache === null;
}
/**
* @deprecated
*/
public function setDirty(bool $dirty = true) : void{
$this->clearSpawnCompoundCache();
}
public function clearSpawnCompoundCache() : void{
$this->spawnCompoundCache = null;
}

View File

@ -23,7 +23,54 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static BannerPatternType BORDER()
* @method static BannerPatternType BRICKS()
* @method static BannerPatternType CIRCLE()
* @method static BannerPatternType CREEPER()
* @method static BannerPatternType CROSS()
* @method static BannerPatternType CURLY_BORDER()
* @method static BannerPatternType DIAGONAL_LEFT()
* @method static BannerPatternType DIAGONAL_RIGHT()
* @method static BannerPatternType DIAGONAL_UP_LEFT()
* @method static BannerPatternType DIAGONAL_UP_RIGHT()
* @method static BannerPatternType FLOWER()
* @method static BannerPatternType GRADIENT()
* @method static BannerPatternType GRADIENT_UP()
* @method static BannerPatternType HALF_HORIZONTAL()
* @method static BannerPatternType HALF_HORIZONTAL_BOTTOM()
* @method static BannerPatternType HALF_VERTICAL()
* @method static BannerPatternType HALF_VERTICAL_RIGHT()
* @method static BannerPatternType MOJANG()
* @method static BannerPatternType RHOMBUS()
* @method static BannerPatternType SKULL()
* @method static BannerPatternType SMALL_STRIPES()
* @method static BannerPatternType SQUARE_BOTTOM_LEFT()
* @method static BannerPatternType SQUARE_BOTTOM_RIGHT()
* @method static BannerPatternType SQUARE_TOP_LEFT()
* @method static BannerPatternType SQUARE_TOP_RIGHT()
* @method static BannerPatternType STRAIGHT_CROSS()
* @method static BannerPatternType STRIPE_BOTTOM()
* @method static BannerPatternType STRIPE_CENTER()
* @method static BannerPatternType STRIPE_DOWNLEFT()
* @method static BannerPatternType STRIPE_DOWNRIGHT()
* @method static BannerPatternType STRIPE_LEFT()
* @method static BannerPatternType STRIPE_MIDDLE()
* @method static BannerPatternType STRIPE_RIGHT()
* @method static BannerPatternType STRIPE_TOP()
* @method static BannerPatternType TRIANGLES_BOTTOM()
* @method static BannerPatternType TRIANGLES_TOP()
* @method static BannerPatternType TRIANGLE_BOTTOM()
* @method static BannerPatternType TRIANGLE_TOP()
*/
enum BannerPatternType{
use LegacyEnumShimTrait;
case BORDER;
case BRICKS;
case CIRCLE;

View File

@ -23,7 +23,20 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static BellAttachmentType CEILING()
* @method static BellAttachmentType FLOOR()
* @method static BellAttachmentType ONE_WALL()
* @method static BellAttachmentType TWO_WALLS()
*/
enum BellAttachmentType{
use LegacyEnumShimTrait;
case CEILING;
case FLOOR;
case ONE_WALL;

View File

@ -24,8 +24,19 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\block\inventory\BrewingStandInventory;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static BrewingStandSlot EAST()
* @method static BrewingStandSlot NORTHWEST()
* @method static BrewingStandSlot SOUTHWEST()
*/
enum BrewingStandSlot{
use LegacyEnumShimTrait;
case EAST;
case NORTHWEST;
case SOUTHWEST;

View File

@ -30,15 +30,9 @@ interface CopperMaterial{
public function getOxidation() : CopperOxidation;
/**
* @return $this
*/
public function setOxidation(CopperOxidation $oxidation) : CopperMaterial;
public function isWaxed() : bool;
/**
* @return $this
*/
public function setWaxed(bool $waxed) : CopperMaterial;
}

View File

@ -23,7 +23,20 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static CopperOxidation EXPOSED()
* @method static CopperOxidation NONE()
* @method static CopperOxidation OXIDIZED()
* @method static CopperOxidation WEATHERED()
*/
enum CopperOxidation : int{
use LegacyEnumShimTrait;
case NONE = 0;
case EXPOSED = 1;
case WEATHERED = 2;

View File

@ -23,7 +23,21 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static CoralType BRAIN()
* @method static CoralType BUBBLE()
* @method static CoralType FIRE()
* @method static CoralType HORN()
* @method static CoralType TUBE()
*/
enum CoralType{
use LegacyEnumShimTrait;
case TUBE;
case BRAIN;
case BUBBLE;

View File

@ -23,7 +23,19 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static DirtType COARSE()
* @method static DirtType NORMAL()
* @method static DirtType ROOTED()
*/
enum DirtType{
use LegacyEnumShimTrait;
case NORMAL;
case COARSE;
case ROOTED;

View File

@ -23,7 +23,20 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static DripleafState FULL_TILT()
* @method static DripleafState PARTIAL_TILT()
* @method static DripleafState STABLE()
* @method static DripleafState UNSTABLE()
*/
enum DripleafState{
use LegacyEnumShimTrait;
case STABLE;
case UNSTABLE;
case PARTIAL_TILT;

View File

@ -24,12 +24,35 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\color\Color;
use pocketmine\utils\LegacyEnumShimTrait;
use function spl_object_id;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static DyeColor BLACK()
* @method static DyeColor BLUE()
* @method static DyeColor BROWN()
* @method static DyeColor CYAN()
* @method static DyeColor GRAY()
* @method static DyeColor GREEN()
* @method static DyeColor LIGHT_BLUE()
* @method static DyeColor LIGHT_GRAY()
* @method static DyeColor LIME()
* @method static DyeColor MAGENTA()
* @method static DyeColor ORANGE()
* @method static DyeColor PINK()
* @method static DyeColor PURPLE()
* @method static DyeColor RED()
* @method static DyeColor WHITE()
* @method static DyeColor YELLOW()
*
* @phpstan-type TMetadata array{0: string, 1: Color}
*/
enum DyeColor{
use LegacyEnumShimTrait;
case WHITE;
case ORANGE;
case MAGENTA;

View File

@ -23,7 +23,19 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static FroglightType OCHRE()
* @method static FroglightType PEARLESCENT()
* @method static FroglightType VERDANT()
*/
enum FroglightType{
use LegacyEnumShimTrait;
case OCHRE;
case PEARLESCENT;
case VERDANT;

View File

@ -23,7 +23,26 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static LeavesType ACACIA()
* @method static LeavesType AZALEA()
* @method static LeavesType BIRCH()
* @method static LeavesType CHERRY()
* @method static LeavesType DARK_OAK()
* @method static LeavesType FLOWERING_AZALEA()
* @method static LeavesType JUNGLE()
* @method static LeavesType MANGROVE()
* @method static LeavesType OAK()
* @method static LeavesType SPRUCE()
*/
enum LeavesType{
use LegacyEnumShimTrait;
case OAK;
case SPRUCE;
case BIRCH;

View File

@ -24,8 +24,24 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\math\Facing;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static LeverFacing DOWN_AXIS_X()
* @method static LeverFacing DOWN_AXIS_Z()
* @method static LeverFacing EAST()
* @method static LeverFacing NORTH()
* @method static LeverFacing SOUTH()
* @method static LeverFacing UP_AXIS_X()
* @method static LeverFacing UP_AXIS_Z()
* @method static LeverFacing WEST()
*/
enum LeverFacing{
use LegacyEnumShimTrait;
case UP_AXIS_X;
case UP_AXIS_Z;
case DOWN_AXIS_X;

View File

@ -23,7 +23,23 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static MobHeadType CREEPER()
* @method static MobHeadType DRAGON()
* @method static MobHeadType PIGLIN()
* @method static MobHeadType PLAYER()
* @method static MobHeadType SKELETON()
* @method static MobHeadType WITHER_SKELETON()
* @method static MobHeadType ZOMBIE()
*/
enum MobHeadType{
use LegacyEnumShimTrait;
case SKELETON;
case WITHER_SKELETON;
case ZOMBIE;

View File

@ -23,7 +23,27 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static MushroomBlockType ALL_CAP()
* @method static MushroomBlockType CAP_EAST()
* @method static MushroomBlockType CAP_MIDDLE()
* @method static MushroomBlockType CAP_NORTH()
* @method static MushroomBlockType CAP_NORTHEAST()
* @method static MushroomBlockType CAP_NORTHWEST()
* @method static MushroomBlockType CAP_SOUTH()
* @method static MushroomBlockType CAP_SOUTHEAST()
* @method static MushroomBlockType CAP_SOUTHWEST()
* @method static MushroomBlockType CAP_WEST()
* @method static MushroomBlockType PORES()
*/
enum MushroomBlockType{
use LegacyEnumShimTrait;
case PORES;
case CAP_NORTHWEST;
case CAP_NORTH;

View File

@ -26,12 +26,34 @@ namespace pocketmine\block\utils;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\Translatable;
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
use pocketmine\utils\LegacyEnumShimTrait;
use function spl_object_id;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static RecordType DISK_11()
* @method static RecordType DISK_13()
* @method static RecordType DISK_5()
* @method static RecordType DISK_BLOCKS()
* @method static RecordType DISK_CAT()
* @method static RecordType DISK_CHIRP()
* @method static RecordType DISK_FAR()
* @method static RecordType DISK_MALL()
* @method static RecordType DISK_MELLOHI()
* @method static RecordType DISK_OTHERSIDE()
* @method static RecordType DISK_PIGSTEP()
* @method static RecordType DISK_STAL()
* @method static RecordType DISK_STRAD()
* @method static RecordType DISK_WAIT()
* @method static RecordType DISK_WARD()
*
* @phpstan-type TMetadata array{0: string, 1: LevelSoundEvent::*, 2: Translatable}
*/
enum RecordType{
use LegacyEnumShimTrait;
case DISK_13;
case DISK_5;
case DISK_CAT;

View File

@ -23,9 +23,23 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
use pocketmine\world\generator\object\TreeType;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static SaplingType ACACIA()
* @method static SaplingType BIRCH()
* @method static SaplingType DARK_OAK()
* @method static SaplingType JUNGLE()
* @method static SaplingType OAK()
* @method static SaplingType SPRUCE()
*/
enum SaplingType{
use LegacyEnumShimTrait;
case OAK;
case SPRUCE;
case BIRCH;

View File

@ -79,7 +79,7 @@ class SignText{
* @throws \InvalidArgumentException if the text is not valid UTF-8
*/
public static function fromBlob(string $blob, ?Color $baseColor = null, bool $glowing = false) : SignText{
return new self(array_slice(array_pad(explode("\n", $blob, limit: self::LINE_COUNT + 1), self::LINE_COUNT, ""), 0, self::LINE_COUNT), $baseColor, $glowing);
return new self(array_slice(array_pad(explode("\n", $blob), self::LINE_COUNT, ""), 0, self::LINE_COUNT), $baseColor, $glowing);
}
/**

View File

@ -23,7 +23,19 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static SlabType BOTTOM()
* @method static SlabType DOUBLE()
* @method static SlabType TOP()
*/
enum SlabType{
use LegacyEnumShimTrait;
case BOTTOM;
case TOP;
case DOUBLE;

View File

@ -23,7 +23,21 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static StairShape INNER_LEFT()
* @method static StairShape INNER_RIGHT()
* @method static StairShape OUTER_LEFT()
* @method static StairShape OUTER_RIGHT()
* @method static StairShape STRAIGHT()
*/
enum StairShape{
use LegacyEnumShimTrait;
case STRAIGHT;
case INNER_LEFT;
case INNER_RIGHT;

View File

@ -23,7 +23,20 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static SupportType CENTER()
* @method static SupportType EDGE()
* @method static SupportType FULL()
* @method static SupportType NONE()
*/
enum SupportType{
use LegacyEnumShimTrait;
case FULL;
case CENTER;
case EDGE;

View File

@ -23,7 +23,18 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static WallConnectionType SHORT()
* @method static WallConnectionType TALL()
*/
enum WallConnectionType{
use LegacyEnumShimTrait;
case SHORT;
case TALL;
}

View File

@ -23,7 +23,26 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static WoodType ACACIA()
* @method static WoodType BIRCH()
* @method static WoodType CHERRY()
* @method static WoodType CRIMSON()
* @method static WoodType DARK_OAK()
* @method static WoodType JUNGLE()
* @method static WoodType MANGROVE()
* @method static WoodType OAK()
* @method static WoodType SPRUCE()
* @method static WoodType WARPED()
*/
enum WoodType{
use LegacyEnumShimTrait;
case OAK;
case SPRUCE;
case BIRCH;

View File

@ -37,7 +37,6 @@ use function array_values;
use function explode;
use function implode;
use function str_replace;
use const PHP_INT_MAX;
abstract class Command{
@ -66,7 +65,7 @@ abstract class Command{
/** @var string[] */
private array $permission = [];
private Translatable|string|null $permissionMessage = null;
private ?string $permissionMessage = null;
/**
* @param string[] $aliases
@ -114,7 +113,7 @@ abstract class Command{
}
public function setPermission(?string $permission) : void{
$this->setPermissions($permission === null ? [] : explode(";", $permission, limit: PHP_INT_MAX));
$this->setPermissions($permission === null ? [] : explode(";", $permission));
}
public function testPermission(CommandSender $target, ?string $permission = null) : bool{
@ -122,11 +121,10 @@ abstract class Command{
return true;
}
$message = $this->permissionMessage ?? KnownTranslationFactory::pocketmine_command_error_permission($this->name);
if($message instanceof Translatable){
$target->sendMessage($message->prefix(TextFormat::RED));
}elseif($message !== ""){
$target->sendMessage(str_replace("<permission>", $permission ?? implode(";", $this->permission), $message));
if($this->permissionMessage === null){
$target->sendMessage(KnownTranslationFactory::pocketmine_command_error_permission($this->name)->prefix(TextFormat::RED));
}elseif($this->permissionMessage !== ""){
$target->sendMessage(str_replace("<permission>", $permission ?? implode(";", $this->permission), $this->permissionMessage));
}
return false;
@ -199,7 +197,7 @@ abstract class Command{
return $this->activeAliases;
}
public function getPermissionMessage() : Translatable|string|null{
public function getPermissionMessage() : ?string{
return $this->permissionMessage;
}
@ -227,7 +225,7 @@ abstract class Command{
$this->description = $description;
}
public function setPermissionMessage(Translatable|string $permissionMessage) : void{
public function setPermissionMessage(string $permissionMessage) : void{
$this->permissionMessage = $permissionMessage;
}

View File

@ -39,7 +39,6 @@ use function ksort;
use function min;
use function sort;
use function strtolower;
use const PHP_INT_MAX;
use const SORT_FLAG_CASE;
use const SORT_NATURAL;
@ -109,7 +108,7 @@ class HelpCommand extends VanillaCommand{
$usage = $cmd->getUsage();
$usageString = $usage instanceof Translatable ? $lang->translate($usage) : $usage;
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_usage(TextFormat::RESET . implode("\n" . TextFormat::RESET, explode("\n", $usageString, limit: PHP_INT_MAX)))
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_usage(TextFormat::RESET . implode("\n" . TextFormat::RESET, explode("\n", $usageString)))
->prefix(TextFormat::GOLD));
$aliases = $cmd->getAliases();

View File

@ -219,11 +219,7 @@ class ParticleCommand extends VanillaCommand{
break;
case "blockdust":
if($data !== null){
//to preserve the old unlimited explode behaviour, allow this to split into at most 5 parts
//this allows the 4th argument to be processed normally if given without forcing it to also consume
//any unexpected parts
//we probably ought to error in this case, but this will do for now
$d = explode("_", $data, limit: 5);
$d = explode("_", $data);
if(count($d) >= 3){
return new DustParticle(new Color(
((int) $d[0]) & 0xff,

View File

@ -62,7 +62,7 @@ class ConsoleCommandSender implements CommandSender{
$message = $this->getLanguage()->translate($message);
}
foreach(explode("\n", trim($message), limit: PHP_INT_MAX) as $line){
foreach(explode("\n", trim($message)) as $line){
Terminal::writeLine(TextFormat::GREEN . "Command output | " . TextFormat::addBase(TextFormat::WHITE, $line));
}
}

View File

@ -29,12 +29,8 @@ use pocketmine\nbt\TreeRoot;
use pocketmine\utils\BinaryStream;
use pocketmine\utils\DestructorCallbackTrait;
use pocketmine\utils\ObjectSet;
use function array_shift;
use function count;
use function implode;
use function ksort;
use function spl_object_id;
use const SORT_STRING;
use function usort;
class CraftingManager{
use DestructorCallbackTrait;
@ -104,7 +100,6 @@ class CraftingManager{
/**
* Function used to arrange Shapeless Recipe ingredient lists into a consistent order.
* @deprecated
*/
public static function sort(Item $i1, Item $i2) : int{
//Use spaceship operator to compare each property, then try the next one if they are equivalent.
@ -113,30 +108,45 @@ class CraftingManager{
return $retval;
}
private static function hashOutput(Item $output) : string{
$write = new BinaryStream();
$write->putVarInt($output->getStateId());
$write->put((new LittleEndianNbtSerializer())->write(new TreeRoot($output->getNamedTag())));
/**
* @param Item[] $items
*
* @return Item[]
* @phpstan-return list<Item>
*/
private static function pack(array $items) : array{
$result = [];
return $write->getBuffer();
foreach($items as $item){
foreach($result as $otherItem){
if($item->canStackWith($otherItem)){
$otherItem->setCount($otherItem->getCount() + $item->getCount());
continue 2;
}
}
//No matching item found
$result[] = clone $item;
}
return $result;
}
/**
* @param Item[] $outputs
*/
private static function hashOutputs(array $outputs) : string{
if(count($outputs) === 1){
return self::hashOutput(array_shift($outputs));
}
$unique = [];
$outputs = self::pack($outputs);
usort($outputs, [self::class, "sort"]);
$result = new BinaryStream();
foreach($outputs as $o){
//count is not written because the outputs might be from multiple repetitions of a single recipe
//this reduces the accuracy of the hash, but it won't matter in most cases.
$hash = self::hashOutput($o);
$unique[$hash] = $hash;
$result->putVarInt($o->getStateId());
$result->put((new LittleEndianNbtSerializer())->write(new TreeRoot($o->getNamedTag())));
}
ksort($unique, SORT_STRING);
return implode("", $unique);
return $result->getBuffer();
}
/**

View File

@ -152,10 +152,10 @@ final class CraftingManagerFromDataHelper{
* @return mixed[]
*
* @phpstan-template TData of object
* @phpstan-param class-string<TData> $modelClass
* @phpstan-param class-string<TData> $modelCLass
* @phpstan-return list<TData>
*/
public static function loadJsonArrayOfObjectsFile(string $filePath, string $modelClass) : array{
public static function loadJsonArrayOfObjectsFile(string $filePath, string $modelCLass) : array{
$recipes = json_decode(Filesystem::fileGetContents($filePath));
if(!is_array($recipes)){
throw new SavedDataLoadingException("$filePath root should be an array, got " . get_debug_type($recipes));
@ -166,7 +166,7 @@ final class CraftingManagerFromDataHelper{
$mapper->bExceptionOnUndefinedProperty = true;
$mapper->bExceptionOnMissingData = true;
return self::loadJsonObjectListIntoModel($mapper, $modelClass, $recipes);
return self::loadJsonObjectListIntoModel($mapper, $modelCLass, $recipes);
}
/**

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\crafting;
use pocketmine\utils\LegacyEnumShimTrait;
use pocketmine\world\sound\BlastFurnaceSound;
use pocketmine\world\sound\CampfireSound;
use pocketmine\world\sound\FurnaceSound;
@ -31,9 +32,20 @@ use pocketmine\world\sound\Sound;
use function spl_object_id;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static FurnaceType BLAST_FURNACE()
* @method static FurnaceType CAMPFIRE()
* @method static FurnaceType FURNACE()
* @method static FurnaceType SMOKER()
* @method static FurnaceType SOUL_CAMPFIRE()
*
* @phpstan-type TMetadata array{0: int, 1: Sound}
*/
enum FurnaceType{
use LegacyEnumShimTrait;
case FURNACE;
case BLAST_FURNACE;
case SMOKER;

View File

@ -97,7 +97,6 @@ class ShapedRecipe implements CraftingRecipe{
$this->shape = $shape;
Utils::validateArrayValueType($ingredients, function(RecipeIngredient $_) : void{});
foreach(Utils::stringifyKeys($ingredients) as $char => $i){
if(!str_contains(implode($this->shape), $char)){
throw new \InvalidArgumentException("Symbol '$char' does not appear in the recipe shape");
@ -106,7 +105,6 @@ class ShapedRecipe implements CraftingRecipe{
$this->ingredientList[$char] = clone $i;
}
Utils::validateArrayValueType($results, function(Item $_) : void{});
$this->results = Utils::cloneObjectArray($results);
}

View File

@ -53,9 +53,7 @@ class ShapelessRecipe implements CraftingRecipe{
if(count($ingredients) > 9){
throw new \InvalidArgumentException("Shapeless recipes cannot have more than 9 ingredients");
}
Utils::validateArrayValueType($ingredients, function(RecipeIngredient $_) : void{});
$this->ingredients = $ingredients;
Utils::validateArrayValueType($results, function(Item $_) : void{});
$this->results = Utils::cloneObjectArray($results);
}

View File

@ -23,7 +23,20 @@ declare(strict_types=1);
namespace pocketmine\crafting;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static ShapelessRecipeType CARTOGRAPHY()
* @method static ShapelessRecipeType CRAFTING()
* @method static ShapelessRecipeType SMITHING()
* @method static ShapelessRecipeType STONECUTTER()
*/
enum ShapelessRecipeType{
use LegacyEnumShimTrait;
case CRAFTING;
case STONECUTTER;
case SMITHING;

View File

@ -166,7 +166,8 @@ use pocketmine\block\WallBanner;
use pocketmine\block\WallCoralFan;
use pocketmine\block\WallSign;
use pocketmine\block\Water;
use pocketmine\block\WeightedPressurePlate;
use pocketmine\block\WeightedPressurePlateHeavy;
use pocketmine\block\WeightedPressurePlateLight;
use pocketmine\block\Wheat;
use pocketmine\block\Wood;
use pocketmine\block\WoodenButton;
@ -213,7 +214,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->registerLeavesSerializers();
$this->registerSaplingSerializers();
$this->registerMobHeadSerializers();
$this->registerCopperSerializers();
$this->registerSimpleSerializers();
$this->registerSerializers();
}
@ -791,178 +791,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
})->writeFacingWithoutDown($block->getFacing()));
}
private function registerCopperSerializers() : void{
$this->map(Blocks::COPPER(), function(Copper $block) : Writer{
$oxidation = $block->getOxidation();
return new Writer($block->isWaxed() ?
Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) :
Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER)
);
});
$this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : Writer{
$oxidation = $block->getOxidation();
return new Writer($block->isWaxed() ?
Helper::selectCopperId($oxidation,
Ids::WAXED_CHISELED_COPPER,
Ids::WAXED_EXPOSED_CHISELED_COPPER,
Ids::WAXED_WEATHERED_CHISELED_COPPER,
Ids::WAXED_OXIDIZED_CHISELED_COPPER
) :
Helper::selectCopperId($oxidation,
Ids::CHISELED_COPPER,
Ids::EXPOSED_CHISELED_COPPER,
Ids::WEATHERED_CHISELED_COPPER,
Ids::OXIDIZED_CHISELED_COPPER
)
);
});
$this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : Writer{
$oxidation = $block->getOxidation();
return new Writer($block->isWaxed() ?
Helper::selectCopperId($oxidation,
Ids::WAXED_COPPER_GRATE,
Ids::WAXED_EXPOSED_COPPER_GRATE,
Ids::WAXED_WEATHERED_COPPER_GRATE,
Ids::WAXED_OXIDIZED_COPPER_GRATE
) :
Helper::selectCopperId($oxidation,
Ids::COPPER_GRATE,
Ids::EXPOSED_COPPER_GRATE,
Ids::WEATHERED_COPPER_GRATE,
Ids::OXIDIZED_COPPER_GRATE
)
);
});
$this->map(Blocks::CUT_COPPER(), function(Copper $block) : Writer{
$oxidation = $block->getOxidation();
return new Writer($block->isWaxed() ?
Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) :
Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER)
);
});
$this->map(Blocks::CUT_COPPER_SLAB(), function(CopperSlab $block) : Writer{
$oxidation = $block->getOxidation();
return Helper::encodeSlab(
$block,
($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_CUT_COPPER_SLAB,
Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB
) :
Helper::selectCopperId(
$oxidation,
Ids::CUT_COPPER_SLAB,
Ids::EXPOSED_CUT_COPPER_SLAB,
Ids::WEATHERED_CUT_COPPER_SLAB,
Ids::OXIDIZED_CUT_COPPER_SLAB
)
),
($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB
) :
Helper::selectCopperId(
$oxidation,
Ids::DOUBLE_CUT_COPPER_SLAB,
Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB
)
)
);
});
$this->map(Blocks::CUT_COPPER_STAIRS(), function(CopperStairs $block) : Writer{
$oxidation = $block->getOxidation();
return Helper::encodeStairs(
$block,
new Writer($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_CUT_COPPER_STAIRS,
Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS
) :
Helper::selectCopperId(
$oxidation,
Ids::CUT_COPPER_STAIRS,
Ids::EXPOSED_CUT_COPPER_STAIRS,
Ids::WEATHERED_CUT_COPPER_STAIRS,
Ids::OXIDIZED_CUT_COPPER_STAIRS
)
)
);
});
$this->map(Blocks::COPPER_BULB(), function(CopperBulb $block) : Writer{
$oxidation = $block->getOxidation();
return Writer::create($block->isWaxed() ?
Helper::selectCopperId($oxidation,
Ids::WAXED_COPPER_BULB,
Ids::WAXED_EXPOSED_COPPER_BULB,
Ids::WAXED_WEATHERED_COPPER_BULB,
Ids::WAXED_OXIDIZED_COPPER_BULB) :
Helper::selectCopperId($oxidation,
Ids::COPPER_BULB,
Ids::EXPOSED_COPPER_BULB,
Ids::WEATHERED_COPPER_BULB,
Ids::OXIDIZED_COPPER_BULB
))
->writeBool(StateNames::LIT, $block->isLit())
->writeBool(StateNames::POWERED_BIT, $block->isPowered());
});
$this->map(Blocks::COPPER_DOOR(), function(CopperDoor $block) : Writer{
$oxidation = $block->getOxidation();
return Helper::encodeDoor(
$block,
new Writer($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_COPPER_DOOR,
Ids::WAXED_EXPOSED_COPPER_DOOR,
Ids::WAXED_WEATHERED_COPPER_DOOR,
Ids::WAXED_OXIDIZED_COPPER_DOOR
) :
Helper::selectCopperId(
$oxidation,
Ids::COPPER_DOOR,
Ids::EXPOSED_COPPER_DOOR,
Ids::WEATHERED_COPPER_DOOR,
Ids::OXIDIZED_COPPER_DOOR
)
)
);
});
$this->map(Blocks::COPPER_TRAPDOOR(), function(CopperTrapdoor $block) : Writer{
$oxidation = $block->getOxidation();
return Helper::encodeTrapdoor(
$block,
new Writer($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_COPPER_TRAPDOOR,
Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR
) :
Helper::selectCopperId(
$oxidation,
Ids::COPPER_TRAPDOOR,
Ids::EXPOSED_COPPER_TRAPDOOR,
Ids::WEATHERED_COPPER_TRAPDOOR,
Ids::OXIDIZED_COPPER_TRAPDOOR
)
)
);
});
}
private function registerSimpleSerializers() : void{
$this->mapSimple(Blocks::AIR(), Ids::AIR);
$this->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK);
@ -1437,6 +1265,175 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->mapSlab(Blocks::COBBLESTONE_SLAB(), Ids::COBBLESTONE_SLAB, Ids::COBBLESTONE_DOUBLE_SLAB);
$this->mapStairs(Blocks::COBBLESTONE_STAIRS(), Ids::STONE_STAIRS);
$this->map(Blocks::COBBLESTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::COBBLESTONE_WALL)));
$this->map(Blocks::COPPER(), function(Copper $block) : Writer{
$oxidation = $block->getOxidation();
return new Writer($block->isWaxed() ?
Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) :
Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER)
);
});
$this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : Writer{
$oxidation = $block->getOxidation();
return new Writer($block->isWaxed() ?
Helper::selectCopperId($oxidation,
Ids::WAXED_CHISELED_COPPER,
Ids::WAXED_EXPOSED_CHISELED_COPPER,
Ids::WAXED_WEATHERED_CHISELED_COPPER,
Ids::WAXED_OXIDIZED_CHISELED_COPPER
) :
Helper::selectCopperId($oxidation,
Ids::CHISELED_COPPER,
Ids::EXPOSED_CHISELED_COPPER,
Ids::WEATHERED_CHISELED_COPPER,
Ids::OXIDIZED_CHISELED_COPPER
)
);
});
$this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : Writer{
$oxidation = $block->getOxidation();
return new Writer($block->isWaxed() ?
Helper::selectCopperId($oxidation,
Ids::WAXED_COPPER_GRATE,
Ids::WAXED_EXPOSED_COPPER_GRATE,
Ids::WAXED_WEATHERED_COPPER_GRATE,
Ids::WAXED_OXIDIZED_COPPER_GRATE
) :
Helper::selectCopperId($oxidation,
Ids::COPPER_GRATE,
Ids::EXPOSED_COPPER_GRATE,
Ids::WEATHERED_COPPER_GRATE,
Ids::OXIDIZED_COPPER_GRATE
)
);
});
$this->map(Blocks::CUT_COPPER(), function(Copper $block) : Writer{
$oxidation = $block->getOxidation();
return new Writer($block->isWaxed() ?
Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) :
Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER)
);
});
$this->map(Blocks::CUT_COPPER_SLAB(), function(CopperSlab $block) : Writer{
$oxidation = $block->getOxidation();
return Helper::encodeSlab(
$block,
($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_CUT_COPPER_SLAB,
Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB
) :
Helper::selectCopperId(
$oxidation,
Ids::CUT_COPPER_SLAB,
Ids::EXPOSED_CUT_COPPER_SLAB,
Ids::WEATHERED_CUT_COPPER_SLAB,
Ids::OXIDIZED_CUT_COPPER_SLAB
)
),
($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB
) :
Helper::selectCopperId(
$oxidation,
Ids::DOUBLE_CUT_COPPER_SLAB,
Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB
)
)
);
});
$this->map(Blocks::CUT_COPPER_STAIRS(), function(CopperStairs $block) : Writer{
$oxidation = $block->getOxidation();
return Helper::encodeStairs(
$block,
new Writer($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_CUT_COPPER_STAIRS,
Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS
) :
Helper::selectCopperId(
$oxidation,
Ids::CUT_COPPER_STAIRS,
Ids::EXPOSED_CUT_COPPER_STAIRS,
Ids::WEATHERED_CUT_COPPER_STAIRS,
Ids::OXIDIZED_CUT_COPPER_STAIRS
)
)
);
});
$this->map(Blocks::COPPER_BULB(), function(CopperBulb $block) : Writer{
$oxidation = $block->getOxidation();
return Writer::create($block->isWaxed() ?
Helper::selectCopperId($oxidation,
Ids::WAXED_COPPER_BULB,
Ids::WAXED_EXPOSED_COPPER_BULB,
Ids::WAXED_WEATHERED_COPPER_BULB,
Ids::WAXED_OXIDIZED_COPPER_BULB) :
Helper::selectCopperId($oxidation,
Ids::COPPER_BULB,
Ids::EXPOSED_COPPER_BULB,
Ids::WEATHERED_COPPER_BULB,
Ids::OXIDIZED_COPPER_BULB
))
->writeBool(StateNames::LIT, $block->isLit())
->writeBool(StateNames::POWERED_BIT, $block->isPowered());
});
$this->map(Blocks::COPPER_DOOR(), function(CopperDoor $block) : Writer{
$oxidation = $block->getOxidation();
return Helper::encodeDoor(
$block,
new Writer($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_COPPER_DOOR,
Ids::WAXED_EXPOSED_COPPER_DOOR,
Ids::WAXED_WEATHERED_COPPER_DOOR,
Ids::WAXED_OXIDIZED_COPPER_DOOR
) :
Helper::selectCopperId(
$oxidation,
Ids::COPPER_DOOR,
Ids::EXPOSED_COPPER_DOOR,
Ids::WEATHERED_COPPER_DOOR,
Ids::OXIDIZED_COPPER_DOOR
)
)
);
});
$this->map(Blocks::COPPER_TRAPDOOR(), function(CopperTrapdoor $block) : Writer{
$oxidation = $block->getOxidation();
return Helper::encodeTrapdoor(
$block,
new Writer($block->isWaxed() ?
Helper::selectCopperId(
$oxidation,
Ids::WAXED_COPPER_TRAPDOOR,
Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR
) :
Helper::selectCopperId(
$oxidation,
Ids::COPPER_TRAPDOOR,
Ids::EXPOSED_COPPER_TRAPDOOR,
Ids::WEATHERED_COPPER_TRAPDOOR,
Ids::OXIDIZED_COPPER_TRAPDOOR
)
)
);
});
$this->map(Blocks::COCOA_POD(), function(CocoaBlock $block) : Writer{
return Writer::create(Ids::COCOA)
->writeInt(StateNames::AGE, $block->getAge())
@ -1868,11 +1865,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create(Ids::WEEPING_VINES)
->writeInt(StateNames::WEEPING_VINES_AGE, $block->getAge());
});
$this->map(Blocks::WEIGHTED_PRESSURE_PLATE_HEAVY(), function(WeightedPressurePlate $block) : Writer{
$this->map(Blocks::WEIGHTED_PRESSURE_PLATE_HEAVY(), function(WeightedPressurePlateHeavy $block) : Writer{
return Writer::create(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE)
->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength());
});
$this->map(Blocks::WEIGHTED_PRESSURE_PLATE_LIGHT(), function(WeightedPressurePlate $block) : Writer{
$this->map(Blocks::WEIGHTED_PRESSURE_PLATE_LIGHT(), function(WeightedPressurePlateLight $block) : Writer{
return Writer::create(Ids::LIGHT_WEIGHTED_PRESSURE_PLATE)
->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength());
});

View File

@ -126,19 +126,12 @@ final class BlockStateDeserializerHelper{
->setOutputSignalStrength($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15));
}
/**
* @phpstan-template TDoor of Door
* @phpstan-param TDoor $block
* @phpstan-return TDoor
*
* @throws BlockStateDeserializeException
*/
/** @throws BlockStateDeserializeException */
public static function decodeDoor(Door $block, BlockStateReader $in) : Door{
//TODO: check if these need any special treatment to get the appropriate data to both halves of the door
return $block
->setTop($in->readBool(BlockStateNames::UPPER_BLOCK_BIT))
//a door facing "east" is actually facing north - thanks mojang
->setFacing(Facing::rotateY($in->readCardinalHorizontalFacing(), clockwise: false))
->setFacing($in->readCardinalHorizontalFacing())
->setHingeRight($in->readBool(BlockStateNames::DOOR_HINGE_BIT))
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
}
@ -243,36 +236,18 @@ final class BlockStateDeserializerHelper{
return $block->setPressed($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15) !== 0);
}
/**
* @phpstan-template TSlab of Slab
* @phpstan-param TSlab $block
* @phpstan-return TSlab
*
* @throws BlockStateDeserializeException
*/
/** @throws BlockStateDeserializeException */
public static function decodeSingleSlab(Slab $block, BlockStateReader $in) : Slab{
return $block->setSlabType($in->readSlabPosition());
}
/**
* @phpstan-template TSlab of Slab
* @phpstan-param TSlab $block
* @phpstan-return TSlab
*
* @throws BlockStateDeserializeException
*/
/** @throws BlockStateDeserializeException */
public static function decodeDoubleSlab(Slab $block, BlockStateReader $in) : Slab{
$in->ignored(StateNames::MC_VERTICAL_HALF);
return $block->setSlabType(SlabType::DOUBLE);
}
/**
* @phpstan-template TStair of Stair
* @phpstan-param TStair $block
* @phpstan-return TStair
*
* @throws BlockStateDeserializeException
*/
/** @throws BlockStateDeserializeException */
public static function decodeStairs(Stair $block, BlockStateReader $in) : Stair{
return $block
->setUpsideDown($in->readBool(BlockStateNames::UPSIDE_DOWN_BIT))
@ -289,13 +264,7 @@ final class BlockStateDeserializerHelper{
->setFacing($facing === Facing::DOWN ? Facing::UP : $facing);
}
/**
* @phpstan-template TTrapdoor of Trapdoor
* @phpstan-param TTrapdoor $block
* @phpstan-return TTrapdoor
*
* @throws BlockStateDeserializeException
*/
/** @throws BlockStateDeserializeException */
public static function decodeTrapdoor(Trapdoor $block, BlockStateReader $in) : Trapdoor{
return $block
->setFacing($in->read5MinusHorizontalFacing())

View File

@ -100,8 +100,7 @@ final class BlockStateSerializerHelper{
public static function encodeDoor(Door $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
//a door facing north is encoded as "east"
->writeCardinalHorizontalFacing(Facing::rotateY($block->getFacing(), clockwise: true))
->writeCardinalHorizontalFacing($block->getFacing())
->writeBool(BlockStateNames::DOOR_HINGE_BIT, $block->isHingeRight())
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
}

View File

@ -33,13 +33,11 @@ use pocketmine\block\DoublePitcherCrop;
use pocketmine\block\Opaque;
use pocketmine\block\PinkPetals;
use pocketmine\block\PitcherCrop;
use pocketmine\block\RuntimeBlockStateRegistry;
use pocketmine\block\Slab;
use pocketmine\block\Stair;
use pocketmine\block\SweetBerryBush;
use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\block\utils\ChiseledBookshelfSlot;
use pocketmine\block\utils\CopperMaterial;
use pocketmine\block\utils\CopperOxidation;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\DirtType;
@ -61,7 +59,6 @@ use pocketmine\data\bedrock\block\convert\BlockStateDeserializerHelper as Helper
use pocketmine\data\bedrock\block\convert\BlockStateReader as Reader;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\utils\Utils;
use function array_key_exists;
use function count;
use function min;
@ -90,7 +87,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->registerSaplingDeserializers();
$this->registerLightDeserializers();
$this->registerMobHeadDeserializers();
$this->registerCopperDeserializers();
$this->registerSimpleDeserializers();
$this->registerDeserializers();
}
@ -98,21 +94,11 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
public function deserialize(BlockStateData $stateData) : int{
if(count($stateData->getStates()) === 0){
//if a block has zero properties, we can keep a map of string ID -> internal blockstate ID
return $this->simpleCache[$stateData->getName()] ??= $this->deserializeToStateId($stateData);
return $this->simpleCache[$stateData->getName()] ??= $this->deserializeBlock($stateData)->getStateId();
}
//we can't cache blocks that have properties - go ahead and deserialize the slow way
return $this->deserializeToStateId($stateData);
}
private function deserializeToStateId(BlockStateData $stateData) : int{
$stateId = $this->deserializeBlock($stateData)->getStateId();
//plugin devs seem to keep missing this and causing core crashes, so we need to verify this at the earliest
//available opportunity
if(!RuntimeBlockStateRegistry::getInstance()->hasStateId($stateId)){
throw new \LogicException("State ID $stateId returned by deserializer for " . $stateData->getName() . " is not registered in RuntimeBlockStateRegistry");
}
return $stateId;
return $this->deserializeBlock($stateData)->getStateId();
}
/** @phpstan-param \Closure(Reader) : Block $c */
@ -737,150 +723,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
}
}
/**
* @phpstan-param \Closure(Reader) : (CopperMaterial&Block) $deserializer
*/
private function mapCopper(
string $normalId,
string $waxedNormalId,
string $exposedId,
string $waxedExposedId,
string $weatheredId,
string $waxedWeatheredId,
string $oxidizedId,
string $waxedOxidizedId,
\Closure $deserializer
) : void{
foreach(Utils::stringifyKeys([
$normalId => [CopperOxidation::NONE, false],
$waxedNormalId => [CopperOxidation::NONE, true],
$exposedId => [CopperOxidation::EXPOSED, false],
$waxedExposedId => [CopperOxidation::EXPOSED, true],
$weatheredId => [CopperOxidation::WEATHERED, false],
$waxedWeatheredId => [CopperOxidation::WEATHERED, true],
$oxidizedId => [CopperOxidation::OXIDIZED, false],
$waxedOxidizedId => [CopperOxidation::OXIDIZED, true],
]) as $id => [$oxidation, $waxed]){
$this->map($id, fn(Reader $in) => $deserializer($in)->setOxidation($oxidation)->setWaxed($waxed));
}
}
private function registerCopperDeserializers() : void{
$this->mapCopper(
Ids::CUT_COPPER_SLAB,
Ids::WAXED_CUT_COPPER_SLAB,
Ids::EXPOSED_CUT_COPPER_SLAB,
Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
Ids::WEATHERED_CUT_COPPER_SLAB,
Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
Ids::OXIDIZED_CUT_COPPER_SLAB,
Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB,
fn(Reader $in) => Helper::decodeSingleSlab(Blocks::CUT_COPPER_SLAB(), $in)
);
$this->mapCopper(
Ids::DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB,
Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB,
fn(Reader $in) => Helper::decodeDoubleSlab(Blocks::CUT_COPPER_SLAB(), $in)
);
$this->mapCopper(
Ids::COPPER_BULB,
Ids::WAXED_COPPER_BULB,
Ids::EXPOSED_COPPER_BULB,
Ids::WAXED_EXPOSED_COPPER_BULB,
Ids::WEATHERED_COPPER_BULB,
Ids::WAXED_WEATHERED_COPPER_BULB,
Ids::OXIDIZED_COPPER_BULB,
Ids::WAXED_OXIDIZED_COPPER_BULB,
fn(Reader $in) => Blocks::COPPER_BULB()
->setLit($in->readBool(StateNames::LIT))
->setPowered($in->readBool(StateNames::POWERED_BIT))
);
$this->mapCopper(
Ids::COPPER_DOOR,
Ids::WAXED_COPPER_DOOR,
Ids::EXPOSED_COPPER_DOOR,
Ids::WAXED_EXPOSED_COPPER_DOOR,
Ids::WEATHERED_COPPER_DOOR,
Ids::WAXED_WEATHERED_COPPER_DOOR,
Ids::OXIDIZED_COPPER_DOOR,
Ids::WAXED_OXIDIZED_COPPER_DOOR,
fn(Reader $in) => Helper::decodeDoor(Blocks::COPPER_DOOR(), $in)
);
$this->mapCopper(
Ids::COPPER_TRAPDOOR,
Ids::WAXED_COPPER_TRAPDOOR,
Ids::EXPOSED_COPPER_TRAPDOOR,
Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
Ids::WEATHERED_COPPER_TRAPDOOR,
Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
Ids::OXIDIZED_COPPER_TRAPDOOR,
Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR,
fn(Reader $in) => Helper::decodeTrapdoor(Blocks::COPPER_TRAPDOOR(), $in)
);
$this->mapCopper(
Ids::COPPER_BLOCK,
Ids::WAXED_COPPER,
Ids::EXPOSED_COPPER,
Ids::WAXED_EXPOSED_COPPER,
Ids::WEATHERED_COPPER,
Ids::WAXED_WEATHERED_COPPER,
Ids::OXIDIZED_COPPER,
Ids::WAXED_OXIDIZED_COPPER,
fn(Reader $in) => Blocks::COPPER()
);
$this->mapCopper(
Ids::CHISELED_COPPER,
Ids::WAXED_CHISELED_COPPER,
Ids::EXPOSED_CHISELED_COPPER,
Ids::WAXED_EXPOSED_CHISELED_COPPER,
Ids::WEATHERED_CHISELED_COPPER,
Ids::WAXED_WEATHERED_CHISELED_COPPER,
Ids::OXIDIZED_CHISELED_COPPER,
Ids::WAXED_OXIDIZED_CHISELED_COPPER,
fn(Reader $in) => Blocks::CHISELED_COPPER()
);
$this->mapCopper(
Ids::COPPER_GRATE,
Ids::WAXED_COPPER_GRATE,
Ids::EXPOSED_COPPER_GRATE,
Ids::WAXED_EXPOSED_COPPER_GRATE,
Ids::WEATHERED_COPPER_GRATE,
Ids::WAXED_WEATHERED_COPPER_GRATE,
Ids::OXIDIZED_COPPER_GRATE,
Ids::WAXED_OXIDIZED_COPPER_GRATE,
fn(Reader $in) => Blocks::COPPER_GRATE()
);
$this->mapCopper(
Ids::CUT_COPPER,
Ids::WAXED_CUT_COPPER,
Ids::EXPOSED_CUT_COPPER,
Ids::WAXED_EXPOSED_CUT_COPPER,
Ids::WEATHERED_CUT_COPPER,
Ids::WAXED_WEATHERED_CUT_COPPER,
Ids::OXIDIZED_CUT_COPPER,
Ids::WAXED_OXIDIZED_CUT_COPPER,
fn(Reader $in) => Blocks::CUT_COPPER()
);
$this->mapCopper(
Ids::CUT_COPPER_STAIRS,
Ids::WAXED_CUT_COPPER_STAIRS,
Ids::EXPOSED_CUT_COPPER_STAIRS,
Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
Ids::WEATHERED_CUT_COPPER_STAIRS,
Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
Ids::OXIDIZED_CUT_COPPER_STAIRS,
Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS,
fn(Reader $in) => Helper::decodeStairs(Blocks::CUT_COPPER_STAIRS(), $in)
);
}
private function registerSimpleDeserializers() : void{
$this->mapSimple(Ids::AIR, fn() => Blocks::AIR());
$this->mapSimple(Ids::AMETHYST_BLOCK, fn() => Blocks::AMETHYST());
@ -1386,6 +1228,18 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->map(Ids::COMPOUND_CREATOR, fn(Reader $in) => Blocks::COMPOUND_CREATOR()
->setFacing(Facing::opposite($in->readLegacyHorizontalFacing()))
);
$this->map(Ids::COPPER_BLOCK, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::NONE));
$this->map(Ids::COPPER_BULB, function(Reader $in) : Block{
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::NONE)
->setLit($in->readBool(StateNames::LIT))
->setPowered($in->readBool(StateNames::POWERED_BIT));
});
$this->map(Ids::COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::NONE), $in));
$this->map(Ids::COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::NONE));
$this->map(Ids::COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::NONE), $in));
$this->map(Ids::CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::NONE));
$this->mapSlab(Ids::CUT_COPPER_SLAB, Ids::DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::NONE));
$this->mapStairs(Ids::CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::NONE));
$this->mapSlab(Ids::CUT_RED_SANDSTONE_SLAB, Ids::CUT_RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_RED_SANDSTONE_SLAB());
$this->mapSlab(Ids::CUT_SANDSTONE_SLAB, Ids::CUT_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_SANDSTONE_SLAB());
$this->mapSlab(Ids::DARK_PRISMARINE_SLAB, Ids::DARK_PRISMARINE_DOUBLE_SLAB, fn() => Blocks::DARK_PRISMARINE_SLAB());
@ -1440,6 +1294,19 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
return Blocks::ENDER_CHEST()
->setFacing($in->readCardinalHorizontalFacing());
});
$this->map(Ids::EXPOSED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::EXPOSED));
$this->map(Ids::EXPOSED_CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::EXPOSED));
$this->map(Ids::EXPOSED_COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::EXPOSED));
$this->map(Ids::EXPOSED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::EXPOSED));
$this->mapSlab(Ids::EXPOSED_CUT_COPPER_SLAB, Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::EXPOSED));
$this->mapStairs(Ids::EXPOSED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::EXPOSED));
$this->map(Ids::EXPOSED_COPPER_BULB, function(Reader $in) : Block{
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::EXPOSED)
->setLit($in->readBool(StateNames::LIT))
->setPowered($in->readBool(StateNames::POWERED_BIT));
});
$this->map(Ids::EXPOSED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::EXPOSED), $in));
$this->map(Ids::EXPOSED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::EXPOSED), $in));
$this->map(Ids::FARMLAND, function(Reader $in) : Block{
return Blocks::FARMLAND()
->setWetness($in->readBoundedInt(StateNames::MOISTURIZED_AMOUNT, 0, 7));
@ -1592,6 +1459,19 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
$this->mapSlab(Ids::NORMAL_STONE_SLAB, Ids::NORMAL_STONE_DOUBLE_SLAB, fn() => Blocks::STONE_SLAB());
$this->mapStairs(Ids::NORMAL_STONE_STAIRS, fn() => Blocks::STONE_STAIRS());
$this->map(Ids::OCHRE_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::OCHRE)->setAxis($in->readPillarAxis()));
$this->map(Ids::OXIDIZED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::OXIDIZED));
$this->map(Ids::OXIDIZED_CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::OXIDIZED));
$this->map(Ids::OXIDIZED_COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::OXIDIZED));
$this->map(Ids::OXIDIZED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::OXIDIZED));
$this->mapSlab(Ids::OXIDIZED_CUT_COPPER_SLAB, Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::OXIDIZED));
$this->mapStairs(Ids::OXIDIZED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::OXIDIZED));
$this->map(Ids::OXIDIZED_COPPER_BULB, function(Reader $in) : Block{
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::OXIDIZED)
->setLit($in->readBool(StateNames::LIT))
->setPowered($in->readBool(StateNames::POWERED_BIT));
});
$this->map(Ids::OXIDIZED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::OXIDIZED), $in));
$this->map(Ids::OXIDIZED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::OXIDIZED), $in));
$this->map(Ids::PEARLESCENT_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::PEARLESCENT)->setAxis($in->readPillarAxis()));
$this->mapSlab(Ids::PETRIFIED_OAK_SLAB, Ids::PETRIFIED_OAK_DOUBLE_SLAB, fn() => Blocks::FAKE_WOODEN_SLAB());
$this->map(Ids::PINK_PETALS, function(Reader $in) : Block{
@ -1864,7 +1744,71 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
->setFacing($in->readHorizontalFacing());
});
$this->map(Ids::WATER, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::WATER(), $in));
$this->map(Ids::WAXED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::NONE));
$this->map(Ids::WAXED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::NONE));
$this->map(Ids::WAXED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::NONE));
$this->map(Ids::WAXED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::NONE));
$this->mapSlab(Ids::WAXED_CUT_COPPER_SLAB, Ids::WAXED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::NONE));
$this->mapStairs(Ids::WAXED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::NONE));
$this->map(Ids::WAXED_COPPER_BULB, function(Reader $in) : Block{
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::NONE)
->setLit($in->readBool(StateNames::LIT))
->setPowered($in->readBool(StateNames::POWERED_BIT));
});
$this->map(Ids::WAXED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::NONE), $in));
$this->map(Ids::WAXED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::NONE), $in));
$this->map(Ids::WAXED_EXPOSED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::EXPOSED));
$this->map(Ids::WAXED_EXPOSED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::EXPOSED));
$this->map(Ids::WAXED_EXPOSED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::EXPOSED));
$this->map(Ids::WAXED_EXPOSED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::EXPOSED));
$this->mapSlab(Ids::WAXED_EXPOSED_CUT_COPPER_SLAB, Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::EXPOSED));
$this->mapStairs(Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::EXPOSED));
$this->map(Ids::WAXED_EXPOSED_COPPER_BULB, function(Reader $in) : Block{
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::EXPOSED)
->setLit($in->readBool(StateNames::LIT))
->setPowered($in->readBool(StateNames::POWERED_BIT));
});
$this->map(Ids::WAXED_EXPOSED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::EXPOSED), $in));
$this->map(Ids::WAXED_EXPOSED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::EXPOSED), $in));
$this->map(Ids::WAXED_OXIDIZED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::OXIDIZED));
$this->map(Ids::WAXED_OXIDIZED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::OXIDIZED));
$this->map(Ids::WAXED_OXIDIZED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::OXIDIZED));
$this->map(Ids::WAXED_OXIDIZED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::OXIDIZED));
$this->mapSlab(Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB, Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::OXIDIZED));
$this->mapStairs(Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::OXIDIZED));
$this->map(Ids::WAXED_OXIDIZED_COPPER_BULB, function(Reader $in) : Block{
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::OXIDIZED)
->setLit($in->readBool(StateNames::LIT))
->setPowered($in->readBool(StateNames::POWERED_BIT));
});
$this->map(Ids::WAXED_OXIDIZED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::OXIDIZED), $in));
$this->map(Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::OXIDIZED), $in));
$this->map(Ids::WAXED_WEATHERED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::WEATHERED));
$this->map(Ids::WAXED_WEATHERED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::WEATHERED));
$this->map(Ids::WAXED_WEATHERED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::WEATHERED));
$this->map(Ids::WAXED_WEATHERED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::WEATHERED));
$this->mapSlab(Ids::WAXED_WEATHERED_CUT_COPPER_SLAB, Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::WEATHERED));
$this->mapStairs(Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::WEATHERED));
$this->map(Ids::WAXED_WEATHERED_COPPER_BULB, function(Reader $in) : Block{
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::WEATHERED)
->setLit($in->readBool(StateNames::LIT))
->setPowered($in->readBool(StateNames::POWERED_BIT));
});
$this->map(Ids::WAXED_WEATHERED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::WEATHERED), $in));
$this->map(Ids::WAXED_WEATHERED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::WEATHERED), $in));
$this->map(Ids::WEATHERED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::WEATHERED));
$this->map(Ids::WEATHERED_CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::WEATHERED));
$this->map(Ids::WEATHERED_COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::WEATHERED));
$this->map(Ids::WEATHERED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::WEATHERED));
$this->mapSlab(Ids::WEATHERED_CUT_COPPER_SLAB, Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::WEATHERED));
$this->mapStairs(Ids::WEATHERED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::WEATHERED));
$this->map(Ids::WEATHERED_COPPER_BULB, function(Reader $in) : Block{
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::WEATHERED)
->setLit($in->readBool(StateNames::LIT))
->setPowered($in->readBool(StateNames::POWERED_BIT));
});
$this->map(Ids::WEATHERED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::WEATHERED), $in));
$this->map(Ids::WEATHERED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::WEATHERED), $in));
$this->map(Ids::WEEPING_VINES, function(Reader $in) : Block{
return Blocks::WEEPING_VINES()
->setAge($in->readBoundedInt(StateNames::WEEPING_VINES_AGE, 0, 25));

View File

@ -0,0 +1,89 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\runtime;
/**
* Provides backwards-compatible shims for the old codegen'd enum describer methods.
* This is kept for plugin backwards compatibility, but these functions should not be used in new code.
* @deprecated
*/
trait LegacyRuntimeEnumDescriberTrait{
abstract protected function enum(\UnitEnum &$case) : void;
public function bellAttachmentType(\pocketmine\block\utils\BellAttachmentType &$value) : void{
$this->enum($value);
}
public function copperOxidation(\pocketmine\block\utils\CopperOxidation &$value) : void{
$this->enum($value);
}
public function coralType(\pocketmine\block\utils\CoralType &$value) : void{
$this->enum($value);
}
public function dirtType(\pocketmine\block\utils\DirtType &$value) : void{
$this->enum($value);
}
public function dripleafState(\pocketmine\block\utils\DripleafState &$value) : void{
$this->enum($value);
}
public function dyeColor(\pocketmine\block\utils\DyeColor &$value) : void{
$this->enum($value);
}
public function froglightType(\pocketmine\block\utils\FroglightType &$value) : void{
$this->enum($value);
}
public function leverFacing(\pocketmine\block\utils\LeverFacing &$value) : void{
$this->enum($value);
}
public function medicineType(\pocketmine\item\MedicineType &$value) : void{
$this->enum($value);
}
public function mobHeadType(\pocketmine\block\utils\MobHeadType &$value) : void{
$this->enum($value);
}
public function mushroomBlockType(\pocketmine\block\utils\MushroomBlockType &$value) : void{
$this->enum($value);
}
public function potionType(\pocketmine\item\PotionType &$value) : void{
$this->enum($value);
}
public function slabType(\pocketmine\block\utils\SlabType &$value) : void{
$this->enum($value);
}
public function suspiciousStewType(\pocketmine\item\SuspiciousStewType &$value) : void{
$this->enum($value);
}
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\data\runtime;
use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\block\utils\WallConnectionType;
use pocketmine\math\Facing;
@ -34,9 +35,14 @@ use pocketmine\math\Facing;
* You may use it as a type for parameters and return values, but it should not be implemented outside of this package.
* New methods may be added without warning.
*/
interface RuntimeDataDescriber{
interface RuntimeDataDescriber extends RuntimeEnumDescriber{
public function int(int $bits, int &$value) : void;
/**
* @deprecated Use {@link RuntimeDataDescriber::boundedIntAuto()} instead.
*/
public function boundedInt(int $bits, int $min, int $max, int &$value) : void;
/**
* Same as boundedInt() but automatically calculates the required number of bits from the range.
* The range bounds must be constant.
@ -71,6 +77,14 @@ interface RuntimeDataDescriber{
*/
public function wallConnections(array &$connections) : void;
/**
* @param BrewingStandSlot[] $slots
* @phpstan-param array<int, BrewingStandSlot> $slots
*
* @deprecated Use {@link enumSet()} instead.
*/
public function brewingStandSlots(array &$slots) : void;
public function railShape(int &$railShape) : void;
public function straightOnlyRailShape(int &$railShape) : void;

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\data\runtime;
use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\block\utils\RailConnectionInfo;
use pocketmine\block\utils\WallConnectionType;
use pocketmine\math\Axis;
@ -34,6 +35,8 @@ use function log;
use function spl_object_id;
final class RuntimeDataReader implements RuntimeDataDescriber{
use LegacyRuntimeEnumDescriberTrait;
private int $offset = 0;
public function __construct(
@ -56,6 +59,18 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
$value = $this->readInt($bits);
}
/**
* @deprecated Use {@link self::boundedIntAuto()} instead.
*/
public function boundedInt(int $bits, int $min, int $max, int &$value) : void{
$offset = $this->offset;
$this->boundedIntAuto($min, $max, $value);
$actualBits = $this->offset - $offset;
if($this->offset !== $offset + $bits){
throw new \InvalidArgumentException("Bits should be $actualBits for the given bounds, but received $bits. Use boundedIntAuto() for automatic bits calculation.");
}
}
private function readBoundedIntAuto(int $min, int $max) : int{
$bits = ((int) log($max - $min, 2)) + 1;
$result = $this->readInt($bits) + $min;
@ -177,6 +192,16 @@ final class RuntimeDataReader implements RuntimeDataDescriber{
$connections = $result;
}
/**
* @param BrewingStandSlot[] $slots
* @phpstan-param array<int, BrewingStandSlot> $slots
*
* @deprecated Use {@link enumSet()} instead.
*/
public function brewingStandSlots(array &$slots) : void{
$this->enumSet($slots, BrewingStandSlot::cases());
}
public function railShape(int &$railShape) : void{
$result = $this->readInt(4);
if(!isset(RailConnectionInfo::CONNECTIONS[$result]) && !isset(RailConnectionInfo::CURVE_CONNECTIONS[$result])){

View File

@ -23,11 +23,14 @@ declare(strict_types=1);
namespace pocketmine\data\runtime;
use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\math\Facing;
use function count;
use function log;
final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
use LegacyRuntimeEnumDescriberTrait;
private int $bits = 0;
protected function addBits(int $bits) : void{
@ -42,6 +45,18 @@ final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
$this->addBits($bits);
}
/**
* @deprecated Use {@link self::boundedIntAuto()} instead.
*/
public function boundedInt(int $bits, int $min, int $max, int &$value) : void{
$currentBits = $this->bits;
$this->boundedIntAuto($min, $max, $value);
$actualBits = $this->bits - $currentBits;
if($actualBits !== $bits){
throw new \InvalidArgumentException("Bits should be $actualBits for the given bounds, but received $bits. Use boundedIntAuto() for automatic bits calculation.");
}
}
public function boundedIntAuto(int $min, int $max, int &$value) : void{
$this->addBits(((int) log($max - $min, 2)) + 1);
}
@ -82,6 +97,10 @@ final class RuntimeDataSizeCalculator implements RuntimeDataDescriber{
$this->addBits(7);
}
public function brewingStandSlots(array &$slots) : void{
$this->addBits(count(BrewingStandSlot::cases()));
}
public function railShape(int &$railShape) : void{
$this->addBits(4);
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\data\runtime;
use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\block\utils\WallConnectionType;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
@ -31,6 +32,8 @@ use function log;
use function spl_object_id;
final class RuntimeDataWriter implements RuntimeDataDescriber{
use LegacyRuntimeEnumDescriberTrait;
private int $value = 0;
private int $offset = 0;
@ -54,6 +57,18 @@ final class RuntimeDataWriter implements RuntimeDataDescriber{
$this->writeInt($bits, $value);
}
/**
* @deprecated Use {@link self::boundedIntAuto()} instead.
*/
public function boundedInt(int $bits, int $min, int $max, int &$value) : void{
$offset = $this->offset;
$this->writeBoundedIntAuto($min, $max, $value);
$actualBits = $this->offset - $offset;
if($actualBits !== $bits){
throw new \InvalidArgumentException("Bits should be $actualBits for the given bounds, but received $bits. Use boundedIntAuto() for automatic bits calculation.");
}
}
private function writeBoundedIntAuto(int $min, int $max, int $value) : void{
if($value < $min || $value > $max){
throw new \InvalidArgumentException("Value $value is outside the range $min - $max");
@ -155,6 +170,16 @@ final class RuntimeDataWriter implements RuntimeDataDescriber{
$this->writeBoundedIntAuto(0, (3 ** 4) - 1, $packed);
}
/**
* @param BrewingStandSlot[] $slots
* @phpstan-param array<int, BrewingStandSlot> $slots
*
* @deprecated Use {@link enumSet()} instead.
*/
public function brewingStandSlots(array &$slots) : void{
$this->enumSet($slots, BrewingStandSlot::cases());
}
public function railShape(int &$railShape) : void{
$this->int(4, $railShape);
}

View File

@ -0,0 +1,61 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\runtime;
/**
* Provides backwards-compatible shims for the old codegen'd enum describer methods.
* This is kept for plugin backwards compatibility, but these functions should not be used in new code.
* @deprecated
*/
interface RuntimeEnumDescriber{
public function bellAttachmentType(\pocketmine\block\utils\BellAttachmentType &$value) : void;
public function copperOxidation(\pocketmine\block\utils\CopperOxidation &$value) : void;
public function coralType(\pocketmine\block\utils\CoralType &$value) : void;
public function dirtType(\pocketmine\block\utils\DirtType &$value) : void;
public function dripleafState(\pocketmine\block\utils\DripleafState &$value) : void;
public function dyeColor(\pocketmine\block\utils\DyeColor &$value) : void;
public function froglightType(\pocketmine\block\utils\FroglightType &$value) : void;
public function leverFacing(\pocketmine\block\utils\LeverFacing &$value) : void;
public function medicineType(\pocketmine\item\MedicineType &$value) : void;
public function mobHeadType(\pocketmine\block\utils\MobHeadType &$value) : void;
public function mushroomBlockType(\pocketmine\block\utils\MushroomBlockType &$value) : void;
public function potionType(\pocketmine\item\PotionType &$value) : void;
public function slabType(\pocketmine\block\utils\SlabType &$value) : void;
public function suspiciousStewType(\pocketmine\item\SuspiciousStewType &$value) : void;
}

View File

@ -1485,7 +1485,7 @@ abstract class Entity{
return $this->hasSpawned;
}
abstract public function getNetworkTypeId() : string;
abstract public static function getNetworkTypeId() : string;
/**
* Called by spawnTo() to send whatever packets needed to spawn the entity to the client.
@ -1494,8 +1494,8 @@ abstract class Entity{
$player->getNetworkSession()->sendDataPacket(AddActorPacket::create(
$this->getId(), //TODO: actor unique ID
$this->getId(),
$this->getNetworkTypeId(),
$this->getOffsetPosition($this->location->asVector3()),
static::getNetworkTypeId(),
$this->location->asVector3(),
$this->getMotion(),
$this->location->pitch,
$this->location->yaw,

View File

@ -99,7 +99,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
private const TAG_SKIN_GEOMETRY_NAME = "GeometryName"; //TAG_String
private const TAG_SKIN_GEOMETRY_DATA = "GeometryData"; //TAG_ByteArray
public function getNetworkTypeId() : string{ return EntityIds::PLAYER; }
public static function getNetworkTypeId() : string{ return EntityIds::PLAYER; }
protected PlayerInventory $inventory;
protected PlayerOffHandInventory $offHandInventory;

View File

@ -38,7 +38,7 @@ use const M_PI;
class Squid extends WaterAnimal{
public function getNetworkTypeId() : string{ return EntityIds::SQUID; }
public static function getNetworkTypeId() : string{ return EntityIds::SQUID; }
public ?Vector3 $swimDirection = null;
public float $swimSpeed = 0.1;

View File

@ -40,7 +40,7 @@ class Villager extends Living implements Ageable{
private const TAG_PROFESSION = "Profession"; //TAG_Int
public function getNetworkTypeId() : string{ return EntityIds::VILLAGER; }
public static function getNetworkTypeId() : string{ return EntityIds::VILLAGER; }
private bool $baby = false;
private int $profession = self::PROFESSION_FARMER;

View File

@ -30,7 +30,7 @@ use function mt_rand;
class Zombie extends Living{
public function getNetworkTypeId() : string{ return EntityIds::ZOMBIE; }
public static function getNetworkTypeId() : string{ return EntityIds::ZOMBIE; }
protected function getInitialSizeInfo() : EntitySizeInfo{
return new EntitySizeInfo(1.8, 0.6); //TODO: eye height ??

View File

@ -47,7 +47,7 @@ class EndCrystal extends Entity implements Explosive{
private const TAG_BLOCKTARGET_Y = "BlockTargetY"; //TAG_Int
private const TAG_BLOCKTARGET_Z = "BlockTargetZ"; //TAG_Int
public function getNetworkTypeId() : string{ return EntityIds::ENDER_CRYSTAL; }
public static function getNetworkTypeId() : string{ return EntityIds::ENDER_CRYSTAL; }
protected bool $showBase = false;
protected ?Vector3 $beamTarget = null;

View File

@ -37,7 +37,7 @@ use function sqrt;
class ExperienceOrb extends Entity{
public function getNetworkTypeId() : string{ return EntityIds::XP_ORB; }
public static function getNetworkTypeId() : string{ return EntityIds::XP_ORB; }
public const TAG_VALUE_PC = "Value"; //short
public const TAG_VALUE_PE = "experience value"; //int (WTF?)

View File

@ -56,7 +56,7 @@ class FallingBlock extends Entity{
private const TAG_TILE = "Tile"; //TAG_Byte
private const TAG_DATA = "Data"; //TAG_Byte
public function getNetworkTypeId() : string{ return EntityIds::FALLING_BLOCK; }
public static function getNetworkTypeId() : string{ return EntityIds::FALLING_BLOCK; }
protected Block $block;

View File

@ -52,7 +52,7 @@ class ItemEntity extends Entity{
private const TAG_THROWER = "Thrower"; //TAG_String
public const TAG_ITEM = "Item"; //TAG_Compound
public function getNetworkTypeId() : string{ return EntityIds::ITEM; }
public static function getNetworkTypeId() : string{ return EntityIds::ITEM; }
public const MERGE_CHECK_PERIOD = 2; //0.1 seconds
public const DEFAULT_DESPAWN_DELAY = 6000; //5 minutes

View File

@ -49,7 +49,7 @@ class Painting extends Entity{
public const TAG_DIRECTION_BE = "Direction"; //TAG_Byte
public const TAG_MOTIVE = "Motive"; //TAG_String
public function getNetworkTypeId() : string{ return EntityIds::PAINTING; }
public static function getNetworkTypeId() : string{ return EntityIds::PAINTING; }
public const DATA_TO_FACING = [
0 => Facing::SOUTH,

View File

@ -43,7 +43,7 @@ class PrimedTNT extends Entity implements Explosive{
private const TAG_FUSE = "Fuse"; //TAG_Short
public function getNetworkTypeId() : string{ return EntityIds::TNT; }
public static function getNetworkTypeId() : string{ return EntityIds::TNT; }
protected int $fuse;
protected bool $worksUnderwater = false;

View File

@ -46,7 +46,7 @@ use function sqrt;
class Arrow extends Projectile{
public function getNetworkTypeId() : string{ return EntityIds::ARROW; }
public static function getNetworkTypeId() : string{ return EntityIds::ARROW; }
public const PICKUP_NONE = 0;
public const PICKUP_ANY = 1;

View File

@ -29,7 +29,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use pocketmine\world\particle\ItemBreakParticle;
class Egg extends Throwable{
public function getNetworkTypeId() : string{ return EntityIds::EGG; }
public static function getNetworkTypeId() : string{ return EntityIds::EGG; }
//TODO: spawn chickens on collision

View File

@ -30,7 +30,7 @@ use pocketmine\world\particle\EndermanTeleportParticle;
use pocketmine\world\sound\EndermanTeleportSound;
class EnderPearl extends Throwable{
public function getNetworkTypeId() : string{ return EntityIds::ENDER_PEARL; }
public static function getNetworkTypeId() : string{ return EntityIds::ENDER_PEARL; }
protected function onHit(ProjectileHitEvent $event) : void{
$owner = $this->getOwningEntity();

View File

@ -30,7 +30,7 @@ use pocketmine\world\sound\PotionSplashSound;
use function mt_rand;
class ExperienceBottle extends Throwable{
public function getNetworkTypeId() : string{ return EntityIds::XP_BOTTLE; }
public static function getNetworkTypeId() : string{ return EntityIds::XP_BOTTLE; }
protected function getInitialGravity() : float{ return 0.07; }

View File

@ -36,7 +36,7 @@ use pocketmine\world\particle\ItemBreakParticle;
use pocketmine\world\sound\IceBombHitSound;
class IceBomb extends Throwable{
public function getNetworkTypeId() : string{ return EntityIds::ICE_BOMB; }
public static function getNetworkTypeId() : string{ return EntityIds::ICE_BOMB; }
public function getResultDamage() : int{
return -1;

View File

@ -28,7 +28,7 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use pocketmine\world\particle\SnowballPoofParticle;
class Snowball extends Throwable{
public function getNetworkTypeId() : string{ return EntityIds::SNOWBALL; }
public static function getNetworkTypeId() : string{ return EntityIds::SNOWBALL; }
protected function onHit(ProjectileHitEvent $event) : void{
$world = $this->getWorld();

View File

@ -52,7 +52,7 @@ class SplashPotion extends Throwable{
public const TAG_POTION_ID = "PotionId"; //TAG_Short
public function getNetworkTypeId() : string{ return EntityIds::SPLASH_POTION; }
public static function getNetworkTypeId() : string{ return EntityIds::SPLASH_POTION; }
protected bool $linger = false;
protected PotionType $potionType;

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\event\block;
use pocketmine\block\Block;
use pocketmine\block\utils\Waterloggable;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
use pocketmine\event\Event;

View File

@ -110,6 +110,7 @@ class InventoryTransaction{
public function addAction(InventoryAction $action) : void{
if(!isset($this->actions[$hash = spl_object_id($action)])){
$this->actions[$hash] = $action;
$action->onAddToTransaction($this);
if($action instanceof SlotChangeAction && !isset($this->inventories[$inventoryId = spl_object_id($action->getInventory())])){
$this->inventories[$inventoryId] = $action->getInventory();
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\inventory\transaction\action;
use pocketmine\inventory\transaction\InventoryTransaction;
use pocketmine\inventory\transaction\TransactionValidationException;
use pocketmine\item\Item;
use pocketmine\player\Player;
@ -57,6 +58,14 @@ abstract class InventoryAction{
*/
abstract public function validate(Player $source) : void;
/**
* Called when the action is added to the specified InventoryTransaction.
* @deprecated
*/
public function onAddToTransaction(InventoryTransaction $transaction) : void{
}
/**
* Called by inventory transactions before any actions are processed. If this returns false, the transaction will
* be cancelled.

View File

@ -24,8 +24,23 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\block\utils\WoodType;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static BoatType ACACIA()
* @method static BoatType BIRCH()
* @method static BoatType DARK_OAK()
* @method static BoatType JUNGLE()
* @method static BoatType MANGROVE()
* @method static BoatType OAK()
* @method static BoatType SPRUCE()
*/
enum BoatType{
use LegacyEnumShimTrait;
case OAK;
case SPRUCE;
case BIRCH;

View File

@ -26,12 +26,10 @@ namespace pocketmine\item;
use pocketmine\block\Block;
use pocketmine\block\BlockTypeIds;
use pocketmine\block\Liquid;
use pocketmine\block\utils\Waterloggable;
use pocketmine\block\VanillaBlocks;
use pocketmine\event\player\PlayerBucketFillEvent;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function var_dump;
class Bucket extends Item{
@ -41,15 +39,11 @@ class Bucket extends Item{
public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, array &$returnedItems) : ItemUseResult{
//TODO: move this to generic placement logic
if($blockClicked instanceof Liquid && $blockClicked->isSource() || $blockClicked instanceof Waterloggable && $blockClicked->getWaterState() !== null){
if($blockClicked instanceof Liquid && $blockClicked->isSource()){
$stack = clone $this;
$stack->pop();
$id = $blockClicked->getTypeId();
if($blockClicked instanceof Waterloggable){
$id = $blockClicked->getWaterState()->getTypeId();
}
$resultItem = match($id){
$resultItem = match($blockClicked->getTypeId()){
BlockTypeIds::LAVA => VanillaItems::LAVA_BUCKET(),
BlockTypeIds::WATER => VanillaItems::WATER_BUCKET(),
default => null
@ -61,16 +55,8 @@ class Bucket extends Item{
$ev = new PlayerBucketFillEvent($player, $blockReplace, $face, $this, $resultItem);
$ev->call();
if(!$ev->isCancelled()){
if($blockClicked instanceof Waterloggable){
var_dump("Setting water state", $blockClicked->__toString());
$sound = $blockClicked->getWaterState()->getBucketFillSound();
$blockClicked->setWaterState(null);
$player->getWorld()->setBlock($blockClicked->getPosition(), $blockClicked);
}else{
$sound = $blockClicked->getBucketFillSound();
$player->getWorld()->setBlock($blockClicked->getPosition(), VanillaBlocks::AIR());
}
$player->getWorld()->addSound($blockClicked->getPosition()->add(0.5, 0.5, 0.5), $sound);
$player->getWorld()->setBlock($blockClicked->getPosition(), VanillaBlocks::AIR());
$player->getWorld()->addSound($blockClicked->getPosition()->add(0.5, 0.5, 0.5), $blockClicked->getBucketFillSound());
$this->pop();
$returnedItems[] = $ev->getItem();

View File

@ -23,7 +23,19 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static ItemUseResult FAIL()
* @method static ItemUseResult NONE()
* @method static ItemUseResult SUCCESS()
*/
enum ItemUseResult{
use LegacyEnumShimTrait;
case NONE;
case FAIL;
case SUCCESS;

View File

@ -111,8 +111,7 @@ final class LegacyStringToItemParser{
*/
public function parse(string $input) : Item{
$key = $this->reprocess($input);
//TODO: this should be limited to 2 parts, but 3 preserves old behaviour when given a string like 351:4:1
$b = explode(":", $key, limit: 3);
$b = explode(":", $key);
if(!isset($b[1])){
$meta = 0;

View File

@ -26,12 +26,9 @@ namespace pocketmine\item;
use pocketmine\block\Block;
use pocketmine\block\Lava;
use pocketmine\block\Liquid;
use pocketmine\block\utils\Waterloggable;
use pocketmine\block\Water;
use pocketmine\event\player\PlayerBucketEmptyEvent;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function var_dump;
class LiquidBucket extends Item{
private Liquid $liquid;
@ -58,7 +55,7 @@ class LiquidBucket extends Item{
}
public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, array &$returnedItems) : ItemUseResult{
if(!$blockReplace->canBeReplaced() && !($blockReplace instanceof Waterloggable)){
if(!$blockReplace->canBeReplaced()){
return ItemUseResult::NONE;
}
@ -68,14 +65,7 @@ class LiquidBucket extends Item{
$ev = new PlayerBucketEmptyEvent($player, $blockReplace, $face, $this, VanillaItems::BUCKET());
$ev->call();
if(!$ev->isCancelled()){
if($blockClicked instanceof Waterloggable && $resultBlock instanceof Water){
var_dump("Setting water state", $resultBlock->__toString());
$blockClicked->setWaterState($resultBlock);
$player->getWorld()->setBlock($blockClicked->getPosition(), $blockClicked);
$blockClicked->onNearbyBlockChange();
}else{
$player->getWorld()->setBlock($blockReplace->getPosition(), $resultBlock->getFlowingForm());
}
$player->getWorld()->setBlock($blockReplace->getPosition(), $resultBlock->getFlowingForm());
$player->getWorld()->addSound($blockReplace->getPosition()->add(0.5, 0.5, 0.5), $resultBlock->getBucketEmptySound());
$this->pop();

View File

@ -25,8 +25,20 @@ namespace pocketmine\item;
use pocketmine\entity\effect\Effect;
use pocketmine\entity\effect\VanillaEffects;
use pocketmine\utils\LegacyEnumShimTrait;
/**
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
* These are retained for backwards compatibility only.
*
* @method static MedicineType ANTIDOTE()
* @method static MedicineType ELIXIR()
* @method static MedicineType EYE_DROPS()
* @method static MedicineType TONIC()
*/
enum MedicineType{
use LegacyEnumShimTrait;
case ANTIDOTE;
case ELIXIR;
case EYE_DROPS;

Some files were not shown because too many files have changed in this diff Show More