mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-20 16:00:20 +00:00
Compare commits
75 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f661443ec7 | ||
|
835c383d4e | ||
|
d3f6c22996 | ||
|
6f3851be80 | ||
|
e88b81a4cb | ||
|
687112f4cd | ||
|
c9e85603b0 | ||
|
c80a4d5b55 | ||
|
f416cb8902 | ||
|
f123df5e0d | ||
|
de26ebd124 | ||
|
1c6a4bde86 | ||
|
c2f8e9365b | ||
|
4ef21fabab | ||
|
4407e585e4 | ||
|
463be36b72 | ||
|
8b57e9007a | ||
|
e03c586c86 | ||
|
802e373bf3 | ||
|
09acbfab4c | ||
|
7cfaf04b87 | ||
|
d9e0e51e14 | ||
|
069ecf007f | ||
|
341c7a03a9 | ||
|
7ae90dda5d | ||
|
73a4b076d6 | ||
|
00df508727 | ||
|
a6553097f4 | ||
|
afc4a3c7f1 | ||
|
ac7b5b3b13 | ||
|
7af5eb3da2 | ||
|
95284bc9de | ||
|
2291546610 | ||
|
aad2bce9e4 | ||
|
09f0ce458c | ||
|
50a1e59aa4 | ||
|
e8824a36b9 | ||
|
b1e63e544f | ||
|
9e9f8a4870 | ||
|
d0d84d4c51 | ||
|
9382e6e5b3 | ||
|
e3e0c14275 | ||
|
afac178cf4 | ||
|
e2f5e3e73c | ||
|
3a2d0d77d1 | ||
|
32b98dcbde | ||
|
092ea07d51 | ||
|
706f391068 | ||
|
7c654271a8 | ||
|
19425e35ea | ||
|
3df2bdb879 | ||
|
1fed9f6cb5 | ||
|
3050af0bc0 | ||
|
a08b06d322 | ||
|
c876253f76 | ||
|
67272f8f2b | ||
|
77be5f8e25 | ||
|
9744bd7073 | ||
|
51cf6817b1 | ||
|
fd04894a7b | ||
|
d2d6a59c72 | ||
|
788ee9a008 | ||
|
34f801ee3c | ||
|
246c1776df | ||
|
2670e81668 | ||
|
e29aa2f337 | ||
|
9b3b45258a | ||
|
ca4debbf08 | ||
|
03f98ee0a9 | ||
|
70368ea653 | ||
|
21ccd90147 | ||
|
0a9a45a126 | ||
|
88937f1785 | ||
|
e5a783cb9e | ||
|
70fb9bbdfd |
3
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
3
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@ -57,6 +57,9 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
## Version, OS and game info
|
## Version, OS and game info
|
||||||
|
> [!WARNING]
|
||||||
|
> "Latest" is not a valid version.
|
||||||
|
> Failure to fill these fields with valid information may result in your issue being closed.
|
||||||
|
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
|
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@ -12,6 +12,10 @@ updates:
|
|||||||
update-types:
|
update-types:
|
||||||
- "version-update:semver-major"
|
- "version-update:semver-major"
|
||||||
- "version-update:semver-minor"
|
- "version-update:semver-minor"
|
||||||
|
|
||||||
|
#since we lock this to exact versions, it causes conflicts with minor-next & major-next in composer.lock
|
||||||
|
#better to just test updates to this locally anyway since almost every version breaks something
|
||||||
|
- dependency-name: phpstan/phpstan
|
||||||
groups:
|
groups:
|
||||||
production-patch-updates:
|
production-patch-updates:
|
||||||
dependency-type: production
|
dependency-type: production
|
||||||
|
10
.github/workflows/build-docker-image.yml
vendored
10
.github/workflows/build-docker-image.yml
vendored
@ -8,7 +8,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Update Docker Hub images
|
name: Update Docker Hub images
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
@ -53,7 +53,7 @@ jobs:
|
|||||||
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build image for tag
|
- name: Build image for tag
|
||||||
uses: docker/build-push-action@v6.13.0
|
uses: docker/build-push-action@v6.15.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
context: ./pocketmine-mp
|
context: ./pocketmine-mp
|
||||||
@ -66,7 +66,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build image for major tag
|
- name: Build image for major tag
|
||||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||||
uses: docker/build-push-action@v6.13.0
|
uses: docker/build-push-action@v6.15.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
context: ./pocketmine-mp
|
context: ./pocketmine-mp
|
||||||
@ -79,7 +79,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build image for minor tag
|
- name: Build image for minor tag
|
||||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||||
uses: docker/build-push-action@v6.13.0
|
uses: docker/build-push-action@v6.15.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
context: ./pocketmine-mp
|
context: ./pocketmine-mp
|
||||||
@ -92,7 +92,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build image for latest tag
|
- name: Build image for latest tag
|
||||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||||
uses: docker/build-push-action@v6.13.0
|
uses: docker/build-push-action@v6.15.0
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
context: ./pocketmine-mp
|
context: ./pocketmine-mp
|
||||||
|
4
.github/workflows/draft-release-pr-check.yml
vendored
4
.github/workflows/draft-release-pr-check.yml
vendored
@ -24,7 +24,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
check-intent:
|
check-intent:
|
||||||
name: Check release trigger
|
name: Check release trigger
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }}
|
valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }}
|
||||||
@ -43,7 +43,7 @@ jobs:
|
|||||||
#don't do these checks if this isn't a release - we don't want to generate unnecessary failed statuses
|
#don't do these checks if this isn't a release - we don't want to generate unnecessary failed statuses
|
||||||
if: needs.check-intent.outputs.valid == 'true'
|
if: needs.check-intent.outputs.valid == 'true'
|
||||||
|
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
10
.github/workflows/draft-release.yml
vendored
10
.github/workflows/draft-release.yml
vendored
@ -23,7 +23,7 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
skip:
|
skip:
|
||||||
name: Check whether to ignore this tag
|
name: Check whether to ignore this tag
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
skip: ${{ steps.exists.outputs.exists == 'true' }}
|
skip: ${{ steps.exists.outputs.exists == 'true' }}
|
||||||
@ -54,7 +54,7 @@ jobs:
|
|||||||
needs: [check]
|
needs: [check]
|
||||||
if: needs.check.outputs.valid == 'true' && github.ref_type != 'tag' #can't do post-commit for a tag
|
if: needs.check.outputs.valid == 'true' && github.ref_type != 'tag' #can't do post-commit for a tag
|
||||||
|
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Generate access token
|
- name: Generate access token
|
||||||
@ -79,7 +79,7 @@ jobs:
|
|||||||
needs: [check]
|
needs: [check]
|
||||||
if: needs.check.outputs.valid == 'true' || github.ref_type == 'tag' #ignore validity check for tags
|
if: needs.check.outputs.valid == 'true' || github.ref_type == 'tag' #ignore validity check for tags
|
||||||
|
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@ -165,7 +165,7 @@ jobs:
|
|||||||
${{ github.workspace }}/core-permissions.rst
|
${{ github.workspace }}/core-permissions.rst
|
||||||
|
|
||||||
- name: Create draft release
|
- name: Create draft release
|
||||||
uses: ncipollo/release-action@v1.15.0
|
uses: ncipollo/release-action@v1.16.0
|
||||||
id: create-draft
|
id: create-draft
|
||||||
with:
|
with:
|
||||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json,${{ github.workspace }}/core-permissions.rst
|
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json,${{ github.workspace }}/core-permissions.rst
|
||||||
@ -182,6 +182,8 @@ jobs:
|
|||||||
|
|
||||||
:information_source: Download the recommended PHP binary [here](${{ steps.php-binary-url.outputs.PHP_BINARY_URL }}).
|
:information_source: Download the recommended PHP binary [here](${{ steps.php-binary-url.outputs.PHP_BINARY_URL }}).
|
||||||
|
|
||||||
|
:warning: Found a bug? Report it on our [issue tracker](${{ github.server_url }}/${{ github.repository }}/issues). **We can't fix bugs if you don't report them.**
|
||||||
|
|
||||||
- name: Post draft release URL on PR
|
- name: Post draft release URL on PR
|
||||||
if: github.event_name == 'pull_request_target'
|
if: github.event_name == 'pull_request_target'
|
||||||
uses: thollander/actions-comment-pull-request@v3
|
uses: thollander/actions-comment-pull-request@v3
|
||||||
|
2
.github/workflows/main-php-matrix.yml
vendored
2
.github/workflows/main-php-matrix.yml
vendored
@ -15,7 +15,7 @@ on:
|
|||||||
type: number
|
type: number
|
||||||
image:
|
image:
|
||||||
description: 'Runner image to use'
|
description: 'Runner image to use'
|
||||||
default: 'ubuntu-20.04'
|
default: 'ubuntu-22.04'
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
|||||||
|
|
||||||
codestyle:
|
codestyle:
|
||||||
name: Code Style checks
|
name: Code Style checks
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ jobs:
|
|||||||
|
|
||||||
shellcheck:
|
shellcheck:
|
||||||
name: ShellCheck
|
name: ShellCheck
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
|
5
.github/workflows/support.yml
vendored
5
.github/workflows/support.yml
vendored
@ -20,10 +20,7 @@ jobs:
|
|||||||
|
|
||||||
- Check our [Documentation](https://doc.pmmp.io) to see if you can find answers there
|
- Check our [Documentation](https://doc.pmmp.io) to see if you can find answers there
|
||||||
|
|
||||||
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG) or our [Forums](https://forums.pmmp.io)
|
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG)
|
||||||
|
|
||||||
|
|
||||||
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
|
|
||||||
|
|
||||||
close-issue: true
|
close-issue: true
|
||||||
lock-issue: false
|
lock-issue: false
|
||||||
|
@ -65,6 +65,8 @@ PocketMine-MP accepts community contributions! The following resources will be u
|
|||||||
* [Building and running PocketMine-MP from source](BUILDING.md)
|
* [Building and running PocketMine-MP from source](BUILDING.md)
|
||||||
* [Contributing Guidelines](CONTRIBUTING.md)
|
* [Contributing Guidelines](CONTRIBUTING.md)
|
||||||
|
|
||||||
|
New here? Check out [issues with the "Easy task" label](https://github.com/pmmp/PocketMine-MP/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Easy%20task%22) for things you could work to familiarise yourself with the codebase.
|
||||||
|
|
||||||
## Donate
|
## Donate
|
||||||
PocketMine-MP is free, but it requires a lot of time and effort from unpaid volunteers to develop. Donations enable us to keep delivering support for new versions and adding features your players love.
|
PocketMine-MP is free, but it requires a lot of time and effort from unpaid volunteers to develop. Donations enable us to keep delivering support for new versions and adding features your players love.
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ require dirname(__DIR__) . '/vendor/autoload.php';
|
|||||||
*/
|
*/
|
||||||
$options = [
|
$options = [
|
||||||
"base_version" => VersionInfo::BASE_VERSION,
|
"base_version" => VersionInfo::BASE_VERSION,
|
||||||
"major_version" => fn() => explode(".", VersionInfo::BASE_VERSION)[0],
|
"major_version" => fn() => explode(".", VersionInfo::BASE_VERSION, limit: 2)[0],
|
||||||
"mcpe_version" => ProtocolInfo::MINECRAFT_VERSION_NETWORK,
|
"mcpe_version" => ProtocolInfo::MINECRAFT_VERSION_NETWORK,
|
||||||
"is_dev" => VersionInfo::IS_DEVELOPMENT_BUILD,
|
"is_dev" => VersionInfo::IS_DEVELOPMENT_BUILD,
|
||||||
"changelog_file_name" => function() : string{
|
"changelog_file_name" => function() : string{
|
||||||
|
@ -36,3 +36,17 @@ It also allows creating new collapsible groups of items, and modifying or removi
|
|||||||
- `BedrockDataFiles` now includes constants for folders at the top level of `BedrockData` as well as files.
|
- `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.
|
- 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.
|
- New information was added to `required_item_list.json` in `BedrockData`, as the server is now required to send item component NBT data in some cases.
|
||||||
|
|
||||||
|
# 5.25.1
|
||||||
|
Released 26th February 2025.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
- Fixed confusing exception message when a block-breaking tool has an efficiency value of zero.
|
||||||
|
- Fixed incorrect facing of doors since 1.21.60 (resulted in mismatched AABBs between client & server, rendering glitches etc.)
|
||||||
|
- Resource pack UUIDs are now validated on load. Previously, invalid UUIDs would be accepted, and potentially cause a server crash on player join.
|
||||||
|
|
||||||
|
# 5.25.2
|
||||||
|
Released 4th March 2025.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
- Added limits to various `explode()` calls.
|
||||||
|
71
changelogs/5.26.md
Normal file
71
changelogs/5.26.md
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# 5.26.0
|
||||||
|
Released 22nd March 2025.
|
||||||
|
|
||||||
|
This is a minor feature release focused on performance improvements.
|
||||||
|
|
||||||
|
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||||
|
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||||
|
|
||||||
|
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||||
|
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
- Significantly improved performance of entity movement. Load testing with item entities showed a 3x increase in the number of entities supported without lag.
|
||||||
|
- Significantly improved performance of on-ground checks for player movement. This still needs further work, but optimisations implemented in this version should improve performance substantially.
|
||||||
|
- Updated `pocketmine/nbt` dependency with performance improvements to `TAG_Compound` and `TAG_List` comparison. This should improve performance of inventory-related actions.
|
||||||
|
- `InventoryTransaction` now avoids useless item clones when processing transactions, which should improve performance of inventory-related actions.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- `pocketmine/bedrock-protocol` has been updated to `36.2.0`, which adds new functions to access some packet fields.
|
||||||
|
- `pocketmine/nbt` has been updated to `1.1.0`, which improves performance when comparing NBT object trees.
|
||||||
|
|
||||||
|
## Gameplay
|
||||||
|
- Block breaking animation speed now takes into account the following: jumping, being in water, haste, mining fatigue
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
- `blockstate-upgrade-schema-utils.php` now has a new `dump-table` command, which turns a `.bin` palette table file into human-readable text for debugging.
|
||||||
|
|
||||||
|
## API
|
||||||
|
### `pocketmine\block`
|
||||||
|
- The following methods have been added:
|
||||||
|
- `public RuntimeBlockStateRegistry->hasStateId(int $stateId) : bool` - checks whether the given state ID is registered
|
||||||
|
|
||||||
|
### `pocketmine\crafting`
|
||||||
|
- The following methods have been deprecated:
|
||||||
|
- `CraftingManager::sort()` - this was implicitly internal anyway
|
||||||
|
|
||||||
|
### `pocketmine\utils`
|
||||||
|
- The following constants have been added:
|
||||||
|
- `TextFormat::MATERIAL_RESIN`
|
||||||
|
- The following static properties have been added:
|
||||||
|
- `Terminal::$COLOR_MATERIAL_RESIN`
|
||||||
|
|
||||||
|
### `pocketmine\data\bedrock\block`
|
||||||
|
- `BlockStateToObjectDeserializer` now permits overriding **deserializers** for Bedrock IDs. This may be useful to implement custom state handling, or to implement missing block variants (such as snow cauldron).
|
||||||
|
- This was originally prohibited since 5.0.0. However, there is no technical reason to disallow overriding **deserializers**.
|
||||||
|
- Overriding **serializers** is still **not permitted**. Reusing type IDs doesn't make any sense and would break internal design contracts.
|
||||||
|
- If you want to make a custom version of a vanilla block, create a custom type ID for it, exactly as you would for a regular custom block.
|
||||||
|
- The following methods have been added:
|
||||||
|
- `public BlockStateToObjectDeserializer->getDeserializerForId(string $id) : ?(\Closure(BlockStateReader) : Block)`
|
||||||
|
|
||||||
|
### `pocketmine\data\bedrock\item`
|
||||||
|
- `ItemDeserializer` now permits overriding **deserializers** for Bedrock IDs. As above, this may be useful to implement custom data handling, or to implement missing variants of existing items.
|
||||||
|
- This was originally prohibited since 5.0.0. However, there is no technical reason to disallow overriding **deserializers**.
|
||||||
|
- Overriding **serializers** is still **not permitted**. Reusing type IDs doesn't make any sense and would break internal design contracts.
|
||||||
|
- As above, if you want to make a custom version of a vanilla item, create a custom type ID for it, exactly as you would for a regular custom item.
|
||||||
|
- The following methods have been added:
|
||||||
|
- `public ItemDeserializer->getDeserializerForId(string $id) : ?(\Closure(SavedItemData) : Item)`
|
||||||
|
|
||||||
|
## Internals
|
||||||
|
- `new $class` is now banned on new internals code by a PHPStan rule. Closures or factory objects should be used instead for greater flexibility and better static analysis.
|
||||||
|
- `CraftingManager` now uses a more stable hash function for recipe output filtering.
|
||||||
|
- `ChunkCache` now accepts `int $dimensionId` in the constructor. This may be useful for plugins which implement the nether.
|
||||||
|
- `RuntimeBlockStateRegistry` now precomputes basic collision info about known states for fast paths.
|
||||||
|
- This permits specialization for common shapes like cubes and collisionless blocks, which allows skipping complex logic in entity movement calculation. This vastly improves performance.
|
||||||
|
- Any block whose class overrides `readStateFromWorld()` or `getModelPositionOffset()` will *not* be optimised.
|
||||||
|
- `Block->recalculateCollisionBoxes()` now has a hard requirement not to depend on anything other than available properties. It must not use `World` or its position.
|
||||||
|
- This change was problematic for `ChorusPlant`, which used nearby blocks to calculate its collision boxes.
|
||||||
|
- Blocks which need nearby blocks should override `readStateFromWorld()` and set dynamic state properties, similar to fences.
|
||||||
|
- This design flaw will be corrected with a major change to `Block` internals currently in planning for a future major version.
|
||||||
|
- `Block->getCollisionBoxes()` may not be called at all during gameplay for blocks with shapes determined to be simple, like cubes and collisionless blocks.
|
||||||
|
- `BlockStateToObjectDeserializer` now checks if the returned blockstate is registered in `RuntimeBlockStateRegistry` to promote earlier error detection (instead of crashing in random code paths).
|
24
changelogs/5.27.md
Normal file
24
changelogs/5.27.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# 5.27.0
|
||||||
|
Released 27th March 2025.
|
||||||
|
|
||||||
|
This is a support release for Minecraft: Bedrock Edition 1.21.70.
|
||||||
|
|
||||||
|
**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.
|
||||||
|
|
||||||
|
## Interim releases
|
||||||
|
If you're upgrading from 5.25.x directly to 5.27.0, please also read the following changelogs, as the interim releases contain important changes:
|
||||||
|
- [5.26.0](https://github.com/pmmp/PocketMine-MP/blob/5.26.0/changelogs/5.26.md#5260) - Performance improvements and other internal improvements
|
||||||
|
|
||||||
|
## General
|
||||||
|
- Aded support for Minecraft: Bedrock Edition 1.21.70.
|
||||||
|
- Removed support for earlier versions.
|
||||||
|
|
||||||
|
# 5.27.1
|
||||||
|
Released 6th April 2025.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
- Updated RakLib to get ping timestamp handling fixes.
|
@ -34,9 +34,9 @@
|
|||||||
"adhocore/json-comment": "~1.2.0",
|
"adhocore/json-comment": "~1.2.0",
|
||||||
"netresearch/jsonmapper": "~v5.0.0",
|
"netresearch/jsonmapper": "~v5.0.0",
|
||||||
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
|
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
|
||||||
"pocketmine/bedrock-data": "~4.0.0+bedrock-1.21.60",
|
"pocketmine/bedrock-data": "~4.1.0+bedrock-1.21.70",
|
||||||
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
|
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
|
||||||
"pocketmine/bedrock-protocol": "~36.0.0+bedrock-1.21.60",
|
"pocketmine/bedrock-protocol": "~37.0.0+bedrock-1.21.70",
|
||||||
"pocketmine/binaryutils": "^0.2.1",
|
"pocketmine/binaryutils": "^0.2.1",
|
||||||
"pocketmine/callback-validator": "^1.0.2",
|
"pocketmine/callback-validator": "^1.0.2",
|
||||||
"pocketmine/color": "^0.3.0",
|
"pocketmine/color": "^0.3.0",
|
||||||
@ -44,15 +44,15 @@
|
|||||||
"pocketmine/locale-data": "~2.24.0",
|
"pocketmine/locale-data": "~2.24.0",
|
||||||
"pocketmine/log": "^0.4.0",
|
"pocketmine/log": "^0.4.0",
|
||||||
"pocketmine/math": "~1.0.0",
|
"pocketmine/math": "~1.0.0",
|
||||||
"pocketmine/nbt": "~1.0.0",
|
"pocketmine/nbt": "~1.1.0",
|
||||||
"pocketmine/raklib": "~1.1.0",
|
"pocketmine/raklib": "~1.1.2",
|
||||||
"pocketmine/raklib-ipc": "~1.0.0",
|
"pocketmine/raklib-ipc": "~1.0.0",
|
||||||
"pocketmine/snooze": "^0.5.0",
|
"pocketmine/snooze": "^0.5.0",
|
||||||
"ramsey/uuid": "~4.7.0",
|
"ramsey/uuid": "~4.7.0",
|
||||||
"symfony/filesystem": "~6.4.0"
|
"symfony/filesystem": "~6.4.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "2.1.4",
|
"phpstan/phpstan": "2.1.11",
|
||||||
"phpstan/phpstan-phpunit": "^2.0.0",
|
"phpstan/phpstan-phpunit": "^2.0.0",
|
||||||
"phpstan/phpstan-strict-rules": "^2.0.0",
|
"phpstan/phpstan-strict-rules": "^2.0.0",
|
||||||
"phpunit/phpunit": "^10.5.24"
|
"phpunit/phpunit": "^10.5.24"
|
||||||
|
193
composer.lock
generated
193
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "af7547291a131bfac6d7087957601325",
|
"content-hash": "818c679a25da8e6b466bc454ad48dec3",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adhocore/json-comment",
|
"name": "adhocore/json-comment",
|
||||||
@ -67,16 +67,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
"version": "0.12.1",
|
"version": "0.12.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/brick/math.git",
|
"url": "https://github.com/brick/math.git",
|
||||||
"reference": "f510c0a40911935b77b86859eb5223d58d660df1"
|
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1",
|
"url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
|
||||||
"reference": "f510c0a40911935b77b86859eb5223d58d660df1",
|
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -85,7 +85,7 @@
|
|||||||
"require-dev": {
|
"require-dev": {
|
||||||
"php-coveralls/php-coveralls": "^2.2",
|
"php-coveralls/php-coveralls": "^2.2",
|
||||||
"phpunit/phpunit": "^10.1",
|
"phpunit/phpunit": "^10.1",
|
||||||
"vimeo/psalm": "5.16.0"
|
"vimeo/psalm": "6.8.8"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -115,7 +115,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/brick/math/issues",
|
"issues": "https://github.com/brick/math/issues",
|
||||||
"source": "https://github.com/brick/math/tree/0.12.1"
|
"source": "https://github.com/brick/math/tree/0.12.3"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -123,7 +123,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-11-29T23:19:16+00:00"
|
"time": "2025-02-28T13:11:00+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "netresearch/jsonmapper",
|
"name": "netresearch/jsonmapper",
|
||||||
@ -204,16 +204,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-data",
|
"name": "pocketmine/bedrock-data",
|
||||||
"version": "4.0.0+bedrock-1.21.60",
|
"version": "4.1.0+bedrock-1.21.70",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/BedrockData.git",
|
"url": "https://github.com/pmmp/BedrockData.git",
|
||||||
"reference": "2e5f16ec2facac653f3f894f22eb831d880ba98e"
|
"reference": "d53fe98cb3b596ac016e275df5bd5e89b04a4817"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/2e5f16ec2facac653f3f894f22eb831d880ba98e",
|
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/d53fe98cb3b596ac016e275df5bd5e89b04a4817",
|
||||||
"reference": "2e5f16ec2facac653f3f894f22eb831d880ba98e",
|
"reference": "d53fe98cb3b596ac016e275df5bd5e89b04a4817",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -224,9 +224,9 @@
|
|||||||
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
|
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/BedrockData/issues",
|
"issues": "https://github.com/pmmp/BedrockData/issues",
|
||||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.60"
|
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.70"
|
||||||
},
|
},
|
||||||
"time": "2025-02-16T15:56:56+00:00"
|
"time": "2025-03-25T19:43:31+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-item-upgrade-schema",
|
"name": "pocketmine/bedrock-item-upgrade-schema",
|
||||||
@ -256,16 +256,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/bedrock-protocol",
|
"name": "pocketmine/bedrock-protocol",
|
||||||
"version": "36.0.0+bedrock-1.21.60",
|
"version": "37.0.0+bedrock-1.21.70",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||||
"reference": "2057de319c5c551001c2a544e08d1bc7727d9963"
|
"reference": "7091dad2c12ed4a4106432df21fc698960c6be9e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/2057de319c5c551001c2a544e08d1bc7727d9963",
|
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/7091dad2c12ed4a4106432df21fc698960c6be9e",
|
||||||
"reference": "2057de319c5c551001c2a544e08d1bc7727d9963",
|
"reference": "7091dad2c12ed4a4106432df21fc698960c6be9e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -296,9 +296,9 @@
|
|||||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/36.0.0+bedrock-1.21.60"
|
"source": "https://github.com/pmmp/BedrockProtocol/tree/37.0.0+bedrock-1.21.70"
|
||||||
},
|
},
|
||||||
"time": "2025-02-16T15:59:08+00:00"
|
"time": "2025-03-27T15:19:36+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/binaryutils",
|
"name": "pocketmine/binaryutils",
|
||||||
@ -471,16 +471,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/locale-data",
|
"name": "pocketmine/locale-data",
|
||||||
"version": "2.24.0",
|
"version": "2.24.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/Language.git",
|
"url": "https://github.com/pmmp/Language.git",
|
||||||
"reference": "6ec5e92c77a2102b2692763733e4763012facae9"
|
"reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/6ec5e92c77a2102b2692763733e4763012facae9",
|
"url": "https://api.github.com/repos/pmmp/Language/zipball/2a00c44c52bce98e7a43aa31517df78cbb2ba23b",
|
||||||
"reference": "6ec5e92c77a2102b2692763733e4763012facae9",
|
"reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@ -488,9 +488,9 @@
|
|||||||
"description": "Language resources used by PocketMine-MP",
|
"description": "Language resources used by PocketMine-MP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/Language/issues",
|
"issues": "https://github.com/pmmp/Language/issues",
|
||||||
"source": "https://github.com/pmmp/Language/tree/2.24.0"
|
"source": "https://github.com/pmmp/Language/tree/2.24.2"
|
||||||
},
|
},
|
||||||
"time": "2025-02-16T20:46:34+00:00"
|
"time": "2025-04-03T01:23:27+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/log",
|
"name": "pocketmine/log",
|
||||||
@ -576,16 +576,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/nbt",
|
"name": "pocketmine/nbt",
|
||||||
"version": "1.0.1",
|
"version": "1.1.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/NBT.git",
|
"url": "https://github.com/pmmp/NBT.git",
|
||||||
"reference": "53db37487bc5ddbfbd84247966e1a073bdcfdb7d"
|
"reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/53db37487bc5ddbfbd84247966e1a073bdcfdb7d",
|
"url": "https://api.github.com/repos/pmmp/NBT/zipball/c3c7b0a7295daeaf7873d90fed5c5d10381d12e1",
|
||||||
"reference": "53db37487bc5ddbfbd84247966e1a073bdcfdb7d",
|
"reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -612,22 +612,22 @@
|
|||||||
"description": "PHP library for working with Named Binary Tags",
|
"description": "PHP library for working with Named Binary Tags",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/NBT/issues",
|
"issues": "https://github.com/pmmp/NBT/issues",
|
||||||
"source": "https://github.com/pmmp/NBT/tree/1.0.1"
|
"source": "https://github.com/pmmp/NBT/tree/1.1.1"
|
||||||
},
|
},
|
||||||
"time": "2025-01-07T22:47:46+00:00"
|
"time": "2025-03-09T01:46:03+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/raklib",
|
"name": "pocketmine/raklib",
|
||||||
"version": "1.1.1",
|
"version": "1.1.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/RakLib.git",
|
"url": "https://github.com/pmmp/RakLib.git",
|
||||||
"reference": "be2783be516bf6e2872ff5c81fb9048596617b97"
|
"reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/be2783be516bf6e2872ff5c81fb9048596617b97",
|
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/4145a31cd812fe8931c3c9c691fcd2ded2f47e7f",
|
||||||
"reference": "be2783be516bf6e2872ff5c81fb9048596617b97",
|
"reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -639,8 +639,8 @@
|
|||||||
"pocketmine/log": "^0.3.0 || ^0.4.0"
|
"pocketmine/log": "^0.3.0 || ^0.4.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "1.10.1",
|
"phpstan/phpstan": "2.1.0",
|
||||||
"phpstan/phpstan-strict-rules": "^1.0"
|
"phpstan/phpstan-strict-rules": "^2.0"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -655,9 +655,9 @@
|
|||||||
"description": "A RakNet server implementation written in PHP",
|
"description": "A RakNet server implementation written in PHP",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pmmp/RakLib/issues",
|
"issues": "https://github.com/pmmp/RakLib/issues",
|
||||||
"source": "https://github.com/pmmp/RakLib/tree/1.1.1"
|
"source": "https://github.com/pmmp/RakLib/tree/1.1.2"
|
||||||
},
|
},
|
||||||
"time": "2024-03-04T14:02:14+00:00"
|
"time": "2025-04-06T03:38:21+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/raklib-ipc",
|
"name": "pocketmine/raklib-ipc",
|
||||||
@ -742,16 +742,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ramsey/collection",
|
"name": "ramsey/collection",
|
||||||
"version": "2.0.0",
|
"version": "2.1.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ramsey/collection.git",
|
"url": "https://github.com/ramsey/collection.git",
|
||||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
|
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
"url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2",
|
||||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -759,25 +759,22 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"captainhook/plugin-composer": "^5.3",
|
"captainhook/plugin-composer": "^5.3",
|
||||||
"ergebnis/composer-normalize": "^2.28.3",
|
"ergebnis/composer-normalize": "^2.45",
|
||||||
"fakerphp/faker": "^1.21",
|
"fakerphp/faker": "^1.24",
|
||||||
"hamcrest/hamcrest-php": "^2.0",
|
"hamcrest/hamcrest-php": "^2.0",
|
||||||
"jangregor/phpstan-prophecy": "^1.0",
|
"jangregor/phpstan-prophecy": "^2.1",
|
||||||
"mockery/mockery": "^1.5",
|
"mockery/mockery": "^1.6",
|
||||||
"php-parallel-lint/php-console-highlighter": "^1.0",
|
"php-parallel-lint/php-console-highlighter": "^1.0",
|
||||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
"php-parallel-lint/php-parallel-lint": "^1.4",
|
||||||
"phpcsstandards/phpcsutils": "^1.0.0-rc1",
|
"phpspec/prophecy-phpunit": "^2.3",
|
||||||
"phpspec/prophecy-phpunit": "^2.0",
|
"phpstan/extension-installer": "^1.4",
|
||||||
"phpstan/extension-installer": "^1.2",
|
"phpstan/phpstan": "^2.1",
|
||||||
"phpstan/phpstan": "^1.9",
|
"phpstan/phpstan-mockery": "^2.0",
|
||||||
"phpstan/phpstan-mockery": "^1.1",
|
"phpstan/phpstan-phpunit": "^2.0",
|
||||||
"phpstan/phpstan-phpunit": "^1.3",
|
"phpunit/phpunit": "^10.5",
|
||||||
"phpunit/phpunit": "^9.5",
|
"ramsey/coding-standard": "^2.3",
|
||||||
"psalm/plugin-mockery": "^1.1",
|
"ramsey/conventional-commits": "^1.6",
|
||||||
"psalm/plugin-phpunit": "^0.18.4",
|
"roave/security-advisories": "dev-latest"
|
||||||
"ramsey/coding-standard": "^2.0.3",
|
|
||||||
"ramsey/conventional-commits": "^1.3",
|
|
||||||
"vimeo/psalm": "^5.4"
|
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
@ -815,19 +812,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/ramsey/collection/issues",
|
"issues": "https://github.com/ramsey/collection/issues",
|
||||||
"source": "https://github.com/ramsey/collection/tree/2.0.0"
|
"source": "https://github.com/ramsey/collection/tree/2.1.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"time": "2025-03-22T05:38:12+00:00"
|
||||||
{
|
|
||||||
"url": "https://github.com/ramsey",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/ramsey/collection",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2022-12-31T21:50:55+00:00"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ramsey/uuid",
|
"name": "ramsey/uuid",
|
||||||
@ -1150,16 +1137,16 @@
|
|||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "myclabs/deep-copy",
|
"name": "myclabs/deep-copy",
|
||||||
"version": "1.12.1",
|
"version": "1.13.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||||
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
|
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
|
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
|
||||||
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
|
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1198,7 +1185,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
|
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1206,7 +1193,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-11-08T17:47:46+00:00"
|
"time": "2025-02-12T12:17:51+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nikic/php-parser",
|
"name": "nikic/php-parser",
|
||||||
@ -1386,16 +1373,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan",
|
"name": "phpstan/phpstan",
|
||||||
"version": "2.1.4",
|
"version": "2.1.11",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpstan.git",
|
"url": "https://github.com/phpstan/phpstan.git",
|
||||||
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a"
|
"reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f99e18eb775dbaf6460c95fa0b65312da9c746a",
|
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8ca5f79a8f63c49b2359065832a654e1ec70ac30",
|
||||||
"reference": "8f99e18eb775dbaf6460c95fa0b65312da9c746a",
|
"reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1440,20 +1427,20 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-02-10T08:25:21+00:00"
|
"time": "2025-03-24T13:45:00+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan-phpunit",
|
"name": "phpstan/phpstan-phpunit",
|
||||||
"version": "2.0.4",
|
"version": "2.0.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||||
"reference": "d09e152f403c843998d7a52b5d87040c937525dd"
|
"reference": "6b92469f8a7995e626da3aa487099617b8dfa260"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d09e152f403c843998d7a52b5d87040c937525dd",
|
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6b92469f8a7995e626da3aa487099617b8dfa260",
|
||||||
"reference": "d09e152f403c843998d7a52b5d87040c937525dd",
|
"reference": "6b92469f8a7995e626da3aa487099617b8dfa260",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1464,7 +1451,9 @@
|
|||||||
"phpunit/phpunit": "<7.0"
|
"phpunit/phpunit": "<7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"nikic/php-parser": "^5",
|
||||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||||
|
"phpstan/phpstan-deprecation-rules": "^2.0",
|
||||||
"phpstan/phpstan-strict-rules": "^2.0",
|
"phpstan/phpstan-strict-rules": "^2.0",
|
||||||
"phpunit/phpunit": "^9.6"
|
"phpunit/phpunit": "^9.6"
|
||||||
},
|
},
|
||||||
@ -1489,22 +1478,22 @@
|
|||||||
"description": "PHPUnit extensions and rules for PHPStan",
|
"description": "PHPUnit extensions and rules for PHPStan",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
||||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.4"
|
"source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.6"
|
||||||
},
|
},
|
||||||
"time": "2025-01-22T13:07:38+00:00"
|
"time": "2025-03-26T12:47:06+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan-strict-rules",
|
"name": "phpstan/phpstan-strict-rules",
|
||||||
"version": "2.0.3",
|
"version": "2.0.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||||
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba"
|
"reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/8b88b5f818bfa301e0c99154ab622dace071c3ba",
|
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
|
||||||
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba",
|
"reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1537,9 +1526,9 @@
|
|||||||
"description": "Extra strict and opinionated rules for PHPStan",
|
"description": "Extra strict and opinionated rules for PHPStan",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
||||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.3"
|
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.4"
|
||||||
},
|
},
|
||||||
"time": "2025-01-21T10:52:14+00:00"
|
"time": "2025-03-18T11:42:40+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
@ -1864,16 +1853,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "10.5.44",
|
"version": "10.5.45",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "1381c62769be4bb88fa4c5aec1366c7c66ca4f36"
|
"reference": "bd68a781d8e30348bc297449f5234b3458267ae8"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1381c62769be4bb88fa4c5aec1366c7c66ca4f36",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8",
|
||||||
"reference": "1381c62769be4bb88fa4c5aec1366c7c66ca4f36",
|
"reference": "bd68a781d8e30348bc297449f5234b3458267ae8",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1945,7 +1934,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.44"
|
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1961,7 +1950,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-01-31T07:00:38+00:00"
|
"time": "2025-02-06T16:08:12+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/cli-parser",
|
"name": "sebastian/cli-parser",
|
||||||
|
@ -11,8 +11,10 @@ includes:
|
|||||||
|
|
||||||
rules:
|
rules:
|
||||||
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
|
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
|
||||||
|
- pocketmine\phpstan\rules\DisallowDynamicNewRule
|
||||||
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
|
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
|
||||||
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
|
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
|
||||||
|
- pocketmine\phpstan\rules\ExplodeLimitRule
|
||||||
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
|
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
|
||||||
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
|
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ use function hrtime;
|
|||||||
use function max;
|
use function max;
|
||||||
use function min;
|
use function min;
|
||||||
use function number_format;
|
use function number_format;
|
||||||
|
use function sprintf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows threads to manually trigger the cyclic garbage collector using a threshold like PHP's own garbage collector,
|
* Allows threads to manually trigger the cyclic garbage collector using a threshold like PHP's own garbage collector,
|
||||||
@ -48,6 +49,7 @@ final class GarbageCollectorManager{
|
|||||||
|
|
||||||
private int $threshold = self::GC_THRESHOLD_DEFAULT;
|
private int $threshold = self::GC_THRESHOLD_DEFAULT;
|
||||||
private int $collectionTimeTotalNs = 0;
|
private int $collectionTimeTotalNs = 0;
|
||||||
|
private int $runs = 0;
|
||||||
|
|
||||||
private \Logger $logger;
|
private \Logger $logger;
|
||||||
private TimingsHandler $timings;
|
private TimingsHandler $timings;
|
||||||
@ -96,7 +98,16 @@ final class GarbageCollectorManager{
|
|||||||
|
|
||||||
$time = $end - $start;
|
$time = $end - $start;
|
||||||
$this->collectionTimeTotalNs += $time;
|
$this->collectionTimeTotalNs += $time;
|
||||||
$this->logger->debug("gc_collect_cycles: " . number_format($time) . " ns ($rootsBefore -> $rootsAfter roots, $cycles cycles collected) - total GC time: " . number_format($this->collectionTimeTotalNs) . " ns");
|
$this->runs++;
|
||||||
|
$this->logger->info(sprintf(
|
||||||
|
"Run #%d took %s ms (%s -> %s roots, %s cycles collected) - cumulative GC time: %s ms",
|
||||||
|
$this->runs,
|
||||||
|
number_format($time / 1_000_000, 2),
|
||||||
|
$rootsBefore,
|
||||||
|
$rootsAfter,
|
||||||
|
$cycles,
|
||||||
|
number_format($this->collectionTimeTotalNs / 1_000_000, 2)
|
||||||
|
));
|
||||||
|
|
||||||
return $cycles;
|
return $cycles;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ JIT_WARNING
|
|||||||
$composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp');
|
$composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp');
|
||||||
if($composerGitHash !== null){
|
if($composerGitHash !== null){
|
||||||
//we can't verify dependency versions if we were installed without using git
|
//we can't verify dependency versions if we were installed without using git
|
||||||
$currentGitHash = explode("-", VersionInfo::GIT_HASH())[0];
|
$currentGitHash = explode("-", VersionInfo::GIT_HASH(), 2)[0];
|
||||||
if($currentGitHash !== $composerGitHash){
|
if($currentGitHash !== $composerGitHash){
|
||||||
critical_error("Composer dependencies and/or autoloader are out of sync.");
|
critical_error("Composer dependencies and/or autoloader are out of sync.");
|
||||||
critical_error("- Current revision is $currentGitHash");
|
critical_error("- Current revision is $currentGitHash");
|
||||||
|
@ -699,7 +699,7 @@ class Server{
|
|||||||
|
|
||||||
public function removeOp(string $name) : void{
|
public function removeOp(string $name) : void{
|
||||||
$lowercaseName = strtolower($name);
|
$lowercaseName = strtolower($name);
|
||||||
foreach($this->operators->getAll() as $operatorName => $_){
|
foreach(Utils::promoteKeys($this->operators->getAll()) as $operatorName => $_){
|
||||||
$operatorName = (string) $operatorName;
|
$operatorName = (string) $operatorName;
|
||||||
if($lowercaseName === strtolower($operatorName)){
|
if($lowercaseName === strtolower($operatorName)){
|
||||||
$this->operators->remove($operatorName);
|
$this->operators->remove($operatorName);
|
||||||
|
@ -31,8 +31,8 @@ use function str_repeat;
|
|||||||
|
|
||||||
final class VersionInfo{
|
final class VersionInfo{
|
||||||
public const NAME = "PocketMine-MP";
|
public const NAME = "PocketMine-MP";
|
||||||
public const BASE_VERSION = "5.25.0";
|
public const BASE_VERSION = "5.27.2";
|
||||||
public const IS_DEVELOPMENT_BUILD = false;
|
public const IS_DEVELOPMENT_BUILD = true;
|
||||||
public const BUILD_CHANNEL = "stable";
|
public const BUILD_CHANNEL = "stable";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,7 +154,7 @@ class BlockBreakInfo{
|
|||||||
|
|
||||||
$efficiency = $item->getMiningEfficiency(($this->toolType & $item->getBlockToolType()) !== 0);
|
$efficiency = $item->getMiningEfficiency(($this->toolType & $item->getBlockToolType()) !== 0);
|
||||||
if($efficiency <= 0){
|
if($efficiency <= 0){
|
||||||
throw new \InvalidArgumentException(get_class($item) . " has invalid mining efficiency: expected >= 0, got $efficiency");
|
throw new \InvalidArgumentException(get_class($item) . " must have a positive mining efficiency, but got $efficiency");
|
||||||
}
|
}
|
||||||
|
|
||||||
$base /= $efficiency;
|
$base /= $efficiency;
|
||||||
|
@ -34,11 +34,16 @@ use function mt_rand;
|
|||||||
final class ChorusPlant extends Flowable{
|
final class ChorusPlant extends Flowable{
|
||||||
use StaticSupportTrait;
|
use StaticSupportTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var true[]
|
||||||
|
* @phpstan-var array<int, true>
|
||||||
|
*/
|
||||||
|
protected array $connections = [];
|
||||||
|
|
||||||
protected function recalculateCollisionBoxes() : array{
|
protected function recalculateCollisionBoxes() : array{
|
||||||
$bb = AxisAlignedBB::one();
|
$bb = AxisAlignedBB::one();
|
||||||
foreach($this->getAllSides() as $facing => $block){
|
foreach(Facing::ALL as $facing){
|
||||||
$id = $block->getTypeId();
|
if(!isset($this->connections[$facing])){
|
||||||
if($id !== BlockTypeIds::END_STONE && $id !== BlockTypeIds::CHORUS_FLOWER && !$block->hasSameTypeId($this)){
|
|
||||||
$bb->trim($facing, 2 / 16);
|
$bb->trim($facing, 2 / 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,6 +51,26 @@ final class ChorusPlant extends Flowable{
|
|||||||
return [$bb];
|
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{
|
private function canBeSupportedBy(Block $block) : bool{
|
||||||
return $block->hasSameTypeId($this) || $block->getTypeId() === BlockTypeIds::END_STONE;
|
return $block->hasSameTypeId($this) || $block->getTypeId() === BlockTypeIds::END_STONE;
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ use pocketmine\block\BlockIdentifier as BID;
|
|||||||
use pocketmine\utils\AssumptionFailedError;
|
use pocketmine\utils\AssumptionFailedError;
|
||||||
use pocketmine\utils\SingletonTrait;
|
use pocketmine\utils\SingletonTrait;
|
||||||
use pocketmine\world\light\LightUpdate;
|
use pocketmine\world\light\LightUpdate;
|
||||||
|
use function count;
|
||||||
use function min;
|
use function min;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,6 +41,11 @@ use function min;
|
|||||||
class RuntimeBlockStateRegistry{
|
class RuntimeBlockStateRegistry{
|
||||||
use SingletonTrait;
|
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[]
|
* @var Block[]
|
||||||
* @phpstan-var array<int, Block>
|
* @phpstan-var array<int, Block>
|
||||||
@ -74,6 +80,13 @@ class RuntimeBlockStateRegistry{
|
|||||||
*/
|
*/
|
||||||
public array $blastResistance = [];
|
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(){
|
public function __construct(){
|
||||||
foreach(VanillaBlocks::getAll() as $block){
|
foreach(VanillaBlocks::getAll() as $block){
|
||||||
$this->register($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{
|
private function fillStaticArrays(int $index, Block $block) : void{
|
||||||
$fullId = $block->getStateId();
|
$fullId = $block->getStateId();
|
||||||
if($index !== $fullId){
|
if($index !== $fullId){
|
||||||
@ -112,6 +189,8 @@ class RuntimeBlockStateRegistry{
|
|||||||
if($block->blocksDirectSkyLight()){
|
if($block->blocksDirectSkyLight()){
|
||||||
$this->blocksDirectSkyLight[$index] = true;
|
$this->blocksDirectSkyLight[$index] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->collisionInfo[$index] = self::calculateCollisionInfo($block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +209,10 @@ class RuntimeBlockStateRegistry{
|
|||||||
return $block;
|
return $block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasStateId(int $stateId) : bool{
|
||||||
|
return isset($this->fullList[$stateId]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Block[]
|
* @return Block[]
|
||||||
* @phpstan-return array<int, Block>
|
* @phpstan-return array<int, Block>
|
||||||
|
@ -62,9 +62,10 @@ class Sign extends Spawnable{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string[]
|
* @return string[]
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
public static function fixTextBlob(string $blob) : array{
|
public static function fixTextBlob(string $blob) : array{
|
||||||
return array_slice(array_pad(explode("\n", $blob), 4, ""), 0, 4);
|
return array_slice(array_pad(explode("\n", $blob, limit: 5), 4, ""), 0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SignText $text;
|
protected SignText $text;
|
||||||
|
@ -30,9 +30,15 @@ interface CopperMaterial{
|
|||||||
|
|
||||||
public function getOxidation() : CopperOxidation;
|
public function getOxidation() : CopperOxidation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
public function setOxidation(CopperOxidation $oxidation) : CopperMaterial;
|
public function setOxidation(CopperOxidation $oxidation) : CopperMaterial;
|
||||||
|
|
||||||
public function isWaxed() : bool;
|
public function isWaxed() : bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
public function setWaxed(bool $waxed) : CopperMaterial;
|
public function setWaxed(bool $waxed) : CopperMaterial;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ class SignText{
|
|||||||
* @throws \InvalidArgumentException if the text is not valid UTF-8
|
* @throws \InvalidArgumentException if the text is not valid UTF-8
|
||||||
*/
|
*/
|
||||||
public static function fromBlob(string $blob, ?Color $baseColor = null, bool $glowing = false) : SignText{
|
public static function fromBlob(string $blob, ?Color $baseColor = null, bool $glowing = false) : SignText{
|
||||||
return new self(array_slice(array_pad(explode("\n", $blob), self::LINE_COUNT, ""), 0, self::LINE_COUNT), $baseColor, $glowing);
|
return new self(array_slice(array_pad(explode("\n", $blob, limit: self::LINE_COUNT + 1), self::LINE_COUNT, ""), 0, self::LINE_COUNT), $baseColor, $glowing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,6 +37,7 @@ use function array_values;
|
|||||||
use function explode;
|
use function explode;
|
||||||
use function implode;
|
use function implode;
|
||||||
use function str_replace;
|
use function str_replace;
|
||||||
|
use const PHP_INT_MAX;
|
||||||
|
|
||||||
abstract class Command{
|
abstract class Command{
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ abstract class Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function setPermission(?string $permission) : void{
|
public function setPermission(?string $permission) : void{
|
||||||
$this->setPermissions($permission === null ? [] : explode(";", $permission));
|
$this->setPermissions($permission === null ? [] : explode(";", $permission, limit: PHP_INT_MAX));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testPermission(CommandSender $target, ?string $permission = null) : bool{
|
public function testPermission(CommandSender $target, ?string $permission = null) : bool{
|
||||||
|
@ -39,6 +39,7 @@ use function ksort;
|
|||||||
use function min;
|
use function min;
|
||||||
use function sort;
|
use function sort;
|
||||||
use function strtolower;
|
use function strtolower;
|
||||||
|
use const PHP_INT_MAX;
|
||||||
use const SORT_FLAG_CASE;
|
use const SORT_FLAG_CASE;
|
||||||
use const SORT_NATURAL;
|
use const SORT_NATURAL;
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ class HelpCommand extends VanillaCommand{
|
|||||||
|
|
||||||
$usage = $cmd->getUsage();
|
$usage = $cmd->getUsage();
|
||||||
$usageString = $usage instanceof Translatable ? $lang->translate($usage) : $usage;
|
$usageString = $usage instanceof Translatable ? $lang->translate($usage) : $usage;
|
||||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_usage(TextFormat::RESET . implode("\n" . TextFormat::RESET, explode("\n", $usageString)))
|
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_usage(TextFormat::RESET . implode("\n" . TextFormat::RESET, explode("\n", $usageString, limit: PHP_INT_MAX)))
|
||||||
->prefix(TextFormat::GOLD));
|
->prefix(TextFormat::GOLD));
|
||||||
|
|
||||||
$aliases = $cmd->getAliases();
|
$aliases = $cmd->getAliases();
|
||||||
|
@ -219,7 +219,11 @@ class ParticleCommand extends VanillaCommand{
|
|||||||
break;
|
break;
|
||||||
case "blockdust":
|
case "blockdust":
|
||||||
if($data !== null){
|
if($data !== null){
|
||||||
$d = explode("_", $data);
|
//to preserve the old unlimited explode behaviour, allow this to split into at most 5 parts
|
||||||
|
//this allows the 4th argument to be processed normally if given without forcing it to also consume
|
||||||
|
//any unexpected parts
|
||||||
|
//we probably ought to error in this case, but this will do for now
|
||||||
|
$d = explode("_", $data, limit: 5);
|
||||||
if(count($d) >= 3){
|
if(count($d) >= 3){
|
||||||
return new DustParticle(new Color(
|
return new DustParticle(new Color(
|
||||||
((int) $d[0]) & 0xff,
|
((int) $d[0]) & 0xff,
|
||||||
|
@ -62,7 +62,7 @@ class ConsoleCommandSender implements CommandSender{
|
|||||||
$message = $this->getLanguage()->translate($message);
|
$message = $this->getLanguage()->translate($message);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(explode("\n", trim($message)) as $line){
|
foreach(explode("\n", trim($message), limit: PHP_INT_MAX) as $line){
|
||||||
Terminal::writeLine(TextFormat::GREEN . "Command output | " . TextFormat::addBase(TextFormat::WHITE, $line));
|
Terminal::writeLine(TextFormat::GREEN . "Command output | " . TextFormat::addBase(TextFormat::WHITE, $line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,12 @@ use pocketmine\nbt\TreeRoot;
|
|||||||
use pocketmine\utils\BinaryStream;
|
use pocketmine\utils\BinaryStream;
|
||||||
use pocketmine\utils\DestructorCallbackTrait;
|
use pocketmine\utils\DestructorCallbackTrait;
|
||||||
use pocketmine\utils\ObjectSet;
|
use pocketmine\utils\ObjectSet;
|
||||||
|
use function array_shift;
|
||||||
|
use function count;
|
||||||
|
use function implode;
|
||||||
|
use function ksort;
|
||||||
use function spl_object_id;
|
use function spl_object_id;
|
||||||
use function usort;
|
use const SORT_STRING;
|
||||||
|
|
||||||
class CraftingManager{
|
class CraftingManager{
|
||||||
use DestructorCallbackTrait;
|
use DestructorCallbackTrait;
|
||||||
@ -100,6 +104,7 @@ class CraftingManager{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Function used to arrange Shapeless Recipe ingredient lists into a consistent order.
|
* Function used to arrange Shapeless Recipe ingredient lists into a consistent order.
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
public static function sort(Item $i1, Item $i2) : int{
|
public static function sort(Item $i1, Item $i2) : int{
|
||||||
//Use spaceship operator to compare each property, then try the next one if they are equivalent.
|
//Use spaceship operator to compare each property, then try the next one if they are equivalent.
|
||||||
@ -108,45 +113,30 @@ class CraftingManager{
|
|||||||
return $retval;
|
return $retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static function hashOutput(Item $output) : string{
|
||||||
* @param Item[] $items
|
$write = new BinaryStream();
|
||||||
*
|
$write->putVarInt($output->getStateId());
|
||||||
* @return Item[]
|
$write->put((new LittleEndianNbtSerializer())->write(new TreeRoot($output->getNamedTag())));
|
||||||
* @phpstan-return list<Item>
|
|
||||||
*/
|
|
||||||
private static function pack(array $items) : array{
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach($items as $item){
|
return $write->getBuffer();
|
||||||
foreach($result as $otherItem){
|
|
||||||
if($item->canStackWith($otherItem)){
|
|
||||||
$otherItem->setCount($otherItem->getCount() + $item->getCount());
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//No matching item found
|
|
||||||
$result[] = clone $item;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Item[] $outputs
|
* @param Item[] $outputs
|
||||||
*/
|
*/
|
||||||
private static function hashOutputs(array $outputs) : string{
|
private static function hashOutputs(array $outputs) : string{
|
||||||
$outputs = self::pack($outputs);
|
if(count($outputs) === 1){
|
||||||
usort($outputs, [self::class, "sort"]);
|
return self::hashOutput(array_shift($outputs));
|
||||||
$result = new BinaryStream();
|
}
|
||||||
|
$unique = [];
|
||||||
foreach($outputs as $o){
|
foreach($outputs as $o){
|
||||||
//count is not written because the outputs might be from multiple repetitions of a single recipe
|
//count is not written because the outputs might be from multiple repetitions of a single recipe
|
||||||
//this reduces the accuracy of the hash, but it won't matter in most cases.
|
//this reduces the accuracy of the hash, but it won't matter in most cases.
|
||||||
$result->putVarInt($o->getStateId());
|
$hash = self::hashOutput($o);
|
||||||
$result->put((new LittleEndianNbtSerializer())->write(new TreeRoot($o->getNamedTag())));
|
$unique[$hash] = $hash;
|
||||||
}
|
}
|
||||||
|
ksort($unique, SORT_STRING);
|
||||||
return $result->getBuffer();
|
return implode("", $unique);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,6 +97,7 @@ class ShapedRecipe implements CraftingRecipe{
|
|||||||
|
|
||||||
$this->shape = $shape;
|
$this->shape = $shape;
|
||||||
|
|
||||||
|
Utils::validateArrayValueType($ingredients, function(RecipeIngredient $_) : void{});
|
||||||
foreach(Utils::stringifyKeys($ingredients) as $char => $i){
|
foreach(Utils::stringifyKeys($ingredients) as $char => $i){
|
||||||
if(!str_contains(implode($this->shape), $char)){
|
if(!str_contains(implode($this->shape), $char)){
|
||||||
throw new \InvalidArgumentException("Symbol '$char' does not appear in the recipe shape");
|
throw new \InvalidArgumentException("Symbol '$char' does not appear in the recipe shape");
|
||||||
@ -105,6 +106,7 @@ class ShapedRecipe implements CraftingRecipe{
|
|||||||
$this->ingredientList[$char] = clone $i;
|
$this->ingredientList[$char] = clone $i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utils::validateArrayValueType($results, function(Item $_) : void{});
|
||||||
$this->results = Utils::cloneObjectArray($results);
|
$this->results = Utils::cloneObjectArray($results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,9 @@ class ShapelessRecipe implements CraftingRecipe{
|
|||||||
if(count($ingredients) > 9){
|
if(count($ingredients) > 9){
|
||||||
throw new \InvalidArgumentException("Shapeless recipes cannot have more than 9 ingredients");
|
throw new \InvalidArgumentException("Shapeless recipes cannot have more than 9 ingredients");
|
||||||
}
|
}
|
||||||
|
Utils::validateArrayValueType($ingredients, function(RecipeIngredient $_) : void{});
|
||||||
$this->ingredients = $ingredients;
|
$this->ingredients = $ingredients;
|
||||||
|
Utils::validateArrayValueType($results, function(Item $_) : void{});
|
||||||
$this->results = Utils::cloneObjectArray($results);
|
$this->results = Utils::cloneObjectArray($results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,8 +45,8 @@ final class BlockStateData{
|
|||||||
public const CURRENT_VERSION =
|
public const CURRENT_VERSION =
|
||||||
(1 << 24) | //major
|
(1 << 24) | //major
|
||||||
(21 << 16) | //minor
|
(21 << 16) | //minor
|
||||||
(60 << 8) | //patch
|
(70 << 8) | //patch
|
||||||
(33); //revision
|
(1); //revision
|
||||||
|
|
||||||
public const TAG_NAME = "name";
|
public const TAG_NAME = "name";
|
||||||
public const TAG_STATES = "states";
|
public const TAG_STATES = "states";
|
||||||
|
@ -175,7 +175,9 @@ final class BlockTypeNames{
|
|||||||
public const BUBBLE_CORAL_FAN = "minecraft:bubble_coral_fan";
|
public const BUBBLE_CORAL_FAN = "minecraft:bubble_coral_fan";
|
||||||
public const BUBBLE_CORAL_WALL_FAN = "minecraft:bubble_coral_wall_fan";
|
public const BUBBLE_CORAL_WALL_FAN = "minecraft:bubble_coral_wall_fan";
|
||||||
public const BUDDING_AMETHYST = "minecraft:budding_amethyst";
|
public const BUDDING_AMETHYST = "minecraft:budding_amethyst";
|
||||||
|
public const BUSH = "minecraft:bush";
|
||||||
public const CACTUS = "minecraft:cactus";
|
public const CACTUS = "minecraft:cactus";
|
||||||
|
public const CACTUS_FLOWER = "minecraft:cactus_flower";
|
||||||
public const CAKE = "minecraft:cake";
|
public const CAKE = "minecraft:cake";
|
||||||
public const CALCITE = "minecraft:calcite";
|
public const CALCITE = "minecraft:calcite";
|
||||||
public const CALIBRATED_SCULK_SENSOR = "minecraft:calibrated_sculk_sensor";
|
public const CALIBRATED_SCULK_SENSOR = "minecraft:calibrated_sculk_sensor";
|
||||||
@ -545,6 +547,7 @@ final class BlockTypeNames{
|
|||||||
public const FIRE_CORAL_BLOCK = "minecraft:fire_coral_block";
|
public const FIRE_CORAL_BLOCK = "minecraft:fire_coral_block";
|
||||||
public const FIRE_CORAL_FAN = "minecraft:fire_coral_fan";
|
public const FIRE_CORAL_FAN = "minecraft:fire_coral_fan";
|
||||||
public const FIRE_CORAL_WALL_FAN = "minecraft:fire_coral_wall_fan";
|
public const FIRE_CORAL_WALL_FAN = "minecraft:fire_coral_wall_fan";
|
||||||
|
public const FIREFLY_BUSH = "minecraft:firefly_bush";
|
||||||
public const FLETCHING_TABLE = "minecraft:fletching_table";
|
public const FLETCHING_TABLE = "minecraft:fletching_table";
|
||||||
public const FLOWER_POT = "minecraft:flower_pot";
|
public const FLOWER_POT = "minecraft:flower_pot";
|
||||||
public const FLOWERING_AZALEA = "minecraft:flowering_azalea";
|
public const FLOWERING_AZALEA = "minecraft:flowering_azalea";
|
||||||
@ -685,6 +688,7 @@ final class BlockTypeNames{
|
|||||||
public const LARGE_AMETHYST_BUD = "minecraft:large_amethyst_bud";
|
public const LARGE_AMETHYST_BUD = "minecraft:large_amethyst_bud";
|
||||||
public const LARGE_FERN = "minecraft:large_fern";
|
public const LARGE_FERN = "minecraft:large_fern";
|
||||||
public const LAVA = "minecraft:lava";
|
public const LAVA = "minecraft:lava";
|
||||||
|
public const LEAF_LITTER = "minecraft:leaf_litter";
|
||||||
public const LECTERN = "minecraft:lectern";
|
public const LECTERN = "minecraft:lectern";
|
||||||
public const LEVER = "minecraft:lever";
|
public const LEVER = "minecraft:lever";
|
||||||
public const LIGHT_BLOCK_0 = "minecraft:light_block_0";
|
public const LIGHT_BLOCK_0 = "minecraft:light_block_0";
|
||||||
@ -1043,6 +1047,7 @@ final class BlockTypeNames{
|
|||||||
public const SEA_LANTERN = "minecraft:sea_lantern";
|
public const SEA_LANTERN = "minecraft:sea_lantern";
|
||||||
public const SEA_PICKLE = "minecraft:sea_pickle";
|
public const SEA_PICKLE = "minecraft:sea_pickle";
|
||||||
public const SEAGRASS = "minecraft:seagrass";
|
public const SEAGRASS = "minecraft:seagrass";
|
||||||
|
public const SHORT_DRY_GRASS = "minecraft:short_dry_grass";
|
||||||
public const SHORT_GRASS = "minecraft:short_grass";
|
public const SHORT_GRASS = "minecraft:short_grass";
|
||||||
public const SHROOMLIGHT = "minecraft:shroomlight";
|
public const SHROOMLIGHT = "minecraft:shroomlight";
|
||||||
public const SILVER_GLAZED_TERRACOTTA = "minecraft:silver_glazed_terracotta";
|
public const SILVER_GLAZED_TERRACOTTA = "minecraft:silver_glazed_terracotta";
|
||||||
@ -1140,6 +1145,7 @@ final class BlockTypeNames{
|
|||||||
public const SUSPICIOUS_GRAVEL = "minecraft:suspicious_gravel";
|
public const SUSPICIOUS_GRAVEL = "minecraft:suspicious_gravel";
|
||||||
public const SUSPICIOUS_SAND = "minecraft:suspicious_sand";
|
public const SUSPICIOUS_SAND = "minecraft:suspicious_sand";
|
||||||
public const SWEET_BERRY_BUSH = "minecraft:sweet_berry_bush";
|
public const SWEET_BERRY_BUSH = "minecraft:sweet_berry_bush";
|
||||||
|
public const TALL_DRY_GRASS = "minecraft:tall_dry_grass";
|
||||||
public const TALL_GRASS = "minecraft:tall_grass";
|
public const TALL_GRASS = "minecraft:tall_grass";
|
||||||
public const TARGET = "minecraft:target";
|
public const TARGET = "minecraft:target";
|
||||||
public const TINTED_GLASS = "minecraft:tinted_glass";
|
public const TINTED_GLASS = "minecraft:tinted_glass";
|
||||||
@ -1267,6 +1273,7 @@ final class BlockTypeNames{
|
|||||||
public const WHITE_TERRACOTTA = "minecraft:white_terracotta";
|
public const WHITE_TERRACOTTA = "minecraft:white_terracotta";
|
||||||
public const WHITE_TULIP = "minecraft:white_tulip";
|
public const WHITE_TULIP = "minecraft:white_tulip";
|
||||||
public const WHITE_WOOL = "minecraft:white_wool";
|
public const WHITE_WOOL = "minecraft:white_wool";
|
||||||
|
public const WILDFLOWERS = "minecraft:wildflowers";
|
||||||
public const WITHER_ROSE = "minecraft:wither_rose";
|
public const WITHER_ROSE = "minecraft:wither_rose";
|
||||||
public const WITHER_SKELETON_SKULL = "minecraft:wither_skeleton_skull";
|
public const WITHER_SKELETON_SKULL = "minecraft:wither_skeleton_skull";
|
||||||
public const WOODEN_BUTTON = "minecraft:wooden_button";
|
public const WOODEN_BUTTON = "minecraft:wooden_button";
|
||||||
|
@ -214,6 +214,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
|||||||
$this->registerLeavesSerializers();
|
$this->registerLeavesSerializers();
|
||||||
$this->registerSaplingSerializers();
|
$this->registerSaplingSerializers();
|
||||||
$this->registerMobHeadSerializers();
|
$this->registerMobHeadSerializers();
|
||||||
|
$this->registerCopperSerializers();
|
||||||
$this->registerSimpleSerializers();
|
$this->registerSimpleSerializers();
|
||||||
$this->registerSerializers();
|
$this->registerSerializers();
|
||||||
}
|
}
|
||||||
@ -791,6 +792,178 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
|||||||
})->writeFacingWithoutDown($block->getFacing()));
|
})->writeFacingWithoutDown($block->getFacing()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function registerCopperSerializers() : void{
|
||||||
|
$this->map(Blocks::COPPER(), function(Copper $block) : Writer{
|
||||||
|
$oxidation = $block->getOxidation();
|
||||||
|
return new Writer($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) :
|
||||||
|
Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
$this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : Writer{
|
||||||
|
$oxidation = $block->getOxidation();
|
||||||
|
return new Writer($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId($oxidation,
|
||||||
|
Ids::WAXED_CHISELED_COPPER,
|
||||||
|
Ids::WAXED_EXPOSED_CHISELED_COPPER,
|
||||||
|
Ids::WAXED_WEATHERED_CHISELED_COPPER,
|
||||||
|
Ids::WAXED_OXIDIZED_CHISELED_COPPER
|
||||||
|
) :
|
||||||
|
Helper::selectCopperId($oxidation,
|
||||||
|
Ids::CHISELED_COPPER,
|
||||||
|
Ids::EXPOSED_CHISELED_COPPER,
|
||||||
|
Ids::WEATHERED_CHISELED_COPPER,
|
||||||
|
Ids::OXIDIZED_CHISELED_COPPER
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
$this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : Writer{
|
||||||
|
$oxidation = $block->getOxidation();
|
||||||
|
return new Writer($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId($oxidation,
|
||||||
|
Ids::WAXED_COPPER_GRATE,
|
||||||
|
Ids::WAXED_EXPOSED_COPPER_GRATE,
|
||||||
|
Ids::WAXED_WEATHERED_COPPER_GRATE,
|
||||||
|
Ids::WAXED_OXIDIZED_COPPER_GRATE
|
||||||
|
) :
|
||||||
|
Helper::selectCopperId($oxidation,
|
||||||
|
Ids::COPPER_GRATE,
|
||||||
|
Ids::EXPOSED_COPPER_GRATE,
|
||||||
|
Ids::WEATHERED_COPPER_GRATE,
|
||||||
|
Ids::OXIDIZED_COPPER_GRATE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
$this->map(Blocks::CUT_COPPER(), function(Copper $block) : Writer{
|
||||||
|
$oxidation = $block->getOxidation();
|
||||||
|
return new Writer($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) :
|
||||||
|
Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
$this->map(Blocks::CUT_COPPER_SLAB(), function(CopperSlab $block) : Writer{
|
||||||
|
$oxidation = $block->getOxidation();
|
||||||
|
return Helper::encodeSlab(
|
||||||
|
$block,
|
||||||
|
($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::WAXED_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB
|
||||||
|
) :
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::CUT_COPPER_SLAB,
|
||||||
|
Ids::EXPOSED_CUT_COPPER_SLAB,
|
||||||
|
Ids::WEATHERED_CUT_COPPER_SLAB,
|
||||||
|
Ids::OXIDIZED_CUT_COPPER_SLAB
|
||||||
|
)
|
||||||
|
),
|
||||||
|
($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB
|
||||||
|
) :
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
$this->map(Blocks::CUT_COPPER_STAIRS(), function(CopperStairs $block) : Writer{
|
||||||
|
$oxidation = $block->getOxidation();
|
||||||
|
return Helper::encodeStairs(
|
||||||
|
$block,
|
||||||
|
new Writer($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::WAXED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS
|
||||||
|
) :
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::CUT_COPPER_STAIRS,
|
||||||
|
Ids::EXPOSED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::WEATHERED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::OXIDIZED_CUT_COPPER_STAIRS
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
$this->map(Blocks::COPPER_BULB(), function(CopperBulb $block) : Writer{
|
||||||
|
$oxidation = $block->getOxidation();
|
||||||
|
return Writer::create($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId($oxidation,
|
||||||
|
Ids::WAXED_COPPER_BULB,
|
||||||
|
Ids::WAXED_EXPOSED_COPPER_BULB,
|
||||||
|
Ids::WAXED_WEATHERED_COPPER_BULB,
|
||||||
|
Ids::WAXED_OXIDIZED_COPPER_BULB) :
|
||||||
|
Helper::selectCopperId($oxidation,
|
||||||
|
Ids::COPPER_BULB,
|
||||||
|
Ids::EXPOSED_COPPER_BULB,
|
||||||
|
Ids::WEATHERED_COPPER_BULB,
|
||||||
|
Ids::OXIDIZED_COPPER_BULB
|
||||||
|
))
|
||||||
|
->writeBool(StateNames::LIT, $block->isLit())
|
||||||
|
->writeBool(StateNames::POWERED_BIT, $block->isPowered());
|
||||||
|
});
|
||||||
|
$this->map(Blocks::COPPER_DOOR(), function(CopperDoor $block) : Writer{
|
||||||
|
$oxidation = $block->getOxidation();
|
||||||
|
return Helper::encodeDoor(
|
||||||
|
$block,
|
||||||
|
new Writer($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::WAXED_COPPER_DOOR,
|
||||||
|
Ids::WAXED_EXPOSED_COPPER_DOOR,
|
||||||
|
Ids::WAXED_WEATHERED_COPPER_DOOR,
|
||||||
|
Ids::WAXED_OXIDIZED_COPPER_DOOR
|
||||||
|
) :
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::COPPER_DOOR,
|
||||||
|
Ids::EXPOSED_COPPER_DOOR,
|
||||||
|
Ids::WEATHERED_COPPER_DOOR,
|
||||||
|
Ids::OXIDIZED_COPPER_DOOR
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
$this->map(Blocks::COPPER_TRAPDOOR(), function(CopperTrapdoor $block) : Writer{
|
||||||
|
$oxidation = $block->getOxidation();
|
||||||
|
return Helper::encodeTrapdoor(
|
||||||
|
$block,
|
||||||
|
new Writer($block->isWaxed() ?
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::WAXED_COPPER_TRAPDOOR,
|
||||||
|
Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
|
||||||
|
Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
|
||||||
|
Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR
|
||||||
|
) :
|
||||||
|
Helper::selectCopperId(
|
||||||
|
$oxidation,
|
||||||
|
Ids::COPPER_TRAPDOOR,
|
||||||
|
Ids::EXPOSED_COPPER_TRAPDOOR,
|
||||||
|
Ids::WEATHERED_COPPER_TRAPDOOR,
|
||||||
|
Ids::OXIDIZED_COPPER_TRAPDOOR
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private function registerSimpleSerializers() : void{
|
private function registerSimpleSerializers() : void{
|
||||||
$this->mapSimple(Blocks::AIR(), Ids::AIR);
|
$this->mapSimple(Blocks::AIR(), Ids::AIR);
|
||||||
$this->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK);
|
$this->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK);
|
||||||
@ -1265,175 +1438,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
|||||||
$this->mapSlab(Blocks::COBBLESTONE_SLAB(), Ids::COBBLESTONE_SLAB, Ids::COBBLESTONE_DOUBLE_SLAB);
|
$this->mapSlab(Blocks::COBBLESTONE_SLAB(), Ids::COBBLESTONE_SLAB, Ids::COBBLESTONE_DOUBLE_SLAB);
|
||||||
$this->mapStairs(Blocks::COBBLESTONE_STAIRS(), Ids::STONE_STAIRS);
|
$this->mapStairs(Blocks::COBBLESTONE_STAIRS(), Ids::STONE_STAIRS);
|
||||||
$this->map(Blocks::COBBLESTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::COBBLESTONE_WALL)));
|
$this->map(Blocks::COBBLESTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::COBBLESTONE_WALL)));
|
||||||
$this->map(Blocks::COPPER(), function(Copper $block) : Writer{
|
|
||||||
$oxidation = $block->getOxidation();
|
|
||||||
return new Writer($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) :
|
|
||||||
Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : Writer{
|
|
||||||
$oxidation = $block->getOxidation();
|
|
||||||
return new Writer($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId($oxidation,
|
|
||||||
Ids::WAXED_CHISELED_COPPER,
|
|
||||||
Ids::WAXED_EXPOSED_CHISELED_COPPER,
|
|
||||||
Ids::WAXED_WEATHERED_CHISELED_COPPER,
|
|
||||||
Ids::WAXED_OXIDIZED_CHISELED_COPPER
|
|
||||||
) :
|
|
||||||
Helper::selectCopperId($oxidation,
|
|
||||||
Ids::CHISELED_COPPER,
|
|
||||||
Ids::EXPOSED_CHISELED_COPPER,
|
|
||||||
Ids::WEATHERED_CHISELED_COPPER,
|
|
||||||
Ids::OXIDIZED_CHISELED_COPPER
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : Writer{
|
|
||||||
$oxidation = $block->getOxidation();
|
|
||||||
return new Writer($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId($oxidation,
|
|
||||||
Ids::WAXED_COPPER_GRATE,
|
|
||||||
Ids::WAXED_EXPOSED_COPPER_GRATE,
|
|
||||||
Ids::WAXED_WEATHERED_COPPER_GRATE,
|
|
||||||
Ids::WAXED_OXIDIZED_COPPER_GRATE
|
|
||||||
) :
|
|
||||||
Helper::selectCopperId($oxidation,
|
|
||||||
Ids::COPPER_GRATE,
|
|
||||||
Ids::EXPOSED_COPPER_GRATE,
|
|
||||||
Ids::WEATHERED_COPPER_GRATE,
|
|
||||||
Ids::OXIDIZED_COPPER_GRATE
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$this->map(Blocks::CUT_COPPER(), function(Copper $block) : Writer{
|
|
||||||
$oxidation = $block->getOxidation();
|
|
||||||
return new Writer($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) :
|
|
||||||
Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$this->map(Blocks::CUT_COPPER_SLAB(), function(CopperSlab $block) : Writer{
|
|
||||||
$oxidation = $block->getOxidation();
|
|
||||||
return Helper::encodeSlab(
|
|
||||||
$block,
|
|
||||||
($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::WAXED_CUT_COPPER_SLAB,
|
|
||||||
Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
|
|
||||||
Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
|
|
||||||
Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB
|
|
||||||
) :
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::CUT_COPPER_SLAB,
|
|
||||||
Ids::EXPOSED_CUT_COPPER_SLAB,
|
|
||||||
Ids::WEATHERED_CUT_COPPER_SLAB,
|
|
||||||
Ids::OXIDIZED_CUT_COPPER_SLAB
|
|
||||||
)
|
|
||||||
),
|
|
||||||
($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
|
|
||||||
Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
|
||||||
Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
|
||||||
Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB
|
|
||||||
) :
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::DOUBLE_CUT_COPPER_SLAB,
|
|
||||||
Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
|
||||||
Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
|
||||||
Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$this->map(Blocks::CUT_COPPER_STAIRS(), function(CopperStairs $block) : Writer{
|
|
||||||
$oxidation = $block->getOxidation();
|
|
||||||
return Helper::encodeStairs(
|
|
||||||
$block,
|
|
||||||
new Writer($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::WAXED_CUT_COPPER_STAIRS,
|
|
||||||
Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
|
|
||||||
Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
|
|
||||||
Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS
|
|
||||||
) :
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::CUT_COPPER_STAIRS,
|
|
||||||
Ids::EXPOSED_CUT_COPPER_STAIRS,
|
|
||||||
Ids::WEATHERED_CUT_COPPER_STAIRS,
|
|
||||||
Ids::OXIDIZED_CUT_COPPER_STAIRS
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$this->map(Blocks::COPPER_BULB(), function(CopperBulb $block) : Writer{
|
|
||||||
$oxidation = $block->getOxidation();
|
|
||||||
return Writer::create($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId($oxidation,
|
|
||||||
Ids::WAXED_COPPER_BULB,
|
|
||||||
Ids::WAXED_EXPOSED_COPPER_BULB,
|
|
||||||
Ids::WAXED_WEATHERED_COPPER_BULB,
|
|
||||||
Ids::WAXED_OXIDIZED_COPPER_BULB) :
|
|
||||||
Helper::selectCopperId($oxidation,
|
|
||||||
Ids::COPPER_BULB,
|
|
||||||
Ids::EXPOSED_COPPER_BULB,
|
|
||||||
Ids::WEATHERED_COPPER_BULB,
|
|
||||||
Ids::OXIDIZED_COPPER_BULB
|
|
||||||
))
|
|
||||||
->writeBool(StateNames::LIT, $block->isLit())
|
|
||||||
->writeBool(StateNames::POWERED_BIT, $block->isPowered());
|
|
||||||
});
|
|
||||||
$this->map(Blocks::COPPER_DOOR(), function(CopperDoor $block) : Writer{
|
|
||||||
$oxidation = $block->getOxidation();
|
|
||||||
return Helper::encodeDoor(
|
|
||||||
$block,
|
|
||||||
new Writer($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::WAXED_COPPER_DOOR,
|
|
||||||
Ids::WAXED_EXPOSED_COPPER_DOOR,
|
|
||||||
Ids::WAXED_WEATHERED_COPPER_DOOR,
|
|
||||||
Ids::WAXED_OXIDIZED_COPPER_DOOR
|
|
||||||
) :
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::COPPER_DOOR,
|
|
||||||
Ids::EXPOSED_COPPER_DOOR,
|
|
||||||
Ids::WEATHERED_COPPER_DOOR,
|
|
||||||
Ids::OXIDIZED_COPPER_DOOR
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$this->map(Blocks::COPPER_TRAPDOOR(), function(CopperTrapdoor $block) : Writer{
|
|
||||||
$oxidation = $block->getOxidation();
|
|
||||||
return Helper::encodeTrapdoor(
|
|
||||||
$block,
|
|
||||||
new Writer($block->isWaxed() ?
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::WAXED_COPPER_TRAPDOOR,
|
|
||||||
Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
|
|
||||||
Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
|
|
||||||
Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR
|
|
||||||
) :
|
|
||||||
Helper::selectCopperId(
|
|
||||||
$oxidation,
|
|
||||||
Ids::COPPER_TRAPDOOR,
|
|
||||||
Ids::EXPOSED_COPPER_TRAPDOOR,
|
|
||||||
Ids::WEATHERED_COPPER_TRAPDOOR,
|
|
||||||
Ids::OXIDIZED_COPPER_TRAPDOOR
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
$this->map(Blocks::COCOA_POD(), function(CocoaBlock $block) : Writer{
|
$this->map(Blocks::COCOA_POD(), function(CocoaBlock $block) : Writer{
|
||||||
return Writer::create(Ids::COCOA)
|
return Writer::create(Ids::COCOA)
|
||||||
->writeInt(StateNames::AGE, $block->getAge())
|
->writeInt(StateNames::AGE, $block->getAge())
|
||||||
|
@ -126,12 +126,19 @@ final class BlockStateDeserializerHelper{
|
|||||||
->setOutputSignalStrength($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15));
|
->setOutputSignalStrength($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @throws BlockStateDeserializeException */
|
/**
|
||||||
|
* @phpstan-template TDoor of Door
|
||||||
|
* @phpstan-param TDoor $block
|
||||||
|
* @phpstan-return TDoor
|
||||||
|
*
|
||||||
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
public static function decodeDoor(Door $block, BlockStateReader $in) : Door{
|
public static function decodeDoor(Door $block, BlockStateReader $in) : Door{
|
||||||
//TODO: check if these need any special treatment to get the appropriate data to both halves of the door
|
//TODO: check if these need any special treatment to get the appropriate data to both halves of the door
|
||||||
return $block
|
return $block
|
||||||
->setTop($in->readBool(BlockStateNames::UPPER_BLOCK_BIT))
|
->setTop($in->readBool(BlockStateNames::UPPER_BLOCK_BIT))
|
||||||
->setFacing($in->readCardinalHorizontalFacing())
|
//a door facing "east" is actually facing north - thanks mojang
|
||||||
|
->setFacing(Facing::rotateY($in->readCardinalHorizontalFacing(), clockwise: false))
|
||||||
->setHingeRight($in->readBool(BlockStateNames::DOOR_HINGE_BIT))
|
->setHingeRight($in->readBool(BlockStateNames::DOOR_HINGE_BIT))
|
||||||
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
|
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
|
||||||
}
|
}
|
||||||
@ -236,18 +243,36 @@ final class BlockStateDeserializerHelper{
|
|||||||
return $block->setPressed($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15) !== 0);
|
return $block->setPressed($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15) !== 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @throws BlockStateDeserializeException */
|
/**
|
||||||
|
* @phpstan-template TSlab of Slab
|
||||||
|
* @phpstan-param TSlab $block
|
||||||
|
* @phpstan-return TSlab
|
||||||
|
*
|
||||||
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
public static function decodeSingleSlab(Slab $block, BlockStateReader $in) : Slab{
|
public static function decodeSingleSlab(Slab $block, BlockStateReader $in) : Slab{
|
||||||
return $block->setSlabType($in->readSlabPosition());
|
return $block->setSlabType($in->readSlabPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @throws BlockStateDeserializeException */
|
/**
|
||||||
|
* @phpstan-template TSlab of Slab
|
||||||
|
* @phpstan-param TSlab $block
|
||||||
|
* @phpstan-return TSlab
|
||||||
|
*
|
||||||
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
public static function decodeDoubleSlab(Slab $block, BlockStateReader $in) : Slab{
|
public static function decodeDoubleSlab(Slab $block, BlockStateReader $in) : Slab{
|
||||||
$in->ignored(StateNames::MC_VERTICAL_HALF);
|
$in->ignored(StateNames::MC_VERTICAL_HALF);
|
||||||
return $block->setSlabType(SlabType::DOUBLE);
|
return $block->setSlabType(SlabType::DOUBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @throws BlockStateDeserializeException */
|
/**
|
||||||
|
* @phpstan-template TStair of Stair
|
||||||
|
* @phpstan-param TStair $block
|
||||||
|
* @phpstan-return TStair
|
||||||
|
*
|
||||||
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
public static function decodeStairs(Stair $block, BlockStateReader $in) : Stair{
|
public static function decodeStairs(Stair $block, BlockStateReader $in) : Stair{
|
||||||
return $block
|
return $block
|
||||||
->setUpsideDown($in->readBool(BlockStateNames::UPSIDE_DOWN_BIT))
|
->setUpsideDown($in->readBool(BlockStateNames::UPSIDE_DOWN_BIT))
|
||||||
@ -264,7 +289,13 @@ final class BlockStateDeserializerHelper{
|
|||||||
->setFacing($facing === Facing::DOWN ? Facing::UP : $facing);
|
->setFacing($facing === Facing::DOWN ? Facing::UP : $facing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @throws BlockStateDeserializeException */
|
/**
|
||||||
|
* @phpstan-template TTrapdoor of Trapdoor
|
||||||
|
* @phpstan-param TTrapdoor $block
|
||||||
|
* @phpstan-return TTrapdoor
|
||||||
|
*
|
||||||
|
* @throws BlockStateDeserializeException
|
||||||
|
*/
|
||||||
public static function decodeTrapdoor(Trapdoor $block, BlockStateReader $in) : Trapdoor{
|
public static function decodeTrapdoor(Trapdoor $block, BlockStateReader $in) : Trapdoor{
|
||||||
return $block
|
return $block
|
||||||
->setFacing($in->read5MinusHorizontalFacing())
|
->setFacing($in->read5MinusHorizontalFacing())
|
||||||
|
@ -100,7 +100,8 @@ final class BlockStateSerializerHelper{
|
|||||||
public static function encodeDoor(Door $block, Writer $out) : Writer{
|
public static function encodeDoor(Door $block, Writer $out) : Writer{
|
||||||
return $out
|
return $out
|
||||||
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
|
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
|
||||||
->writeCardinalHorizontalFacing($block->getFacing())
|
//a door facing north is encoded as "east"
|
||||||
|
->writeCardinalHorizontalFacing(Facing::rotateY($block->getFacing(), clockwise: true))
|
||||||
->writeBool(BlockStateNames::DOOR_HINGE_BIT, $block->isHingeRight())
|
->writeBool(BlockStateNames::DOOR_HINGE_BIT, $block->isHingeRight())
|
||||||
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
|
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,13 @@ use pocketmine\block\DoublePitcherCrop;
|
|||||||
use pocketmine\block\Opaque;
|
use pocketmine\block\Opaque;
|
||||||
use pocketmine\block\PinkPetals;
|
use pocketmine\block\PinkPetals;
|
||||||
use pocketmine\block\PitcherCrop;
|
use pocketmine\block\PitcherCrop;
|
||||||
|
use pocketmine\block\RuntimeBlockStateRegistry;
|
||||||
use pocketmine\block\Slab;
|
use pocketmine\block\Slab;
|
||||||
use pocketmine\block\Stair;
|
use pocketmine\block\Stair;
|
||||||
use pocketmine\block\SweetBerryBush;
|
use pocketmine\block\SweetBerryBush;
|
||||||
use pocketmine\block\utils\BrewingStandSlot;
|
use pocketmine\block\utils\BrewingStandSlot;
|
||||||
use pocketmine\block\utils\ChiseledBookshelfSlot;
|
use pocketmine\block\utils\ChiseledBookshelfSlot;
|
||||||
|
use pocketmine\block\utils\CopperMaterial;
|
||||||
use pocketmine\block\utils\CopperOxidation;
|
use pocketmine\block\utils\CopperOxidation;
|
||||||
use pocketmine\block\utils\CoralType;
|
use pocketmine\block\utils\CoralType;
|
||||||
use pocketmine\block\utils\DirtType;
|
use pocketmine\block\utils\DirtType;
|
||||||
@ -59,6 +61,7 @@ use pocketmine\data\bedrock\block\convert\BlockStateDeserializerHelper as Helper
|
|||||||
use pocketmine\data\bedrock\block\convert\BlockStateReader as Reader;
|
use pocketmine\data\bedrock\block\convert\BlockStateReader as Reader;
|
||||||
use pocketmine\math\Axis;
|
use pocketmine\math\Axis;
|
||||||
use pocketmine\math\Facing;
|
use pocketmine\math\Facing;
|
||||||
|
use pocketmine\utils\Utils;
|
||||||
use function array_key_exists;
|
use function array_key_exists;
|
||||||
use function count;
|
use function count;
|
||||||
use function min;
|
use function min;
|
||||||
@ -87,6 +90,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
|||||||
$this->registerSaplingDeserializers();
|
$this->registerSaplingDeserializers();
|
||||||
$this->registerLightDeserializers();
|
$this->registerLightDeserializers();
|
||||||
$this->registerMobHeadDeserializers();
|
$this->registerMobHeadDeserializers();
|
||||||
|
$this->registerCopperDeserializers();
|
||||||
$this->registerSimpleDeserializers();
|
$this->registerSimpleDeserializers();
|
||||||
$this->registerDeserializers();
|
$this->registerDeserializers();
|
||||||
}
|
}
|
||||||
@ -94,19 +98,37 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
|||||||
public function deserialize(BlockStateData $stateData) : int{
|
public function deserialize(BlockStateData $stateData) : int{
|
||||||
if(count($stateData->getStates()) === 0){
|
if(count($stateData->getStates()) === 0){
|
||||||
//if a block has zero properties, we can keep a map of string ID -> internal blockstate ID
|
//if a block has zero properties, we can keep a map of string ID -> internal blockstate ID
|
||||||
return $this->simpleCache[$stateData->getName()] ??= $this->deserializeBlock($stateData)->getStateId();
|
return $this->simpleCache[$stateData->getName()] ??= $this->deserializeToStateId($stateData);
|
||||||
}
|
}
|
||||||
|
|
||||||
//we can't cache blocks that have properties - go ahead and deserialize the slow way
|
//we can't cache blocks that have properties - go ahead and deserialize the slow way
|
||||||
return $this->deserializeBlock($stateData)->getStateId();
|
return $this->deserializeToStateId($stateData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function deserializeToStateId(BlockStateData $stateData) : int{
|
||||||
|
$stateId = $this->deserializeBlock($stateData)->getStateId();
|
||||||
|
//plugin devs seem to keep missing this and causing core crashes, so we need to verify this at the earliest
|
||||||
|
//available opportunity
|
||||||
|
if(!RuntimeBlockStateRegistry::getInstance()->hasStateId($stateId)){
|
||||||
|
throw new \LogicException("State ID $stateId returned by deserializer for " . $stateData->getName() . " is not registered in RuntimeBlockStateRegistry");
|
||||||
|
}
|
||||||
|
return $stateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @phpstan-param \Closure(Reader) : Block $c */
|
/** @phpstan-param \Closure(Reader) : Block $c */
|
||||||
public function map(string $id, \Closure $c) : void{
|
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->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 */
|
/** @phpstan-param \Closure() : Block $getBlock */
|
||||||
@ -715,6 +737,150 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-param \Closure(Reader) : (CopperMaterial&Block) $deserializer
|
||||||
|
*/
|
||||||
|
private function mapCopper(
|
||||||
|
string $normalId,
|
||||||
|
string $waxedNormalId,
|
||||||
|
string $exposedId,
|
||||||
|
string $waxedExposedId,
|
||||||
|
string $weatheredId,
|
||||||
|
string $waxedWeatheredId,
|
||||||
|
string $oxidizedId,
|
||||||
|
string $waxedOxidizedId,
|
||||||
|
\Closure $deserializer
|
||||||
|
) : void{
|
||||||
|
foreach(Utils::stringifyKeys([
|
||||||
|
$normalId => [CopperOxidation::NONE, false],
|
||||||
|
$waxedNormalId => [CopperOxidation::NONE, true],
|
||||||
|
$exposedId => [CopperOxidation::EXPOSED, false],
|
||||||
|
$waxedExposedId => [CopperOxidation::EXPOSED, true],
|
||||||
|
$weatheredId => [CopperOxidation::WEATHERED, false],
|
||||||
|
$waxedWeatheredId => [CopperOxidation::WEATHERED, true],
|
||||||
|
$oxidizedId => [CopperOxidation::OXIDIZED, false],
|
||||||
|
$waxedOxidizedId => [CopperOxidation::OXIDIZED, true],
|
||||||
|
]) as $id => [$oxidation, $waxed]){
|
||||||
|
$this->map($id, fn(Reader $in) => $deserializer($in)->setOxidation($oxidation)->setWaxed($waxed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerCopperDeserializers() : void{
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_CUT_COPPER_SLAB,
|
||||||
|
Ids::EXPOSED_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
|
||||||
|
Ids::WEATHERED_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
|
||||||
|
Ids::OXIDIZED_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB,
|
||||||
|
fn(Reader $in) => Helper::decodeSingleSlab(Blocks::CUT_COPPER_SLAB(), $in)
|
||||||
|
);
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB,
|
||||||
|
fn(Reader $in) => Helper::decodeDoubleSlab(Blocks::CUT_COPPER_SLAB(), $in)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::COPPER_BULB,
|
||||||
|
Ids::WAXED_COPPER_BULB,
|
||||||
|
Ids::EXPOSED_COPPER_BULB,
|
||||||
|
Ids::WAXED_EXPOSED_COPPER_BULB,
|
||||||
|
Ids::WEATHERED_COPPER_BULB,
|
||||||
|
Ids::WAXED_WEATHERED_COPPER_BULB,
|
||||||
|
Ids::OXIDIZED_COPPER_BULB,
|
||||||
|
Ids::WAXED_OXIDIZED_COPPER_BULB,
|
||||||
|
fn(Reader $in) => Blocks::COPPER_BULB()
|
||||||
|
->setLit($in->readBool(StateNames::LIT))
|
||||||
|
->setPowered($in->readBool(StateNames::POWERED_BIT))
|
||||||
|
);
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::COPPER_DOOR,
|
||||||
|
Ids::WAXED_COPPER_DOOR,
|
||||||
|
Ids::EXPOSED_COPPER_DOOR,
|
||||||
|
Ids::WAXED_EXPOSED_COPPER_DOOR,
|
||||||
|
Ids::WEATHERED_COPPER_DOOR,
|
||||||
|
Ids::WAXED_WEATHERED_COPPER_DOOR,
|
||||||
|
Ids::OXIDIZED_COPPER_DOOR,
|
||||||
|
Ids::WAXED_OXIDIZED_COPPER_DOOR,
|
||||||
|
fn(Reader $in) => Helper::decodeDoor(Blocks::COPPER_DOOR(), $in)
|
||||||
|
);
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::COPPER_TRAPDOOR,
|
||||||
|
Ids::WAXED_COPPER_TRAPDOOR,
|
||||||
|
Ids::EXPOSED_COPPER_TRAPDOOR,
|
||||||
|
Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
|
||||||
|
Ids::WEATHERED_COPPER_TRAPDOOR,
|
||||||
|
Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
|
||||||
|
Ids::OXIDIZED_COPPER_TRAPDOOR,
|
||||||
|
Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR,
|
||||||
|
fn(Reader $in) => Helper::decodeTrapdoor(Blocks::COPPER_TRAPDOOR(), $in)
|
||||||
|
);
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::COPPER_BLOCK,
|
||||||
|
Ids::WAXED_COPPER,
|
||||||
|
Ids::EXPOSED_COPPER,
|
||||||
|
Ids::WAXED_EXPOSED_COPPER,
|
||||||
|
Ids::WEATHERED_COPPER,
|
||||||
|
Ids::WAXED_WEATHERED_COPPER,
|
||||||
|
Ids::OXIDIZED_COPPER,
|
||||||
|
Ids::WAXED_OXIDIZED_COPPER,
|
||||||
|
fn(Reader $in) => Blocks::COPPER()
|
||||||
|
);
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::CHISELED_COPPER,
|
||||||
|
Ids::WAXED_CHISELED_COPPER,
|
||||||
|
Ids::EXPOSED_CHISELED_COPPER,
|
||||||
|
Ids::WAXED_EXPOSED_CHISELED_COPPER,
|
||||||
|
Ids::WEATHERED_CHISELED_COPPER,
|
||||||
|
Ids::WAXED_WEATHERED_CHISELED_COPPER,
|
||||||
|
Ids::OXIDIZED_CHISELED_COPPER,
|
||||||
|
Ids::WAXED_OXIDIZED_CHISELED_COPPER,
|
||||||
|
fn(Reader $in) => Blocks::CHISELED_COPPER()
|
||||||
|
);
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::COPPER_GRATE,
|
||||||
|
Ids::WAXED_COPPER_GRATE,
|
||||||
|
Ids::EXPOSED_COPPER_GRATE,
|
||||||
|
Ids::WAXED_EXPOSED_COPPER_GRATE,
|
||||||
|
Ids::WEATHERED_COPPER_GRATE,
|
||||||
|
Ids::WAXED_WEATHERED_COPPER_GRATE,
|
||||||
|
Ids::OXIDIZED_COPPER_GRATE,
|
||||||
|
Ids::WAXED_OXIDIZED_COPPER_GRATE,
|
||||||
|
fn(Reader $in) => Blocks::COPPER_GRATE()
|
||||||
|
);
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::CUT_COPPER,
|
||||||
|
Ids::WAXED_CUT_COPPER,
|
||||||
|
Ids::EXPOSED_CUT_COPPER,
|
||||||
|
Ids::WAXED_EXPOSED_CUT_COPPER,
|
||||||
|
Ids::WEATHERED_CUT_COPPER,
|
||||||
|
Ids::WAXED_WEATHERED_CUT_COPPER,
|
||||||
|
Ids::OXIDIZED_CUT_COPPER,
|
||||||
|
Ids::WAXED_OXIDIZED_CUT_COPPER,
|
||||||
|
fn(Reader $in) => Blocks::CUT_COPPER()
|
||||||
|
);
|
||||||
|
$this->mapCopper(
|
||||||
|
Ids::CUT_COPPER_STAIRS,
|
||||||
|
Ids::WAXED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::EXPOSED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::WEATHERED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::OXIDIZED_CUT_COPPER_STAIRS,
|
||||||
|
Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS,
|
||||||
|
fn(Reader $in) => Helper::decodeStairs(Blocks::CUT_COPPER_STAIRS(), $in)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private function registerSimpleDeserializers() : void{
|
private function registerSimpleDeserializers() : void{
|
||||||
$this->mapSimple(Ids::AIR, fn() => Blocks::AIR());
|
$this->mapSimple(Ids::AIR, fn() => Blocks::AIR());
|
||||||
$this->mapSimple(Ids::AMETHYST_BLOCK, fn() => Blocks::AMETHYST());
|
$this->mapSimple(Ids::AMETHYST_BLOCK, fn() => Blocks::AMETHYST());
|
||||||
@ -1220,18 +1386,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
|||||||
$this->map(Ids::COMPOUND_CREATOR, fn(Reader $in) => Blocks::COMPOUND_CREATOR()
|
$this->map(Ids::COMPOUND_CREATOR, fn(Reader $in) => Blocks::COMPOUND_CREATOR()
|
||||||
->setFacing(Facing::opposite($in->readLegacyHorizontalFacing()))
|
->setFacing(Facing::opposite($in->readLegacyHorizontalFacing()))
|
||||||
);
|
);
|
||||||
$this->map(Ids::COPPER_BLOCK, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::NONE));
|
|
||||||
$this->map(Ids::COPPER_BULB, function(Reader $in) : Block{
|
|
||||||
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::NONE)
|
|
||||||
->setLit($in->readBool(StateNames::LIT))
|
|
||||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
|
||||||
});
|
|
||||||
$this->map(Ids::COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::NONE), $in));
|
|
||||||
$this->map(Ids::COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::NONE));
|
|
||||||
$this->map(Ids::COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::NONE), $in));
|
|
||||||
$this->map(Ids::CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::NONE));
|
|
||||||
$this->mapSlab(Ids::CUT_COPPER_SLAB, Ids::DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::NONE));
|
|
||||||
$this->mapStairs(Ids::CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::NONE));
|
|
||||||
$this->mapSlab(Ids::CUT_RED_SANDSTONE_SLAB, Ids::CUT_RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_RED_SANDSTONE_SLAB());
|
$this->mapSlab(Ids::CUT_RED_SANDSTONE_SLAB, Ids::CUT_RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_RED_SANDSTONE_SLAB());
|
||||||
$this->mapSlab(Ids::CUT_SANDSTONE_SLAB, Ids::CUT_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_SANDSTONE_SLAB());
|
$this->mapSlab(Ids::CUT_SANDSTONE_SLAB, Ids::CUT_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_SANDSTONE_SLAB());
|
||||||
$this->mapSlab(Ids::DARK_PRISMARINE_SLAB, Ids::DARK_PRISMARINE_DOUBLE_SLAB, fn() => Blocks::DARK_PRISMARINE_SLAB());
|
$this->mapSlab(Ids::DARK_PRISMARINE_SLAB, Ids::DARK_PRISMARINE_DOUBLE_SLAB, fn() => Blocks::DARK_PRISMARINE_SLAB());
|
||||||
@ -1286,19 +1440,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
|||||||
return Blocks::ENDER_CHEST()
|
return Blocks::ENDER_CHEST()
|
||||||
->setFacing($in->readCardinalHorizontalFacing());
|
->setFacing($in->readCardinalHorizontalFacing());
|
||||||
});
|
});
|
||||||
$this->map(Ids::EXPOSED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::EXPOSED));
|
|
||||||
$this->map(Ids::EXPOSED_CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::EXPOSED));
|
|
||||||
$this->map(Ids::EXPOSED_COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::EXPOSED));
|
|
||||||
$this->map(Ids::EXPOSED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::EXPOSED));
|
|
||||||
$this->mapSlab(Ids::EXPOSED_CUT_COPPER_SLAB, Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::EXPOSED));
|
|
||||||
$this->mapStairs(Ids::EXPOSED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::EXPOSED));
|
|
||||||
$this->map(Ids::EXPOSED_COPPER_BULB, function(Reader $in) : Block{
|
|
||||||
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::EXPOSED)
|
|
||||||
->setLit($in->readBool(StateNames::LIT))
|
|
||||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
|
||||||
});
|
|
||||||
$this->map(Ids::EXPOSED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::EXPOSED), $in));
|
|
||||||
$this->map(Ids::EXPOSED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::EXPOSED), $in));
|
|
||||||
$this->map(Ids::FARMLAND, function(Reader $in) : Block{
|
$this->map(Ids::FARMLAND, function(Reader $in) : Block{
|
||||||
return Blocks::FARMLAND()
|
return Blocks::FARMLAND()
|
||||||
->setWetness($in->readBoundedInt(StateNames::MOISTURIZED_AMOUNT, 0, 7));
|
->setWetness($in->readBoundedInt(StateNames::MOISTURIZED_AMOUNT, 0, 7));
|
||||||
@ -1451,19 +1592,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
|||||||
$this->mapSlab(Ids::NORMAL_STONE_SLAB, Ids::NORMAL_STONE_DOUBLE_SLAB, fn() => Blocks::STONE_SLAB());
|
$this->mapSlab(Ids::NORMAL_STONE_SLAB, Ids::NORMAL_STONE_DOUBLE_SLAB, fn() => Blocks::STONE_SLAB());
|
||||||
$this->mapStairs(Ids::NORMAL_STONE_STAIRS, fn() => Blocks::STONE_STAIRS());
|
$this->mapStairs(Ids::NORMAL_STONE_STAIRS, fn() => Blocks::STONE_STAIRS());
|
||||||
$this->map(Ids::OCHRE_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::OCHRE)->setAxis($in->readPillarAxis()));
|
$this->map(Ids::OCHRE_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::OCHRE)->setAxis($in->readPillarAxis()));
|
||||||
$this->map(Ids::OXIDIZED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->map(Ids::OXIDIZED_CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->map(Ids::OXIDIZED_COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->map(Ids::OXIDIZED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->mapSlab(Ids::OXIDIZED_CUT_COPPER_SLAB, Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->mapStairs(Ids::OXIDIZED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->map(Ids::OXIDIZED_COPPER_BULB, function(Reader $in) : Block{
|
|
||||||
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::OXIDIZED)
|
|
||||||
->setLit($in->readBool(StateNames::LIT))
|
|
||||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
|
||||||
});
|
|
||||||
$this->map(Ids::OXIDIZED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::OXIDIZED), $in));
|
|
||||||
$this->map(Ids::OXIDIZED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::OXIDIZED), $in));
|
|
||||||
$this->map(Ids::PEARLESCENT_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::PEARLESCENT)->setAxis($in->readPillarAxis()));
|
$this->map(Ids::PEARLESCENT_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::PEARLESCENT)->setAxis($in->readPillarAxis()));
|
||||||
$this->mapSlab(Ids::PETRIFIED_OAK_SLAB, Ids::PETRIFIED_OAK_DOUBLE_SLAB, fn() => Blocks::FAKE_WOODEN_SLAB());
|
$this->mapSlab(Ids::PETRIFIED_OAK_SLAB, Ids::PETRIFIED_OAK_DOUBLE_SLAB, fn() => Blocks::FAKE_WOODEN_SLAB());
|
||||||
$this->map(Ids::PINK_PETALS, function(Reader $in) : Block{
|
$this->map(Ids::PINK_PETALS, function(Reader $in) : Block{
|
||||||
@ -1736,71 +1864,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
|||||||
->setFacing($in->readHorizontalFacing());
|
->setFacing($in->readHorizontalFacing());
|
||||||
});
|
});
|
||||||
$this->map(Ids::WATER, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::WATER(), $in));
|
$this->map(Ids::WATER, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::WATER(), $in));
|
||||||
$this->map(Ids::WAXED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::NONE));
|
|
||||||
$this->map(Ids::WAXED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::NONE));
|
|
||||||
$this->map(Ids::WAXED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::NONE));
|
|
||||||
$this->map(Ids::WAXED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::NONE));
|
|
||||||
$this->mapSlab(Ids::WAXED_CUT_COPPER_SLAB, Ids::WAXED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::NONE));
|
|
||||||
$this->mapStairs(Ids::WAXED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::NONE));
|
|
||||||
$this->map(Ids::WAXED_COPPER_BULB, function(Reader $in) : Block{
|
|
||||||
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::NONE)
|
|
||||||
->setLit($in->readBool(StateNames::LIT))
|
|
||||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
|
||||||
});
|
|
||||||
$this->map(Ids::WAXED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::NONE), $in));
|
|
||||||
$this->map(Ids::WAXED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::NONE), $in));
|
|
||||||
$this->map(Ids::WAXED_EXPOSED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::EXPOSED));
|
|
||||||
$this->map(Ids::WAXED_EXPOSED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::EXPOSED));
|
|
||||||
$this->map(Ids::WAXED_EXPOSED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::EXPOSED));
|
|
||||||
$this->map(Ids::WAXED_EXPOSED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::EXPOSED));
|
|
||||||
$this->mapSlab(Ids::WAXED_EXPOSED_CUT_COPPER_SLAB, Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::EXPOSED));
|
|
||||||
$this->mapStairs(Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::EXPOSED));
|
|
||||||
$this->map(Ids::WAXED_EXPOSED_COPPER_BULB, function(Reader $in) : Block{
|
|
||||||
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::EXPOSED)
|
|
||||||
->setLit($in->readBool(StateNames::LIT))
|
|
||||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
|
||||||
});
|
|
||||||
$this->map(Ids::WAXED_EXPOSED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::EXPOSED), $in));
|
|
||||||
$this->map(Ids::WAXED_EXPOSED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::EXPOSED), $in));
|
|
||||||
$this->map(Ids::WAXED_OXIDIZED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->map(Ids::WAXED_OXIDIZED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->map(Ids::WAXED_OXIDIZED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->map(Ids::WAXED_OXIDIZED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->mapSlab(Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB, Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->mapStairs(Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::OXIDIZED));
|
|
||||||
$this->map(Ids::WAXED_OXIDIZED_COPPER_BULB, function(Reader $in) : Block{
|
|
||||||
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::OXIDIZED)
|
|
||||||
->setLit($in->readBool(StateNames::LIT))
|
|
||||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
|
||||||
});
|
|
||||||
$this->map(Ids::WAXED_OXIDIZED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::OXIDIZED), $in));
|
|
||||||
$this->map(Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::OXIDIZED), $in));
|
|
||||||
$this->map(Ids::WAXED_WEATHERED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::WEATHERED));
|
|
||||||
$this->map(Ids::WAXED_WEATHERED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::WEATHERED));
|
|
||||||
$this->map(Ids::WAXED_WEATHERED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::WEATHERED));
|
|
||||||
$this->map(Ids::WAXED_WEATHERED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::WEATHERED));
|
|
||||||
$this->mapSlab(Ids::WAXED_WEATHERED_CUT_COPPER_SLAB, Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::WEATHERED));
|
|
||||||
$this->mapStairs(Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::WEATHERED));
|
|
||||||
$this->map(Ids::WAXED_WEATHERED_COPPER_BULB, function(Reader $in) : Block{
|
|
||||||
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::WEATHERED)
|
|
||||||
->setLit($in->readBool(StateNames::LIT))
|
|
||||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
|
||||||
});
|
|
||||||
$this->map(Ids::WAXED_WEATHERED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::WEATHERED), $in));
|
|
||||||
$this->map(Ids::WAXED_WEATHERED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::WEATHERED), $in));
|
|
||||||
$this->map(Ids::WEATHERED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::WEATHERED));
|
|
||||||
$this->map(Ids::WEATHERED_CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::WEATHERED));
|
|
||||||
$this->map(Ids::WEATHERED_COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::WEATHERED));
|
|
||||||
$this->map(Ids::WEATHERED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::WEATHERED));
|
|
||||||
$this->mapSlab(Ids::WEATHERED_CUT_COPPER_SLAB, Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::WEATHERED));
|
|
||||||
$this->mapStairs(Ids::WEATHERED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::WEATHERED));
|
|
||||||
$this->map(Ids::WEATHERED_COPPER_BULB, function(Reader $in) : Block{
|
|
||||||
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::WEATHERED)
|
|
||||||
->setLit($in->readBool(StateNames::LIT))
|
|
||||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
|
||||||
});
|
|
||||||
$this->map(Ids::WEATHERED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::WEATHERED), $in));
|
|
||||||
$this->map(Ids::WEATHERED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::WEATHERED), $in));
|
|
||||||
$this->map(Ids::WEEPING_VINES, function(Reader $in) : Block{
|
$this->map(Ids::WEEPING_VINES, function(Reader $in) : Block{
|
||||||
return Blocks::WEEPING_VINES()
|
return Blocks::WEEPING_VINES()
|
||||||
->setAge($in->readBoundedInt(StateNames::WEEPING_VINES_AGE, 0, 25));
|
->setAge($in->readBoundedInt(StateNames::WEEPING_VINES_AGE, 0, 25));
|
||||||
|
@ -51,12 +51,19 @@ final class ItemDeserializer{
|
|||||||
* @phpstan-param \Closure(Data) : Item $deserializer
|
* @phpstan-param \Closure(Data) : Item $deserializer
|
||||||
*/
|
*/
|
||||||
public function map(string $id, \Closure $deserializer) : void{
|
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;
|
$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
|
* @phpstan-param \Closure(Data) : Block $deserializer
|
||||||
*/
|
*/
|
||||||
|
@ -75,6 +75,7 @@ final class ItemTypeNames{
|
|||||||
public const BLEACH = "minecraft:bleach";
|
public const BLEACH = "minecraft:bleach";
|
||||||
public const BLUE_BUNDLE = "minecraft:blue_bundle";
|
public const BLUE_BUNDLE = "minecraft:blue_bundle";
|
||||||
public const BLUE_DYE = "minecraft:blue_dye";
|
public const BLUE_DYE = "minecraft:blue_dye";
|
||||||
|
public const BLUE_EGG = "minecraft:blue_egg";
|
||||||
public const BOARD = "minecraft:board";
|
public const BOARD = "minecraft:board";
|
||||||
public const BOAT = "minecraft:boat";
|
public const BOAT = "minecraft:boat";
|
||||||
public const BOGGED_SPAWN_EGG = "minecraft:bogged_spawn_egg";
|
public const BOGGED_SPAWN_EGG = "minecraft:bogged_spawn_egg";
|
||||||
@ -93,6 +94,7 @@ final class ItemTypeNames{
|
|||||||
public const BRICK = "minecraft:brick";
|
public const BRICK = "minecraft:brick";
|
||||||
public const BROWN_BUNDLE = "minecraft:brown_bundle";
|
public const BROWN_BUNDLE = "minecraft:brown_bundle";
|
||||||
public const BROWN_DYE = "minecraft:brown_dye";
|
public const BROWN_DYE = "minecraft:brown_dye";
|
||||||
|
public const BROWN_EGG = "minecraft:brown_egg";
|
||||||
public const BRUSH = "minecraft:brush";
|
public const BRUSH = "minecraft:brush";
|
||||||
public const BUCKET = "minecraft:bucket";
|
public const BUCKET = "minecraft:bucket";
|
||||||
public const BUNDLE = "minecraft:bundle";
|
public const BUNDLE = "minecraft:bundle";
|
||||||
|
@ -1495,7 +1495,7 @@ abstract class Entity{
|
|||||||
$this->getId(), //TODO: actor unique ID
|
$this->getId(), //TODO: actor unique ID
|
||||||
$this->getId(),
|
$this->getId(),
|
||||||
static::getNetworkTypeId(),
|
static::getNetworkTypeId(),
|
||||||
$this->location->asVector3(),
|
$this->getOffsetPosition($this->location->asVector3()),
|
||||||
$this->getMotion(),
|
$this->getMotion(),
|
||||||
$this->location->pitch,
|
$this->location->pitch,
|
||||||
$this->location->yaw,
|
$this->location->yaw,
|
||||||
|
@ -144,8 +144,9 @@ class InventoryTransaction{
|
|||||||
$needItems = [];
|
$needItems = [];
|
||||||
$haveItems = [];
|
$haveItems = [];
|
||||||
foreach($this->actions as $key => $action){
|
foreach($this->actions as $key => $action){
|
||||||
if(!$action->getTargetItem()->isNull()){
|
$targetItem = $action->getTargetItem();
|
||||||
$needItems[] = $action->getTargetItem();
|
if(!$targetItem->isNull()){
|
||||||
|
$needItems[] = $targetItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
@ -154,8 +155,9 @@ class InventoryTransaction{
|
|||||||
throw new TransactionValidationException(get_class($action) . "#" . spl_object_id($action) . ": " . $e->getMessage(), 0, $e);
|
throw new TransactionValidationException(get_class($action) . "#" . spl_object_id($action) . ": " . $e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$action->getSourceItem()->isNull()){
|
$sourceItem = $action->getSourceItem();
|
||||||
$haveItems[] = $action->getSourceItem();
|
if(!$sourceItem->isNull()){
|
||||||
|
$haveItems[] = $sourceItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,8 @@ final class LegacyStringToItemParser{
|
|||||||
*/
|
*/
|
||||||
public function parse(string $input) : Item{
|
public function parse(string $input) : Item{
|
||||||
$key = $this->reprocess($input);
|
$key = $this->reprocess($input);
|
||||||
$b = explode(":", $key);
|
//TODO: this should be limited to 2 parts, but 3 preserves old behaviour when given a string like 351:4:1
|
||||||
|
$b = explode(":", $key, limit: 3);
|
||||||
|
|
||||||
if(!isset($b[1])){
|
if(!isset($b[1])){
|
||||||
$meta = 0;
|
$meta = 0;
|
||||||
|
@ -71,7 +71,7 @@ class Language{
|
|||||||
|
|
||||||
foreach($files as $file){
|
foreach($files as $file){
|
||||||
try{
|
try{
|
||||||
$code = explode(".", $file)[0];
|
$code = explode(".", $file, limit: 2)[0];
|
||||||
$strings = self::loadLang($path, $code);
|
$strings = self::loadLang($path, $code);
|
||||||
if(isset($strings[KnownTranslationKeys::LANGUAGE_NAME])){
|
if(isset($strings[KnownTranslationKeys::LANGUAGE_NAME])){
|
||||||
$result[$code] = $strings[KnownTranslationKeys::LANGUAGE_NAME];
|
$result[$code] = $strings[KnownTranslationKeys::LANGUAGE_NAME];
|
||||||
|
@ -72,9 +72,11 @@ final class JwtUtils{
|
|||||||
* @throws JwtException
|
* @throws JwtException
|
||||||
*/
|
*/
|
||||||
public static function split(string $jwt) : array{
|
public static function split(string $jwt) : array{
|
||||||
$v = explode(".", $jwt);
|
//limit of 4 allows us to detect too many parts without having to split the string up into a potentially large
|
||||||
|
//number of parts
|
||||||
|
$v = explode(".", $jwt, limit: 4);
|
||||||
if(count($v) !== 3){
|
if(count($v) !== 3){
|
||||||
throw new JwtException("Expected exactly 3 JWT parts, got " . count($v));
|
throw new JwtException("Expected exactly 3 JWT parts delimited by a period");
|
||||||
}
|
}
|
||||||
return [$v[0], $v[1], $v[2]]; //workaround phpstan bug
|
return [$v[0], $v[1], $v[2]]; //workaround phpstan bug
|
||||||
}
|
}
|
||||||
|
8
src/network/mcpe/cache/ChunkCache.php
vendored
8
src/network/mcpe/cache/ChunkCache.php
vendored
@ -88,9 +88,13 @@ class ChunkCache implements ChunkListener{
|
|||||||
private int $hits = 0;
|
private int $hits = 0;
|
||||||
private int $misses = 0;
|
private int $misses = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-param DimensionIds::* $dimensionId
|
||||||
|
*/
|
||||||
private function __construct(
|
private function __construct(
|
||||||
private World $world,
|
private World $world,
|
||||||
private Compressor $compressor
|
private Compressor $compressor,
|
||||||
|
private int $dimensionId = DimensionIds::OVERWORLD
|
||||||
){}
|
){}
|
||||||
|
|
||||||
private function prepareChunkAsync(int $chunkX, int $chunkZ, int $chunkHash) : CompressBatchPromise{
|
private function prepareChunkAsync(int $chunkX, int $chunkZ, int $chunkHash) : CompressBatchPromise{
|
||||||
@ -109,7 +113,7 @@ class ChunkCache implements ChunkListener{
|
|||||||
new ChunkRequestTask(
|
new ChunkRequestTask(
|
||||||
$chunkX,
|
$chunkX,
|
||||||
$chunkZ,
|
$chunkZ,
|
||||||
DimensionIds::OVERWORLD, //TODO: not hardcode this
|
$this->dimensionId,
|
||||||
$chunk,
|
$chunk,
|
||||||
$promise,
|
$promise,
|
||||||
$this->compressor
|
$this->compressor
|
||||||
|
@ -64,7 +64,6 @@ use pocketmine\network\mcpe\protocol\ItemStackResponsePacket;
|
|||||||
use pocketmine\network\mcpe\protocol\LabTablePacket;
|
use pocketmine\network\mcpe\protocol\LabTablePacket;
|
||||||
use pocketmine\network\mcpe\protocol\LecternUpdatePacket;
|
use pocketmine\network\mcpe\protocol\LecternUpdatePacket;
|
||||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacketV1;
|
|
||||||
use pocketmine\network\mcpe\protocol\MapInfoRequestPacket;
|
use pocketmine\network\mcpe\protocol\MapInfoRequestPacket;
|
||||||
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
|
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
|
||||||
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
||||||
@ -296,10 +295,6 @@ class InGamePacketHandler extends PacketHandler{
|
|||||||
return $packetHandled;
|
return $packetHandled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleLevelSoundEventPacketV1(LevelSoundEventPacketV1 $packet) : bool{
|
|
||||||
return true; //useless leftover from 1.8
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleActorEvent(ActorEventPacket $packet) : bool{
|
public function handleActorEvent(ActorEventPacket $packet) : bool{
|
||||||
if($packet->actorRuntimeId !== $this->player->getId()){
|
if($packet->actorRuntimeId !== $this->player->getId()){
|
||||||
//TODO HACK: EATING_ITEM is sent back to the server when the server sends it for other players (1.14 bug, maybe earlier)
|
//TODO HACK: EATING_ITEM is sent back to the server when the server sends it for other players (1.14 bug, maybe earlier)
|
||||||
|
@ -148,7 +148,9 @@ class BanEntry{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$parts = explode("|", trim($str));
|
//we expect at most 5 parts, but accept 6 in case of an extra unexpected delimiter
|
||||||
|
//we don't want to include unexpected data into the ban reason
|
||||||
|
$parts = explode("|", trim($str), limit: 6);
|
||||||
$entry = new BanEntry(trim(array_shift($parts)));
|
$entry = new BanEntry(trim(array_shift($parts)));
|
||||||
if(count($parts) > 0){
|
if(count($parts) > 0){
|
||||||
$entry->setCreated(self::parseDate(array_shift($parts)));
|
$entry->setCreated(self::parseDate(array_shift($parts)));
|
||||||
|
@ -25,6 +25,8 @@ namespace pocketmine\player;
|
|||||||
|
|
||||||
use pocketmine\block\Block;
|
use pocketmine\block\Block;
|
||||||
use pocketmine\entity\animation\ArmSwingAnimation;
|
use pocketmine\entity\animation\ArmSwingAnimation;
|
||||||
|
use pocketmine\entity\effect\VanillaEffects;
|
||||||
|
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||||
use pocketmine\math\Facing;
|
use pocketmine\math\Facing;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
use pocketmine\network\mcpe\protocol\LevelEventPacket;
|
||||||
@ -65,11 +67,29 @@ final class SurvivalBlockBreakHandler{
|
|||||||
if(!$this->block->getBreakInfo()->isBreakable()){
|
if(!$this->block->getBreakInfo()->isBreakable()){
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
//TODO: improve this to take stuff like swimming, ladders, enchanted tools into account, fix wrong tool break time calculations for bad tools (pmmp/PocketMine-MP#211)
|
|
||||||
$breakTimePerTick = $this->block->getBreakInfo()->getBreakTime($this->player->getInventory()->getItemInHand()) * 20;
|
$breakTimePerTick = $this->block->getBreakInfo()->getBreakTime($this->player->getInventory()->getItemInHand()) * 20;
|
||||||
|
if(!$this->player->isOnGround() && !$this->player->isFlying()){
|
||||||
|
$breakTimePerTick *= 5;
|
||||||
|
}
|
||||||
|
if($this->player->isUnderwater() && !$this->player->getArmorInventory()->getHelmet()->hasEnchantment(VanillaEnchantments::AQUA_AFFINITY())){
|
||||||
|
$breakTimePerTick *= 5;
|
||||||
|
}
|
||||||
if($breakTimePerTick > 0){
|
if($breakTimePerTick > 0){
|
||||||
return 1 / $breakTimePerTick;
|
$progressPerTick = 1 / $breakTimePerTick;
|
||||||
|
|
||||||
|
$haste = $this->player->getEffects()->get(VanillaEffects::HASTE());
|
||||||
|
if($haste !== null){
|
||||||
|
$hasteLevel = $haste->getEffectLevel();
|
||||||
|
$progressPerTick *= (1 + 0.2 * $hasteLevel) * (1.2 ** $hasteLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
$miningFatigue = $this->player->getEffects()->get(VanillaEffects::MINING_FATIGUE());
|
||||||
|
if($miningFatigue !== null){
|
||||||
|
$miningFatigueLevel = $miningFatigue->getEffectLevel();
|
||||||
|
$progressPerTick *= 0.21 ** $miningFatigueLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $progressPerTick;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -82,7 +102,10 @@ final class SurvivalBlockBreakHandler{
|
|||||||
$newBreakSpeed = $this->calculateBreakProgressPerTick();
|
$newBreakSpeed = $this->calculateBreakProgressPerTick();
|
||||||
if(abs($newBreakSpeed - $this->breakSpeed) > 0.0001){
|
if(abs($newBreakSpeed - $this->breakSpeed) > 0.0001){
|
||||||
$this->breakSpeed = $newBreakSpeed;
|
$this->breakSpeed = $newBreakSpeed;
|
||||||
//TODO: sync with client
|
$this->player->getWorld()->broadcastPacketToViewers(
|
||||||
|
$this->blockPos,
|
||||||
|
LevelEventPacket::create(LevelEvent::BLOCK_BREAK_SPEED, (int) (65535 * $this->breakSpeed), $this->blockPos)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->breakProgress += $this->breakSpeed;
|
$this->breakProgress += $this->breakSpeed;
|
||||||
|
@ -26,6 +26,7 @@ namespace pocketmine\resourcepacks;
|
|||||||
use pocketmine\utils\Config;
|
use pocketmine\utils\Config;
|
||||||
use pocketmine\utils\Filesystem;
|
use pocketmine\utils\Filesystem;
|
||||||
use pocketmine\utils\Utils;
|
use pocketmine\utils\Utils;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
use Symfony\Component\Filesystem\Path;
|
use Symfony\Component\Filesystem\Path;
|
||||||
use function array_keys;
|
use function array_keys;
|
||||||
use function copy;
|
use function copy;
|
||||||
@ -103,9 +104,14 @@ class ResourcePackManager{
|
|||||||
try{
|
try{
|
||||||
$newPack = $this->loadPackFromPath(Path::join($this->path, $pack));
|
$newPack = $this->loadPackFromPath(Path::join($this->path, $pack));
|
||||||
|
|
||||||
$this->resourcePacks[] = $newPack;
|
|
||||||
$index = strtolower($newPack->getPackId());
|
$index = strtolower($newPack->getPackId());
|
||||||
|
if(!Uuid::isValid($index)){
|
||||||
|
//TODO: we should use Uuid in ResourcePack interface directly but that would break BC
|
||||||
|
//for now we need to validate this here to make sure it doesn't cause crashes later on
|
||||||
|
throw new ResourcePackException("Invalid UUID ($index)");
|
||||||
|
}
|
||||||
$this->uuidList[$index] = $newPack;
|
$this->uuidList[$index] = $newPack;
|
||||||
|
$this->resourcePacks[] = $newPack;
|
||||||
|
|
||||||
$keyPath = Path::join($this->path, $pack . ".key");
|
$keyPath = Path::join($this->path, $pack . ".key");
|
||||||
if(file_exists($keyPath)){
|
if(file_exists($keyPath)){
|
||||||
@ -190,6 +196,11 @@ class ResourcePackManager{
|
|||||||
$resourcePacks = [];
|
$resourcePacks = [];
|
||||||
foreach($resourceStack as $pack){
|
foreach($resourceStack as $pack){
|
||||||
$uuid = strtolower($pack->getPackId());
|
$uuid = strtolower($pack->getPackId());
|
||||||
|
if(!Uuid::isValid($uuid)){
|
||||||
|
//TODO: we should use Uuid in ResourcePack interface directly but that would break BC
|
||||||
|
//for now we need to validate this here to make sure it doesn't cause crashes later on
|
||||||
|
throw new \InvalidArgumentException("Invalid resource pack UUID ($uuid)");
|
||||||
|
}
|
||||||
if(isset($uuidList[$uuid])){
|
if(isset($uuidList[$uuid])){
|
||||||
throw new \InvalidArgumentException("Cannot load two resource pack with the same UUID ($uuid)");
|
throw new \InvalidArgumentException("Cannot load two resource pack with the same UUID ($uuid)");
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ use const CASE_LOWER;
|
|||||||
use const JSON_BIGINT_AS_STRING;
|
use const JSON_BIGINT_AS_STRING;
|
||||||
use const JSON_PRETTY_PRINT;
|
use const JSON_PRETTY_PRINT;
|
||||||
use const JSON_THROW_ON_ERROR;
|
use const JSON_THROW_ON_ERROR;
|
||||||
|
use const PHP_INT_MAX;
|
||||||
use const YAML_UTF8_ENCODING;
|
use const YAML_UTF8_ENCODING;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -339,7 +340,7 @@ class Config{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function setNested(string $key, mixed $value) : void{
|
public function setNested(string $key, mixed $value) : void{
|
||||||
$vars = explode(".", $key);
|
$vars = explode(".", $key, limit: PHP_INT_MAX);
|
||||||
$base = array_shift($vars);
|
$base = array_shift($vars);
|
||||||
|
|
||||||
if(!isset($this->config[$base])){
|
if(!isset($this->config[$base])){
|
||||||
@ -366,7 +367,7 @@ class Config{
|
|||||||
return $this->nestedCache[$key];
|
return $this->nestedCache[$key];
|
||||||
}
|
}
|
||||||
|
|
||||||
$vars = explode(".", $key);
|
$vars = explode(".", $key, limit: PHP_INT_MAX);
|
||||||
$base = array_shift($vars);
|
$base = array_shift($vars);
|
||||||
if(isset($this->config[$base])){
|
if(isset($this->config[$base])){
|
||||||
$base = $this->config[$base];
|
$base = $this->config[$base];
|
||||||
@ -390,7 +391,7 @@ class Config{
|
|||||||
$this->nestedCache = [];
|
$this->nestedCache = [];
|
||||||
$this->changed = true;
|
$this->changed = true;
|
||||||
|
|
||||||
$vars = explode(".", $key);
|
$vars = explode(".", $key, limit: PHP_INT_MAX);
|
||||||
|
|
||||||
$currentNode = &$this->config;
|
$currentNode = &$this->config;
|
||||||
while(count($vars) > 0){
|
while(count($vars) > 0){
|
||||||
@ -495,7 +496,7 @@ class Config{
|
|||||||
*/
|
*/
|
||||||
public static function parseList(string $content) : array{
|
public static function parseList(string $content) : array{
|
||||||
$result = [];
|
$result = [];
|
||||||
foreach(explode("\n", trim(str_replace("\r\n", "\n", $content))) as $v){
|
foreach(explode("\n", trim(str_replace("\r\n", "\n", $content)), limit: PHP_INT_MAX) as $v){
|
||||||
$v = trim($v);
|
$v = trim($v);
|
||||||
if($v === ""){
|
if($v === ""){
|
||||||
continue;
|
continue;
|
||||||
|
@ -60,6 +60,7 @@ use const CURLOPT_RETURNTRANSFER;
|
|||||||
use const CURLOPT_SSL_VERIFYHOST;
|
use const CURLOPT_SSL_VERIFYHOST;
|
||||||
use const CURLOPT_SSL_VERIFYPEER;
|
use const CURLOPT_SSL_VERIFYPEER;
|
||||||
use const CURLOPT_TIMEOUT_MS;
|
use const CURLOPT_TIMEOUT_MS;
|
||||||
|
use const PHP_INT_MAX;
|
||||||
use const SOCK_DGRAM;
|
use const SOCK_DGRAM;
|
||||||
use const SOL_UDP;
|
use const SOL_UDP;
|
||||||
|
|
||||||
@ -227,9 +228,10 @@ class Internet{
|
|||||||
$rawHeaders = substr($raw, 0, $headerSize);
|
$rawHeaders = substr($raw, 0, $headerSize);
|
||||||
$body = substr($raw, $headerSize);
|
$body = substr($raw, $headerSize);
|
||||||
$headers = [];
|
$headers = [];
|
||||||
foreach(explode("\r\n\r\n", $rawHeaders) as $rawHeaderGroup){
|
//TODO: explore if we can set these limits lower
|
||||||
|
foreach(explode("\r\n\r\n", $rawHeaders, limit: PHP_INT_MAX) as $rawHeaderGroup){
|
||||||
$headerGroup = [];
|
$headerGroup = [];
|
||||||
foreach(explode("\r\n", $rawHeaderGroup) as $line){
|
foreach(explode("\r\n", $rawHeaderGroup, limit: PHP_INT_MAX) as $line){
|
||||||
$nameValue = explode(":", $line, 2);
|
$nameValue = explode(":", $line, 2);
|
||||||
if(isset($nameValue[1])){
|
if(isset($nameValue[1])){
|
||||||
$headerGroup[trim(strtolower($nameValue[0]))] = trim($nameValue[1]);
|
$headerGroup[trim(strtolower($nameValue[0]))] = trim($nameValue[1]);
|
||||||
|
@ -69,6 +69,7 @@ abstract class Terminal{
|
|||||||
public static string $COLOR_MATERIAL_DIAMOND = "";
|
public static string $COLOR_MATERIAL_DIAMOND = "";
|
||||||
public static string $COLOR_MATERIAL_LAPIS = "";
|
public static string $COLOR_MATERIAL_LAPIS = "";
|
||||||
public static string $COLOR_MATERIAL_AMETHYST = "";
|
public static string $COLOR_MATERIAL_AMETHYST = "";
|
||||||
|
public static string $COLOR_MATERIAL_RESIN = "";
|
||||||
|
|
||||||
private static ?bool $formattingCodes = null;
|
private static ?bool $formattingCodes = null;
|
||||||
|
|
||||||
@ -131,6 +132,7 @@ abstract class Terminal{
|
|||||||
self::$COLOR_MATERIAL_DIAMOND = $color(37);
|
self::$COLOR_MATERIAL_DIAMOND = $color(37);
|
||||||
self::$COLOR_MATERIAL_LAPIS = $color(24);
|
self::$COLOR_MATERIAL_LAPIS = $color(24);
|
||||||
self::$COLOR_MATERIAL_AMETHYST = $color(98);
|
self::$COLOR_MATERIAL_AMETHYST = $color(98);
|
||||||
|
self::$COLOR_MATERIAL_RESIN = $color(208);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function getEscapeCodes() : void{
|
protected static function getEscapeCodes() : void{
|
||||||
@ -174,11 +176,12 @@ abstract class Terminal{
|
|||||||
self::$COLOR_MATERIAL_DIAMOND = $colors >= 256 ? $setaf(37) : $setaf(14);
|
self::$COLOR_MATERIAL_DIAMOND = $colors >= 256 ? $setaf(37) : $setaf(14);
|
||||||
self::$COLOR_MATERIAL_LAPIS = $colors >= 256 ? $setaf(24) : $setaf(12);
|
self::$COLOR_MATERIAL_LAPIS = $colors >= 256 ? $setaf(24) : $setaf(12);
|
||||||
self::$COLOR_MATERIAL_AMETHYST = $colors >= 256 ? $setaf(98) : $setaf(13);
|
self::$COLOR_MATERIAL_AMETHYST = $colors >= 256 ? $setaf(98) : $setaf(13);
|
||||||
|
self::$COLOR_MATERIAL_RESIN = $colors >= 256 ? $setaf(208) : $setaf(11);
|
||||||
}else{
|
}else{
|
||||||
self::$COLOR_BLACK = self::$COLOR_DARK_GRAY = self::$COLOR_MATERIAL_NETHERITE = $setaf(0);
|
self::$COLOR_BLACK = self::$COLOR_DARK_GRAY = self::$COLOR_MATERIAL_NETHERITE = $setaf(0);
|
||||||
self::$COLOR_RED = self::$COLOR_DARK_RED = self::$COLOR_MATERIAL_REDSTONE = self::$COLOR_MATERIAL_COPPER = $setaf(1);
|
self::$COLOR_RED = self::$COLOR_DARK_RED = self::$COLOR_MATERIAL_REDSTONE = self::$COLOR_MATERIAL_COPPER = $setaf(1);
|
||||||
self::$COLOR_GREEN = self::$COLOR_DARK_GREEN = self::$COLOR_MATERIAL_EMERALD = $setaf(2);
|
self::$COLOR_GREEN = self::$COLOR_DARK_GREEN = self::$COLOR_MATERIAL_EMERALD = $setaf(2);
|
||||||
self::$COLOR_YELLOW = self::$COLOR_GOLD = self::$COLOR_MINECOIN_GOLD = self::$COLOR_MATERIAL_GOLD = $setaf(3);
|
self::$COLOR_YELLOW = self::$COLOR_GOLD = self::$COLOR_MINECOIN_GOLD = self::$COLOR_MATERIAL_GOLD = self::$COLOR_MATERIAL_RESIN = $setaf(3);
|
||||||
self::$COLOR_BLUE = self::$COLOR_DARK_BLUE = self::$COLOR_MATERIAL_LAPIS = $setaf(4);
|
self::$COLOR_BLUE = self::$COLOR_DARK_BLUE = self::$COLOR_MATERIAL_LAPIS = $setaf(4);
|
||||||
self::$COLOR_LIGHT_PURPLE = self::$COLOR_PURPLE = self::$COLOR_MATERIAL_AMETHYST = $setaf(5);
|
self::$COLOR_LIGHT_PURPLE = self::$COLOR_PURPLE = self::$COLOR_MATERIAL_AMETHYST = $setaf(5);
|
||||||
self::$COLOR_AQUA = self::$COLOR_DARK_AQUA = self::$COLOR_MATERIAL_DIAMOND = $setaf(6);
|
self::$COLOR_AQUA = self::$COLOR_DARK_AQUA = self::$COLOR_MATERIAL_DIAMOND = $setaf(6);
|
||||||
@ -253,6 +256,7 @@ abstract class Terminal{
|
|||||||
TextFormat::MATERIAL_DIAMOND => Terminal::$COLOR_MATERIAL_DIAMOND,
|
TextFormat::MATERIAL_DIAMOND => Terminal::$COLOR_MATERIAL_DIAMOND,
|
||||||
TextFormat::MATERIAL_LAPIS => Terminal::$COLOR_MATERIAL_LAPIS,
|
TextFormat::MATERIAL_LAPIS => Terminal::$COLOR_MATERIAL_LAPIS,
|
||||||
TextFormat::MATERIAL_AMETHYST => Terminal::$COLOR_MATERIAL_AMETHYST,
|
TextFormat::MATERIAL_AMETHYST => Terminal::$COLOR_MATERIAL_AMETHYST,
|
||||||
|
TextFormat::MATERIAL_RESIN => Terminal::$COLOR_MATERIAL_RESIN,
|
||||||
default => $token,
|
default => $token,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ abstract class TextFormat{
|
|||||||
public const MATERIAL_DIAMOND = TextFormat::ESCAPE . "s";
|
public const MATERIAL_DIAMOND = TextFormat::ESCAPE . "s";
|
||||||
public const MATERIAL_LAPIS = TextFormat::ESCAPE . "t";
|
public const MATERIAL_LAPIS = TextFormat::ESCAPE . "t";
|
||||||
public const MATERIAL_AMETHYST = TextFormat::ESCAPE . "u";
|
public const MATERIAL_AMETHYST = TextFormat::ESCAPE . "u";
|
||||||
|
public const MATERIAL_RESIN = TextFormat::ESCAPE . "v";
|
||||||
|
|
||||||
public const COLORS = [
|
public const COLORS = [
|
||||||
self::BLACK => self::BLACK,
|
self::BLACK => self::BLACK,
|
||||||
@ -102,6 +103,7 @@ abstract class TextFormat{
|
|||||||
self::MATERIAL_DIAMOND => self::MATERIAL_DIAMOND,
|
self::MATERIAL_DIAMOND => self::MATERIAL_DIAMOND,
|
||||||
self::MATERIAL_LAPIS => self::MATERIAL_LAPIS,
|
self::MATERIAL_LAPIS => self::MATERIAL_LAPIS,
|
||||||
self::MATERIAL_AMETHYST => self::MATERIAL_AMETHYST,
|
self::MATERIAL_AMETHYST => self::MATERIAL_AMETHYST,
|
||||||
|
self::MATERIAL_RESIN => self::MATERIAL_RESIN,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const OBFUSCATED = TextFormat::ESCAPE . "k";
|
public const OBFUSCATED = TextFormat::ESCAPE . "k";
|
||||||
@ -150,7 +152,7 @@ abstract class TextFormat{
|
|||||||
* @return string[]
|
* @return string[]
|
||||||
*/
|
*/
|
||||||
public static function tokenize(string $string) : array{
|
public static function tokenize(string $string) : array{
|
||||||
$result = preg_split("/(" . TextFormat::ESCAPE . "[0-9a-u])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
$result = preg_split("/(" . TextFormat::ESCAPE . "[0-9a-v])/u", $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
|
||||||
if($result === false) throw self::makePcreError();
|
if($result === false) throw self::makePcreError();
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
@ -164,7 +166,7 @@ abstract class TextFormat{
|
|||||||
$string = mb_scrub($string, 'UTF-8');
|
$string = mb_scrub($string, 'UTF-8');
|
||||||
$string = self::preg_replace("/[\x{E000}-\x{F8FF}]/u", "", $string); //remove unicode private-use-area characters (they might break the console)
|
$string = self::preg_replace("/[\x{E000}-\x{F8FF}]/u", "", $string); //remove unicode private-use-area characters (they might break the console)
|
||||||
if($removeFormat){
|
if($removeFormat){
|
||||||
$string = str_replace(TextFormat::ESCAPE, "", self::preg_replace("/" . TextFormat::ESCAPE . "[0-9a-u]/u", "", $string));
|
$string = str_replace(TextFormat::ESCAPE, "", self::preg_replace("/" . TextFormat::ESCAPE . "[0-9a-v]/u", "", $string));
|
||||||
}
|
}
|
||||||
return str_replace("\x1b", "", self::preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string));
|
return str_replace("\x1b", "", self::preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string));
|
||||||
}
|
}
|
||||||
@ -175,7 +177,7 @@ abstract class TextFormat{
|
|||||||
* @param string $placeholder default "&"
|
* @param string $placeholder default "&"
|
||||||
*/
|
*/
|
||||||
public static function colorize(string $string, string $placeholder = "&") : string{
|
public static function colorize(string $string, string $placeholder = "&") : string{
|
||||||
return self::preg_replace('/' . preg_quote($placeholder, "/") . '([0-9a-u])/u', TextFormat::ESCAPE . '$1', $string);
|
return self::preg_replace('/' . preg_quote($placeholder, "/") . '([0-9a-v])/u', TextFormat::ESCAPE . '$1', $string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -252,6 +254,7 @@ abstract class TextFormat{
|
|||||||
TextFormat::MATERIAL_DIAMOND => "color:#2cb9a8",
|
TextFormat::MATERIAL_DIAMOND => "color:#2cb9a8",
|
||||||
TextFormat::MATERIAL_LAPIS => "color:#20487a",
|
TextFormat::MATERIAL_LAPIS => "color:#20487a",
|
||||||
TextFormat::MATERIAL_AMETHYST => "color:#9a5cc5",
|
TextFormat::MATERIAL_AMETHYST => "color:#9a5cc5",
|
||||||
|
TextFormat::MATERIAL_RESIN => "color:#fc7812",
|
||||||
TextFormat::BOLD => "font-weight:bold",
|
TextFormat::BOLD => "font-weight:bold",
|
||||||
TextFormat::ITALIC => "font-style:italic",
|
TextFormat::ITALIC => "font-style:italic",
|
||||||
default => null
|
default => null
|
||||||
|
@ -369,7 +369,7 @@ final class Utils{
|
|||||||
debug_zval_dump($value);
|
debug_zval_dump($value);
|
||||||
$contents = ob_get_contents();
|
$contents = ob_get_contents();
|
||||||
if($contents === false) throw new AssumptionFailedError("ob_get_contents() should never return false here");
|
if($contents === false) throw new AssumptionFailedError("ob_get_contents() should never return false here");
|
||||||
$ret = explode("\n", $contents);
|
$ret = explode("\n", $contents, limit: 2);
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
|
|
||||||
if(preg_match('/^.* refcount\\(([0-9]+)\\)\\{$/', trim($ret[0]), $m) > 0){
|
if(preg_match('/^.* refcount\\(([0-9]+)\\)\\{$/', trim($ret[0]), $m) > 0){
|
||||||
@ -587,7 +587,7 @@ final class Utils{
|
|||||||
* @phpstan-param \Closure(TMemberType) : void $validator
|
* @phpstan-param \Closure(TMemberType) : void $validator
|
||||||
*/
|
*/
|
||||||
public static function validateArrayValueType(array $array, \Closure $validator) : void{
|
public static function validateArrayValueType(array $array, \Closure $validator) : void{
|
||||||
foreach($array as $k => $v){
|
foreach(Utils::promoteKeys($array) as $k => $v){
|
||||||
try{
|
try{
|
||||||
$validator($v);
|
$validator($v);
|
||||||
}catch(\TypeError $e){
|
}catch(\TypeError $e){
|
||||||
|
@ -375,6 +375,8 @@ class World implements ChunkManager{
|
|||||||
|
|
||||||
private \Logger $logger;
|
private \Logger $logger;
|
||||||
|
|
||||||
|
private RuntimeBlockStateRegistry $blockStateRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phpstan-return ChunkPosHash
|
* @phpstan-return ChunkPosHash
|
||||||
*/
|
*/
|
||||||
@ -488,6 +490,7 @@ class World implements ChunkManager{
|
|||||||
$this->displayName = $this->provider->getWorldData()->getName();
|
$this->displayName = $this->provider->getWorldData()->getName();
|
||||||
$this->logger = new \PrefixedLogger($server->getLogger(), "World: $this->displayName");
|
$this->logger = new \PrefixedLogger($server->getLogger(), "World: $this->displayName");
|
||||||
|
|
||||||
|
$this->blockStateRegistry = RuntimeBlockStateRegistry::getInstance();
|
||||||
$this->minY = $this->provider->getWorldMinY();
|
$this->minY = $this->provider->getWorldMinY();
|
||||||
$this->maxY = $this->provider->getWorldMaxY();
|
$this->maxY = $this->provider->getWorldMaxY();
|
||||||
|
|
||||||
@ -559,7 +562,7 @@ class World implements ChunkManager{
|
|||||||
}catch(BlockStateDeserializeException){
|
}catch(BlockStateDeserializeException){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$block = RuntimeBlockStateRegistry::getInstance()->fromStateId(GlobalBlockStateHandlers::getDeserializer()->deserialize($blockStateData));
|
$block = $this->blockStateRegistry->fromStateId(GlobalBlockStateHandlers::getDeserializer()->deserialize($blockStateData));
|
||||||
}else{
|
}else{
|
||||||
//TODO: we probably ought to log an error here
|
//TODO: we probably ought to log an error here
|
||||||
continue;
|
continue;
|
||||||
@ -570,7 +573,7 @@ class World implements ChunkManager{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(RuntimeBlockStateRegistry::getInstance()->getAllKnownStates() as $state){
|
foreach($this->blockStateRegistry->getAllKnownStates() as $state){
|
||||||
$dontTickName = $dontTickBlocks[$state->getTypeId()] ?? null;
|
$dontTickName = $dontTickBlocks[$state->getTypeId()] ?? null;
|
||||||
if($dontTickName === null && $state->ticksRandomly()){
|
if($dontTickName === null && $state->ticksRandomly()){
|
||||||
$this->randomTickBlocks[$state->getStateId()] = true;
|
$this->randomTickBlocks[$state->getStateId()] = true;
|
||||||
@ -1394,7 +1397,7 @@ class World implements ChunkManager{
|
|||||||
$entity->onRandomUpdate();
|
$entity->onRandomUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
$blockFactory = RuntimeBlockStateRegistry::getInstance();
|
$blockFactory = $this->blockStateRegistry;
|
||||||
foreach($chunk->getSubChunks() as $Y => $subChunk){
|
foreach($chunk->getSubChunks() as $Y => $subChunk){
|
||||||
if(!$subChunk->isEmptyFast()){
|
if(!$subChunk->isEmptyFast()){
|
||||||
$k = 0;
|
$k = 0;
|
||||||
@ -1528,24 +1531,48 @@ class World implements ChunkManager{
|
|||||||
|
|
||||||
$collides = [];
|
$collides = [];
|
||||||
|
|
||||||
|
$collisionInfo = $this->blockStateRegistry->collisionInfo;
|
||||||
if($targetFirst){
|
if($targetFirst){
|
||||||
for($z = $minZ; $z <= $maxZ; ++$z){
|
for($z = $minZ; $z <= $maxZ; ++$z){
|
||||||
|
$zOverflow = $z === $minZ || $z === $maxZ;
|
||||||
for($x = $minX; $x <= $maxX; ++$x){
|
for($x = $minX; $x <= $maxX; ++$x){
|
||||||
|
$zxOverflow = $zOverflow || $x === $minX || $x === $maxX;
|
||||||
for($y = $minY; $y <= $maxY; ++$y){
|
for($y = $minY; $y <= $maxY; ++$y){
|
||||||
$block = $this->getBlockAt($x, $y, $z);
|
$overflow = $zxOverflow || $y === $minY || $y === $maxY;
|
||||||
if($block->collidesWithBB($bb)){
|
|
||||||
return [$block];
|
$stateCollisionInfo = $this->getBlockCollisionInfo($x, $y, $z, $collisionInfo);
|
||||||
|
if($overflow ?
|
||||||
|
$stateCollisionInfo === RuntimeBlockStateRegistry::COLLISION_MAY_OVERFLOW && $this->getBlockAt($x, $y, $z)->collidesWithBB($bb) :
|
||||||
|
match ($stateCollisionInfo) {
|
||||||
|
RuntimeBlockStateRegistry::COLLISION_CUBE => true,
|
||||||
|
RuntimeBlockStateRegistry::COLLISION_NONE => false,
|
||||||
|
default => $this->getBlockAt($x, $y, $z)->collidesWithBB($bb)
|
||||||
|
}
|
||||||
|
){
|
||||||
|
return [$this->getBlockAt($x, $y, $z)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
//TODO: duplicated code :( this way is better for performance though
|
||||||
for($z = $minZ; $z <= $maxZ; ++$z){
|
for($z = $minZ; $z <= $maxZ; ++$z){
|
||||||
|
$zOverflow = $z === $minZ || $z === $maxZ;
|
||||||
for($x = $minX; $x <= $maxX; ++$x){
|
for($x = $minX; $x <= $maxX; ++$x){
|
||||||
|
$zxOverflow = $zOverflow || $x === $minX || $x === $maxX;
|
||||||
for($y = $minY; $y <= $maxY; ++$y){
|
for($y = $minY; $y <= $maxY; ++$y){
|
||||||
$block = $this->getBlockAt($x, $y, $z);
|
$overflow = $zxOverflow || $y === $minY || $y === $maxY;
|
||||||
if($block->collidesWithBB($bb)){
|
|
||||||
$collides[] = $block;
|
$stateCollisionInfo = $this->getBlockCollisionInfo($x, $y, $z, $collisionInfo);
|
||||||
|
if($overflow ?
|
||||||
|
$stateCollisionInfo === RuntimeBlockStateRegistry::COLLISION_MAY_OVERFLOW && $this->getBlockAt($x, $y, $z)->collidesWithBB($bb) :
|
||||||
|
match ($stateCollisionInfo) {
|
||||||
|
RuntimeBlockStateRegistry::COLLISION_CUBE => true,
|
||||||
|
RuntimeBlockStateRegistry::COLLISION_NONE => false,
|
||||||
|
default => $this->getBlockAt($x, $y, $z)->collidesWithBB($bb)
|
||||||
|
}
|
||||||
|
){
|
||||||
|
$collides[] = $this->getBlockAt($x, $y, $z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1555,24 +1582,64 @@ class World implements ChunkManager{
|
|||||||
return $collides;
|
return $collides;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int[] $collisionInfo
|
||||||
|
* @phpstan-param array<int, int> $collisionInfo
|
||||||
|
*/
|
||||||
|
private function getBlockCollisionInfo(int $x, int $y, int $z, array $collisionInfo) : int{
|
||||||
|
if(!$this->isInWorld($x, $y, $z)){
|
||||||
|
return RuntimeBlockStateRegistry::COLLISION_NONE;
|
||||||
|
}
|
||||||
|
$chunk = $this->getChunk($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE);
|
||||||
|
if($chunk === null){
|
||||||
|
return RuntimeBlockStateRegistry::COLLISION_NONE;
|
||||||
|
}
|
||||||
|
$stateId = $chunk
|
||||||
|
->getSubChunk($y >> SubChunk::COORD_BIT_SIZE)
|
||||||
|
->getBlockStateId(
|
||||||
|
$x & SubChunk::COORD_MASK,
|
||||||
|
$y & SubChunk::COORD_MASK,
|
||||||
|
$z & SubChunk::COORD_MASK
|
||||||
|
);
|
||||||
|
return $collisionInfo[$stateId];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of all block AABBs which overlap the full block area at the given coordinates.
|
* Returns a list of all block AABBs which overlap the full block area at the given coordinates.
|
||||||
* This checks a padding of 1 block around the coordinates to account for oversized AABBs of blocks like fences.
|
* This checks a padding of 1 block around the coordinates to account for oversized AABBs of blocks like fences.
|
||||||
* Larger AABBs (>= 2 blocks on any axis) are not accounted for.
|
* Larger AABBs (>= 2 blocks on any axis) are not accounted for.
|
||||||
*
|
*
|
||||||
|
* @param int[] $collisionInfo
|
||||||
|
* @phpstan-param array<int, int> $collisionInfo
|
||||||
|
*
|
||||||
* @return AxisAlignedBB[]
|
* @return AxisAlignedBB[]
|
||||||
* @phpstan-return list<AxisAlignedBB>
|
* @phpstan-return list<AxisAlignedBB>
|
||||||
*/
|
*/
|
||||||
private function getBlockCollisionBoxesForCell(int $x, int $y, int $z) : array{
|
private function getBlockCollisionBoxesForCell(int $x, int $y, int $z, array $collisionInfo) : array{
|
||||||
$block = $this->getBlockAt($x, $y, $z);
|
$stateCollisionInfo = $this->getBlockCollisionInfo($x, $y, $z, $collisionInfo);
|
||||||
$boxes = $block->getCollisionBoxes();
|
$boxes = match($stateCollisionInfo){
|
||||||
|
RuntimeBlockStateRegistry::COLLISION_NONE => [],
|
||||||
|
RuntimeBlockStateRegistry::COLLISION_CUBE => [AxisAlignedBB::one()->offset($x, $y, $z)],
|
||||||
|
default => $this->getBlockAt($x, $y, $z)->getCollisionBoxes()
|
||||||
|
};
|
||||||
|
|
||||||
$cellBB = AxisAlignedBB::one()->offset($x, $y, $z);
|
//overlapping AABBs can't make any difference if this is a cube, so we can save some CPU cycles in this common case
|
||||||
foreach(Facing::OFFSET as [$dx, $dy, $dz]){
|
if($stateCollisionInfo !== RuntimeBlockStateRegistry::COLLISION_CUBE){
|
||||||
$extraBoxes = $this->getBlockAt($x + $dx, $y + $dy, $z + $dz)->getCollisionBoxes();
|
$cellBB = null;
|
||||||
foreach($extraBoxes as $extraBox){
|
foreach(Facing::OFFSET as [$dx, $dy, $dz]){
|
||||||
if($extraBox->intersectsWith($cellBB)){
|
$offsetX = $x + $dx;
|
||||||
$boxes[] = $extraBox;
|
$offsetY = $y + $dy;
|
||||||
|
$offsetZ = $z + $dz;
|
||||||
|
$stateCollisionInfo = $this->getBlockCollisionInfo($offsetX, $offsetY, $offsetZ, $collisionInfo);
|
||||||
|
if($stateCollisionInfo === RuntimeBlockStateRegistry::COLLISION_MAY_OVERFLOW){
|
||||||
|
//avoid allocating this unless it's needed
|
||||||
|
$cellBB ??= AxisAlignedBB::one()->offset($x, $y, $z);
|
||||||
|
$extraBoxes = $this->getBlockAt($offsetX, $offsetY, $offsetZ)->getCollisionBoxes();
|
||||||
|
foreach($extraBoxes as $extraBox){
|
||||||
|
if($extraBox->intersectsWith($cellBB)){
|
||||||
|
$boxes[] = $extraBox;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1594,13 +1661,15 @@ class World implements ChunkManager{
|
|||||||
|
|
||||||
$collides = [];
|
$collides = [];
|
||||||
|
|
||||||
|
$collisionInfo = $this->blockStateRegistry->collisionInfo;
|
||||||
|
|
||||||
for($z = $minZ; $z <= $maxZ; ++$z){
|
for($z = $minZ; $z <= $maxZ; ++$z){
|
||||||
for($x = $minX; $x <= $maxX; ++$x){
|
for($x = $minX; $x <= $maxX; ++$x){
|
||||||
$chunkPosHash = World::chunkHash($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE);
|
$chunkPosHash = World::chunkHash($x >> Chunk::COORD_BIT_SIZE, $z >> Chunk::COORD_BIT_SIZE);
|
||||||
for($y = $minY; $y <= $maxY; ++$y){
|
for($y = $minY; $y <= $maxY; ++$y){
|
||||||
$relativeBlockHash = World::chunkBlockHash($x, $y, $z);
|
$relativeBlockHash = World::chunkBlockHash($x, $y, $z);
|
||||||
|
|
||||||
$boxes = $this->blockCollisionBoxCache[$chunkPosHash][$relativeBlockHash] ??= $this->getBlockCollisionBoxesForCell($x, $y, $z);
|
$boxes = $this->blockCollisionBoxCache[$chunkPosHash][$relativeBlockHash] ??= $this->getBlockCollisionBoxesForCell($x, $y, $z, $collisionInfo);
|
||||||
|
|
||||||
foreach($boxes as $blockBB){
|
foreach($boxes as $blockBB){
|
||||||
if($blockBB->intersectsWith($bb)){
|
if($blockBB->intersectsWith($bb)){
|
||||||
@ -1795,7 +1864,7 @@ class World implements ChunkManager{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$blockFactory = RuntimeBlockStateRegistry::getInstance();
|
$blockFactory = $this->blockStateRegistry;
|
||||||
$this->timings->doBlockSkyLightUpdates->startTiming();
|
$this->timings->doBlockSkyLightUpdates->startTiming();
|
||||||
if($this->skyLightUpdate === null){
|
if($this->skyLightUpdate === null){
|
||||||
$this->skyLightUpdate = new SkyLightUpdate(new SubChunkExplorer($this), $blockFactory->lightFilter, $blockFactory->blocksDirectSkyLight);
|
$this->skyLightUpdate = new SkyLightUpdate(new SubChunkExplorer($this), $blockFactory->lightFilter, $blockFactory->blocksDirectSkyLight);
|
||||||
@ -1914,7 +1983,7 @@ class World implements ChunkManager{
|
|||||||
|
|
||||||
$chunk = $this->chunks[$chunkHash] ?? null;
|
$chunk = $this->chunks[$chunkHash] ?? null;
|
||||||
if($chunk !== null){
|
if($chunk !== null){
|
||||||
$block = RuntimeBlockStateRegistry::getInstance()->fromStateId($chunk->getBlockStateId($x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK));
|
$block = $this->blockStateRegistry->fromStateId($chunk->getBlockStateId($x & Chunk::COORD_MASK, $y, $z & Chunk::COORD_MASK));
|
||||||
}else{
|
}else{
|
||||||
$addToCache = false;
|
$addToCache = false;
|
||||||
$block = VanillaBlocks::AIR();
|
$block = VanillaBlocks::AIR();
|
||||||
@ -2573,7 +2642,7 @@ class World implements ChunkManager{
|
|||||||
$localY = $tilePosition->getFloorY();
|
$localY = $tilePosition->getFloorY();
|
||||||
$localZ = $tilePosition->getFloorZ() & Chunk::COORD_MASK;
|
$localZ = $tilePosition->getFloorZ() & Chunk::COORD_MASK;
|
||||||
|
|
||||||
$newBlock = RuntimeBlockStateRegistry::getInstance()->fromStateId($chunk->getBlockStateId($localX, $localY, $localZ));
|
$newBlock = $this->blockStateRegistry->fromStateId($chunk->getBlockStateId($localX, $localY, $localZ));
|
||||||
$expectedTileClass = $newBlock->getIdInfo()->getTileClass();
|
$expectedTileClass = $newBlock->getIdInfo()->getTileClass();
|
||||||
if(
|
if(
|
||||||
$expectedTileClass === null || //new block doesn't expect a tile
|
$expectedTileClass === null || //new block doesn't expect a tile
|
||||||
|
@ -51,12 +51,12 @@ use function time;
|
|||||||
class BedrockWorldData extends BaseNbtWorldData{
|
class BedrockWorldData extends BaseNbtWorldData{
|
||||||
|
|
||||||
public const CURRENT_STORAGE_VERSION = 10;
|
public const CURRENT_STORAGE_VERSION = 10;
|
||||||
public const CURRENT_STORAGE_NETWORK_VERSION = 776;
|
public const CURRENT_STORAGE_NETWORK_VERSION = 786;
|
||||||
public const CURRENT_CLIENT_VERSION_TARGET = [
|
public const CURRENT_CLIENT_VERSION_TARGET = [
|
||||||
1, //major
|
1, //major
|
||||||
21, //minor
|
21, //minor
|
||||||
60, //patch
|
70, //patch
|
||||||
33, //revision
|
3, //revision
|
||||||
0 //is beta
|
0 //is beta
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -26,10 +26,12 @@ namespace pocketmine\world\generator;
|
|||||||
use pocketmine\data\bedrock\BiomeIds;
|
use pocketmine\data\bedrock\BiomeIds;
|
||||||
use pocketmine\item\LegacyStringToItemParser;
|
use pocketmine\item\LegacyStringToItemParser;
|
||||||
use pocketmine\item\LegacyStringToItemParserException;
|
use pocketmine\item\LegacyStringToItemParserException;
|
||||||
|
use pocketmine\world\World;
|
||||||
use function array_map;
|
use function array_map;
|
||||||
use function explode;
|
use function explode;
|
||||||
use function preg_match;
|
use function preg_match;
|
||||||
use function preg_match_all;
|
use function preg_match_all;
|
||||||
|
use const PHP_INT_MAX;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@ -70,7 +72,7 @@ final class FlatGeneratorOptions{
|
|||||||
*/
|
*/
|
||||||
public static function parseLayers(string $layers) : array{
|
public static function parseLayers(string $layers) : array{
|
||||||
$result = [];
|
$result = [];
|
||||||
$split = array_map('\trim', explode(',', $layers));
|
$split = array_map('\trim', explode(',', $layers, limit: World::Y_MAX - World::Y_MIN));
|
||||||
$y = 0;
|
$y = 0;
|
||||||
$itemParser = LegacyStringToItemParser::getInstance();
|
$itemParser = LegacyStringToItemParser::getInstance();
|
||||||
foreach($split as $line){
|
foreach($split as $line){
|
||||||
@ -96,7 +98,7 @@ final class FlatGeneratorOptions{
|
|||||||
* @throws InvalidGeneratorOptionsException
|
* @throws InvalidGeneratorOptionsException
|
||||||
*/
|
*/
|
||||||
public static function parsePreset(string $presetString) : self{
|
public static function parsePreset(string $presetString) : self{
|
||||||
$preset = explode(";", $presetString);
|
$preset = explode(";", $presetString, limit: 4);
|
||||||
$blocks = $preset[1] ?? "";
|
$blocks = $preset[1] ?? "";
|
||||||
$biomeId = (int) ($preset[2] ?? BiomeIds::PLAINS);
|
$biomeId = (int) ($preset[2] ?? BiomeIds::PLAINS);
|
||||||
$optionsString = $preset[3] ?? "";
|
$optionsString = $preset[3] ?? "";
|
||||||
@ -109,9 +111,10 @@ final class FlatGeneratorOptions{
|
|||||||
$params = true;
|
$params = true;
|
||||||
if($matches[3][$i] !== ""){
|
if($matches[3][$i] !== ""){
|
||||||
$params = [];
|
$params = [];
|
||||||
$p = explode(" ", $matches[3][$i]);
|
$p = explode(" ", $matches[3][$i], limit: PHP_INT_MAX);
|
||||||
foreach($p as $k){
|
foreach($p as $k){
|
||||||
$k = explode("=", $k);
|
//TODO: this should be limited to 2 parts, but 3 preserves old behaviour when given e.g. treecount=20=1
|
||||||
|
$k = explode("=", $k, limit: 3);
|
||||||
if(isset($k[1])){
|
if(isset($k[1])){
|
||||||
$params[$k[0]] = $k[1];
|
$params[$k[0]] = $k[1];
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,8 @@ class EntityAttackNoDamageSound implements Sound{
|
|||||||
-1,
|
-1,
|
||||||
"minecraft:player",
|
"minecraft:player",
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
-1
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,8 @@ class EntityAttackSound implements Sound{
|
|||||||
-1,
|
-1,
|
||||||
"minecraft:player",
|
"minecraft:player",
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
-1
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,8 @@ class EntityLandSound implements Sound{
|
|||||||
TypeConverter::getInstance()->getBlockTranslator()->internalIdToNetworkId($this->blockLandedOn->getStateId()),
|
TypeConverter::getInstance()->getBlockTranslator()->internalIdToNetworkId($this->blockLandedOn->getStateId()),
|
||||||
$this->entity::getNetworkTypeId(),
|
$this->entity::getNetworkTypeId(),
|
||||||
false, //TODO: does isBaby have any relevance here?
|
false, //TODO: does isBaby have any relevance here?
|
||||||
false
|
false,
|
||||||
|
$this->entity->getId()
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,8 @@ class EntityLongFallSound implements Sound{
|
|||||||
-1,
|
-1,
|
||||||
$this->entity::getNetworkTypeId(),
|
$this->entity::getNetworkTypeId(),
|
||||||
false, //TODO: is isBaby relevant here?
|
false, //TODO: is isBaby relevant here?
|
||||||
false
|
false,
|
||||||
|
$this->entity->getId()
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,8 @@ class EntityShortFallSound implements Sound{
|
|||||||
-1,
|
-1,
|
||||||
$this->entity::getNetworkTypeId(),
|
$this->entity::getNetworkTypeId(),
|
||||||
false, //TODO: does isBaby have any relevance here?
|
false, //TODO: does isBaby have any relevance here?
|
||||||
false
|
false,
|
||||||
|
-1
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,6 @@ use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
|
|||||||
class ThrowSound implements Sound{
|
class ThrowSound implements Sound{
|
||||||
|
|
||||||
public function encode(Vector3 $pos) : array{
|
public function encode(Vector3 $pos) : array{
|
||||||
return [LevelSoundEventPacket::create(LevelSoundEvent::THROW, $pos, -1, "minecraft:player", false, false)];
|
return [LevelSoundEventPacket::create(LevelSoundEvent::THROW, $pos, -1, "minecraft:player", false, false, -1)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,8 @@ final class WaterSplashSound implements Sound{
|
|||||||
(int) ($this->volume * 16777215),
|
(int) ($this->volume * 16777215),
|
||||||
":",
|
":",
|
||||||
false,
|
false,
|
||||||
false
|
false,
|
||||||
|
-1
|
||||||
)];
|
)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,12 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/Server.php
|
path: ../../../src/Server.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Dynamic new is not allowed\.$#'
|
||||||
|
identifier: pocketmine.new.dynamic
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/Server.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Method pocketmine\\Server\:\:getCommandAliases\(\) should return array\<string, list\<string\>\> but returns array\<string, array\<mixed\>\>\.$#'
|
message: '#^Method pocketmine\\Server\:\:getCommandAliases\(\) should return array\<string, list\<string\>\> but returns array\<string, array\<mixed\>\>\.$#'
|
||||||
identifier: return.type
|
identifier: return.type
|
||||||
@ -48,18 +54,18 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/VersionInfo.php
|
path: ../../../src/VersionInfo.php
|
||||||
|
|
||||||
-
|
|
||||||
message: '#^Method pocketmine\\VersionInfo\:\:GIT_HASH\(\) should return string but returns mixed\.$#'
|
|
||||||
identifier: return.type
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/VersionInfo.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Static property pocketmine\\VersionInfo\:\:\$gitHash \(string\|null\) does not accept mixed\.$#'
|
message: '#^Static property pocketmine\\VersionInfo\:\:\$gitHash \(string\|null\) does not accept mixed\.$#'
|
||||||
identifier: assign.propertyType
|
identifier: assign.propertyType
|
||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/VersionInfo.php
|
path: ../../../src/VersionInfo.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Dynamic new is not allowed\.$#'
|
||||||
|
identifier: pocketmine.new.dynamic
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/block/Block.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#'
|
message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getBlockAt\(\) expects int, float\|int given\.$#'
|
||||||
identifier: argument.type
|
identifier: argument.type
|
||||||
@ -516,6 +522,12 @@ parameters:
|
|||||||
count: 3
|
count: 3
|
||||||
path: ../../../src/block/tile/Spawnable.php
|
path: ../../../src/block/tile/Spawnable.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Dynamic new is not allowed\.$#'
|
||||||
|
identifier: pocketmine.new.dynamic
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/block/tile/TileFactory.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getPotentialLightAt\(\) expects int, float\|int given\.$#'
|
message: '#^Parameter \#1 \$x of method pocketmine\\world\\World\:\:getPotentialLightAt\(\) expects int, float\|int given\.$#'
|
||||||
identifier: argument.type
|
identifier: argument.type
|
||||||
@ -918,24 +930,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/plugin/PluginDescription.php
|
path: ../../../src/plugin/PluginDescription.php
|
||||||
|
|
||||||
-
|
|
||||||
message: '#^Parameter \#1 \$haystack of function stripos expects string, mixed given\.$#'
|
|
||||||
identifier: argument.type
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/plugin/PluginDescription.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: '#^Parameter \#2 \$subject of function preg_match expects string, mixed given\.$#'
|
|
||||||
identifier: argument.type
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/plugin/PluginDescription.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: '#^Parameter \#3 \$subject of function str_replace expects array\<string\>\|string, mixed given\.$#'
|
|
||||||
identifier: argument.type
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/plugin/PluginDescription.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Property pocketmine\\plugin\\PluginDescription\:\:\$authors \(array\<string\>\) does not accept list\<mixed\>\.$#'
|
message: '#^Property pocketmine\\plugin\\PluginDescription\:\:\$authors \(array\<string\>\) does not accept list\<mixed\>\.$#'
|
||||||
identifier: assign.propertyType
|
identifier: assign.propertyType
|
||||||
@ -961,13 +955,13 @@ parameters:
|
|||||||
path: ../../../src/plugin/PluginManager.php
|
path: ../../../src/plugin/PluginManager.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Method pocketmine\\resourcepacks\\ZippedResourcePack\:\:getPackSize\(\) should return int but returns int\<0, max\>\|false\.$#'
|
message: '#^Dynamic new is not allowed\.$#'
|
||||||
identifier: return.type
|
identifier: pocketmine.new.dynamic
|
||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/resourcepacks/ZippedResourcePack.php
|
path: ../../../src/plugin/PluginManager.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Method pocketmine\\resourcepacks\\ZippedResourcePack\:\:getSha256\(\) should return string but returns string\|false\.$#'
|
message: '#^Method pocketmine\\resourcepacks\\ZippedResourcePack\:\:getPackSize\(\) should return int but returns int\<0, max\>\|false\.$#'
|
||||||
identifier: return.type
|
identifier: return.type
|
||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/resourcepacks/ZippedResourcePack.php
|
path: ../../../src/resourcepacks/ZippedResourcePack.php
|
||||||
@ -1009,7 +1003,7 @@ parameters:
|
|||||||
path: ../../../src/utils/Config.php
|
path: ../../../src/utils/Config.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Parameter \#1 \$config of static method pocketmine\\utils\\Config\:\:writeProperties\(\) expects array\<int\|string, bool\|float\|int\|string\>, array\<int\|string, mixed\> given\.$#'
|
message: '#^Parameter \#1 \$config of static method pocketmine\\utils\\Config\:\:writeProperties\(\) expects array\<int\|string, bool\|float\|int\|string\>, array\<mixed\> given\.$#'
|
||||||
identifier: argument.type
|
identifier: argument.type
|
||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/utils/Config.php
|
path: ../../../src/utils/Config.php
|
||||||
@ -1278,6 +1272,12 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/world/format/io/region/RegionLoader.php
|
path: ../../../src/world/format/io/region/RegionLoader.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Dynamic new is not allowed\.$#'
|
||||||
|
identifier: pocketmine.new.dynamic
|
||||||
|
count: 1
|
||||||
|
path: ../../../src/world/generator/GeneratorRegisterTask.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Method pocketmine\\world\\generator\\biome\\BiomeSelector\:\:pickBiome\(\) should return pocketmine\\world\\biome\\Biome but returns pocketmine\\world\\biome\\Biome\|null\.$#'
|
message: '#^Method pocketmine\\world\\generator\\biome\\BiomeSelector\:\:pickBiome\(\) should return pocketmine\\world\\biome\\Biome but returns pocketmine\\world\\biome\\Biome\|null\.$#'
|
||||||
identifier: return.type
|
identifier: return.type
|
||||||
|
@ -114,12 +114,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: ../../../src/crash/CrashDump.php
|
path: ../../../src/crash/CrashDump.php
|
||||||
|
|
||||||
-
|
|
||||||
message: '#^Call to function assert\(\) with false and ''unknown hit type'' will always evaluate to false\.$#'
|
|
||||||
identifier: function.impossibleType
|
|
||||||
count: 1
|
|
||||||
path: ../../../src/entity/projectile/Projectile.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: '#^Property pocketmine\\item\\WritableBookBase\:\:\$pages \(list\<pocketmine\\item\\WritableBookPage\>\) does not accept non\-empty\-array\<int, pocketmine\\item\\WritableBookPage\>\.$#'
|
message: '#^Property pocketmine\\item\\WritableBookBase\:\:\$pages \(list\<pocketmine\\item\\WritableBookPage\>\) does not accept non\-empty\-array\<int, pocketmine\\item\\WritableBookPage\>\.$#'
|
||||||
identifier: assign.propertyType
|
identifier: assign.propertyType
|
||||||
|
55
tests/phpstan/rules/DisallowDynamicNewRule.php
Normal file
55
tests/phpstan/rules/DisallowDynamicNewRule.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?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\phpstan\rules;
|
||||||
|
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Expr;
|
||||||
|
use PhpParser\Node\Expr\New_;
|
||||||
|
use PHPStan\Analyser\Scope;
|
||||||
|
use PHPStan\Rules\Rule;
|
||||||
|
use PHPStan\Rules\RuleErrorBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-implements Rule<New_>
|
||||||
|
*/
|
||||||
|
final class DisallowDynamicNewRule implements Rule{
|
||||||
|
|
||||||
|
public function getNodeType() : string{
|
||||||
|
return New_::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processNode(Node $node, Scope $scope) : array{
|
||||||
|
/** @var New_ $node */
|
||||||
|
if($node->class instanceof Expr){
|
||||||
|
return [
|
||||||
|
RuleErrorBuilder::message("Dynamic new is not allowed.")
|
||||||
|
->tip("For factories, use closures instead. Closures can implement custom logic, are statically analyzable, and don't restrict the constructor signature.")
|
||||||
|
->identifier("pocketmine.new.dynamic")
|
||||||
|
->build()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
92
tests/phpstan/rules/ExplodeLimitRule.php
Normal file
92
tests/phpstan/rules/ExplodeLimitRule.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?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\phpstan\rules;
|
||||||
|
|
||||||
|
use PhpParser\Node;
|
||||||
|
use PhpParser\Node\Expr\FuncCall;
|
||||||
|
use PhpParser\Node\Name;
|
||||||
|
use PHPStan\Analyser\ArgumentsNormalizer;
|
||||||
|
use PHPStan\Analyser\Scope;
|
||||||
|
use PHPStan\Reflection\ParametersAcceptorSelector;
|
||||||
|
use PHPStan\Reflection\ReflectionProvider;
|
||||||
|
use PHPStan\Rules\Rule;
|
||||||
|
use PHPStan\Rules\RuleErrorBuilder;
|
||||||
|
use function count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @phpstan-implements Rule<FuncCall>
|
||||||
|
*/
|
||||||
|
final class ExplodeLimitRule implements Rule{
|
||||||
|
private ReflectionProvider $reflectionProvider;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ReflectionProvider $reflectionProvider
|
||||||
|
){
|
||||||
|
$this->reflectionProvider = $reflectionProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNodeType() : string{
|
||||||
|
return FuncCall::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processNode(Node $node, Scope $scope) : array{
|
||||||
|
if(!$node->name instanceof Name){
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$this->reflectionProvider->hasFunction($node->name, $scope)){
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$functionReflection = $this->reflectionProvider->getFunction($node->name, $scope);
|
||||||
|
|
||||||
|
if($functionReflection->getName() !== 'explode'){
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$parametersAcceptor = ParametersAcceptorSelector::selectFromArgs(
|
||||||
|
$scope,
|
||||||
|
$node->getArgs(),
|
||||||
|
$functionReflection->getVariants(),
|
||||||
|
$functionReflection->getNamedArgumentsVariants(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$normalizedFuncCall = ArgumentsNormalizer::reorderFuncArguments($parametersAcceptor, $node);
|
||||||
|
|
||||||
|
if($normalizedFuncCall === null){
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = count($normalizedFuncCall->getArgs());
|
||||||
|
if($count !== 3){
|
||||||
|
return [
|
||||||
|
RuleErrorBuilder::message('The $limit parameter of explode() must be set to prevent malicious client data wasting resources.')
|
||||||
|
->identifier("pocketmine.explode.limit")
|
||||||
|
->build()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
@ -51,8 +51,10 @@ use function array_unique;
|
|||||||
use function array_values;
|
use function array_values;
|
||||||
use function count;
|
use function count;
|
||||||
use function dirname;
|
use function dirname;
|
||||||
|
use function fclose;
|
||||||
use function file_exists;
|
use function file_exists;
|
||||||
use function file_put_contents;
|
use function file_put_contents;
|
||||||
|
use function fopen;
|
||||||
use function fwrite;
|
use function fwrite;
|
||||||
use function get_class;
|
use function get_class;
|
||||||
use function get_debug_type;
|
use function get_debug_type;
|
||||||
@ -885,6 +887,44 @@ function cmdUpdateAll(array $argv) : int{
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[] $argv
|
||||||
|
*/
|
||||||
|
function cmdDumpTable(array $argv) : int{
|
||||||
|
$tableFile = $argv[2];
|
||||||
|
$outputFile = $argv[3];
|
||||||
|
|
||||||
|
$output = fopen($outputFile, 'wb');
|
||||||
|
if($output === false){
|
||||||
|
fwrite(STDERR, "Failed to open output file: $outputFile\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = loadUpgradeTableFromFile($tableFile, reverse: false);
|
||||||
|
ksort($table, SORT_STRING);
|
||||||
|
|
||||||
|
foreach(Utils::stringifyKeys($table) as $oldName => $mappings){
|
||||||
|
fwrite($output, "---------- MAPPING LIST: $oldName ----------\n");
|
||||||
|
foreach($mappings as $mapping){
|
||||||
|
$oldNbt = $mapping->old->toVanillaNbt();
|
||||||
|
$oldNbt->setInt("version", $mapping->new->getVersion());
|
||||||
|
|
||||||
|
//intentionally not reused result of toVanillaNbt otherwise output wouldn't include version
|
||||||
|
fwrite($output, "OLD: " . $mapping->old->toVanillaNbt() . "\n");
|
||||||
|
if(!$oldNbt->equals($mapping->new->toVanillaNbt())){
|
||||||
|
fwrite($output, "NEW: " . $mapping->new->toVanillaNbt() . "\n");
|
||||||
|
}else{
|
||||||
|
fwrite($output, "NEW: version bump only (" . $mapping->new->getVersion() . ")\n");
|
||||||
|
}
|
||||||
|
fwrite($output, "-----\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($output);
|
||||||
|
\GlobalLogger::get()->info("Table dump file $outputFile generated successfully.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string[] $argv
|
* @param string[] $argv
|
||||||
*/
|
*/
|
||||||
@ -893,7 +933,8 @@ function main(array $argv) : int{
|
|||||||
"generate" => [["palette upgrade table file", "schema output file"], cmdGenerate(...)],
|
"generate" => [["palette upgrade table file", "schema output file"], cmdGenerate(...)],
|
||||||
"test" => [["palette upgrade table file", "schema output file"], cmdTest(...)],
|
"test" => [["palette upgrade table file", "schema output file"], cmdTest(...)],
|
||||||
"update" => [["schema input file", "old palette file", "updated schema output file"], cmdUpdate(...)],
|
"update" => [["schema input file", "old palette file", "updated schema output file"], cmdUpdate(...)],
|
||||||
"update-all" => [["schema folder", "path to BlockPaletteArchive"], cmdUpdateAll(...)]
|
"update-all" => [["schema folder", "path to BlockPaletteArchive"], cmdUpdateAll(...)],
|
||||||
|
"dump-table" => [["palette upgrade table file", "txt output file"], cmdDumpTable(...)]
|
||||||
];
|
];
|
||||||
|
|
||||||
$selected = $argv[1] ?? null;
|
$selected = $argv[1] ?? null;
|
||||||
|
@ -624,7 +624,7 @@ function main(array $argv) : int{
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach($packets as $lineNum => $line){
|
foreach($packets as $lineNum => $line){
|
||||||
$parts = explode(':', $line);
|
$parts = explode(':', $line, limit: 3);
|
||||||
if(count($parts) !== 2){
|
if(count($parts) !== 2){
|
||||||
fwrite(STDERR, 'Wrong packet format at line ' . ($lineNum + 1) . ', expected read:base64 or write:base64');
|
fwrite(STDERR, 'Wrong packet format at line ' . ($lineNum + 1) . ', expected read:base64 or write:base64');
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user