Compare commits

..

101 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
51cf6817b1 World: fixed overflow checks for getCollisionBlocks(), closes #6630 2025-02-16 23:24:39 +00:00
fd04894a7b Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2025-02-16 23:18:34 +00:00
d2d6a59c72 ItemDeserializer: fix doc comment typo 2025-02-16 22:52:11 +00:00
788ee9a008 Allow overriding deserializers for block and item IDs
there's no technical reason not to support this, since it doesn't violate any assumptions and the type returned is a base anyway.

this enables implementing stuff like snow cauldrons in a plugin, which previously would require reflection due to the minecraft:cauldron deserializer being registered already.
it also enables overriding IDs to map to custom blocks, which might be useful for overriding some functionality (although this is inadvisable - and won't alter the usage of stuff like VanillaBlocks::WHATEVER()).

we do *not* allow overriding serializers, since type IDs are expected to be paired to block implementations, and allowing them to be reassigned could lead to crashes if the new class was incorrect. So the correct approach for overriding nether portals would be to create a custom type ID as if you were adding a fully custom item. This will also allow other plugins to distinguish between your implementation and the built-in one.
2025-02-16 22:49:40 +00:00
34f801ee3c 5.25.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/13359320328
2025-02-16 22:18:20 +00:00
d96ef21c4d Prepare 5.25.0 release (#6631) 2025-02-16 22:16:47 +00:00
246c1776df InventoryAction: avoid throwaway Item clones 2025-02-16 21:47:35 +00:00
03e4b53ac4 BedrockDataFiles: added constants for folders as well as files
we probably should have it recurse too, but this is an easy win.
2025-02-16 20:57:16 +00:00
91ac64783f Bedrock 1.21.60 (#6627)
Co-authored-by: Dylan K. Taylor <dktapps@pmmp.io>
2025-02-16 20:51:53 +00:00
9402a20ee3 Update Utils::getOS() doc comment
closes #6628
2025-02-16 16:12:29 +00:00
2670e81668 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2025-02-12 02:14:51 +00:00
e29aa2f337 Added resin material color (#6622) 2025-02-11 16:15:42 +00:00
5ef89200c6 Bump phpstan/phpstan in the development-patch-updates group (#6620) 2025-02-10 22:14:30 +00:00
9b3b45258a Optimise collision box checks by caching some basic info (#6606)
This PR significantly improves performance of entity movement calculation.

Previous attempts to optimise this were ineffective, as they used a cache to mitigate the cost of recomputing AABBs. Entities tend to move around randomly, so the non-cached pathway really needed to be optimized.

This change improves performance on multiple fronts:
1) avoiding Block allocations for blocks with 1x1x1 AABBs and with no AABBs (the most common)
2) avoiding Block allocations and overlapping intersection checks unless a stateID is specifically known to potentially exceed its cell boundaries (like fences)
3) avoiding overlapping AABB checks when overlaps can't make any difference anyway (cubes)

Together, these changes improve the performance of World->getBlockCollisionBoxes() by a factor of 5. In real-world terms, this shows up as a major performance improvement in situations with lots of entities moving in random directions. Testing with item entities showed an increase from 400 to 1200 moving items with the same CPU usage.

This change is built on the assumption that `Block->recalculateCollisionBoxes()` and its overrides don't interact with any world. This is technically possible due to the crappy design of the `Block` architecture, but should be avoided. As a world is not available during `RuntimeBlockStateRegistry` initialization, attempting to interact with a world during `recalculateCollisionBoxes()` will now cause a crash.

This turned out to be a problem for `ChorusPlant`, which was fixed by 70fb9bbdfd. The correct solution in this case was to use dynamic states similar to how we currently deal with fence connections.
2025-02-06 15:42:10 +00:00
ca4debbf08 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13126338048
2025-02-04 01:22:15 +00:00
39e69276a1 Bump tests/plugins/DevTools from c6dca35 to a030d39 (#6617) 2025-02-03 11:43:03 +00:00
94797e3afa Bump build/php from ae94694 to 1549433 (#6616) 2025-02-03 11:42:37 +00:00
03f98ee0a9 New version of NBT for performance improvements 2025-02-02 19:47:47 +00:00
70368ea653 Merge branch 'stable' into minor-next 2025-02-02 19:47:03 +00:00
9d6a0cc738 Update composer dependencies 2025-02-02 19:46:54 +00:00
21ccd90147 ChunkCache: parameterize dimension ID
(cc @Muqsit)
2025-02-02 19:43:04 +00:00
0a9a45a126 Improve block break progress
closes #6500

This fixes break time animations for mining fatigue and haste, and
improves the underwater and on-ground behaviour.

on-ground is still not quite right for reasons not related to this PR
(see #6547).
I'm also not quite sure the underwater logic is correct (in water vs
underwater?) but it's definitely better than what we have currently.
2025-02-02 19:34:14 +00:00
88937f1785 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13094301661
2025-02-02 01:26:08 +00:00
07987890a0 Bump the github-actions group with 2 updates (#6613) 2025-02-01 13:38:25 +00:00
e5a783cb9e Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13001707314
2025-01-28 01:21:43 +00:00
70fb9bbdfd ChorusPlant: fixed recalculateCollisionBoxes() depending on the world 2025-01-27 21:28:26 +00:00
f60120a75e Bump the development-patch-updates group with 3 updates (#6603) 2025-01-27 10:43:28 +00:00
fc86d3a44e 5.24.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/12916833718
2025-01-22 20:50:42 +00:00
393d7f72a9 5.24.0
5.24.0 minor release
2025-01-22 20:49:38 +00:00
b625fee94b Prepare 5.24.0 release 2025-01-22 18:00:41 +00:00
6b606dca95 UPnP: better fix for postURL error that doesn't require behavioural breaks 2025-01-22 17:46:43 +00:00
406ddf3e53 Revert "Internet: make postURL() error reporting behaviour more predictable"
This reverts commit 97c5902ae2.
2025-01-22 17:44:23 +00:00
ec6077776a Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into minor-next 2025-01-22 16:45:49 +00:00
f7b5cd7ff3 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12899221905
2025-01-22 01:23:49 +00:00
3453ff03fd 5.23.4 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/12898306655
2025-01-22 00:10:10 +00:00
04e63172c3 5.23.3 (#6597) 2025-01-22 00:08:49 +00:00
51cb1875bb Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12839491049
2025-01-18 01:19:32 +00:00
0b60a47cde Noteblock instrument changes from 1.21.50 (#6596)
Good thing this isn't saved on disk :|
2025-01-17 19:56:19 +00:00
d1066d0199 Bump build/php from 56cec11 to ae94694 (#6595) 2025-01-17 19:54:48 +00:00
f349ce75e4 Player: add ability to get & set flight speed multiplier (#6076)
Since this doesn't directly correspond to flight speed (it's multiplied by different values depending on whether sprinting or not, and possibly other states), "multiplier" was preferred instead of directly calling it flight speed.

Default value is 0.05.
2025-01-09 20:13:46 +00:00
b3f15435cc Projectile: clean up dodgy code 2025-01-08 02:31:50 +00:00
847ae26cad PHPStan: don't remember possibly-impure function return values
I don't think we get much benefit from this, and the assumption that functions with a return value are pure is sketchy.
In any case, it's better to avoid these repeated calls anyway.
2025-01-08 02:04:06 +00:00
d42ec06647 ZippedResourcePack: don't pass exception code to new exception
this is a BUT (int|string) under PHPStan, and we don't need the errors. We don't care about this code anyway.
2025-01-08 01:48:55 +00:00
5e0f03dff0 Stub PalettedBlockArray functions that work with arrays
and workaround PHPStan stupidity
2025-01-08 01:48:15 +00:00
4a83920db9 PlayerPreLoginEvent: improve array type info 2025-01-08 01:47:04 +00:00
0a16daa619 Avoid dodgy array_flip hash building
the conventional way is using array_keys and array_fill_keys. Behaviour is more predictable & also avoids benevolent union fuckery from PHPStan.
2025-01-08 01:45:28 +00:00
e34f34f9f4 Update BedrockProtocol dependency 2025-01-07 23:09:28 +00:00
e8c4b743b5 LevelDB: stop overriding types from NBT
NBT has better quality type info already
2025-01-07 22:54:10 +00:00
689a7996b9 Update NBT dependency 2025-01-07 22:51:38 +00:00
794641c0f8 Utils: split some horrifying code across multiple lines 2025-01-07 22:35:19 +00:00
9633b7d8a7 Update to PHPStan 2.x 2025-01-07 22:34:43 +00:00
d25ec58a6f AsyncPoolTest: phpdoc 2025-01-07 22:25:37 +00:00
d69a887b0d Utils: fix parameter doc for printableExceptionInfo() 2025-01-07 22:24:26 +00:00
38441a6ba3 build: avoid weak comparison 2025-01-07 22:23:16 +00:00
47cb04f6a6 tools: fix PHPStan 2.0 issues 2025-01-07 22:15:50 +00:00
b1c7fc017a CS 2025-01-07 22:13:20 +00:00
cd59e272bc PHPStan 2.0 fixes 2025-01-07 22:10:42 +00:00
7b1b35ab1f generator: fixup issues reported by PHPStan 2.0 2025-01-07 22:07:38 +00:00
28d31c97f8 Server: fixup PHPStan 2.x reported issues 2025-01-07 22:05:01 +00:00
a17512de93 Command: don't trust plugins not to pass junk 2025-01-06 23:26:13 +00:00
601be3fb33 stfu 2025-01-06 23:09:26 +00:00
2e32c50670 NetworkSession: apparently aliases are already a list at this point??? 2025-01-06 23:08:48 +00:00
d1fa6edc50 InGamePacketHandler: fix weak comparisons 2025-01-06 23:08:18 +00:00
a1ba8bc3da NetworkSession: improve PHPDoc types 2025-01-06 23:07:54 +00:00
73edb8799d SignalHandler: fixed dodgy setup logic 2025-01-06 23:06:19 +00:00
9592f066f3 PHPDoc: Restrict ReversePriorityQueue to numeric priorities 2025-01-06 23:05:49 +00:00
db9ba83001 Make some assumptions about proc_open() 2025-01-06 23:05:06 +00:00
1b2d2a3fe1 plugin: improve PHPDocs and type compliance 2025-01-06 23:04:00 +00:00
84ec8b7abe Removed dead error patterns
I do think these are PHPStan bugs, since the trait should inherit the parent class's doc comment
But for the sake of catching more bugs, these doc comments have been manually added anyway.
2025-01-06 23:02:18 +00:00
357dfb5c7e Fixed build 2025-01-06 23:01:14 +00:00
0358b7dce4 utils: avoid weak comparisons 2025-01-06 22:53:35 +00:00
97c5902ae2 Internet: make postURL() error reporting behaviour more predictable
err is now always set to null when doing a new operation.

previously, if the same var was used multiple times and a previous one failed,
code might think that a previous error belonged to the current operation.
2025-01-06 22:52:05 +00:00
9a130bce32 Config: remove bad assumptions about string root keys
these could just as easily be integers and the code should still work.
2025-01-06 22:50:25 +00:00
20849d6268 Fixed potential crashes in type ID tests
if the constants had any non-stringable values, these would blow up.
this would still be fine in the sense that the tests would fail, but better that they fail gracefully if possible.
2025-01-06 22:48:22 +00:00
b6bd3ef30c Improve PHPDocs in world package 2025-01-06 22:46:16 +00:00
c5a1c15389 TimingsCommand: beware crash on invalid timings server response 2025-01-06 22:44:17 +00:00
e30ae487dc SimpleCommandMap: ensure we always pass a list to Command::setAliases()
some offsets may have been removed if the alias failed to be registered.
2025-01-06 22:44:17 +00:00
59f6c85105 Command: mark execute $args as being list<string> 2025-01-06 22:44:17 +00:00
90f0b85d2e Eliminate weak comparisons in entity package
Weak comparisons were used in cases when we were worried about comparing int and float.

In some cases (particularly involving Vector3) we do need to be wary of this, so floatval() is used to avoid incorrect type comparisons.
In other cases, we were already exclusively comparing float-float, so weak compare wasn't needed anyway.
2025-01-06 22:44:17 +00:00
8ee70b209e MemoryDump: fix PHPDoc types 2025-01-06 22:44:16 +00:00
5c905d9a95 BlockBreakInfo: use strict comparison
weak compare isn't needed here since this can be float/float
2025-01-06 22:44:16 +00:00
8b23231537 Fixup PHPDoc for blocks 2025-01-06 22:44:16 +00:00
8e039f2711 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12615442245
2025-01-05 01:37:22 +00:00
4a4572131f Bump shivammathur/setup-php in the github-actions group (#6591) 2025-01-04 22:26:14 +00:00
3da0b82b86 Merge branch 'stable' into minor-next 2025-01-03 19:26:45 +00:00
da62eb9f33 ... 2025-01-03 19:26:24 +00:00
09c434983b Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12510342531
2024-12-27 01:23:47 +00:00
fbaa125d0c Bump build/php from 9728fa5 to 56cec11 (#6588)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `9728fa5` to `56cec11`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](9728fa57f7...56cec11745)

---
updated-dependencies:
- dependency-name: build/php
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-26 12:36:17 +00:00
6ad9dde43d Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12498201064
2024-12-26 01:23:25 +00:00
d634a5fa3d Bump build/php from b1eaaa4 to 9728fa5 (#6587)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `b1eaaa4` to `9728fa5`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](b1eaaa48ec...9728fa57f7)

---
updated-dependencies:
- dependency-name: build/php
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-25 13:06:46 +00:00
8cea4c13c4 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12487960388
2024-12-25 01:23:09 +00:00
dc2e82df7f crash.yml: add field ID for crash archive "report github issue" button 2024-12-24 16:37:18 +00:00
debf8d18fc Upgrade issue templates 2024-12-24 16:27:40 +00:00
81e3730b99 Fixed crashes containing PHP internal stack frames being flagged as plugin-caused 2024-12-24 14:20:16 +00:00
8a5eb71432 ChunkCache: track strings in cache directly instead of CompressBatchPromise
this reduces memory footprint slightly, but more importantly reduces GC workload.
Since it also reduces the work done on cache hit, it might *slightly* improve performance,
but any improvement is likely to be minimal.
2024-12-23 21:04:33 +00:00
172 changed files with 3626 additions and 2100 deletions

View File

@ -1,19 +0,0 @@
---
name: API change request
about: Suggest a change, addition or removal to the plugin API
title: ''
labels: ''
assignees: ''
---
<!--- Describe the problem you want to solve -->
## Problem description
<!--- Describe what changes you want to make to solve this problem -->
## Proposed solution
<!--- (optional) describe alternative methods you've explored to achieve your goal -->
## Alternative solutions that don't require API changes

84
.github/ISSUE_TEMPLATE/bug-report.yml vendored Normal file
View File

@ -0,0 +1,84 @@
name: Bug report
description: Report a feature of PocketMine-MP not working as expected
body:
- type: markdown
attributes:
value: |
## Plugin information
> [!IMPORTANT]
> It's strongly recommended to test for bugs without plugins before reporting an issue.
> This helps avoid wasting maintainers' time on bugs that are not actually caused by PocketMine-MP.
>
> If you're not sure whether a plugin might be causing your issue, please seek help on our [Discord](https://discord.gg/bmSAZBG) before writing an issue.
- type: dropdown
attributes:
label: Plugin information
options:
- "I haven't tested without plugins"
- Bug happens without plugins
- Bug only happens with certain plugins (describe below)
validations:
required: true
- type: markdown
attributes:
value: |
## Bug description
> [!TIP]
> Helpful information to include:
> - Steps to reproduce the issue
> - Error backtraces
> - Crashdumps
> - Plugin code that triggers the issue
> - List of installed plugins (use /plugins)
> [!IMPORTANT]
> **Steps to reproduce are critical to finding the cause of the problem!**
> Without reproducing steps, the issue will probably not be solvable and may be closed.
- type: textarea
attributes:
label: Problem description
description: Describe the problem, and how you encountered it
placeholder: e.g. Steps to reproduce the issue
validations:
required: true
- type: textarea
attributes:
label: Expected behaviour
description: What did you expect to happen?
validations:
required: true
- type: markdown
attributes:
value: |
## Version, OS and game info
- type: input
attributes:
label: PocketMine-MP version
placeholder: Use the /version command in PocketMine-MP
validations:
required: true
- type: input
attributes:
label: PHP version
placeholder: Use the /version command in PocketMine-MP
validations:
required: true
- type: input
attributes:
label: Server OS
placeholder: Use the /version command in PocketMine-MP
validations:
required: true
- type: input
attributes:
label: Game version (if applicable)
placeholder: e.g. Android, iOS, Windows, Xbox, PS4, Switch
validations:
required: false

View File

@ -1,37 +0,0 @@
---
name: Bug report
about: Unexpected non-crash behaviour (except missing gameplay features)
title: ''
labels: ''
assignees: ''
---
### Issue description
- Expected result: What were you expecting to happen?
- Actual result: What actually happened?
### Steps to reproduce the issue
1. ...
2. ...
### OS and versions
<!-- try the `version` command | LATEST IS NOT A VALID VERSION -->
* PocketMine-MP:
* PHP:
* Using JIT: yes/no (delete as appropriate) <!-- look for the giant yellow warning in the log that says you're using JIT -->
* Server OS:
* Game version: Android/iOS/Win10/Xbox/PS4/Switch (delete as appropriate)
### Plugins
<!--- use the `plugins` command and paste the output below -->
- If you remove all plugins, does the issue still occur?
- If the issue is **not** reproducible without plugins:
- Have you asked for help on our forums before creating an issue?
- Can you provide sample, *minimal* reproducing code for the issue? If so, paste it in the bottom section
### Crashdump, backtrace or other files
<!--- Submit crashdumps at https://crash.pmmp.io and paste a link -->
<!--- Use gist or anything else to add other files and add links here -->

View File

@ -1,16 +0,0 @@
---
name: Crash
about: Report a crash in PocketMine-MP (not plugins)
title: Server crashed
labels: ''
assignees: ''
---
<!--- submit crashdump files to https://crash.pmmp.io -->
<!--- or, copy the data between ===BEGIN CRASH DUMP=== and ===END CRASH DUMP and paste it on a site like https://pastebin.com -->
<!--- DON'T JUST PASTE the crashdump into an issue -->
Link to crashdump:
<!--- write additional information about the crash to help us find the problem -->
### Additional comments (optional)

25
.github/ISSUE_TEMPLATE/crash.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Crash
description: Report a crash in PocketMine-MP (not plugins)
title: Server crashed
body:
- type: markdown
attributes:
value: |
> [!TIP]
> Submit crashdump `.log` files to the [Crash Archive](https://crash.pmmp.io/submit).
> If you can't submit the crashdump to the Crash Archive, paste it on a site like [GitHub Gist](https://gist.github.com) or [Pastebin](https://pastebin.com).
> [!CAUTION]
> DON'T paste the crashdump data directly into an issue.
- type: input
id: crashdump-url
attributes:
label: Link to crashdump
validations:
required: true
- type: textarea
attributes:
label: Additional comments (optional)
description: Any other information that might help us solve the problem

View File

@ -0,0 +1,19 @@
name: Feature addition, change, or removal
description: Propose adding new features, or changing/removing existing ones
body:
- type: textarea
attributes:
label: Problem description
description: Explain why a change is needed
validations:
required: true
- type: textarea
attributes:
label: Proposed solution
description: Describe what changes you think should be made
validations:
required: true
- type: textarea
attributes:
label: "Alternative solutions or workarounds"
description: "Describe other ways you've explored to achieve your goal"

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.10.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.10.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.10.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.10.0
uses: docker/build-push-action@v6.13.0
with:
push: true
context: ./pocketmine-mp

View File

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

View File

@ -49,7 +49,7 @@ jobs:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@2.31.1
uses: shivammathur/setup-php@2.32.0
with:
php-version: 8.2

View File

@ -87,7 +87,7 @@ jobs:
submodules: true
- name: Setup PHP
uses: shivammathur/setup-php@2.31.1
uses: shivammathur/setup-php@2.32.0
with:
php-version: ${{ env.PHP_VERSION }}
@ -165,7 +165,7 @@ jobs:
${{ github.workspace }}/core-permissions.rst
- name: Create draft release
uses: ncipollo/release-action@v1.14.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

View File

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

View File

@ -28,6 +28,7 @@ use function dirname;
use function fclose;
use function fopen;
use function fwrite;
use function is_dir;
use function is_file;
use function scandir;
use function str_replace;
@ -59,7 +60,7 @@ foreach($files as $file){
continue;
}
$path = Path::join(BEDROCK_DATA_PATH, $file);
if(!is_file($path)){
if(!is_file($path) && !is_dir($path)){
continue;
}
@ -67,6 +68,7 @@ foreach($files as $file){
'README.md',
'LICENSE',
'composer.json',
'.github'
] as $ignored){
if($file === $ignored){
continue 2;

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

@ -129,7 +129,7 @@ function buildPhar(string $pharPath, string $basePath, array $includedPaths, arr
}
function main() : void{
if(ini_get("phar.readonly") == 1){
if(ini_get("phar.readonly") === "1"){
echo "Set phar.readonly to 0 with -dphar.readonly=0" . PHP_EOL;
exit(1);
}

View File

@ -127,3 +127,13 @@ Released 9th December 2024.
## Internals
- Removed legacy `build/make-release.php` script. This script is no longer used, as all releases should now follow the PR workflow.
# 5.23.3
Released 22nd January 2025.
## Fixes
- Fixed crashes with PHP internal stack frames being flagged as plugin crashes.
- Fixed note block instrument sounds in 1.21.50.
## Internals
- Updated GitHub issue templates to use issue forms.

108
changelogs/5.24.md Normal file
View File

@ -0,0 +1,108 @@
# 5.24.0
Released 22nd January 2025.
This is a minor feature release, including new gameplay features, performance improvements, and minor API additions.
**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
- PHP garbage collection is now managed by the server, instead of being automatically triggered by PHP.
- The mechanism for GC triggering is designed to mimic PHP's to avoid behavioural changes. Only the place it's triggered from should be significantly different.
- This change also avoids unnecessary GCs during object-heavy operations, such as encoding `CraftingDataPacket`. As such, performance during server join should see an improvement.
- Timings is now able to directly measure the impact of GC. Previously, GC would show up as random spikes under random timers, skewing timing results.
- `ChunkCache` now uses `string` for completed caches directly instead of keeping them wrapped in `CompressBatchPromise`s. This reduces memory usage, improves performance, and reduces GC workload.
## Configuration
- The following settings have been removed from `pocketmine.yml` and will no longer have any effect:
- `memory.garbage-collection.collect-async-worker` (now always `true`)
- `memory.garbage-collection.low-memory-trigger` (now always `true`)
- `memory.max-chunks.trigger-chunk-collect` (now always `true`)
- `memory.world-caches.disable-chunk-cache` (now always `true`)
- `memory.world-caches.low-memory-trigger` (now always `true`)
## Gameplay
- Added the following new blocks:
- All types of pale oak wood, and leaves
- Resin
- Resin Bricks, Slabs, Stairs, and Walls
- Resin Clump
- Chiseled Resin Bricks
- Some blocks have had their tool tier requirements adjusted to match latest Bedrock updates.
- Added the following new items:
- Resin Brick
- Music Disc - Creator
- Music Disc - Creator (Music Box)
- Music Disc - Precipice
- Music Disc - Relic
## API
### General
- Many places had their PHPDoc improved to address issues highlighted by PHPStan 2.x. This may cause new, previously unreported issues to be reported in plugins using PHPStan.
### `pocketmine`
- The following methods have been deprecated:
- `MemoryManager->canUseChunkCache()`
- `MemoryManager::dumpMemory()` - relocated to `MemoryDump` class
### `pocketmine\item`
- The following new enum cases have been added:
- `RecordType::DISK_CREATOR`
- `RecordType::DISK_CREATOR_MUSIC_BOX`
- `RecordType::DISK_PRECIPICE`
- `RecordType::DISK_RELIC`
### `pocketmine\player`
- The following new methods have been added:
- `public Player->getFlightSpeedMultiplier() : float` - a base multiplier for player's flight speed
- `public Player->setFlightSpeedMultiplier(float $flightSpeedMultiplier) : void` - sets the player's flight speed multiplier
- The following new constants have been added:
- `Player::DEFAULT_FLIGHT_SPEED_MULTIPLIER`
### `pocketmine\utils`
- The following new methods have been added:
- `public static TextFormat::javaToBedrock(string $string) : string` - removes unsupported Java Edition format codes to prevent them being incorrectly displayed on Bedrock
- The following methods have behavioural changes:
- `TextFormat::toHTML()` now converts `§m` to redstone red (instead of strikethrough), and `§n` to copper orange (instead of underline). This is because the codes previously used for `STRIKETHROUGH` and `UNDERLINE` conflict with the new material codes introduced by Minecraft Bedrock.
- `Terminal::toANSI()` now converts `§m` to redstone red (instead of strikethrough), and `§n` to copper orange (instead of underline), as above. However, underline and strikethrough can still be used on the terminal using `Terminal::$FORMAT_UNDERLINE` and `Terminal::$FORMAT_STRIKETHROUGH` respectively.
- The following new constants have been added:
- `TextFormat::MATERIAL_QUARTZ`
- `TextFormat::MATERIAL_IRON`
- `TextFormat::MATERIAL_NETHERITE`
- `TextFormat::MATERIAL_REDSTONE`
- `TextFormat::MATERIAL_COPPER`
- `TextFormat::MATERIAL_GOLD`
- `TextFormat::MATERIAL_EMERALD`
- `TextFormat::MATERIAL_DIAMOND`
- `TextFormat::MATERIAL_LAPIS`
- `TextFormat::MATERIAL_AMETHYST`
- The following constants have been deprecated:
- `TextFormat::STRIKETHROUGH`
- `TextFormat::UNDERLINE`
- The following static properties have been added:
- `Terminal::$COLOR_MATERIAL_QUARTZ`
- `Terminal::$COLOR_MATERIAL_IRON`
- `Terminal::$COLOR_MATERIAL_NETHERITE`
- `Terminal::$COLOR_MATERIAL_REDSTONE`
- `Terminal::$COLOR_MATERIAL_COPPER`
- `Terminal::$COLOR_MATERIAL_GOLD`
- `Terminal::$COLOR_MATERIAL_EMERALD`
- `Terminal::$COLOR_MATERIAL_DIAMOND`
- `Terminal::$COLOR_MATERIAL_LAPIS`
- `Terminal::$COLOR_MATERIAL_AMETHYST`
## Tools
- Fixed some UI issues in `tools/convert-world.php`
## Internals
- Block cache in `World` is now size-limited. This prevents memory exhaustion when plugins call `getBlock()` many thousands of times with cache misses.
- `RakLibServer` now disables PHP GC. As RakLib doesn't generate any unmanaged cycles, GC is just a waste of CPU time in this context.
- `MemoryManager` now has the responsibility for triggering cycle GC. It's checked every tick, but GC won't take place unless the GC threshold is exceeded, similar to PHP.
- This mechanism could probably do with alterations to better suit PocketMine-MP, but it was chosen to mimic PHP's own GC to minimize behavioural changes for now.
- `AsyncTask` now triggers cycle GC after `onRun()` completes. As with `MemoryManager`, this is based on a threshold designed to mimic PHP's own behaviour.
- `FormatConverter` now performs world provider GC periodically. This is not needed with current active providers, but was found to be a problem while developing custom providers.
- Various internal adjustments were made to avoid returning incorrectly-keyed arrays in the code. These changes shouldn't affect anything as the arrays should have been properly ordered anyway.
- Many places that previously used `==` and `!=` have been updated to use strict variants. This kind of change needs to be done carefully to avoid breaking `int|float` comparisons.

38
changelogs/5.25.md Normal file
View File

@ -0,0 +1,38 @@
# 5.25.0
Released 16th February 2025.
This is a support release for Minecraft: Bedrock Edition 1.21.60. It also includes some minor API additions supporting new features in this version.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.21.60.
- Removed support for earlier versions.
## Documentation
- Fixed the documentation of `Utils::getOS()`. It now refers to the `Utils::OS_*` constants instead of a list of hardcoded strings.
## API
### `pocketmine\inventory`
This release allows plugins to decide which creative tab they want to add their new items to.
It also allows creating new collapsible groups of items, and modifying or removing existing ones.
- The following new methods have been added:
- `public CreativeInventory->getAllEntries() : list<CreativeInventoryEntry>` - returns an array of objects, each containing a creative item and information about its category and collapsible group (if applicable).
- `public CreativeInventory->getEntry(int $index) : ?CreativeInventoryEntry` - returns the creative item with the specified identifier, or `null` if not found
- The following methods have signature changes:
- `CreativeInventory->add()` now accepts two additional optional parameters: `CreativeCategory $category, ?CreativeGroup $group`. If not specified, the item will be added to the Items tab without a group.
- The following new classes have been added:
- `CreativeCategory` - enum of possible creative inventory categories (each has its own tab on the GUI)
- `CreativeGroup` - contains information about a collapsible group of creative items, including tooltip text and icon
- `CreativeInventoryEntry` - contains information about a creative inventory item, including its category and collapsible group (if applicable)
## Internals
- `CreativeContentPacket` is no longer fully cached due to the requirement for translation context during construction. The individual items are still cached (which is the most expensive part), but the packet itself is now constructed on demand, and group entries are constructed on the fly. This may affect performance, but this has not been investigated.
- `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.

View File

@ -33,18 +33,18 @@
"composer-runtime-api": "^2.0",
"adhocore/json-comment": "~1.2.0",
"netresearch/jsonmapper": "~v5.0.0",
"pocketmine/bedrock-block-upgrade-schema": "~5.0.0+bedrock-1.21.40",
"pocketmine/bedrock-data": "~2.15.0+bedrock-1.21.50",
"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": "~35.0.0+bedrock-1.21.50",
"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",
"pocketmine/errorhandler": "^0.7.0",
"pocketmine/locale-data": "~2.22.0",
"pocketmine/locale-data": "~2.24.0",
"pocketmine/log": "^0.4.0",
"pocketmine/math": "~1.0.0",
"pocketmine/nbt": "~1.0.0",
"pocketmine/nbt": "~1.1.0",
"pocketmine/raklib": "~1.1.0",
"pocketmine/raklib-ipc": "~1.0.0",
"pocketmine/snooze": "^0.5.0",
@ -52,9 +52,9 @@
"symfony/filesystem": "~6.4.0"
},
"require-dev": {
"phpstan/phpstan": "1.11.11",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0",
"phpstan/phpstan": "2.1.4",
"phpstan/phpstan-phpunit": "^2.0.0",
"phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^10.5.24"
},
"autoload": {

164
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": "732102eca72dc1d29e7b67dfbce07653",
"content-hash": "663122b8f03ef5ec6718a419923a0851",
"packages": [
{
"name": "adhocore/json-comment",
@ -178,16 +178,16 @@
},
{
"name": "pocketmine/bedrock-block-upgrade-schema",
"version": "5.0.0",
"version": "5.1.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
"reference": "20dd5c11e9915bacea4fe2cf649e1d23697a6e52"
"reference": "2218512e4b91f5bfd09ef55f7a4c4b04e169e41a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/20dd5c11e9915bacea4fe2cf649e1d23697a6e52",
"reference": "20dd5c11e9915bacea4fe2cf649e1d23697a6e52",
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/2218512e4b91f5bfd09ef55f7a4c4b04e169e41a",
"reference": "2218512e4b91f5bfd09ef55f7a4c4b04e169e41a",
"shasum": ""
},
"type": "library",
@ -198,22 +198,22 @@
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
"support": {
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/5.0.0"
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/5.1.0"
},
"time": "2024-11-03T14:13:50+00:00"
"time": "2025-02-11T17:41:44+00:00"
},
{
"name": "pocketmine/bedrock-data",
"version": "2.15.0+bedrock-1.21.50",
"version": "4.0.0+bedrock-1.21.60",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
"reference": "6e819f36d781866ce63d2406be2ce7f2d1afd9ad"
"reference": "2e5f16ec2facac653f3f894f22eb831d880ba98e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/6e819f36d781866ce63d2406be2ce7f2d1afd9ad",
"reference": "6e819f36d781866ce63d2406be2ce7f2d1afd9ad",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/2e5f16ec2facac653f3f894f22eb831d880ba98e",
"reference": "2e5f16ec2facac653f3f894f22eb831d880ba98e",
"shasum": ""
},
"type": "library",
@ -224,9 +224,9 @@
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/BedrockData/issues",
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.50"
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.60"
},
"time": "2024-12-04T12:59:12+00:00"
"time": "2025-02-16T15:56:56+00:00"
},
{
"name": "pocketmine/bedrock-item-upgrade-schema",
@ -256,16 +256,16 @@
},
{
"name": "pocketmine/bedrock-protocol",
"version": "35.0.0+bedrock-1.21.50",
"version": "36.0.0+bedrock-1.21.60",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "bd1ec79bae8c88aa984e1c5f0c3313be5ae9b435"
"reference": "2057de319c5c551001c2a544e08d1bc7727d9963"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/bd1ec79bae8c88aa984e1c5f0c3313be5ae9b435",
"reference": "bd1ec79bae8c88aa984e1c5f0c3313be5ae9b435",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/2057de319c5c551001c2a544e08d1bc7727d9963",
"reference": "2057de319c5c551001c2a544e08d1bc7727d9963",
"shasum": ""
},
"require": {
@ -278,10 +278,10 @@
"ramsey/uuid": "^4.1"
},
"require-dev": {
"phpstan/phpstan": "1.11.9",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5 || ^10.0"
"phpstan/phpstan": "2.1.0",
"phpstan/phpstan-phpunit": "^2.0.0",
"phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^9.5 || ^10.0 || ^11.0"
},
"type": "library",
"autoload": {
@ -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/35.0.0+bedrock-1.21.50"
"source": "https://github.com/pmmp/BedrockProtocol/tree/36.0.0+bedrock-1.21.60"
},
"time": "2024-12-04T13:02:00+00:00"
"time": "2025-02-16T15:59:08+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -471,16 +471,16 @@
},
{
"name": "pocketmine/locale-data",
"version": "2.22.1",
"version": "2.24.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Language.git",
"reference": "fa4e377c437391cfcfdedd08eea3a848eabd1b49"
"reference": "6ec5e92c77a2102b2692763733e4763012facae9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Language/zipball/fa4e377c437391cfcfdedd08eea3a848eabd1b49",
"reference": "fa4e377c437391cfcfdedd08eea3a848eabd1b49",
"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.22.1"
"source": "https://github.com/pmmp/Language/tree/2.24.0"
},
"time": "2024-12-06T14:44:17+00:00"
"time": "2025-02-16T20:46:34+00:00"
},
{
"name": "pocketmine/log",
@ -576,16 +576,16 @@
},
{
"name": "pocketmine/nbt",
"version": "1.0.0",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/NBT.git",
"reference": "20540271cb59e04672cb163dca73366f207974f1"
"reference": "cfd53a86166b851786967fc560cdb372e66fde96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/20540271cb59e04672cb163dca73366f207974f1",
"reference": "20540271cb59e04672cb163dca73366f207974f1",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/cfd53a86166b851786967fc560cdb372e66fde96",
"reference": "cfd53a86166b851786967fc560cdb372e66fde96",
"shasum": ""
},
"require": {
@ -595,8 +595,8 @@
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "1.10.25",
"phpstan/phpstan-strict-rules": "^1.0",
"phpstan/phpstan": "2.1.0",
"phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^9.5"
},
"type": "library",
@ -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.0.0"
"source": "https://github.com/pmmp/NBT/tree/1.1.0"
},
"time": "2023-07-14T13:01:49+00:00"
"time": "2025-02-01T21:20:26+00:00"
},
{
"name": "pocketmine/raklib",
@ -1013,8 +1013,8 @@
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
@ -1092,8 +1092,8 @@
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
@ -1210,16 +1210,16 @@
},
{
"name": "nikic/php-parser",
"version": "v5.3.1",
"version": "v5.4.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b"
"reference": "447a020a1f875a434d62f2a401f53b82a396e494"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b",
"reference": "8eea230464783aa9671db8eea6f8c6ac5285794b",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
"reference": "447a020a1f875a434d62f2a401f53b82a396e494",
"shasum": ""
},
"require": {
@ -1262,9 +1262,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
},
"time": "2024-10-08T18:51:32+00:00"
"time": "2024-12-30T11:07:19+00:00"
},
{
"name": "phar-io/manifest",
@ -1386,20 +1386,20 @@
},
{
"name": "phpstan/phpstan",
"version": "1.11.11",
"version": "2.1.4",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3"
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/707c2aed5d8d0075666e673a5e71440c1d01a5a3",
"reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f99e18eb775dbaf6460c95fa0b65312da9c746a",
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a",
"shasum": ""
},
"require": {
"php": "^7.2|^8.0"
"php": "^7.4|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
@ -1440,34 +1440,33 @@
"type": "github"
}
],
"time": "2024-08-19T14:37:29+00:00"
"time": "2025-02-10T08:25:21+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "1.4.0",
"version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "f3ea021866f4263f07ca3636bf22c64be9610c11"
"reference": "d09e152f403c843998d7a52b5d87040c937525dd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/f3ea021866f4263f07ca3636bf22c64be9610c11",
"reference": "f3ea021866f4263f07ca3636bf22c64be9610c11",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d09e152f403c843998d7a52b5d87040c937525dd",
"reference": "d09e152f403c843998d7a52b5d87040c937525dd",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.11"
"php": "^7.4 || ^8.0",
"phpstan/phpstan": "^2.0.4"
},
"conflict": {
"phpunit/phpunit": "<7.0"
},
"require-dev": {
"nikic/php-parser": "^4.13.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-strict-rules": "^1.5.1",
"phpunit/phpunit": "^9.5"
"phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^9.6"
},
"type": "phpstan-extension",
"extra": {
@ -1490,34 +1489,33 @@
"description": "PHPUnit extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.0"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.4"
},
"time": "2024-04-20T06:39:00+00:00"
"time": "2025-01-22T13:07:38+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "1.6.0",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "363f921dd8441777d4fc137deb99beb486c77df1"
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/363f921dd8441777d4fc137deb99beb486c77df1",
"reference": "363f921dd8441777d4fc137deb99beb486c77df1",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/8b88b5f818bfa301e0c99154ab622dace071c3ba",
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"phpstan/phpstan": "^1.11"
"php": "^7.4 || ^8.0",
"phpstan/phpstan": "^2.0.4"
},
"require-dev": {
"nikic/php-parser": "^4.13.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-deprecation-rules": "^1.1",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.5"
"phpstan/phpstan-deprecation-rules": "^2.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^9.6"
},
"type": "phpstan-extension",
"extra": {
@ -1539,9 +1537,9 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.0"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.3"
},
"time": "2024-04-20T06:37:51+00:00"
"time": "2025-01-21T10:52:14+00:00"
},
{
"name": "phpunit/php-code-coverage",
@ -1866,16 +1864,16 @@
},
{
"name": "phpunit/phpunit",
"version": "10.5.38",
"version": "10.5.44",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "a86773b9e887a67bc53efa9da9ad6e3f2498c132"
"reference": "1381c62769be4bb88fa4c5aec1366c7c66ca4f36"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a86773b9e887a67bc53efa9da9ad6e3f2498c132",
"reference": "a86773b9e887a67bc53efa9da9ad6e3f2498c132",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1381c62769be4bb88fa4c5aec1366c7c66ca4f36",
"reference": "1381c62769be4bb88fa4c5aec1366c7c66ca4f36",
"shasum": ""
},
"require": {
@ -1885,7 +1883,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.12.0",
"myclabs/deep-copy": "^1.12.1",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.1",
@ -1947,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.38"
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.44"
},
"funding": [
{
@ -1963,7 +1961,7 @@
"type": "tidelift"
}
],
"time": "2024-10-28T13:06:21+00:00"
"time": "2025-01-31T07:00:38+00:00"
},
{
"name": "sebastian/cli-parser",

View File

@ -19,6 +19,7 @@ rules:
parameters:
level: 9
checkMissingCallableSignature: true
rememberPossiblyImpureFunctionValues: false #risky to remember these, better for performance to avoid repeated calls anyway
treatPhpDocTypesAsCertain: false
bootstrapFiles:
- tests/phpstan/bootstrap.php
@ -31,6 +32,7 @@ parameters:
paths:
- build
- src
- tests/phpstan/DummyPluginOwned.php
- tests/phpstan/rules
- tests/phpunit
- tests/plugins/TesterPlugin
@ -44,6 +46,7 @@ parameters:
- pocketmine\DEBUG
- pocketmine\IS_DEVELOPMENT_BUILD
stubFiles:
- tests/phpstan/stubs/chunkutils2.stub
- tests/phpstan/stubs/JsonMapper.stub
- tests/phpstan/stubs/leveldb.stub
- tests/phpstan/stubs/pmmpthread.stub

View File

@ -253,12 +253,12 @@ final class MemoryDump{
}
/**
* @param object[] $objects reference parameter
* @param int[] $refCounts reference parameter
* @param object[]|true[] $objects reference parameter
* @param int[] $refCounts reference parameter
*
* @phpstan-param array<string, object> $objects
* @phpstan-param array<string, object|true> $objects
* @phpstan-param array<string, int> $refCounts
* @phpstan-param-out array<string, object> $objects
* @phpstan-param-out array<string, object|true> $objects
* @phpstan-param-out array<string, int> $refCounts
*/
private static function continueDump(mixed $from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : mixed{

View File

@ -36,6 +36,7 @@ use pocketmine\crafting\CraftingManager;
use pocketmine\crafting\CraftingManagerFromDataHelper;
use pocketmine\crash\CrashDump;
use pocketmine\crash\CrashDumpRenderer;
use pocketmine\data\bedrock\BedrockDataFiles;
use pocketmine\entity\EntityDataHelper;
use pocketmine\entity\Location;
use pocketmine\event\HandlerListManager;
@ -138,6 +139,7 @@ use function file_put_contents;
use function filemtime;
use function fopen;
use function get_class;
use function gettype;
use function ini_set;
use function is_array;
use function is_dir;
@ -918,6 +920,7 @@ class Server{
TimingsHandler::getCollectCallbacks()->add(function() : array{
$promises = [];
foreach($this->asyncPool->getRunningWorkers() as $workerId){
/** @phpstan-var PromiseResolver<list<string>> $resolver */
$resolver = new PromiseResolver();
$this->asyncPool->submitTaskToWorker(new TimingsCollectionTask($resolver), $workerId);
@ -1003,7 +1006,7 @@ class Server{
$this->commandMap = new SimpleCommandMap($this);
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes"));
$this->craftingManager = CraftingManagerFromDataHelper::make(BedrockDataFiles::RECIPES);
$this->resourceManager = new ResourcePackManager(Path::join($this->dataPath, "resource_packs"), $this->logger);
@ -1013,7 +1016,11 @@ class Server{
copy(Path::join(\pocketmine\RESOURCE_PATH, 'plugin_list.yml'), $graylistFile);
}
try{
$pluginGraylist = PluginGraylist::fromArray(yaml_parse(Filesystem::fileGetContents($graylistFile)));
$array = yaml_parse(Filesystem::fileGetContents($graylistFile));
if(!is_array($array)){
throw new \InvalidArgumentException("Expected array for root, but have " . gettype($array));
}
$pluginGraylist = PluginGraylist::fromArray($array);
}catch(\InvalidArgumentException $e){
$this->logger->emergency("Failed to load $graylistFile: " . $e->getMessage());
$this->forceShutdownExit();
@ -1174,7 +1181,7 @@ class Server{
if($this->worldManager->getDefaultWorld() === null){
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
if(trim($default) == ""){
if(trim($default) === ""){
$this->logger->warning("level-name cannot be null, using default");
$default = "world";
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");

View File

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

View File

@ -70,9 +70,6 @@ class Anvil extends Transparent implements Fallable{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->squash(Facing::axis(Facing::rotateY($this->facing, false)), 1 / 8)];
}

View File

@ -87,9 +87,6 @@ class Bamboo extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//this places the BB at the northwest corner, not the center
$inset = 1 - (($this->thick ? 3 : 2) / 16);

View File

@ -30,7 +30,6 @@ use pocketmine\block\utils\SupportType;
use pocketmine\item\Banner as ItemBanner;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
@ -97,9 +96,6 @@ abstract class BaseBanner extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -34,7 +34,6 @@ use pocketmine\event\block\SignChangeEvent;
use pocketmine\item\Dye;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
@ -95,9 +94,6 @@ abstract class BaseSign extends Transparent{
return 16;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -76,9 +76,6 @@ class Bed extends Transparent{
}
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 16)];
}

View File

@ -75,7 +75,10 @@ class Block{
protected BlockTypeInfo $typeInfo;
protected Position $position;
/** @var AxisAlignedBB[]|null */
/**
* @var AxisAlignedBB[]|null
* @phpstan-var list<AxisAlignedBB>|null
*/
protected ?array $collisionBoxes = null;
private int $requiredBlockItemStateDataBits;
@ -907,6 +910,7 @@ class Block{
* - anti-cheat checks in plugins
*
* @return AxisAlignedBB[]
* @phpstan-return list<AxisAlignedBB>
*/
final public function getCollisionBoxes() : array{
if($this->collisionBoxes === null){
@ -931,6 +935,7 @@ class Block{
/**
* @return AxisAlignedBB[]
* @phpstan-return list<AxisAlignedBB>
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()];

View File

@ -95,7 +95,7 @@ class BlockBreakInfo{
* Returns whether this block can be instantly broken.
*/
public function breaksInstantly() : bool{
return $this->hardness == 0.0;
return $this->hardness === 0.0;
}
/**

View File

@ -43,9 +43,6 @@ class Cactus extends Transparent{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$shrinkSize = 1 / 16;
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];

View File

@ -40,9 +40,6 @@ class Cake extends BaseCake{
$w->boundedIntAuto(0, self::MAX_BITES, $this->bites);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()

View File

@ -36,9 +36,6 @@ class CakeWithCandle extends BaseCake{
onInteract as onInteractCandle;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()

View File

@ -36,9 +36,6 @@ class Carpet extends Flowable{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 15 / 16)];
}

View File

@ -36,9 +36,6 @@ use pocketmine\player\Player;
class Chest extends Transparent{
use FacesOppositePlacingPlayerTrait;
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//these are slightly bigger than in PC
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];

View File

@ -34,11 +34,16 @@ use function mt_rand;
final class ChorusPlant extends Flowable{
use StaticSupportTrait;
/**
* @var true[]
* @phpstan-var array<int, true>
*/
protected array $connections = [];
protected function recalculateCollisionBoxes() : array{
$bb = AxisAlignedBB::one();
foreach($this->getAllSides() as $facing => $block){
$id = $block->getTypeId();
if($id !== BlockTypeIds::END_STONE && $id !== BlockTypeIds::CHORUS_FLOWER && !$block->hasSameTypeId($this)){
foreach(Facing::ALL as $facing){
if(!isset($this->connections[$facing])){
$bb->trim($facing, 2 / 16);
}
}
@ -46,6 +51,26 @@ final class ChorusPlant extends Flowable{
return [$bb];
}
public function readStateFromWorld() : Block{
parent::readStateFromWorld();
$this->collisionBoxes = null;
foreach(Facing::ALL as $facing){
$block = $this->getSide($facing);
if(match($block->getTypeId()){
BlockTypeIds::END_STONE, BlockTypeIds::CHORUS_FLOWER, $this->getTypeId() => true,
default => false
}){
$this->connections[$facing] = true;
}else{
unset($this->connections[$facing]);
}
}
return $this;
}
private function canBeSupportedBy(Block $block) : bool{
return $block->hasSameTypeId($this) || $block->getTypeId() === BlockTypeIds::END_STONE;
}

View File

@ -50,9 +50,6 @@ class CocoaBlock extends Flowable{
$w->boundedIntAuto(0, self::MAX_AGE, $this->age);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()

View File

@ -62,9 +62,6 @@ class DaylightSensor extends Transparent{
return 300;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 10 / 16)];
}

View File

@ -95,9 +95,6 @@ class Door extends Transparent{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//TODO: doors are 0.1825 blocks thick, instead of 0.1875 like JE (https://bugs.mojang.com/browse/MCPE-19214)
return [AxisAlignedBB::one()->trim($this->open ? Facing::rotateY($this->facing, !$this->hingeRight) : $this->facing, 327 / 400)];

View File

@ -33,9 +33,6 @@ use pocketmine\player\Player;
class EnchantingTable extends Transparent{
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 0.25)];
}

View File

@ -50,9 +50,6 @@ class EndPortalFrame extends Opaque{
return 1;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 3 / 16)];
}

View File

@ -52,9 +52,6 @@ class EndRod extends Flowable{
return 14;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$myAxis = Facing::axis($this->facing);

View File

@ -40,9 +40,6 @@ class EnderChest extends Transparent{
return 7;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//these are slightly bigger than in PC
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];

View File

@ -94,9 +94,6 @@ class Farmland extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
}

View File

@ -54,13 +54,9 @@ class Fence extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$inset = 0.5 - $this->getThickness() / 2;
/** @var AxisAlignedBB[] $bbs */
$bbs = [];
$connectWest = isset($this->connections[Facing::WEST]);

View File

@ -64,9 +64,6 @@ class FenceGate extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return $this->open ? [] : [AxisAlignedBB::one()->extend(Facing::UP, 0.5)->squash(Facing::axis($this->facing), 6 / 16)];
}

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
/**
@ -46,9 +45,6 @@ abstract class Flowable extends Transparent{
parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -83,9 +83,6 @@ class FlowerPot extends Flowable{
return $block->hasTypeTag(BlockTypeTags::POTTABLE_PLANTS);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->contract(3 / 16, 0, 3 / 16)->trim(Facing::UP, 5 / 8)];
}

View File

@ -28,7 +28,6 @@ use pocketmine\block\utils\MultiAnySupportTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
@ -47,9 +46,6 @@ class GlowLichen extends Transparent{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -29,9 +29,6 @@ use pocketmine\math\Facing;
class GrassPath extends Transparent{
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
}

View File

@ -58,9 +58,6 @@ class Ladder extends Transparent{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim($this->facing, 13 / 16)];
}

View File

@ -59,9 +59,6 @@ class Lantern extends Transparent{
return $this->lightLevel;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()

View File

@ -30,7 +30,6 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\utils\Utils;
@ -89,9 +88,6 @@ abstract class Liquid extends Transparent{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -104,9 +104,6 @@ class MobHead extends Flowable{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$collisionBox = AxisAlignedBB::one()
->contract(0.25, 0, 0.25)

View File

@ -28,7 +28,6 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
class NetherPortal extends Transparent{
@ -62,9 +61,6 @@ class NetherPortal extends Transparent{
return false;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -79,9 +79,6 @@ class RedstoneComparator extends Flowable{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 8)];
}

View File

@ -62,9 +62,6 @@ class RedstoneRepeater extends Flowable{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 8)];
}

View File

@ -28,6 +28,7 @@ use pocketmine\block\BlockIdentifier as BID;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\SingletonTrait;
use pocketmine\world\light\LightUpdate;
use function count;
use function min;
/**
@ -40,6 +41,11 @@ use function min;
class RuntimeBlockStateRegistry{
use SingletonTrait;
public const COLLISION_CUSTOM = 0;
public const COLLISION_CUBE = 1;
public const COLLISION_NONE = 2;
public const COLLISION_MAY_OVERFLOW = 3;
/**
* @var Block[]
* @phpstan-var array<int, Block>
@ -74,6 +80,13 @@ class RuntimeBlockStateRegistry{
*/
public array $blastResistance = [];
/**
* Map of state ID -> useful AABB info to avoid unnecessary block allocations
* @var int[]
* @phpstan-var array<int, int>
*/
public array $collisionInfo = [];
public function __construct(){
foreach(VanillaBlocks::getAll() as $block){
$this->register($block);
@ -100,6 +113,70 @@ class RuntimeBlockStateRegistry{
}
}
/**
* Checks if the given class method overrides a method in Block.
* Used to determine if a block might need to disable fast path optimizations.
*
* @phpstan-param anyClosure $closure
*/
private static function overridesBlockMethod(\Closure $closure) : bool{
$declarer = (new \ReflectionFunction($closure))->getClosureScopeClass();
return $declarer !== null && $declarer->getName() !== Block::class;
}
/**
* A big ugly hack to set up fast paths for handling collisions on blocks with common shapes.
* The information returned here is stored in RuntimeBlockStateRegistry->collisionInfo, and is used during entity
* collision box calculations to avoid complex logic and unnecessary block object allocations.
* This hack allows significant performance improvements.
*
* TODO: We'll want to redesign block collision box handling and block shapes in the future, but that's a job for a
* major version. For now, this hack nets major performance wins.
*/
private static function calculateCollisionInfo(Block $block) : int{
if(
self::overridesBlockMethod($block->getModelPositionOffset(...)) ||
self::overridesBlockMethod($block->readStateFromWorld(...))
){
//getModelPositionOffset() might cause AABBs to shift outside the cell
//readStateFromWorld() might cause overflow in ways we can't predict just by looking at known states
//TODO: excluding overriders of readStateFromWorld() also excludes blocks with tiles that don't do anything
//weird with their AABBs, but for now this is the best we can do.
return self::COLLISION_MAY_OVERFLOW;
}
//TODO: this could blow up if any recalculateCollisionBoxes() uses the world
//it shouldn't, but that doesn't mean that custom blocks won't...
$boxes = $block->getCollisionBoxes();
if(count($boxes) === 0){
return self::COLLISION_NONE;
}
if(
count($boxes) === 1 &&
$boxes[0]->minX === 0.0 &&
$boxes[0]->minY === 0.0 &&
$boxes[0]->minZ === 0.0 &&
$boxes[0]->maxX === 1.0 &&
$boxes[0]->maxY === 1.0 &&
$boxes[0]->maxZ === 1.0
){
return self::COLLISION_CUBE;
}
foreach($boxes as $box){
if(
$box->minX < 0 || $box->maxX > 1 ||
$box->minY < 0 || $box->maxY > 1 ||
$box->minZ < 0 || $box->maxZ > 1
){
return self::COLLISION_MAY_OVERFLOW;
}
}
return self::COLLISION_CUSTOM;
}
private function fillStaticArrays(int $index, Block $block) : void{
$fullId = $block->getStateId();
if($index !== $fullId){
@ -112,6 +189,8 @@ class RuntimeBlockStateRegistry{
if($block->blocksDirectSkyLight()){
$this->blocksDirectSkyLight[$index] = true;
}
$this->collisionInfo[$index] = self::calculateCollisionInfo($block);
}
}

View File

@ -26,7 +26,6 @@ namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
@ -70,9 +69,6 @@ class SeaPickle extends Transparent{
return $this->underwater ? ($this->count + 1) * 3 : 0;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}

View File

@ -93,9 +93,6 @@ class Slab extends Transparent{
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
if($this->slabType === SlabType::DOUBLE){
return [AxisAlignedBB::one()];

View File

@ -65,9 +65,6 @@ class SnowLayer extends Flowable implements Fallable{
return $this->layers < self::MAX_LAYERS;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//TODO: this zero-height BB is intended to stay in lockstep with a MCPE bug
return [AxisAlignedBB::one()->trim(Facing::UP, $this->layers >= 4 ? 0.5 : 1)];

View File

@ -28,9 +28,6 @@ use pocketmine\math\Facing;
class SoulSand extends Opaque{
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 8)];
}

View File

@ -56,7 +56,6 @@ class Thin extends Transparent{
protected function recalculateCollisionBoxes() : array{
$inset = 7 / 16;
/** @var AxisAlignedBB[] $bbs */
$bbs = [];
if(isset($this->connections[Facing::WEST]) || isset($this->connections[Facing::EAST])){

View File

@ -62,9 +62,6 @@ class Trapdoor extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim($this->open ? $this->facing : ($this->top ? Facing::DOWN : Facing::UP), 13 / 16)];
}

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()
@ -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

@ -33,9 +33,6 @@ class WaterLily extends Flowable{
canBePlacedAt as supportedWhenPlacedAt;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->contract(1 / 16, 0, 1 / 16)->trim(Facing::UP, 63 / 64)];
}

View File

@ -43,7 +43,10 @@ trait CandleTrait{
return $this->lit ? 3 : 0;
}
/** @see Block::onInteract() */
/**
* @param Item[] &$returnedItems
* @see Block::onInteract()
*/
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE || $item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
if($this->lit){

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block\utils;
use pocketmine\block\Block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Axe;
use pocketmine\item\Item;
@ -58,6 +59,10 @@ trait CopperTrait{
return $this;
}
/**
* @param Item[] &$returnedItems
* @see Block::onInteract()
*/
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if(!$this->waxed && $item->getTypeId() === ItemTypeIds::HONEYCOMB){
$this->waxed = true;

View File

@ -33,6 +33,7 @@ use pocketmine\permission\PermissionManager;
use pocketmine\Server;
use pocketmine\utils\BroadcastLoggerForwarder;
use pocketmine\utils\TextFormat;
use function array_values;
use function explode;
use function implode;
use function str_replace;
@ -80,6 +81,7 @@ abstract class Command{
/**
* @param string[] $args
* @phpstan-param list<string> $args
*
* @return mixed
* @throws CommandException
@ -212,6 +214,7 @@ abstract class Command{
* @phpstan-param list<string> $aliases
*/
public function setAliases(array $aliases) : void{
$aliases = array_values($aliases); //because plugins can and will pass crap
$this->aliases = $aliases;
if(!$this->isRegistered()){
$this->activeAliases = $aliases;

View File

@ -121,6 +121,7 @@ class FormattedCommandAlias extends Command{
/**
* @param string[] $args
* @phpstan-param list<string> $args
*/
private function buildCommand(string $formatString, array $args) : ?string{
$index = 0;

View File

@ -73,6 +73,7 @@ use pocketmine\timings\Timings;
use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils;
use function array_shift;
use function array_values;
use function count;
use function implode;
use function str_contains;
@ -163,7 +164,7 @@ class SimpleCommandMap implements CommandMap{
unset($aliases[$index]);
}
}
$command->setAliases($aliases);
$command->setAliases(array_values($aliases));
if(!$registered){
$command->setLabel($fallbackPrefix . ":" . $label);

View File

@ -46,6 +46,8 @@ use function fwrite;
use function http_build_query;
use function implode;
use function is_array;
use function is_int;
use function is_string;
use function json_decode;
use function mkdir;
use function strtolower;
@ -178,7 +180,7 @@ class TimingsCommand extends VanillaCommand{
return;
}
$response = json_decode($result->getBody(), true);
if(is_array($response) && isset($response["id"])){
if(is_array($response) && isset($response["id"]) && (is_int($response["id"]) || is_string($response["id"]))){
Command::broadcastCommandMessage($sender, KnownTranslationFactory::pocketmine_command_timings_timingsRead(
"https://" . $host . "/?id=" . $response["id"]));
}else{

View File

@ -51,9 +51,8 @@ final class CommandStringHelper{
foreach($matches[0] as $k => $_){
for($i = 1; $i <= 2; ++$i){
if($matches[$i][$k] !== ""){
/** @var string $match */ //phpstan can't understand preg_match and friends by itself :(
$match = $matches[$i][$k];
$args[(int) $k] = preg_replace('/\\\\([\\\\"])/u', '$1', $match) ?? throw new AssumptionFailedError(preg_last_error_msg());
$args[] = preg_replace('/\\\\([\\\\"])/u', '$1', $match) ?? throw new AssumptionFailedError(preg_last_error_msg());
break;
}
}

View File

@ -110,7 +110,6 @@ class CraftingManager{
/**
* @param Item[] $items
* @phpstan-param list<Item> $items
*
* @return Item[]
* @phpstan-return list<Item>
@ -135,7 +134,6 @@ class CraftingManager{
/**
* @param Item[] $outputs
* @phpstan-param list<Item> $outputs
*/
private static function hashOutputs(array $outputs) : string{
$outputs = self::pack($outputs);

View File

@ -39,14 +39,16 @@ final class BedrockDataFiles{
public const BLOCK_STATE_META_MAP_JSON = BEDROCK_DATA_PATH . '/block_state_meta_map.json';
public const CANONICAL_BLOCK_STATES_NBT = BEDROCK_DATA_PATH . '/canonical_block_states.nbt';
public const COMMAND_ARG_TYPES_JSON = BEDROCK_DATA_PATH . '/command_arg_types.json';
public const CREATIVEITEMS_JSON = BEDROCK_DATA_PATH . '/creativeitems.json';
public const CREATIVE = BEDROCK_DATA_PATH . '/creative';
public const ENTITY_ID_MAP_JSON = BEDROCK_DATA_PATH . '/entity_id_map.json';
public const ENTITY_IDENTIFIERS_NBT = BEDROCK_DATA_PATH . '/entity_identifiers.nbt';
public const ENUMS = BEDROCK_DATA_PATH . '/enums';
public const ENUMS_PY = BEDROCK_DATA_PATH . '/enums.py';
public const ITEM_TAGS_JSON = BEDROCK_DATA_PATH . '/item_tags.json';
public const LEVEL_SOUND_ID_MAP_JSON = BEDROCK_DATA_PATH . '/level_sound_id_map.json';
public const PARTICLE_ID_MAP_JSON = BEDROCK_DATA_PATH . '/particle_id_map.json';
public const PROTOCOL_INFO_JSON = BEDROCK_DATA_PATH . '/protocol_info.json';
public const R12_TO_CURRENT_BLOCK_MAP_BIN = BEDROCK_DATA_PATH . '/r12_to_current_block_map.bin';
public const R16_TO_CURRENT_ITEM_MAP_JSON = BEDROCK_DATA_PATH . '/r16_to_current_item_map.json';
public const RECIPES = BEDROCK_DATA_PATH . '/recipes';
public const REQUIRED_ITEM_LIST_JSON = BEDROCK_DATA_PATH . '/required_item_list.json';
}

View File

@ -39,10 +39,10 @@ final class NoteInstrumentIdMap{
NoteInstrument::SNARE => 2,
NoteInstrument::CLICKS_AND_STICKS => 3,
NoteInstrument::DOUBLE_BASS => 4,
NoteInstrument::BELL => 5,
NoteInstrument::FLUTE => 6,
NoteInstrument::CHIME => 7,
NoteInstrument::GUITAR => 8,
NoteInstrument::FLUTE => 5,
NoteInstrument::BELL => 6,
NoteInstrument::GUITAR => 7,
NoteInstrument::CHIME => 8,
NoteInstrument::XYLOPHONE => 9,
NoteInstrument::IRON_XYLOPHONE => 10,
NoteInstrument::COW_BELL => 11,

View File

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

View File

@ -59,6 +59,7 @@ final class BlockStateNames{
public const COVERED_BIT = "covered_bit";
public const CRACKED_STATE = "cracked_state";
public const CRAFTING = "crafting";
public const CREAKING_HEART_STATE = "creaking_heart_state";
public const DEAD_BIT = "dead_bit";
public const DEPRECATED = "deprecated";
public const DIRECTION = "direction";

View File

@ -56,6 +56,10 @@ final class BlockStateStringValues{
public const CRACKED_STATE_MAX_CRACKED = "max_cracked";
public const CRACKED_STATE_NO_CRACKS = "no_cracks";
public const CREAKING_HEART_STATE_AWAKE = "awake";
public const CREAKING_HEART_STATE_DORMANT = "dormant";
public const CREAKING_HEART_STATE_UPROOTED = "uprooted";
public const DRIPSTONE_THICKNESS_BASE = "base";
public const DRIPSTONE_THICKNESS_FRUSTUM = "frustum";
public const DRIPSTONE_THICKNESS_MERGE = "merge";

View File

@ -131,7 +131,7 @@ final class BlockStateDeserializerHelper{
//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))
->setFacing(Facing::rotateY($in->readLegacyHorizontalFacing(), false))
->setFacing($in->readCardinalHorizontalFacing())
->setHingeRight($in->readBool(BlockStateNames::DOOR_HINGE_BIT))
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
}
@ -145,7 +145,7 @@ final class BlockStateDeserializerHelper{
/** @throws BlockStateDeserializeException */
public static function decodeFenceGate(FenceGate $block, BlockStateReader $in) : FenceGate{
return $block
->setFacing($in->readLegacyHorizontalFacing())
->setFacing($in->readCardinalHorizontalFacing())
->setInWall($in->readBool(BlockStateNames::IN_WALL_BIT))
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
}

View File

@ -100,7 +100,7 @@ final class BlockStateSerializerHelper{
public static function encodeDoor(Door $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
->writeLegacyHorizontalFacing(Facing::rotateY($block->getFacing(), true))
->writeCardinalHorizontalFacing($block->getFacing())
->writeBool(BlockStateNames::DOOR_HINGE_BIT, $block->isHingeRight())
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
}
@ -112,7 +112,7 @@ final class BlockStateSerializerHelper{
public static function encodeFenceGate(FenceGate $block, Writer $out) : Writer{
return $out
->writeLegacyHorizontalFacing($block->getFacing())
->writeCardinalHorizontalFacing($block->getFacing())
->writeBool(BlockStateNames::IN_WALL_BIT, $block->isInWall())
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
}

View File

@ -103,10 +103,18 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
/** @phpstan-param \Closure(Reader) : Block $c */
public function map(string $id, \Closure $c) : void{
if(array_key_exists($id, $this->deserializeFuncs)){
throw new \InvalidArgumentException("Deserializer is already assigned for \"$id\"");
}
$this->deserializeFuncs[$id] = $c;
$this->simpleCache = [];
}
/**
* Returns the existing data deserializer for the given ID, or null if none exists.
* This may be useful if you need to override a deserializer, but still want to be able to fall back to the original.
*
* @phpstan-return ?\Closure(Reader) : Block
*/
public function getDeserializerForId(string $id) : ?\Closure{
return $this->deserializeFuncs[$id] ?? null;
}
/** @phpstan-param \Closure() : Block $getBlock */

View File

@ -37,7 +37,6 @@ use pocketmine\utils\Utils;
use Symfony\Component\Filesystem\Path;
use function array_key_last;
use function array_map;
use function array_values;
use function assert;
use function count;
use function get_debug_type;
@ -138,8 +137,8 @@ final class BlockStateUpgradeSchemaUtils{
$convertedRemappedValuesIndex = [];
foreach(Utils::stringifyKeys($model->remappedPropertyValuesIndex ?? []) as $mappingKey => $mappingValues){
foreach($mappingValues as $k => $oldNew){
$convertedRemappedValuesIndex[$mappingKey][$k] = new BlockStateUpgradeSchemaValueRemap(
foreach($mappingValues as $oldNew){
$convertedRemappedValuesIndex[$mappingKey][] = new BlockStateUpgradeSchemaValueRemap(
self::jsonModelToTag($oldNew->old),
self::jsonModelToTag($oldNew->new)
);
@ -361,7 +360,7 @@ final class BlockStateUpgradeSchemaUtils{
//remaps with the same number of criteria should be sorted alphabetically, but this is not strictly necessary
return json_encode($a->oldState ?? []) <=> json_encode($b->oldState ?? []);
});
$result->remappedStates[$oldBlockName] = array_values($keyedRemaps);
$result->remappedStates[$oldBlockName] = $keyedRemaps; //usort strips keys, so this is already a list
}
if(isset($result->remappedStates)){
ksort($result->remappedStates);

View File

@ -51,12 +51,19 @@ final class ItemDeserializer{
* @phpstan-param \Closure(Data) : Item $deserializer
*/
public function map(string $id, \Closure $deserializer) : void{
if(isset($this->deserializers[$id])){
throw new \InvalidArgumentException("Deserializer is already assigned for \"$id\"");
}
$this->deserializers[$id] = $deserializer;
}
/**
* Returns the existing data deserializer for the given ID, or null if none exists.
* This may be useful if you need to override a deserializer, but still want to be able to fall back to the original.
*
* @phpstan-return ?\Closure(Data) : Item
*/
public function getDeserializerForId(string $id) : ?\Closure{
return $this->deserializers[$id] ?? null;
}
/**
* @phpstan-param \Closure(Data) : Block $deserializer
*/

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\data\runtime;
use function array_values;
use function ceil;
use function count;
use function log;
@ -60,7 +59,7 @@ final class RuntimeEnumMetadata{
usort($members, fn(\UnitEnum $a, \UnitEnum $b) => $a->name <=> $b->name); //sort by name to ensure consistent ordering (and thus consistent bit assignments)
$this->bits = (int) ceil(log(count($members), 2));
$this->intToEnum = array_values($members);
$this->intToEnum = $members; //usort strips keys so this is already a list
$reversed = [];
foreach($this->intToEnum as $int => $enum){

View File

@ -76,7 +76,7 @@ class Attribute{
throw new \InvalidArgumentException("Minimum $minValue is greater than the maximum $max");
}
if($this->minValue != $minValue){
if($this->minValue !== $minValue){
$this->desynchronized = true;
$this->minValue = $minValue;
}
@ -95,7 +95,7 @@ class Attribute{
throw new \InvalidArgumentException("Maximum $maxValue is less than the minimum $min");
}
if($this->maxValue != $maxValue){
if($this->maxValue !== $maxValue){
$this->desynchronized = true;
$this->maxValue = $maxValue;
}
@ -140,7 +140,7 @@ class Attribute{
$value = min(max($value, $this->getMinValue()), $this->getMaxValue());
}
if($this->currentValue != $value){
if($this->currentValue !== $value){
$this->desynchronized = true;
$this->currentValue = $value;
}elseif($forceSend){

View File

@ -72,6 +72,7 @@ use function assert;
use function cos;
use function count;
use function deg2rad;
use function floatval;
use function floor;
use function fmod;
use function get_class;
@ -591,7 +592,7 @@ abstract class Entity{
* Sets the health of the Entity. This won't send any update to the players
*/
public function setHealth(float $amount) : void{
if($amount == $this->health){
if($amount === $this->health){
return;
}
@ -760,8 +761,8 @@ abstract class Entity{
$diffMotion = $this->motion->subtractVector($this->lastMotion)->lengthSquared();
$still = $this->motion->lengthSquared() == 0.0;
$wasStill = $this->lastMotion->lengthSquared() == 0.0;
$still = $this->motion->lengthSquared() === 0.0;
$wasStill = $this->lastMotion->lengthSquared() === 0.0;
if($wasStill !== $still){
//TODO: hack for client-side AI interference: prevent client sided movement when motion is 0
$this->setNoClientPredictions($still);
@ -1004,7 +1005,7 @@ abstract class Entity{
abs($this->motion->z) <= self::MOTION_THRESHOLD ? 0 : null
);
if($this->motion->x != 0 || $this->motion->y != 0 || $this->motion->z != 0){
if(floatval($this->motion->x) !== 0.0 || floatval($this->motion->y) !== 0.0 || floatval($this->motion->z) !== 0.0){
$this->move($this->motion->x, $this->motion->y, $this->motion->z);
}
@ -1058,9 +1059,9 @@ abstract class Entity{
public function hasMovementUpdate() : bool{
return (
$this->forceMovementUpdate ||
$this->motion->x != 0 ||
$this->motion->y != 0 ||
$this->motion->z != 0 ||
floatval($this->motion->x) !== 0.0 ||
floatval($this->motion->y) !== 0.0 ||
floatval($this->motion->z) !== 0.0 ||
!$this->onGround
);
}
@ -1163,7 +1164,7 @@ abstract class Entity{
$moveBB->offset(0, $dy, 0);
$fallingFlag = ($this->onGround || ($dy != $wantedY && $wantedY < 0));
$fallingFlag = ($this->onGround || ($dy !== $wantedY && $wantedY < 0));
foreach($list as $bb){
$dx = $bb->calculateXOffset($moveBB, $dx);
@ -1177,7 +1178,7 @@ abstract class Entity{
$moveBB->offset(0, 0, $dz);
if($this->stepHeight > 0 && $fallingFlag && ($wantedX != $dx || $wantedZ != $dz)){
if($this->stepHeight > 0 && $fallingFlag && ($wantedX !== $dx || $wantedZ !== $dz)){
$cx = $dx;
$cy = $dy;
$cz = $dz;
@ -1242,9 +1243,9 @@ abstract class Entity{
$postFallVerticalVelocity = $this->updateFallState($dy, $this->onGround);
$this->motion = $this->motion->withComponents(
$wantedX != $dx ? 0 : null,
$postFallVerticalVelocity ?? ($wantedY != $dy ? 0 : null),
$wantedZ != $dz ? 0 : null
$wantedX !== $dx ? 0 : null,
$postFallVerticalVelocity ?? ($wantedY !== $dy ? 0 : null),
$wantedZ !== $dz ? 0 : null
);
//TODO: vehicle collision events (first we need to spawn them!)
@ -1253,10 +1254,10 @@ abstract class Entity{
}
protected function checkGroundState(float $wantedX, float $wantedY, float $wantedZ, float $dx, float $dy, float $dz) : void{
$this->isCollidedVertically = $wantedY != $dy;
$this->isCollidedHorizontally = ($wantedX != $dx || $wantedZ != $dz);
$this->isCollidedVertically = $wantedY !== $dy;
$this->isCollidedHorizontally = ($wantedX !== $dx || $wantedZ !== $dz);
$this->isCollided = ($this->isCollidedHorizontally || $this->isCollidedVertically);
$this->onGround = ($wantedY != $dy && $wantedY < 0);
$this->onGround = ($wantedY !== $dy && $wantedY < 0);
}
/**

View File

@ -513,6 +513,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
AbilitiesLayer::LAYER_BASE,
array_fill(0, AbilitiesLayer::NUMBER_OF_ABILITIES, false),
0.0,
0.0,
0.0
)
])),

View File

@ -66,7 +66,7 @@ class Location extends Position{
public function equals(Vector3 $v) : bool{
if($v instanceof Location){
return parent::equals($v) && $v->yaw == $this->yaw && $v->pitch == $this->pitch;
return parent::equals($v) && $v->yaw === $this->yaw && $v->pitch === $this->pitch;
}
return parent::equals($v);
}

View File

@ -44,7 +44,6 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\timings\Timings;
use function assert;
use function atan2;
use function ceil;
use function count;
@ -170,8 +169,6 @@ abstract class Projectile extends Entity{
$start = $this->location->asVector3();
$end = $start->add($dx, $dy, $dz);
$blockHit = null;
$entityHit = null;
$hitResult = null;
$world = $this->getWorld();
@ -181,8 +178,7 @@ abstract class Projectile extends Entity{
$blockHitResult = $this->calculateInterceptWithBlock($block, $start, $end);
if($blockHitResult !== null){
$end = $blockHitResult->hitVector;
$blockHit = $block;
$hitResult = $blockHitResult;
$hitResult = [$block, $blockHitResult];
break;
}
}
@ -206,8 +202,7 @@ abstract class Projectile extends Entity{
if($distance < $entityDistance){
$entityDistance = $distance;
$entityHit = $entity;
$hitResult = $entityHitResult;
$hitResult = [$entity, $entityHitResult];
$end = $entityHitResult->hitVector;
}
}
@ -223,26 +218,18 @@ abstract class Projectile extends Entity{
$this->recalculateBoundingBox();
if($hitResult !== null){
/** @var ProjectileHitEvent|null $ev */
$ev = null;
if($entityHit !== null){
$ev = new ProjectileHitEntityEvent($this, $hitResult, $entityHit);
}elseif($blockHit !== null){
$ev = new ProjectileHitBlockEvent($this, $hitResult, $blockHit);
[$objectHit, $rayTraceResult] = $hitResult;
if($objectHit instanceof Entity){
$ev = new ProjectileHitEntityEvent($this, $rayTraceResult, $objectHit);
$specificHitFunc = fn() => $this->onHitEntity($objectHit, $rayTraceResult);
}else{
assert(false, "unknown hit type");
$ev = new ProjectileHitBlockEvent($this, $rayTraceResult, $objectHit);
$specificHitFunc = fn() => $this->onHitBlock($objectHit, $rayTraceResult);
}
if($ev !== null){
$ev->call();
$this->onHit($ev);
if($ev instanceof ProjectileHitEntityEvent){
$this->onHitEntity($ev->getEntityHit(), $ev->getRayTraceResult());
}elseif($ev instanceof ProjectileHitBlockEvent){
$this->onHitBlock($ev->getBlockHit(), $ev->getRayTraceResult());
}
}
$ev->call();
$this->onHit($ev);
$specificHitFunc();
$this->isCollided = $this->onGround = true;
$this->motion = Vector3::zero();
@ -290,10 +277,11 @@ abstract class Projectile extends Entity{
$damage = $this->getResultDamage();
if($damage >= 0){
if($this->getOwningEntity() === null){
$owner = $this->getOwningEntity();
if($owner === null){
$ev = new EntityDamageByEntityEvent($this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
}else{
$ev = new EntityDamageByChildEntityEvent($this->getOwningEntity(), $this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
$ev = new EntityDamageByChildEntityEvent($owner, $this, $entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
}
$entityHit->attack($ev);

View File

@ -119,7 +119,7 @@ class HandlerListManager{
public function getHandlersFor(string $event) : array{
$cache = $this->handlerCaches[$event] ?? null;
//getListFor() will populate the cache for the next call
return $cache?->list ?? $this->getListFor($event)->getListenerList();
return $cache->list ?? $this->getListFor($event)->getListenerList();
}
/**

View File

@ -52,9 +52,15 @@ class PlayerPreLoginEvent extends Event{
self::KICK_FLAG_BANNED
];
/** @var Translatable[]|string[] reason const => associated message */
/**
* @var Translatable[]|string[] reason const => associated message
* @phpstan-var array<int, Translatable|string>
*/
protected array $disconnectReasons = [];
/** @var Translatable[]|string[] */
/**
* @var Translatable[]|string[]
* @phpstan-var array<int, Translatable|string>
*/
protected array $disconnectScreenMessages = [];
public function __construct(
@ -93,6 +99,7 @@ class PlayerPreLoginEvent extends Event{
* Returns an array of kick flags currently assigned.
*
* @return int[]
* @phpstan-return list<int>
*/
public function getKickFlags() : array{
return array_keys($this->disconnectReasons);

View File

@ -0,0 +1,34 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory;
/**
* Available tabs in the creative inventory that an item can be displayed in.
*/
enum CreativeCategory{
case CONSTRUCTION;
case NATURE;
case EQUIPMENT;
case ITEMS;
}

View File

@ -0,0 +1,51 @@
<?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\inventory;
use pocketmine\item\Item;
use pocketmine\lang\Translatable;
use function strlen;
/**
* Info for an item group in the creative inventory menu.
*/
final class CreativeGroup{
/**
* @param Translatable|string $name Tooltip shown to the player on hover
* @param Item $icon Item shown when the group is collapsed
*/
public function __construct(
private readonly Translatable|string $name,
private readonly Item $icon
){
$nameLength = $name instanceof Translatable ? strlen($name->getText()) : strlen($name);
if($nameLength === 0){
throw new \InvalidArgumentException("Creative group name cannot be empty");
}
}
public function getName() : Translatable|string{ return $this->name; }
public function getIcon() : Item{ return clone $this->icon; }
}

View File

@ -24,21 +24,24 @@ declare(strict_types=1);
namespace pocketmine\inventory;
use pocketmine\crafting\CraftingManagerFromDataHelper;
use pocketmine\crafting\json\ItemStackData;
use pocketmine\data\bedrock\BedrockDataFiles;
use pocketmine\inventory\json\CreativeGroupData;
use pocketmine\item\Item;
use pocketmine\lang\Translatable;
use pocketmine\utils\DestructorCallbackTrait;
use pocketmine\utils\ObjectSet;
use pocketmine\utils\SingletonTrait;
use pocketmine\utils\Utils;
use Symfony\Component\Filesystem\Path;
use function array_filter;
use function array_map;
final class CreativeInventory{
use SingletonTrait;
use DestructorCallbackTrait;
/**
* @var Item[]
* @phpstan-var array<int, Item>
* @var CreativeInventoryEntry[]
* @phpstan-var array<int, CreativeInventoryEntry>
*/
private array $creative = [];
@ -47,17 +50,32 @@ final class CreativeInventory{
private function __construct(){
$this->contentChangedCallbacks = new ObjectSet();
$creativeItems = CraftingManagerFromDataHelper::loadJsonArrayOfObjectsFile(
BedrockDataFiles::CREATIVEITEMS_JSON,
ItemStackData::class
);
foreach($creativeItems as $data){
$item = CraftingManagerFromDataHelper::deserializeItemStack($data);
if($item === null){
//unknown item
continue;
foreach([
"construction" => CreativeCategory::CONSTRUCTION,
"nature" => CreativeCategory::NATURE,
"equipment" => CreativeCategory::EQUIPMENT,
"items" => CreativeCategory::ITEMS,
] as $categoryId => $categoryEnum){
$groups = CraftingManagerFromDataHelper::loadJsonArrayOfObjectsFile(
Path::join(BedrockDataFiles::CREATIVE, $categoryId . ".json"),
CreativeGroupData::class
);
foreach($groups as $groupData){
$icon = $groupData->group_icon === null ? null : CraftingManagerFromDataHelper::deserializeItemStack($groupData->group_icon);
$group = $icon === null ? null : new CreativeGroup(
new Translatable($groupData->group_name),
$icon
);
$items = array_filter(array_map(static fn($itemStack) => CraftingManagerFromDataHelper::deserializeItemStack($itemStack), $groupData->items));
foreach($items as $item){
$this->add($item, $categoryEnum, $group);
}
}
$this->add($item);
}
}
@ -75,16 +93,28 @@ final class CreativeInventory{
* @phpstan-return array<int, Item>
*/
public function getAll() : array{
return Utils::cloneObjectArray($this->creative);
return array_map(fn(CreativeInventoryEntry $entry) => $entry->getItem(), $this->creative);
}
/**
* @return CreativeInventoryEntry[]
* @phpstan-return array<int, CreativeInventoryEntry>
*/
public function getAllEntries() : array{
return $this->creative;
}
public function getItem(int $index) : ?Item{
return isset($this->creative[$index]) ? clone $this->creative[$index] : null;
return $this->getEntry($index)?->getItem();
}
public function getEntry(int $index) : ?CreativeInventoryEntry{
return $this->creative[$index] ?? null;
}
public function getItemIndex(Item $item) : int{
foreach($this->creative as $i => $d){
if($item->equals($d, true, false)){
if($d->matchesItem($item)){
return $i;
}
}
@ -96,8 +126,8 @@ final class CreativeInventory{
* Adds an item to the creative menu.
* Note: Players who are already online when this is called will not see this change.
*/
public function add(Item $item) : void{
$this->creative[] = clone $item;
public function add(Item $item, CreativeCategory $category = CreativeCategory::ITEMS, ?CreativeGroup $group = null) : void{
$this->creative[] = new CreativeInventoryEntry($item, $category, $group);
$this->onContentChange();
}

View File

@ -0,0 +1,48 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory;
use pocketmine\item\Item;
final class CreativeInventoryEntry{
private readonly Item $item;
public function __construct(
Item $item,
private readonly CreativeCategory $category,
private readonly ?CreativeGroup $group = null
){
$this->item = clone $item;
}
public function getItem() : Item{ return clone $this->item; }
public function getCategory() : CreativeCategory{ return $this->category; }
public function getGroup() : ?CreativeGroup{ return $this->group; }
public function matchesItem(Item $item) : bool{
return $item->equals($this->item, checkDamage: true, checkCompound: false);
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\inventory\json;
use pocketmine\crafting\json\ItemStackData;
final class CreativeGroupData{
/** @required */
public string $group_name;
/** @required */
public ?ItemStackData $group_icon;
/**
* @var \pocketmine\crafting\json\ItemStackData[]
* @required
*/
public array $items;
}

View File

@ -144,8 +144,9 @@ class InventoryTransaction{
$needItems = [];
$haveItems = [];
foreach($this->actions as $key => $action){
if(!$action->getTargetItem()->isNull()){
$needItems[] = $action->getTargetItem();
$targetItem = $action->getTargetItem();
if(!$targetItem->isNull()){
$needItems[] = $targetItem;
}
try{
@ -154,8 +155,9 @@ class InventoryTransaction{
throw new TransactionValidationException(get_class($action) . "#" . spl_object_id($action) . ": " . $e->getMessage(), 0, $e);
}
if(!$action->getSourceItem()->isNull()){
$haveItems[] = $action->getSourceItem();
$sourceItem = $action->getSourceItem();
if(!$sourceItem->isNull()){
$haveItems[] = $sourceItem;
}
}
@ -232,7 +234,7 @@ class InventoryTransaction{
/**
* @param SlotChangeAction[] $possibleActions
* @phpstan-param list<SlotChangeAction> $possibleActions
* @phpstan-param array<int, SlotChangeAction> $possibleActions
*/
protected function findResultItem(Item $needOrigin, array $possibleActions) : ?Item{
assert(count($possibleActions) > 0);

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\block\utils\RecordType;
use pocketmine\block\utils\WoodType;
use pocketmine\block\VanillaBlocks as Blocks;
use pocketmine\entity\Entity;
use pocketmine\entity\Location;
@ -47,6 +48,8 @@ use function strtolower;
* @see build/generate-registry-annotations.php
* @generate-registry-docblock
*
* @method static Boat BOAT(BoatType $boatType)
* @method static ItemBlockWallOrFloor SIGN(\pocketmine\block\utils\WoodType $woodType)
* @method static Boat ACACIA_BOAT()
* @method static ItemBlockWallOrFloor ACACIA_SIGN()
* @method static ItemBlock AIR()
@ -396,7 +399,6 @@ final class VanillaItems{
//in the future we'll probably want to dissociate this from the air block and make a proper null item
self::_registryRegister("air", Blocks::AIR()->asItem()->setCount(0));
self::register("acacia_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::ACACIA_SIGN(), Blocks::ACACIA_WALL_SIGN()));
self::register("amethyst_shard", fn(IID $id) => new Item($id, "Amethyst Shard"));
self::register("apple", fn(IID $id) => new Apple($id, "Apple"));
self::register("arrow", fn(IID $id) => new Arrow($id, "Arrow"));
@ -406,7 +408,6 @@ final class VanillaItems{
self::register("beetroot", fn(IID $id) => new Beetroot($id, "Beetroot"));
self::register("beetroot_seeds", fn(IID $id) => new BeetrootSeeds($id, "Beetroot Seeds"));
self::register("beetroot_soup", fn(IID $id) => new BeetrootSoup($id, "Beetroot Soup"));
self::register("birch_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::BIRCH_SIGN(), Blocks::BIRCH_WALL_SIGN()));
self::register("blaze_powder", fn(IID $id) => new Item($id, "Blaze Powder"));
self::register("blaze_rod", fn(IID $id) => new BlazeRod($id, "Blaze Rod"));
self::register("bleach", fn(IID $id) => new Item($id, "Bleach"));
@ -420,7 +421,6 @@ final class VanillaItems{
self::register("bucket", fn(IID $id) => new Bucket($id, "Bucket"));
self::register("carrot", fn(IID $id) => new Carrot($id, "Carrot"));
self::register("charcoal", fn(IID $id) => new Coal($id, "Charcoal"));
self::register("cherry_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::CHERRY_SIGN(), Blocks::CHERRY_WALL_SIGN()));
self::register("chemical_aluminium_oxide", fn(IID $id) => new Item($id, "Aluminium Oxide"));
self::register("chemical_ammonia", fn(IID $id) => new Item($id, "Ammonia"));
self::register("chemical_barium_sulphate", fn(IID $id) => new Item($id, "Barium Sulphate"));
@ -475,8 +475,6 @@ final class VanillaItems{
self::register("cookie", fn(IID $id) => new Cookie($id, "Cookie"));
self::register("copper_ingot", fn(IID $id) => new Item($id, "Copper Ingot"));
self::register("coral_fan", fn(IID $id) => new CoralFan($id));
self::register("crimson_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::CRIMSON_SIGN(), Blocks::CRIMSON_WALL_SIGN()));
self::register("dark_oak_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::DARK_OAK_SIGN(), Blocks::DARK_OAK_WALL_SIGN()));
self::register("diamond", fn(IID $id) => new Item($id, "Diamond"));
self::register("disc_fragment_5", fn(IID $id) => new Item($id, "Disc Fragment (5)"));
self::register("dragon_breath", fn(IID $id) => new Item($id, "Dragon's Breath"));
@ -516,12 +514,10 @@ final class VanillaItems{
self::register("ink_sac", fn(IID $id) => new Item($id, "Ink Sac"));
self::register("iron_ingot", fn(IID $id) => new Item($id, "Iron Ingot"));
self::register("iron_nugget", fn(IID $id) => new Item($id, "Iron Nugget"));
self::register("jungle_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::JUNGLE_SIGN(), Blocks::JUNGLE_WALL_SIGN()));
self::register("lapis_lazuli", fn(IID $id) => new Item($id, "Lapis Lazuli"));
self::register("lava_bucket", fn(IID $id) => new LiquidBucket($id, "Lava Bucket", Blocks::LAVA()));
self::register("leather", fn(IID $id) => new Item($id, "Leather"));
self::register("magma_cream", fn(IID $id) => new Item($id, "Magma Cream"));
self::register("mangrove_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::MANGROVE_SIGN(), Blocks::MANGROVE_WALL_SIGN()));
self::register("medicine", fn(IID $id) => new Medicine($id, "Medicine"));
self::register("melon", fn(IID $id) => new Melon($id, "Melon"));
self::register("melon_seeds", fn(IID $id) => new MelonSeeds($id, "Melon Seeds"));
@ -539,9 +535,7 @@ final class VanillaItems{
self::register("netherite_scrap", fn(IID $id) => new class($id, "Netherite Scrap") extends Item{
public function isFireProof() : bool{ return true; }
});
self::register("oak_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::OAK_SIGN(), Blocks::OAK_WALL_SIGN()));
self::register("painting", fn(IID $id) => new PaintingItem($id, "Painting"));
self::register("pale_oak_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::PALE_OAK_SIGN(), Blocks::PALE_OAK_WALL_SIGN()));
self::register("paper", fn(IID $id) => new Item($id, "Paper"));
self::register("phantom_membrane", fn(IID $id) => new Item($id, "Phantom Membrane"));
self::register("pitcher_pod", fn(IID $id) => new PitcherPod($id, "Pitcher Pod"));
@ -597,7 +591,6 @@ final class VanillaItems{
self::register("snowball", fn(IID $id) => new Snowball($id, "Snowball"));
self::register("spider_eye", fn(IID $id) => new SpiderEye($id, "Spider Eye"));
self::register("splash_potion", fn(IID $id) => new SplashPotion($id, "Splash Potion"));
self::register("spruce_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::SPRUCE_SIGN(), Blocks::SPRUCE_WALL_SIGN()));
self::register("spyglass", fn(IID $id) => new Spyglass($id, "Spyglass"));
self::register("steak", fn(IID $id) => new Steak($id, "Steak"));
self::register("stick", fn(IID $id) => new Stick($id, "Stick"));
@ -607,7 +600,6 @@ final class VanillaItems{
self::register("sweet_berries", fn(IID $id) => new SweetBerries($id, "Sweet Berries"));
self::register("torchflower_seeds", fn(IID $id) => new TorchflowerSeeds($id, "Torchflower Seeds"));
self::register("totem", fn(IID $id) => new Totem($id, "Totem of Undying"));
self::register("warped_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::WARPED_SIGN(), Blocks::WARPED_WALL_SIGN()));
self::register("water_bucket", fn(IID $id) => new LiquidBucket($id, "Water Bucket", Blocks::WATER()));
self::register("wheat", fn(IID $id) => new Item($id, "Wheat"));
self::register("wheat_seeds", fn(IID $id) => new WheatSeeds($id, "Wheat Seeds"));
@ -618,6 +610,12 @@ final class VanillaItems{
//boat type is static, because different types of wood may have different properties
self::register(strtolower($type->name) . "_boat", fn(IID $id) => new Boat($id, $type->getDisplayName() . " Boat", $type));
}
self::registerOverloaded("boat", BoatType::class, Boat::class);
foreach(WoodType::cases() as $woodType){
self::register("{$woodType->name}_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::SIGN($woodType), Blocks::WALL_SIGN($woodType)));
}
self::registerOverloaded("sign", WoodType::class, ItemBlockWallOrFloor::class);
}
private static function registerSpawnEggs() : void{

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