mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-09 19:24:12 +00:00
Compare commits
43 Commits
feat/anvil
...
5.28.1
Author | SHA1 | Date | |
---|---|---|---|
abb004fbc5 | |||
e0864e7ee8 | |||
dca37d5842 | |||
67f3bb9c52 | |||
04de72e85e | |||
d90fc3415c | |||
134c7309c5 | |||
5e830c7320 | |||
d789c75c00 | |||
f2e7473629 | |||
6f3506360e | |||
1ea5c060fd | |||
4a5c1e7540 | |||
2548422973 | |||
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 |
3
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
3
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@ -57,6 +57,9 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
## Version, OS and game info
|
||||
> [!WARNING]
|
||||
> "Latest" is not a valid version.
|
||||
> Failure to fill these fields with valid information may result in your issue being closed.
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
|
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@ -12,6 +12,10 @@ updates:
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- "version-update:semver-minor"
|
||||
|
||||
#since we lock this to exact versions, it causes conflicts with minor-next & major-next in composer.lock
|
||||
#better to just test updates to this locally anyway since almost every version breaks something
|
||||
- dependency-name: phpstan/phpstan
|
||||
groups:
|
||||
production-patch-updates:
|
||||
dependency-type: production
|
||||
|
10
.github/workflows/build-docker-image.yml
vendored
10
.github/workflows/build-docker-image.yml
vendored
@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Update Docker Hub images
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
@ -53,7 +53,7 @@ jobs:
|
||||
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
uses: docker/build-push-action@v6.16.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
uses: docker/build-push-action@v6.16.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
uses: docker/build-push-action@v6.16.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
uses: docker/build-push-action@v6.16.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.32.0
|
||||
uses: shivammathur/setup-php@2.33.0
|
||||
with:
|
||||
php-version: 8.2
|
||||
|
||||
|
6
.github/workflows/draft-release-pr-check.yml
vendored
6
.github/workflows/draft-release-pr-check.yml
vendored
@ -24,7 +24,7 @@ permissions:
|
||||
jobs:
|
||||
check-intent:
|
||||
name: Check release trigger
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
outputs:
|
||||
valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }}
|
||||
@ -43,13 +43,13 @@ jobs:
|
||||
#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'
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.32.0
|
||||
uses: shivammathur/setup-php@2.33.0
|
||||
with:
|
||||
php-version: 8.2
|
||||
|
||||
|
10
.github/workflows/draft-release.yml
vendored
10
.github/workflows/draft-release.yml
vendored
@ -23,7 +23,7 @@ env:
|
||||
jobs:
|
||||
skip:
|
||||
name: Check whether to ignore this tag
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
outputs:
|
||||
skip: ${{ steps.exists.outputs.exists == 'true' }}
|
||||
@ -54,12 +54,12 @@ jobs:
|
||||
needs: [check]
|
||||
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:
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
uses: actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
|
||||
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
needs: [check]
|
||||
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:
|
||||
- uses: actions/checkout@v4
|
||||
@ -87,7 +87,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.32.0
|
||||
uses: shivammathur/setup-php@2.33.0
|
||||
with:
|
||||
php-version: ${{ env.PHP_VERSION }}
|
||||
|
||||
|
2
.github/workflows/main-php-matrix.yml
vendored
2
.github/workflows/main-php-matrix.yml
vendored
@ -15,7 +15,7 @@ on:
|
||||
type: number
|
||||
image:
|
||||
description: 'Runner image to use'
|
||||
default: 'ubuntu-20.04'
|
||||
default: 'ubuntu-22.04'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
|
10
.github/workflows/main.yml
vendored
10
.github/workflows/main.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
|
||||
codestyle:
|
||||
name: Code Style checks
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@ -28,10 +28,10 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.32.0
|
||||
uses: shivammathur/setup-php@2.33.0
|
||||
with:
|
||||
php-version: 8.2
|
||||
tools: php-cs-fixer:3.49
|
||||
php-version: 8.3
|
||||
tools: php-cs-fixer:3.75
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
shellcheck:
|
||||
name: ShellCheck
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
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
|
||||
|
||||
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG) or our [Forums](https://forums.pmmp.io)
|
||||
|
||||
|
||||
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
|
||||
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG)
|
||||
|
||||
close-issue: true
|
||||
lock-issue: false
|
||||
|
2
.github/workflows/team-pr-auto-approve.yml
vendored
2
.github/workflows/team-pr-auto-approve.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
steps:
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
uses: actions/create-github-app-token@v2
|
||||
with:
|
||||
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
|
||||
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
|
||||
|
@ -6,6 +6,12 @@ $finder = PhpCsFixer\Finder::create()
|
||||
->in(__DIR__ . '/tests')
|
||||
->in(__DIR__ . '/tools')
|
||||
->notPath('plugins/DevTools')
|
||||
//JsonMapper will break if the FQNs in the doc comments for these are shortened :(
|
||||
->notPath('crafting/json')
|
||||
->notPath('inventory/json')
|
||||
->notPath('data/bedrock/block/upgrade/model')
|
||||
->notPath('data/bedrock/item/upgrade/model')
|
||||
|
||||
->notName('PocketMine.php');
|
||||
|
||||
return (new PhpCsFixer\Config)
|
||||
|
@ -31,8 +31,8 @@ require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var string[]|\Closure[] $options
|
||||
* @phpstan-var array<string, string|\Closure() : string> $options
|
||||
* @var string[]|Closure[] $options
|
||||
* @phpstan-var array<string, string|Closure() : string> $options
|
||||
*/
|
||||
$options = [
|
||||
"base_version" => VersionInfo::BASE_VERSION,
|
||||
|
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.
|
27
changelogs/5.28.md
Normal file
27
changelogs/5.28.md
Normal file
@ -0,0 +1,27 @@
|
||||
# 5.28.0
|
||||
Released 9th May 2025.
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.80.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.80.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
## Fixes
|
||||
- `AvailableEnchantmentRegistry` now requires provided tags to always be `string`. Previously, this wasn't enforced, leading to random crashes in core code related to enchanting.
|
||||
- `Entity->setFireTicks()` and `Entity->setOnFire()` now truncate the fire time to the max value instead of throwing exceptions.
|
||||
|
||||
## Internals
|
||||
- Improved PHPStan error reporting for unsafe foreaches. Foreach on an array with implicit keys now generates different errors than foreach on an array with string keys.
|
||||
|
||||
# 5.28.1
|
||||
Released 17th May 2025.
|
||||
|
||||
## Fixes
|
||||
- Fixed errors when PlayStation players attempt to join due to null `TitleID`.
|
@ -34,9 +34,9 @@
|
||||
"adhocore/json-comment": "~1.2.0",
|
||||
"netresearch/jsonmapper": "~v5.0.0",
|
||||
"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": "5.0.0+bedrock-1.21.80",
|
||||
"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": "38.0.0+bedrock-1.21.80",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
@ -45,18 +45,22 @@
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/math": "~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/snooze": "^0.5.0",
|
||||
"ramsey/uuid": "~4.7.0",
|
||||
"symfony/filesystem": "~6.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "2.1.6",
|
||||
"phpstan/phpstan": "2.1.16",
|
||||
"phpstan/phpstan-phpunit": "^2.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0.0",
|
||||
"phpunit/phpunit": "^10.5.24"
|
||||
},
|
||||
"provide": {
|
||||
"symfony/polyfill-ctype": "*",
|
||||
"symfony/polyfill-mbstring": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"pocketmine\\": "src/"
|
||||
|
364
composer.lock
generated
364
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "2a56fc6dee1dac2ade34d965aa49dc82",
|
||||
"content-hash": "b25d87be51beaaad7285a6b2e771ab4e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -67,16 +67,16 @@
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.12.2",
|
||||
"version": "0.12.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/brick/math.git",
|
||||
"reference": "901eddb1e45a8e0f689302e40af871c181ecbe40"
|
||||
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/901eddb1e45a8e0f689302e40af871c181ecbe40",
|
||||
"reference": "901eddb1e45a8e0f689302e40af871c181ecbe40",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
|
||||
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -115,7 +115,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/brick/math/issues",
|
||||
"source": "https://github.com/brick/math/tree/0.12.2"
|
||||
"source": "https://github.com/brick/math/tree/0.12.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -123,7 +123,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-26T10:21:45+00:00"
|
||||
"time": "2025-02-28T13:11:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
@ -204,16 +204,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-data",
|
||||
"version": "4.0.0+bedrock-1.21.60",
|
||||
"version": "5.0.0+bedrock-1.21.80",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "2e5f16ec2facac653f3f894f22eb831d880ba98e"
|
||||
"reference": "e38d5ea19f794ec5216e5f96742237e8c4e7f080"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/2e5f16ec2facac653f3f894f22eb831d880ba98e",
|
||||
"reference": "2e5f16ec2facac653f3f894f22eb831d880ba98e",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/e38d5ea19f794ec5216e5f96742237e8c4e7f080",
|
||||
"reference": "e38d5ea19f794ec5216e5f96742237e8c4e7f080",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -224,9 +224,9 @@
|
||||
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockData/issues",
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.60"
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.80"
|
||||
},
|
||||
"time": "2025-02-16T15:56:56+00:00"
|
||||
"time": "2025-05-09T14:15:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-item-upgrade-schema",
|
||||
@ -256,16 +256,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "36.0.0+bedrock-1.21.60",
|
||||
"version": "38.0.0+bedrock-1.21.80",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "2057de319c5c551001c2a544e08d1bc7727d9963"
|
||||
"reference": "a626561eaefeb6333c0d2726e2789ceb0aac0724"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/2057de319c5c551001c2a544e08d1bc7727d9963",
|
||||
"reference": "2057de319c5c551001c2a544e08d1bc7727d9963",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/a626561eaefeb6333c0d2726e2789ceb0aac0724",
|
||||
"reference": "a626561eaefeb6333c0d2726e2789ceb0aac0724",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -296,9 +296,9 @@
|
||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/36.0.0+bedrock-1.21.60"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/38.0.0+bedrock-1.21.80"
|
||||
},
|
||||
"time": "2025-02-16T15:59:08+00:00"
|
||||
"time": "2025-05-09T14:17:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -471,16 +471,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/locale-data",
|
||||
"version": "2.24.0",
|
||||
"version": "2.24.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Language.git",
|
||||
"reference": "6ec5e92c77a2102b2692763733e4763012facae9"
|
||||
"reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/6ec5e92c77a2102b2692763733e4763012facae9",
|
||||
"reference": "6ec5e92c77a2102b2692763733e4763012facae9",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/2a00c44c52bce98e7a43aa31517df78cbb2ba23b",
|
||||
"reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -488,9 +488,9 @@
|
||||
"description": "Language resources used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/Language/issues",
|
||||
"source": "https://github.com/pmmp/Language/tree/2.24.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",
|
||||
@ -576,16 +576,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/nbt",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/NBT.git",
|
||||
"reference": "cfd53a86166b851786967fc560cdb372e66fde96"
|
||||
"reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/cfd53a86166b851786967fc560cdb372e66fde96",
|
||||
"reference": "cfd53a86166b851786967fc560cdb372e66fde96",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/c3c7b0a7295daeaf7873d90fed5c5d10381d12e1",
|
||||
"reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -612,22 +612,22 @@
|
||||
"description": "PHP library for working with Named Binary Tags",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/NBT/issues",
|
||||
"source": "https://github.com/pmmp/NBT/tree/1.1.0"
|
||||
"source": "https://github.com/pmmp/NBT/tree/1.1.1"
|
||||
},
|
||||
"time": "2025-02-01T21:20:26+00:00"
|
||||
"time": "2025-03-09T01:46:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/RakLib.git",
|
||||
"reference": "be2783be516bf6e2872ff5c81fb9048596617b97"
|
||||
"reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/be2783be516bf6e2872ff5c81fb9048596617b97",
|
||||
"reference": "be2783be516bf6e2872ff5c81fb9048596617b97",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/4145a31cd812fe8931c3c9c691fcd2ded2f47e7f",
|
||||
"reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -639,8 +639,8 @@
|
||||
"pocketmine/log": "^0.3.0 || ^0.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "1.10.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.0"
|
||||
"phpstan/phpstan": "2.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -655,9 +655,9 @@
|
||||
"description": "A RakNet server implementation written in PHP",
|
||||
"support": {
|
||||
"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",
|
||||
@ -742,16 +742,16 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/collection",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/collection.git",
|
||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
|
||||
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2",
|
||||
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -759,25 +759,22 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"ergebnis/composer-normalize": "^2.28.3",
|
||||
"fakerphp/faker": "^1.21",
|
||||
"ergebnis/composer-normalize": "^2.45",
|
||||
"fakerphp/faker": "^1.24",
|
||||
"hamcrest/hamcrest-php": "^2.0",
|
||||
"jangregor/phpstan-prophecy": "^1.0",
|
||||
"mockery/mockery": "^1.5",
|
||||
"jangregor/phpstan-prophecy": "^2.1",
|
||||
"mockery/mockery": "^1.6",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||
"phpcsstandards/phpcsutils": "^1.0.0-rc1",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpstan/extension-installer": "^1.2",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpstan/phpstan-mockery": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/plugin-mockery": "^1.1",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"ramsey/coding-standard": "^2.0.3",
|
||||
"ramsey/conventional-commits": "^1.3",
|
||||
"vimeo/psalm": "^5.4"
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4",
|
||||
"phpspec/prophecy-phpunit": "^2.3",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-mockery": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"ramsey/coding-standard": "^2.3",
|
||||
"ramsey/conventional-commits": "^1.6",
|
||||
"roave/security-advisories": "dev-latest"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -815,19 +812,9 @@
|
||||
],
|
||||
"support": {
|
||||
"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": [
|
||||
{
|
||||
"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"
|
||||
"time": "2025-03-22T05:38:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
@ -986,180 +973,21 @@
|
||||
}
|
||||
],
|
||||
"time": "2024-10-25T15:07:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-ctype": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Ctype\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Gert de Pagter",
|
||||
"email": "BackEndTea@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for ctype functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"ctype",
|
||||
"polyfill",
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.13.0",
|
||||
"version": "1.13.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
|
||||
"reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c",
|
||||
"reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1198,7 +1026,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1206,7 +1034,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-12T12:17:51+00:00"
|
||||
"time": "2025-04-29T12:36:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
@ -1386,16 +1214,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.6",
|
||||
"version": "2.1.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c"
|
||||
"reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c",
|
||||
"reference": "6eaec7c6c9e90dcfe46ad1e1ffa5171e2dab641c",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9",
|
||||
"reference": "b8c1cf533cba0c305d91c6ccd23f3dd0566ba5f9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1440,20 +1268,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-19T15:46:42+00:00"
|
||||
"time": "2025-05-16T09:40:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "d09e152f403c843998d7a52b5d87040c937525dd"
|
||||
"reference": "6b92469f8a7995e626da3aa487099617b8dfa260"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d09e152f403c843998d7a52b5d87040c937525dd",
|
||||
"reference": "d09e152f403c843998d7a52b5d87040c937525dd",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6b92469f8a7995e626da3aa487099617b8dfa260",
|
||||
"reference": "6b92469f8a7995e626da3aa487099617b8dfa260",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1464,7 +1292,9 @@
|
||||
"phpunit/phpunit": "<7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^5",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/phpstan-deprecation-rules": "^2.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpunit/phpunit": "^9.6"
|
||||
},
|
||||
@ -1489,22 +1319,22 @@
|
||||
"description": "PHPUnit extensions and rules for PHPStan",
|
||||
"support": {
|
||||
"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",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba"
|
||||
"reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/8b88b5f818bfa301e0c99154ab622dace071c3ba",
|
||||
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
|
||||
"reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1537,9 +1367,9 @@
|
||||
"description": "Extra strict and opinionated rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/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",
|
||||
@ -1864,16 +1694,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "10.5.45",
|
||||
"version": "10.5.46",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "bd68a781d8e30348bc297449f5234b3458267ae8"
|
||||
"reference": "8080be387a5be380dda48c6f41cee4a13aadab3d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8",
|
||||
"reference": "bd68a781d8e30348bc297449f5234b3458267ae8",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/8080be387a5be380dda48c6f41cee4a13aadab3d",
|
||||
"reference": "8080be387a5be380dda48c6f41cee4a13aadab3d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1883,7 +1713,7 @@
|
||||
"ext-mbstring": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"myclabs/deep-copy": "^1.12.1",
|
||||
"myclabs/deep-copy": "^1.13.1",
|
||||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"php": ">=8.1",
|
||||
@ -1945,7 +1775,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.46"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1956,12 +1786,20 @@
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/sebastianbergmann",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/sebastianbergmann",
|
||||
"type": "thanks_dev"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-06T16:08:12+00:00"
|
||||
"time": "2025-05-02T06:46:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@ -2932,7 +2770,7 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
@ -2963,7 +2801,7 @@
|
||||
"ext-zlib": ">=1.2.11",
|
||||
"composer-runtime-api": "^2.0"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-dev": {},
|
||||
"platform-overrides": {
|
||||
"php": "8.1.0"
|
||||
},
|
||||
|
@ -15,7 +15,7 @@ rules:
|
||||
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
|
||||
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
|
||||
- pocketmine\phpstan\rules\ExplodeLimitRule
|
||||
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
|
||||
- pocketmine\phpstan\rules\UnsafeForeachRule
|
||||
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
|
||||
|
||||
parameters:
|
||||
|
@ -31,6 +31,7 @@ use function hrtime;
|
||||
use function max;
|
||||
use function min;
|
||||
use function number_format;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Allows threads to manually trigger the cyclic garbage collector using a threshold like PHP's own garbage collector,
|
||||
@ -48,6 +49,7 @@ final class GarbageCollectorManager{
|
||||
|
||||
private int $threshold = self::GC_THRESHOLD_DEFAULT;
|
||||
private int $collectionTimeTotalNs = 0;
|
||||
private int $runs = 0;
|
||||
|
||||
private \Logger $logger;
|
||||
private TimingsHandler $timings;
|
||||
@ -96,7 +98,16 @@ final class GarbageCollectorManager{
|
||||
|
||||
$time = $end - $start;
|
||||
$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;
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.25.3";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BASE_VERSION = "5.28.1";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
/**
|
||||
|
@ -209,6 +209,10 @@ class RuntimeBlockStateRegistry{
|
||||
return $block;
|
||||
}
|
||||
|
||||
public function hasStateId(int $stateId) : bool{
|
||||
return isset($this->fullList[$stateId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Block[]
|
||||
* @phpstan-return array<int, Block>
|
||||
|
@ -25,7 +25,6 @@ namespace pocketmine\block\inventory;
|
||||
|
||||
use pocketmine\inventory\SimpleInventory;
|
||||
use pocketmine\inventory\TemporaryInventory;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\world\Position;
|
||||
|
||||
class AnvilInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
|
||||
@ -38,12 +37,4 @@ class AnvilInventory extends SimpleInventory implements BlockInventory, Temporar
|
||||
$this->holder = $holder;
|
||||
parent::__construct(2);
|
||||
}
|
||||
|
||||
public function getInput() : Item {
|
||||
return $this->getItem(self::SLOT_INPUT);
|
||||
}
|
||||
|
||||
public function getMaterial() : Item {
|
||||
return $this->getItem(self::SLOT_MATERIAL);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
||||
use function get_class;
|
||||
|
||||
abstract class Spawnable extends Tile{
|
||||
/** @phpstan-var CacheableNbt<\pocketmine\nbt\tag\CompoundTag>|null */
|
||||
/** @phpstan-var CacheableNbt<CompoundTag>|null */
|
||||
private ?CacheableNbt $spawnCompoundCache = null;
|
||||
|
||||
/**
|
||||
@ -73,7 +73,7 @@ abstract class Spawnable extends Tile{
|
||||
* Returns encoded NBT (varint, little-endian) used to spawn this tile to clients. Uses cache where possible,
|
||||
* populates cache if it is null.
|
||||
*
|
||||
* @phpstan-return CacheableNbt<\pocketmine\nbt\tag\CompoundTag>
|
||||
* @phpstan-return CacheableNbt<CompoundTag>
|
||||
*/
|
||||
final public function getSerializedSpawnCompound() : CacheableNbt{
|
||||
if($this->spawnCompoundCache === null){
|
||||
|
@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\crafting\AnvilCraftResult;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\Server;
|
||||
|
||||
final class AnvilHelper{
|
||||
private const COST_LIMIT = 39;
|
||||
|
||||
/**
|
||||
* Attempts to calculate the result of an anvil operation.
|
||||
*
|
||||
* Returns null if the operation can't do anything.
|
||||
*/
|
||||
public static function calculateResult(Item $base, Item $material, ?string $customName, bool $isCreative) : ?AnvilCraftResult{
|
||||
|
||||
$recipe = Server::getInstance()->getCraftingManager()->matchAnvilRecipe($base, $material);
|
||||
if($recipe === null){
|
||||
return null;
|
||||
}
|
||||
$result = $recipe->getResultFor($base, $material);
|
||||
|
||||
if($result !== null){
|
||||
$resultItem = $result->getOutput();
|
||||
$xpCost = $result->getXpCost();
|
||||
if(($customName === null || $customName === "") && $resultItem->hasCustomName()){
|
||||
$xpCost++;
|
||||
$resultItem->clearCustomName();
|
||||
}elseif($customName !== null && $resultItem->getCustomName() !== $customName){
|
||||
$xpCost++;
|
||||
$resultItem->setCustomName($customName);
|
||||
}
|
||||
|
||||
$result = new AnvilCraftResult($xpCost, $resultItem, $result->getSacrificeResult());
|
||||
}
|
||||
|
||||
if($result === null || $result->getXpCost() <= 0 || ($result->getXpCost() > self::COST_LIMIT && !$isCreative)){
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -30,9 +30,15 @@ interface CopperMaterial{
|
||||
|
||||
public function getOxidation() : CopperOxidation;
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setOxidation(CopperOxidation $oxidation) : CopperMaterial;
|
||||
|
||||
public function isWaxed() : bool;
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setWaxed(bool $waxed) : CopperMaterial;
|
||||
}
|
||||
|
@ -1,66 +0,0 @@
|
||||
<?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\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
/**
|
||||
* This class is here to hold the result of an anvil crafting process.
|
||||
*/
|
||||
final class AnvilCraftResult{
|
||||
/**
|
||||
* @param Item|null $sacrificeResult If the given item is considered as null (count <= 0), the value will be set to null.
|
||||
*/
|
||||
public function __construct(
|
||||
private int $xpCost,
|
||||
private Item $output,
|
||||
private ?Item $sacrificeResult
|
||||
){
|
||||
if($this->sacrificeResult !== null && $this->sacrificeResult->isNull()){
|
||||
$this->sacrificeResult = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent the amount of experience points required to craft the output item.
|
||||
*/
|
||||
public function getXpCost() : int{
|
||||
return $this->xpCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent the item given as output of the crafting process.
|
||||
*/
|
||||
public function getOutput() : Item{
|
||||
return $this->output;
|
||||
}
|
||||
|
||||
/**
|
||||
* This result has to be null if the sacrifice slot need to be emptied.
|
||||
* If not null, it represent the item that will be left in the sacrifice slot after the crafting process.
|
||||
*/
|
||||
public function getSacrificeResult() : ?Item{
|
||||
return $this->sacrificeResult;
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
<?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\crafting;
|
||||
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\ToolTier;
|
||||
use pocketmine\item\VanillaArmorMaterials;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\world\format\io\GlobalItemDataHandlers;
|
||||
|
||||
final class AnvilCraftingManagerDataFiller{
|
||||
public static function fillData(CraftingManager $manager) : CraftingManager{
|
||||
foreach([
|
||||
[
|
||||
VanillaItems::DIAMOND(),
|
||||
[VanillaArmorMaterials::DIAMOND(), ToolTier::DIAMOND]
|
||||
], [
|
||||
VanillaItems::GOLD_INGOT(),
|
||||
[VanillaArmorMaterials::GOLD(), ToolTier::GOLD]
|
||||
], [
|
||||
VanillaItems::IRON_INGOT(),
|
||||
[VanillaArmorMaterials::IRON(), ToolTier::IRON]
|
||||
], [
|
||||
VanillaItems::NETHERITE_INGOT(),
|
||||
[VanillaArmorMaterials::NETHERITE(), ToolTier::NETHERITE]
|
||||
], [
|
||||
VanillaItems::SCUTE(),
|
||||
[VanillaArmorMaterials::TURTLE(), null]
|
||||
], [
|
||||
VanillaItems::LEATHER(),
|
||||
[VanillaArmorMaterials::LEATHER(), null]
|
||||
]
|
||||
] as [$item, [$armorMaterial, $toolTier]]){
|
||||
$manager->registerAnvilRecipe(new MaterialRepairRecipe(
|
||||
new ArmorRecipeIngredient($armorMaterial),
|
||||
new ExactRecipeIngredient($item)
|
||||
));
|
||||
if($toolTier !== null){
|
||||
$manager->registerAnvilRecipe(new MaterialRepairRecipe(
|
||||
new TieredToolRecipeIngredient($toolTier),
|
||||
new ExactRecipeIngredient($item)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
foreach(VanillaItems::getAll() as $item){
|
||||
if($item instanceof Durable){
|
||||
$itemId = GlobalItemDataHandlers::getSerializer()->serializeType($item)->getName();
|
||||
$manager->registerAnvilRecipe(new ItemSelfCombineRecipe(
|
||||
new MetaWildcardRecipeIngredient($itemId)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return $manager;
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<?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\crafting;
|
||||
|
||||
use pocketmine\item\Armor;
|
||||
use pocketmine\item\ArmorMaterial;
|
||||
use pocketmine\item\Item;
|
||||
use function spl_object_id;
|
||||
|
||||
class ArmorRecipeIngredient implements RecipeIngredient{
|
||||
public function __construct(
|
||||
private ArmorMaterial $material
|
||||
){
|
||||
}
|
||||
|
||||
public function getMaterial() : ArmorMaterial{ return $this->material; }
|
||||
|
||||
public function accepts(Item $item) : bool{
|
||||
if($item->getCount() < 1){
|
||||
return false;
|
||||
}
|
||||
|
||||
return $item instanceof Armor && $item->getMaterial() === $this->material;
|
||||
}
|
||||
|
||||
public function __toString() : string{
|
||||
return "ArmorRecipeIngredient(ArmorMaterial@" . spl_object_id($this->material) . ")";
|
||||
}
|
||||
}
|
@ -80,18 +80,6 @@ class CraftingManager{
|
||||
*/
|
||||
private array $brewingRecipeCache = [];
|
||||
|
||||
/**
|
||||
* @var AnvilRecipe[]
|
||||
* @phpstan-var list<AnvilRecipe>
|
||||
*/
|
||||
private array $anvilRecipes = [];
|
||||
|
||||
/**
|
||||
* @var AnvilRecipe[][]
|
||||
* @phpstan-var array<int, array<int, AnvilRecipe>>
|
||||
*/
|
||||
private array $anvilRecipeCache = [];
|
||||
|
||||
/** @phpstan-var ObjectSet<\Closure() : void> */
|
||||
private ObjectSet $recipeRegisteredCallbacks;
|
||||
|
||||
@ -199,14 +187,6 @@ class CraftingManager{
|
||||
return $this->potionContainerChangeRecipes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AnvilRecipe[][]
|
||||
* @phpstan-return list<AnvilRecipe>
|
||||
*/
|
||||
public function getAnvilRecipes() : array{
|
||||
return $this->anvilRecipes;
|
||||
}
|
||||
|
||||
public function registerShapedRecipe(ShapedRecipe $recipe) : void{
|
||||
$this->shapedRecipes[self::hashOutputs($recipe->getResults())][] = $recipe;
|
||||
$this->craftingRecipeIndex[] = $recipe;
|
||||
@ -241,14 +221,6 @@ class CraftingManager{
|
||||
}
|
||||
}
|
||||
|
||||
public function registerAnvilRecipe(AnvilRecipe $recipe) : void{
|
||||
$this->anvilRecipes[] = $recipe;
|
||||
|
||||
foreach($this->recipeRegisteredCallbacks as $callback){
|
||||
$callback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Item[] $outputs
|
||||
*/
|
||||
@ -322,21 +294,4 @@ class CraftingManager{
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function matchAnvilRecipe(Item $input, Item $material) : ?AnvilRecipe{
|
||||
$inputHash = $input->getStateId();
|
||||
$materialHash = $material->getStateId();
|
||||
$cached = $this->anvilRecipeCache[$inputHash][$materialHash] ?? null;
|
||||
if($cached !== null){
|
||||
return $cached;
|
||||
}
|
||||
|
||||
foreach($this->anvilRecipes as $recipe){
|
||||
if($recipe->getResultFor($input, $material) !== null){
|
||||
return $this->anvilRecipeCache[$inputHash][$materialHash] = $recipe;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,6 @@ final class CraftingManagerFromDataHelper{
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*
|
||||
* @return object[]
|
||||
*
|
||||
* @phpstan-template TRecipeData of object
|
||||
@ -211,7 +210,7 @@ final class CraftingManagerFromDataHelper{
|
||||
$result = new CraftingManager();
|
||||
|
||||
foreach(self::loadJsonArrayOfObjectsFile(Path::join($directoryPath, 'shapeless_crafting.json'), ShapelessRecipeData::class) as $recipe){
|
||||
$recipeType = match ($recipe->block) {
|
||||
$recipeType = match($recipe->block){
|
||||
"crafting_table" => ShapelessRecipeType::CRAFTING,
|
||||
"stonecutter" => ShapelessRecipeType::STONECUTTER,
|
||||
"smithing_table" => ShapelessRecipeType::SMITHING,
|
||||
@ -272,7 +271,7 @@ final class CraftingManagerFromDataHelper{
|
||||
));
|
||||
}
|
||||
foreach(self::loadJsonArrayOfObjectsFile(Path::join($directoryPath, 'smelting.json'), FurnaceRecipeData::class) as $recipe){
|
||||
$furnaceType = match ($recipe->block) {
|
||||
$furnaceType = match ($recipe->block){
|
||||
"furnace" => FurnaceType::FURNACE,
|
||||
"blast_furnace" => FurnaceType::BLAST_FURNACE,
|
||||
"smoker" => FurnaceType::SMOKER,
|
||||
@ -334,8 +333,6 @@ final class CraftingManagerFromDataHelper{
|
||||
));
|
||||
}
|
||||
|
||||
$result = AnvilCraftingManagerDataFiller::fillData($result);
|
||||
|
||||
//TODO: smithing
|
||||
|
||||
return $result;
|
||||
|
@ -1,123 +0,0 @@
|
||||
<?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\crafting;
|
||||
|
||||
use pocketmine\inventory\transaction\TransactionValidationException;
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\EnchantedBook;
|
||||
use pocketmine\item\enchantment\AvailableEnchantmentRegistry;
|
||||
use pocketmine\item\enchantment\EnchantmentInstance;
|
||||
use pocketmine\item\enchantment\Rarity;
|
||||
use pocketmine\item\Item;
|
||||
use function floor;
|
||||
use function max;
|
||||
use function min;
|
||||
|
||||
abstract class ItemCombineRecipe implements AnvilRecipe{
|
||||
abstract protected function validate(Item $input, Item $material) : bool;
|
||||
|
||||
public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult{
|
||||
if($this->validate($input, $material)){
|
||||
$result = (clone $input);
|
||||
$xpCost = 0;
|
||||
if($result instanceof Durable && $material instanceof Durable && $this->repair($result, $material)){
|
||||
// The two items are compatible for repair
|
||||
$xpCost = 2;
|
||||
}
|
||||
|
||||
// combining enchantments
|
||||
foreach($material->getEnchantments() as $instance){
|
||||
$enchantment = $instance->getType();
|
||||
$level = $instance->getLevel();
|
||||
if(!AvailableEnchantmentRegistry::getInstance()->isAvailableForItem($enchantment, $input)){
|
||||
continue;
|
||||
}
|
||||
if(($targetEnchantment = $input->getEnchantment($enchantment)) !== null){
|
||||
// Enchant already present on the target item
|
||||
$targetLevel = $targetEnchantment->getLevel();
|
||||
$newLevel = ($targetLevel === $level ? $targetLevel + 1 : max($targetLevel, $level));
|
||||
$level = min($newLevel, $enchantment->getMaxLevel());
|
||||
$instance = new EnchantmentInstance($enchantment, $level);
|
||||
}else{
|
||||
// Check if the enchantment is compatible with the existing enchantments
|
||||
foreach($input->getEnchantments() as $testedInstance){
|
||||
$testedEnchantment = $testedInstance->getType();
|
||||
if(!$testedEnchantment->isCompatibleWith($enchantment)){
|
||||
$xpCost++;
|
||||
//TODO: XP COST
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$costAddition = match ($enchantment->getRarity()) {
|
||||
Rarity::COMMON => 1,
|
||||
Rarity::UNCOMMON => 2,
|
||||
Rarity::RARE => 4,
|
||||
Rarity::MYTHIC => 8,
|
||||
default => throw new TransactionValidationException("Invalid rarity " . $enchantment->getRarity() . " found")
|
||||
};
|
||||
|
||||
if($material instanceof EnchantedBook){
|
||||
// Enchanted books are half as expensive to combine
|
||||
$costAddition = max(1, $costAddition / 2);
|
||||
}
|
||||
$levelDifference = $instance->getLevel() - $input->getEnchantmentLevel($instance->getType());
|
||||
$xpCost += (int) floor($costAddition * $levelDifference);
|
||||
$result->addEnchantment($instance);
|
||||
|
||||
$xpCost += 2 ** $input->getAnvilRepairCost() - 1;
|
||||
$xpCost += 2 ** $material->getAnvilRepairCost() - 1;
|
||||
$result->setAnvilRepairCost(
|
||||
max($result->getAnvilRepairCost(), $material->getAnvilRepairCost()) + 1
|
||||
);
|
||||
}
|
||||
|
||||
if($xpCost !== 0){
|
||||
return new AnvilCraftResult($xpCost, $result, null);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function repair(Durable $result, Durable $material) : bool{
|
||||
$damage = $result->getDamage();
|
||||
if($damage === 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
$baseMaxDurability = $result->getMaxDurability();
|
||||
$baseDurability = $baseMaxDurability - $damage;
|
||||
$materialDurability = $material->getMaxDurability() - $material->getDamage();
|
||||
$addDurability = (int) ($baseMaxDurability * 12 / 100);
|
||||
|
||||
$result->setDamage($baseMaxDurability - min(
|
||||
$baseMaxDurability,
|
||||
$baseDurability + $materialDurability + $addDurability
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
<?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\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
/**
|
||||
* Represent a recipe that repair an item with a material in an anvil.
|
||||
*/
|
||||
class ItemDifferentCombineRecipe extends ItemCombineRecipe{
|
||||
public function __construct(
|
||||
private RecipeIngredient $base,
|
||||
private RecipeIngredient $material
|
||||
){
|
||||
}
|
||||
|
||||
protected function validate(Item $input, Item $material) : bool{
|
||||
return $this->base->accepts($input) && $this->material->accepts($material);
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
<?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\crafting;
|
||||
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\Item;
|
||||
use function ceil;
|
||||
use function floor;
|
||||
use function max;
|
||||
use function min;
|
||||
|
||||
/**
|
||||
* Represent a recipe that repair an item with a material in an anvil.
|
||||
*/
|
||||
class MaterialRepairRecipe implements AnvilRecipe{
|
||||
public function __construct(
|
||||
private RecipeIngredient $input,
|
||||
private RecipeIngredient $material
|
||||
){
|
||||
}
|
||||
|
||||
public function getInput() : RecipeIngredient{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
public function getMaterial() : RecipeIngredient{
|
||||
return $this->material;
|
||||
}
|
||||
|
||||
public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult{
|
||||
if($this->input->accepts($input) && $this->material->accepts($material) && $input instanceof Durable){
|
||||
$damage = $input->getDamage();
|
||||
if($damage !== 0){
|
||||
$quarter = min($damage, (int) floor($input->getMaxDurability() / 4));
|
||||
$numberRepair = min($material->getCount(), (int) ceil($damage / $quarter));
|
||||
$damage -= $quarter * $numberRepair;
|
||||
|
||||
return new AnvilCraftResult(
|
||||
$numberRepair,
|
||||
(clone $input)->setDamage(max(0, $damage)),
|
||||
(clone $material)->setCount($material->getCount() - $numberRepair)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
<?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\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\TieredTool;
|
||||
use pocketmine\item\ToolTier;
|
||||
|
||||
class TieredToolRecipeIngredient implements RecipeIngredient{
|
||||
public function __construct(
|
||||
private ToolTier $tier
|
||||
){
|
||||
}
|
||||
|
||||
public function getTier() : ToolTier{ return $this->tier; }
|
||||
|
||||
public function accepts(Item $item) : bool{
|
||||
if($item->getCount() < 1){
|
||||
return false;
|
||||
}
|
||||
|
||||
return $item instanceof TieredTool && $item->getTier() === $this->tier;
|
||||
}
|
||||
|
||||
public function __toString() : string{
|
||||
return "TieredToolRecipeIngredient(" . $this->tier->name . ")";
|
||||
}
|
||||
}
|
@ -31,8 +31,7 @@ final class BedrockDataFiles{
|
||||
}
|
||||
|
||||
public const BANNER_PATTERNS_JSON = BEDROCK_DATA_PATH . '/banner_patterns.json';
|
||||
public const BIOME_DEFINITIONS_NBT = BEDROCK_DATA_PATH . '/biome_definitions.nbt';
|
||||
public const BIOME_DEFINITIONS_FULL_NBT = BEDROCK_DATA_PATH . '/biome_definitions_full.nbt';
|
||||
public const BIOME_DEFINITIONS_JSON = BEDROCK_DATA_PATH . '/biome_definitions.json';
|
||||
public const BIOME_ID_MAP_JSON = BEDROCK_DATA_PATH . '/biome_id_map.json';
|
||||
public const BLOCK_ID_TO_ITEM_ID_MAP_JSON = BEDROCK_DATA_PATH . '/block_id_to_item_id_map.json';
|
||||
public const BLOCK_PROPERTIES_TABLE_JSON = BEDROCK_DATA_PATH . '/block_properties_table.json';
|
||||
|
@ -113,6 +113,7 @@ final class BlockStateNames{
|
||||
public const RAIL_DATA_BIT = "rail_data_bit";
|
||||
public const RAIL_DIRECTION = "rail_direction";
|
||||
public const REDSTONE_SIGNAL = "redstone_signal";
|
||||
public const REHYDRATION_LEVEL = "rehydration_level";
|
||||
public const REPEATER_DELAY = "repeater_delay";
|
||||
public const RESPAWN_ANCHOR_CHARGE = "respawn_anchor_charge";
|
||||
public const ROTATION = "rotation";
|
||||
|
@ -175,7 +175,9 @@ final class BlockTypeNames{
|
||||
public const BUBBLE_CORAL_FAN = "minecraft:bubble_coral_fan";
|
||||
public const BUBBLE_CORAL_WALL_FAN = "minecraft:bubble_coral_wall_fan";
|
||||
public const BUDDING_AMETHYST = "minecraft:budding_amethyst";
|
||||
public const BUSH = "minecraft:bush";
|
||||
public const CACTUS = "minecraft:cactus";
|
||||
public const CACTUS_FLOWER = "minecraft:cactus_flower";
|
||||
public const CAKE = "minecraft:cake";
|
||||
public const CALCITE = "minecraft:calcite";
|
||||
public const CALIBRATED_SCULK_SENSOR = "minecraft:calibrated_sculk_sensor";
|
||||
@ -390,6 +392,7 @@ final class BlockTypeNames{
|
||||
public const DOUBLE_CUT_COPPER_SLAB = "minecraft:double_cut_copper_slab";
|
||||
public const DRAGON_EGG = "minecraft:dragon_egg";
|
||||
public const DRAGON_HEAD = "minecraft:dragon_head";
|
||||
public const DRIED_GHAST = "minecraft:dried_ghast";
|
||||
public const DRIED_KELP_BLOCK = "minecraft:dried_kelp_block";
|
||||
public const DRIPSTONE_BLOCK = "minecraft:dripstone_block";
|
||||
public const DROPPER = "minecraft:dropper";
|
||||
@ -545,6 +548,7 @@ final class BlockTypeNames{
|
||||
public const FIRE_CORAL_BLOCK = "minecraft:fire_coral_block";
|
||||
public const FIRE_CORAL_FAN = "minecraft:fire_coral_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 FLOWER_POT = "minecraft:flower_pot";
|
||||
public const FLOWERING_AZALEA = "minecraft:flowering_azalea";
|
||||
@ -685,6 +689,7 @@ final class BlockTypeNames{
|
||||
public const LARGE_AMETHYST_BUD = "minecraft:large_amethyst_bud";
|
||||
public const LARGE_FERN = "minecraft:large_fern";
|
||||
public const LAVA = "minecraft:lava";
|
||||
public const LEAF_LITTER = "minecraft:leaf_litter";
|
||||
public const LECTERN = "minecraft:lectern";
|
||||
public const LEVER = "minecraft:lever";
|
||||
public const LIGHT_BLOCK_0 = "minecraft:light_block_0";
|
||||
@ -1043,6 +1048,7 @@ final class BlockTypeNames{
|
||||
public const SEA_LANTERN = "minecraft:sea_lantern";
|
||||
public const SEA_PICKLE = "minecraft:sea_pickle";
|
||||
public const SEAGRASS = "minecraft:seagrass";
|
||||
public const SHORT_DRY_GRASS = "minecraft:short_dry_grass";
|
||||
public const SHORT_GRASS = "minecraft:short_grass";
|
||||
public const SHROOMLIGHT = "minecraft:shroomlight";
|
||||
public const SILVER_GLAZED_TERRACOTTA = "minecraft:silver_glazed_terracotta";
|
||||
@ -1140,6 +1146,7 @@ final class BlockTypeNames{
|
||||
public const SUSPICIOUS_GRAVEL = "minecraft:suspicious_gravel";
|
||||
public const SUSPICIOUS_SAND = "minecraft:suspicious_sand";
|
||||
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 TARGET = "minecraft:target";
|
||||
public const TINTED_GLASS = "minecraft:tinted_glass";
|
||||
@ -1267,6 +1274,7 @@ final class BlockTypeNames{
|
||||
public const WHITE_TERRACOTTA = "minecraft:white_terracotta";
|
||||
public const WHITE_TULIP = "minecraft:white_tulip";
|
||||
public const WHITE_WOOL = "minecraft:white_wool";
|
||||
public const WILDFLOWERS = "minecraft:wildflowers";
|
||||
public const WITHER_ROSE = "minecraft:wither_rose";
|
||||
public const WITHER_SKELETON_SKULL = "minecraft:wither_skeleton_skull";
|
||||
public const WOODEN_BUTTON = "minecraft:wooden_button";
|
||||
|
@ -214,6 +214,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->registerLeavesSerializers();
|
||||
$this->registerSaplingSerializers();
|
||||
$this->registerMobHeadSerializers();
|
||||
$this->registerCopperSerializers();
|
||||
$this->registerSimpleSerializers();
|
||||
$this->registerSerializers();
|
||||
}
|
||||
@ -791,6 +792,178 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
})->writeFacingWithoutDown($block->getFacing()));
|
||||
}
|
||||
|
||||
private function registerCopperSerializers() : void{
|
||||
$this->map(Blocks::COPPER(), function(Copper $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) :
|
||||
Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::WAXED_CHISELED_COPPER,
|
||||
Ids::WAXED_EXPOSED_CHISELED_COPPER,
|
||||
Ids::WAXED_WEATHERED_CHISELED_COPPER,
|
||||
Ids::WAXED_OXIDIZED_CHISELED_COPPER
|
||||
) :
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::CHISELED_COPPER,
|
||||
Ids::EXPOSED_CHISELED_COPPER,
|
||||
Ids::WEATHERED_CHISELED_COPPER,
|
||||
Ids::OXIDIZED_CHISELED_COPPER
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::WAXED_COPPER_GRATE,
|
||||
Ids::WAXED_EXPOSED_COPPER_GRATE,
|
||||
Ids::WAXED_WEATHERED_COPPER_GRATE,
|
||||
Ids::WAXED_OXIDIZED_COPPER_GRATE
|
||||
) :
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::COPPER_GRATE,
|
||||
Ids::EXPOSED_COPPER_GRATE,
|
||||
Ids::WEATHERED_COPPER_GRATE,
|
||||
Ids::OXIDIZED_COPPER_GRATE
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::CUT_COPPER(), function(Copper $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) :
|
||||
Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::CUT_COPPER_SLAB(), function(CopperSlab $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Helper::encodeSlab(
|
||||
$block,
|
||||
($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::CUT_COPPER_SLAB,
|
||||
Ids::EXPOSED_CUT_COPPER_SLAB,
|
||||
Ids::WEATHERED_CUT_COPPER_SLAB,
|
||||
Ids::OXIDIZED_CUT_COPPER_SLAB
|
||||
)
|
||||
),
|
||||
($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::CUT_COPPER_STAIRS(), function(CopperStairs $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Helper::encodeStairs(
|
||||
$block,
|
||||
new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_CUT_COPPER_STAIRS,
|
||||
Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
|
||||
Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
|
||||
Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::CUT_COPPER_STAIRS,
|
||||
Ids::EXPOSED_CUT_COPPER_STAIRS,
|
||||
Ids::WEATHERED_CUT_COPPER_STAIRS,
|
||||
Ids::OXIDIZED_CUT_COPPER_STAIRS
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::COPPER_BULB(), function(CopperBulb $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Writer::create($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::WAXED_COPPER_BULB,
|
||||
Ids::WAXED_EXPOSED_COPPER_BULB,
|
||||
Ids::WAXED_WEATHERED_COPPER_BULB,
|
||||
Ids::WAXED_OXIDIZED_COPPER_BULB) :
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::COPPER_BULB,
|
||||
Ids::EXPOSED_COPPER_BULB,
|
||||
Ids::WEATHERED_COPPER_BULB,
|
||||
Ids::OXIDIZED_COPPER_BULB
|
||||
))
|
||||
->writeBool(StateNames::LIT, $block->isLit())
|
||||
->writeBool(StateNames::POWERED_BIT, $block->isPowered());
|
||||
});
|
||||
$this->map(Blocks::COPPER_DOOR(), function(CopperDoor $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Helper::encodeDoor(
|
||||
$block,
|
||||
new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_COPPER_DOOR,
|
||||
Ids::WAXED_EXPOSED_COPPER_DOOR,
|
||||
Ids::WAXED_WEATHERED_COPPER_DOOR,
|
||||
Ids::WAXED_OXIDIZED_COPPER_DOOR
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::COPPER_DOOR,
|
||||
Ids::EXPOSED_COPPER_DOOR,
|
||||
Ids::WEATHERED_COPPER_DOOR,
|
||||
Ids::OXIDIZED_COPPER_DOOR
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::COPPER_TRAPDOOR(), function(CopperTrapdoor $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Helper::encodeTrapdoor(
|
||||
$block,
|
||||
new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_COPPER_TRAPDOOR,
|
||||
Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
|
||||
Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
|
||||
Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::COPPER_TRAPDOOR,
|
||||
Ids::EXPOSED_COPPER_TRAPDOOR,
|
||||
Ids::WEATHERED_COPPER_TRAPDOOR,
|
||||
Ids::OXIDIZED_COPPER_TRAPDOOR
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private function registerSimpleSerializers() : void{
|
||||
$this->mapSimple(Blocks::AIR(), Ids::AIR);
|
||||
$this->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK);
|
||||
@ -1265,175 +1438,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
|
||||
$this->mapSlab(Blocks::COBBLESTONE_SLAB(), Ids::COBBLESTONE_SLAB, Ids::COBBLESTONE_DOUBLE_SLAB);
|
||||
$this->mapStairs(Blocks::COBBLESTONE_STAIRS(), Ids::STONE_STAIRS);
|
||||
$this->map(Blocks::COBBLESTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::COBBLESTONE_WALL)));
|
||||
$this->map(Blocks::COPPER(), function(Copper $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) :
|
||||
Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::WAXED_CHISELED_COPPER,
|
||||
Ids::WAXED_EXPOSED_CHISELED_COPPER,
|
||||
Ids::WAXED_WEATHERED_CHISELED_COPPER,
|
||||
Ids::WAXED_OXIDIZED_CHISELED_COPPER
|
||||
) :
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::CHISELED_COPPER,
|
||||
Ids::EXPOSED_CHISELED_COPPER,
|
||||
Ids::WEATHERED_CHISELED_COPPER,
|
||||
Ids::OXIDIZED_CHISELED_COPPER
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::WAXED_COPPER_GRATE,
|
||||
Ids::WAXED_EXPOSED_COPPER_GRATE,
|
||||
Ids::WAXED_WEATHERED_COPPER_GRATE,
|
||||
Ids::WAXED_OXIDIZED_COPPER_GRATE
|
||||
) :
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::COPPER_GRATE,
|
||||
Ids::EXPOSED_COPPER_GRATE,
|
||||
Ids::WEATHERED_COPPER_GRATE,
|
||||
Ids::OXIDIZED_COPPER_GRATE
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::CUT_COPPER(), function(Copper $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) :
|
||||
Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::CUT_COPPER_SLAB(), function(CopperSlab $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Helper::encodeSlab(
|
||||
$block,
|
||||
($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_EXPOSED_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_WEATHERED_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::CUT_COPPER_SLAB,
|
||||
Ids::EXPOSED_CUT_COPPER_SLAB,
|
||||
Ids::WEATHERED_CUT_COPPER_SLAB,
|
||||
Ids::OXIDIZED_CUT_COPPER_SLAB
|
||||
)
|
||||
),
|
||||
($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB,
|
||||
Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::CUT_COPPER_STAIRS(), function(CopperStairs $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Helper::encodeStairs(
|
||||
$block,
|
||||
new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_CUT_COPPER_STAIRS,
|
||||
Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS,
|
||||
Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS,
|
||||
Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::CUT_COPPER_STAIRS,
|
||||
Ids::EXPOSED_CUT_COPPER_STAIRS,
|
||||
Ids::WEATHERED_CUT_COPPER_STAIRS,
|
||||
Ids::OXIDIZED_CUT_COPPER_STAIRS
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::COPPER_BULB(), function(CopperBulb $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Writer::create($block->isWaxed() ?
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::WAXED_COPPER_BULB,
|
||||
Ids::WAXED_EXPOSED_COPPER_BULB,
|
||||
Ids::WAXED_WEATHERED_COPPER_BULB,
|
||||
Ids::WAXED_OXIDIZED_COPPER_BULB) :
|
||||
Helper::selectCopperId($oxidation,
|
||||
Ids::COPPER_BULB,
|
||||
Ids::EXPOSED_COPPER_BULB,
|
||||
Ids::WEATHERED_COPPER_BULB,
|
||||
Ids::OXIDIZED_COPPER_BULB
|
||||
))
|
||||
->writeBool(StateNames::LIT, $block->isLit())
|
||||
->writeBool(StateNames::POWERED_BIT, $block->isPowered());
|
||||
});
|
||||
$this->map(Blocks::COPPER_DOOR(), function(CopperDoor $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Helper::encodeDoor(
|
||||
$block,
|
||||
new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_COPPER_DOOR,
|
||||
Ids::WAXED_EXPOSED_COPPER_DOOR,
|
||||
Ids::WAXED_WEATHERED_COPPER_DOOR,
|
||||
Ids::WAXED_OXIDIZED_COPPER_DOOR
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::COPPER_DOOR,
|
||||
Ids::EXPOSED_COPPER_DOOR,
|
||||
Ids::WEATHERED_COPPER_DOOR,
|
||||
Ids::OXIDIZED_COPPER_DOOR
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::COPPER_TRAPDOOR(), function(CopperTrapdoor $block) : Writer{
|
||||
$oxidation = $block->getOxidation();
|
||||
return Helper::encodeTrapdoor(
|
||||
$block,
|
||||
new Writer($block->isWaxed() ?
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::WAXED_COPPER_TRAPDOOR,
|
||||
Ids::WAXED_EXPOSED_COPPER_TRAPDOOR,
|
||||
Ids::WAXED_WEATHERED_COPPER_TRAPDOOR,
|
||||
Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR
|
||||
) :
|
||||
Helper::selectCopperId(
|
||||
$oxidation,
|
||||
Ids::COPPER_TRAPDOOR,
|
||||
Ids::EXPOSED_COPPER_TRAPDOOR,
|
||||
Ids::WEATHERED_COPPER_TRAPDOOR,
|
||||
Ids::OXIDIZED_COPPER_TRAPDOOR
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
$this->map(Blocks::COCOA_POD(), function(CocoaBlock $block) : Writer{
|
||||
return Writer::create(Ids::COCOA)
|
||||
->writeInt(StateNames::AGE, $block->getAge())
|
||||
|
@ -126,7 +126,13 @@ final class BlockStateDeserializerHelper{
|
||||
->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{
|
||||
//TODO: check if these need any special treatment to get the appropriate data to both halves of the door
|
||||
return $block
|
||||
@ -237,18 +243,36 @@ final class BlockStateDeserializerHelper{
|
||||
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{
|
||||
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{
|
||||
$in->ignored(StateNames::MC_VERTICAL_HALF);
|
||||
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{
|
||||
return $block
|
||||
->setUpsideDown($in->readBool(BlockStateNames::UPSIDE_DOWN_BIT))
|
||||
@ -265,7 +289,13 @@ final class BlockStateDeserializerHelper{
|
||||
->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{
|
||||
return $block
|
||||
->setFacing($in->read5MinusHorizontalFacing())
|
||||
|
@ -33,11 +33,13 @@ use pocketmine\block\DoublePitcherCrop;
|
||||
use pocketmine\block\Opaque;
|
||||
use pocketmine\block\PinkPetals;
|
||||
use pocketmine\block\PitcherCrop;
|
||||
use pocketmine\block\RuntimeBlockStateRegistry;
|
||||
use pocketmine\block\Slab;
|
||||
use pocketmine\block\Stair;
|
||||
use pocketmine\block\SweetBerryBush;
|
||||
use pocketmine\block\utils\BrewingStandSlot;
|
||||
use pocketmine\block\utils\ChiseledBookshelfSlot;
|
||||
use pocketmine\block\utils\CopperMaterial;
|
||||
use pocketmine\block\utils\CopperOxidation;
|
||||
use pocketmine\block\utils\CoralType;
|
||||
use pocketmine\block\utils\DirtType;
|
||||
@ -59,6 +61,7 @@ use pocketmine\data\bedrock\block\convert\BlockStateDeserializerHelper as Helper
|
||||
use pocketmine\data\bedrock\block\convert\BlockStateReader as Reader;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use function min;
|
||||
@ -87,6 +90,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->registerSaplingDeserializers();
|
||||
$this->registerLightDeserializers();
|
||||
$this->registerMobHeadDeserializers();
|
||||
$this->registerCopperDeserializers();
|
||||
$this->registerSimpleDeserializers();
|
||||
$this->registerDeserializers();
|
||||
}
|
||||
@ -94,11 +98,21 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
public function deserialize(BlockStateData $stateData) : int{
|
||||
if(count($stateData->getStates()) === 0){
|
||||
//if a block has zero properties, we can keep a map of string ID -> internal blockstate ID
|
||||
return $this->simpleCache[$stateData->getName()] ??= $this->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
|
||||
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 */
|
||||
@ -723,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{
|
||||
$this->mapSimple(Ids::AIR, fn() => Blocks::AIR());
|
||||
$this->mapSimple(Ids::AMETHYST_BLOCK, fn() => Blocks::AMETHYST());
|
||||
@ -1228,18 +1386,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->map(Ids::COMPOUND_CREATOR, fn(Reader $in) => Blocks::COMPOUND_CREATOR()
|
||||
->setFacing(Facing::opposite($in->readLegacyHorizontalFacing()))
|
||||
);
|
||||
$this->map(Ids::COPPER_BLOCK, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::NONE));
|
||||
$this->map(Ids::COPPER_BULB, function(Reader $in) : Block{
|
||||
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::NONE)
|
||||
->setLit($in->readBool(StateNames::LIT))
|
||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
||||
});
|
||||
$this->map(Ids::COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::NONE), $in));
|
||||
$this->map(Ids::COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::NONE));
|
||||
$this->map(Ids::COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::NONE), $in));
|
||||
$this->map(Ids::CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::NONE));
|
||||
$this->mapSlab(Ids::CUT_COPPER_SLAB, Ids::DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::NONE));
|
||||
$this->mapStairs(Ids::CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::NONE));
|
||||
$this->mapSlab(Ids::CUT_RED_SANDSTONE_SLAB, Ids::CUT_RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_RED_SANDSTONE_SLAB());
|
||||
$this->mapSlab(Ids::CUT_SANDSTONE_SLAB, Ids::CUT_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_SANDSTONE_SLAB());
|
||||
$this->mapSlab(Ids::DARK_PRISMARINE_SLAB, Ids::DARK_PRISMARINE_DOUBLE_SLAB, fn() => Blocks::DARK_PRISMARINE_SLAB());
|
||||
@ -1294,19 +1440,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
return Blocks::ENDER_CHEST()
|
||||
->setFacing($in->readCardinalHorizontalFacing());
|
||||
});
|
||||
$this->map(Ids::EXPOSED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::EXPOSED));
|
||||
$this->map(Ids::EXPOSED_CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::EXPOSED));
|
||||
$this->map(Ids::EXPOSED_COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::EXPOSED));
|
||||
$this->map(Ids::EXPOSED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::EXPOSED));
|
||||
$this->mapSlab(Ids::EXPOSED_CUT_COPPER_SLAB, Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::EXPOSED));
|
||||
$this->mapStairs(Ids::EXPOSED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::EXPOSED));
|
||||
$this->map(Ids::EXPOSED_COPPER_BULB, function(Reader $in) : Block{
|
||||
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::EXPOSED)
|
||||
->setLit($in->readBool(StateNames::LIT))
|
||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
||||
});
|
||||
$this->map(Ids::EXPOSED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::EXPOSED), $in));
|
||||
$this->map(Ids::EXPOSED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::EXPOSED), $in));
|
||||
$this->map(Ids::FARMLAND, function(Reader $in) : Block{
|
||||
return Blocks::FARMLAND()
|
||||
->setWetness($in->readBoundedInt(StateNames::MOISTURIZED_AMOUNT, 0, 7));
|
||||
@ -1459,19 +1592,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
$this->mapSlab(Ids::NORMAL_STONE_SLAB, Ids::NORMAL_STONE_DOUBLE_SLAB, fn() => Blocks::STONE_SLAB());
|
||||
$this->mapStairs(Ids::NORMAL_STONE_STAIRS, fn() => Blocks::STONE_STAIRS());
|
||||
$this->map(Ids::OCHRE_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::OCHRE)->setAxis($in->readPillarAxis()));
|
||||
$this->map(Ids::OXIDIZED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::OXIDIZED));
|
||||
$this->map(Ids::OXIDIZED_CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::OXIDIZED));
|
||||
$this->map(Ids::OXIDIZED_COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::OXIDIZED));
|
||||
$this->map(Ids::OXIDIZED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::OXIDIZED));
|
||||
$this->mapSlab(Ids::OXIDIZED_CUT_COPPER_SLAB, Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::OXIDIZED));
|
||||
$this->mapStairs(Ids::OXIDIZED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::OXIDIZED));
|
||||
$this->map(Ids::OXIDIZED_COPPER_BULB, function(Reader $in) : Block{
|
||||
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::OXIDIZED)
|
||||
->setLit($in->readBool(StateNames::LIT))
|
||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
||||
});
|
||||
$this->map(Ids::OXIDIZED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::OXIDIZED), $in));
|
||||
$this->map(Ids::OXIDIZED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::OXIDIZED), $in));
|
||||
$this->map(Ids::PEARLESCENT_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::PEARLESCENT)->setAxis($in->readPillarAxis()));
|
||||
$this->mapSlab(Ids::PETRIFIED_OAK_SLAB, Ids::PETRIFIED_OAK_DOUBLE_SLAB, fn() => Blocks::FAKE_WOODEN_SLAB());
|
||||
$this->map(Ids::PINK_PETALS, function(Reader $in) : Block{
|
||||
@ -1744,71 +1864,7 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{
|
||||
->setFacing($in->readHorizontalFacing());
|
||||
});
|
||||
$this->map(Ids::WATER, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::WATER(), $in));
|
||||
$this->map(Ids::WAXED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::NONE));
|
||||
$this->map(Ids::WAXED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::NONE));
|
||||
$this->map(Ids::WAXED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::NONE));
|
||||
$this->map(Ids::WAXED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::NONE));
|
||||
$this->mapSlab(Ids::WAXED_CUT_COPPER_SLAB, Ids::WAXED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::NONE));
|
||||
$this->mapStairs(Ids::WAXED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::NONE));
|
||||
$this->map(Ids::WAXED_COPPER_BULB, function(Reader $in) : Block{
|
||||
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::NONE)
|
||||
->setLit($in->readBool(StateNames::LIT))
|
||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
||||
});
|
||||
$this->map(Ids::WAXED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::NONE), $in));
|
||||
$this->map(Ids::WAXED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::NONE), $in));
|
||||
$this->map(Ids::WAXED_EXPOSED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::EXPOSED));
|
||||
$this->map(Ids::WAXED_EXPOSED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::EXPOSED));
|
||||
$this->map(Ids::WAXED_EXPOSED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::EXPOSED));
|
||||
$this->map(Ids::WAXED_EXPOSED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::EXPOSED));
|
||||
$this->mapSlab(Ids::WAXED_EXPOSED_CUT_COPPER_SLAB, Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::EXPOSED));
|
||||
$this->mapStairs(Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::EXPOSED));
|
||||
$this->map(Ids::WAXED_EXPOSED_COPPER_BULB, function(Reader $in) : Block{
|
||||
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::EXPOSED)
|
||||
->setLit($in->readBool(StateNames::LIT))
|
||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
||||
});
|
||||
$this->map(Ids::WAXED_EXPOSED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::EXPOSED), $in));
|
||||
$this->map(Ids::WAXED_EXPOSED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::EXPOSED), $in));
|
||||
$this->map(Ids::WAXED_OXIDIZED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::OXIDIZED));
|
||||
$this->map(Ids::WAXED_OXIDIZED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::OXIDIZED));
|
||||
$this->map(Ids::WAXED_OXIDIZED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::OXIDIZED));
|
||||
$this->map(Ids::WAXED_OXIDIZED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::OXIDIZED));
|
||||
$this->mapSlab(Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB, Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::OXIDIZED));
|
||||
$this->mapStairs(Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::OXIDIZED));
|
||||
$this->map(Ids::WAXED_OXIDIZED_COPPER_BULB, function(Reader $in) : Block{
|
||||
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::OXIDIZED)
|
||||
->setLit($in->readBool(StateNames::LIT))
|
||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
||||
});
|
||||
$this->map(Ids::WAXED_OXIDIZED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::OXIDIZED), $in));
|
||||
$this->map(Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::OXIDIZED), $in));
|
||||
$this->map(Ids::WAXED_WEATHERED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::COPPER(), CopperOxidation::WEATHERED));
|
||||
$this->map(Ids::WAXED_WEATHERED_CHISELED_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CHISELED_COPPER(), CopperOxidation::WEATHERED));
|
||||
$this->map(Ids::WAXED_WEATHERED_COPPER_GRATE, fn() => Helper::decodeWaxedCopper(Blocks::COPPER_GRATE(), CopperOxidation::WEATHERED));
|
||||
$this->map(Ids::WAXED_WEATHERED_CUT_COPPER, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER(), CopperOxidation::WEATHERED));
|
||||
$this->mapSlab(Ids::WAXED_WEATHERED_CUT_COPPER_SLAB, Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::WEATHERED));
|
||||
$this->mapStairs(Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS, fn() => Helper::decodeWaxedCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::WEATHERED));
|
||||
$this->map(Ids::WAXED_WEATHERED_COPPER_BULB, function(Reader $in) : Block{
|
||||
return Helper::decodeWaxedCopper(Blocks::COPPER_BULB(), CopperOxidation::WEATHERED)
|
||||
->setLit($in->readBool(StateNames::LIT))
|
||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
||||
});
|
||||
$this->map(Ids::WAXED_WEATHERED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeWaxedCopper(Blocks::COPPER_DOOR(), CopperOxidation::WEATHERED), $in));
|
||||
$this->map(Ids::WAXED_WEATHERED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeWaxedCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::WEATHERED), $in));
|
||||
$this->map(Ids::WEATHERED_COPPER, fn() => Helper::decodeCopper(Blocks::COPPER(), CopperOxidation::WEATHERED));
|
||||
$this->map(Ids::WEATHERED_CHISELED_COPPER, fn() => Helper::decodeCopper(Blocks::CHISELED_COPPER(), CopperOxidation::WEATHERED));
|
||||
$this->map(Ids::WEATHERED_COPPER_GRATE, fn() => Helper::decodeCopper(Blocks::COPPER_GRATE(), CopperOxidation::WEATHERED));
|
||||
$this->map(Ids::WEATHERED_CUT_COPPER, fn() => Helper::decodeCopper(Blocks::CUT_COPPER(), CopperOxidation::WEATHERED));
|
||||
$this->mapSlab(Ids::WEATHERED_CUT_COPPER_SLAB, Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_SLAB(), CopperOxidation::WEATHERED));
|
||||
$this->mapStairs(Ids::WEATHERED_CUT_COPPER_STAIRS, fn() => Helper::decodeCopper(Blocks::CUT_COPPER_STAIRS(), CopperOxidation::WEATHERED));
|
||||
$this->map(Ids::WEATHERED_COPPER_BULB, function(Reader $in) : Block{
|
||||
return Helper::decodeCopper(Blocks::COPPER_BULB(), CopperOxidation::WEATHERED)
|
||||
->setLit($in->readBool(StateNames::LIT))
|
||||
->setPowered($in->readBool(StateNames::POWERED_BIT));
|
||||
});
|
||||
$this->map(Ids::WEATHERED_COPPER_DOOR, fn(Reader $in) => Helper::decodeDoor(Helper::decodeCopper(Blocks::COPPER_DOOR(), CopperOxidation::WEATHERED), $in));
|
||||
$this->map(Ids::WEATHERED_COPPER_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Helper::decodeCopper(Blocks::COPPER_TRAPDOOR(), CopperOxidation::WEATHERED), $in));
|
||||
|
||||
$this->map(Ids::WEEPING_VINES, function(Reader $in) : Block{
|
||||
return Blocks::WEEPING_VINES()
|
||||
->setAge($in->readBoundedInt(StateNames::WEEPING_VINES_AGE, 0, 25));
|
||||
|
@ -68,6 +68,7 @@ final class ItemTypeNames{
|
||||
public const BIRCH_SIGN = "minecraft:birch_sign";
|
||||
public const BLACK_BUNDLE = "minecraft:black_bundle";
|
||||
public const BLACK_DYE = "minecraft:black_dye";
|
||||
public const BLACK_HARNESS = "minecraft:black_harness";
|
||||
public const BLADE_POTTERY_SHERD = "minecraft:blade_pottery_sherd";
|
||||
public const BLAZE_POWDER = "minecraft:blaze_powder";
|
||||
public const BLAZE_ROD = "minecraft:blaze_rod";
|
||||
@ -75,6 +76,8 @@ final class ItemTypeNames{
|
||||
public const BLEACH = "minecraft:bleach";
|
||||
public const BLUE_BUNDLE = "minecraft:blue_bundle";
|
||||
public const BLUE_DYE = "minecraft:blue_dye";
|
||||
public const BLUE_EGG = "minecraft:blue_egg";
|
||||
public const BLUE_HARNESS = "minecraft:blue_harness";
|
||||
public const BOARD = "minecraft:board";
|
||||
public const BOAT = "minecraft:boat";
|
||||
public const BOGGED_SPAWN_EGG = "minecraft:bogged_spawn_egg";
|
||||
@ -93,6 +96,8 @@ final class ItemTypeNames{
|
||||
public const BRICK = "minecraft:brick";
|
||||
public const BROWN_BUNDLE = "minecraft:brown_bundle";
|
||||
public const BROWN_DYE = "minecraft:brown_dye";
|
||||
public const BROWN_EGG = "minecraft:brown_egg";
|
||||
public const BROWN_HARNESS = "minecraft:brown_harness";
|
||||
public const BRUSH = "minecraft:brush";
|
||||
public const BUCKET = "minecraft:bucket";
|
||||
public const BUNDLE = "minecraft:bundle";
|
||||
@ -164,6 +169,7 @@ final class ItemTypeNames{
|
||||
public const CROSSBOW = "minecraft:crossbow";
|
||||
public const CYAN_BUNDLE = "minecraft:cyan_bundle";
|
||||
public const CYAN_DYE = "minecraft:cyan_dye";
|
||||
public const CYAN_HARNESS = "minecraft:cyan_harness";
|
||||
public const DANGER_POTTERY_SHERD = "minecraft:danger_pottery_sherd";
|
||||
public const DARK_OAK_BOAT = "minecraft:dark_oak_boat";
|
||||
public const DARK_OAK_CHEST_BOAT = "minecraft:dark_oak_chest_boat";
|
||||
@ -263,12 +269,15 @@ final class ItemTypeNames{
|
||||
public const GOLDEN_SWORD = "minecraft:golden_sword";
|
||||
public const GRAY_BUNDLE = "minecraft:gray_bundle";
|
||||
public const GRAY_DYE = "minecraft:gray_dye";
|
||||
public const GRAY_HARNESS = "minecraft:gray_harness";
|
||||
public const GREEN_BUNDLE = "minecraft:green_bundle";
|
||||
public const GREEN_DYE = "minecraft:green_dye";
|
||||
public const GREEN_HARNESS = "minecraft:green_harness";
|
||||
public const GUARDIAN_SPAWN_EGG = "minecraft:guardian_spawn_egg";
|
||||
public const GUNPOWDER = "minecraft:gunpowder";
|
||||
public const GUSTER_BANNER_PATTERN = "minecraft:guster_banner_pattern";
|
||||
public const GUSTER_POTTERY_SHERD = "minecraft:guster_pottery_sherd";
|
||||
public const HAPPY_GHAST_SPAWN_EGG = "minecraft:happy_ghast_spawn_egg";
|
||||
public const HARD_STAINED_GLASS = "minecraft:hard_stained_glass";
|
||||
public const HARD_STAINED_GLASS_PANE = "minecraft:hard_stained_glass_pane";
|
||||
public const HEART_OF_THE_SEA = "minecraft:heart_of_the_sea";
|
||||
@ -319,10 +328,13 @@ final class ItemTypeNames{
|
||||
public const LIGHT_BLOCK = "minecraft:light_block";
|
||||
public const LIGHT_BLUE_BUNDLE = "minecraft:light_blue_bundle";
|
||||
public const LIGHT_BLUE_DYE = "minecraft:light_blue_dye";
|
||||
public const LIGHT_BLUE_HARNESS = "minecraft:light_blue_harness";
|
||||
public const LIGHT_GRAY_BUNDLE = "minecraft:light_gray_bundle";
|
||||
public const LIGHT_GRAY_DYE = "minecraft:light_gray_dye";
|
||||
public const LIGHT_GRAY_HARNESS = "minecraft:light_gray_harness";
|
||||
public const LIME_BUNDLE = "minecraft:lime_bundle";
|
||||
public const LIME_DYE = "minecraft:lime_dye";
|
||||
public const LIME_HARNESS = "minecraft:lime_harness";
|
||||
public const LINGERING_POTION = "minecraft:lingering_potion";
|
||||
public const LLAMA_SPAWN_EGG = "minecraft:llama_spawn_egg";
|
||||
public const LODESTONE_COMPASS = "minecraft:lodestone_compass";
|
||||
@ -331,6 +343,7 @@ final class ItemTypeNames{
|
||||
public const MACE = "minecraft:mace";
|
||||
public const MAGENTA_BUNDLE = "minecraft:magenta_bundle";
|
||||
public const MAGENTA_DYE = "minecraft:magenta_dye";
|
||||
public const MAGENTA_HARNESS = "minecraft:magenta_harness";
|
||||
public const MAGMA_CREAM = "minecraft:magma_cream";
|
||||
public const MAGMA_CUBE_SPAWN_EGG = "minecraft:magma_cube_spawn_egg";
|
||||
public const MANGROVE_BOAT = "minecraft:mangrove_boat";
|
||||
@ -398,6 +411,7 @@ final class ItemTypeNames{
|
||||
public const OMINOUS_TRIAL_KEY = "minecraft:ominous_trial_key";
|
||||
public const ORANGE_BUNDLE = "minecraft:orange_bundle";
|
||||
public const ORANGE_DYE = "minecraft:orange_dye";
|
||||
public const ORANGE_HARNESS = "minecraft:orange_harness";
|
||||
public const OXIDIZED_COPPER_DOOR = "minecraft:oxidized_copper_door";
|
||||
public const PAINTING = "minecraft:painting";
|
||||
public const PALE_OAK_BOAT = "minecraft:pale_oak_boat";
|
||||
@ -417,6 +431,7 @@ final class ItemTypeNames{
|
||||
public const PILLAGER_SPAWN_EGG = "minecraft:pillager_spawn_egg";
|
||||
public const PINK_BUNDLE = "minecraft:pink_bundle";
|
||||
public const PINK_DYE = "minecraft:pink_dye";
|
||||
public const PINK_HARNESS = "minecraft:pink_harness";
|
||||
public const PITCHER_POD = "minecraft:pitcher_pod";
|
||||
public const PLANKS = "minecraft:planks";
|
||||
public const PLENTY_POTTERY_SHERD = "minecraft:plenty_pottery_sherd";
|
||||
@ -437,6 +452,7 @@ final class ItemTypeNames{
|
||||
public const PUMPKIN_SEEDS = "minecraft:pumpkin_seeds";
|
||||
public const PURPLE_BUNDLE = "minecraft:purple_bundle";
|
||||
public const PURPLE_DYE = "minecraft:purple_dye";
|
||||
public const PURPLE_HARNESS = "minecraft:purple_harness";
|
||||
public const QUARTZ = "minecraft:quartz";
|
||||
public const RABBIT = "minecraft:rabbit";
|
||||
public const RABBIT_FOOT = "minecraft:rabbit_foot";
|
||||
@ -453,6 +469,7 @@ final class ItemTypeNames{
|
||||
public const RED_BUNDLE = "minecraft:red_bundle";
|
||||
public const RED_DYE = "minecraft:red_dye";
|
||||
public const RED_FLOWER = "minecraft:red_flower";
|
||||
public const RED_HARNESS = "minecraft:red_harness";
|
||||
public const REDSTONE = "minecraft:redstone";
|
||||
public const REPEATER = "minecraft:repeater";
|
||||
public const RESIN_BRICK = "minecraft:resin_brick";
|
||||
@ -561,6 +578,7 @@ final class ItemTypeNames{
|
||||
public const WHEAT_SEEDS = "minecraft:wheat_seeds";
|
||||
public const WHITE_BUNDLE = "minecraft:white_bundle";
|
||||
public const WHITE_DYE = "minecraft:white_dye";
|
||||
public const WHITE_HARNESS = "minecraft:white_harness";
|
||||
public const WILD_ARMOR_TRIM_SMITHING_TEMPLATE = "minecraft:wild_armor_trim_smithing_template";
|
||||
public const WIND_CHARGE = "minecraft:wind_charge";
|
||||
public const WITCH_SPAWN_EGG = "minecraft:witch_spawn_egg";
|
||||
@ -581,6 +599,7 @@ final class ItemTypeNames{
|
||||
public const WRITTEN_BOOK = "minecraft:written_book";
|
||||
public const YELLOW_BUNDLE = "minecraft:yellow_bundle";
|
||||
public const YELLOW_DYE = "minecraft:yellow_dye";
|
||||
public const YELLOW_HARNESS = "minecraft:yellow_harness";
|
||||
public const ZOGLIN_SPAWN_EGG = "minecraft:zoglin_spawn_egg";
|
||||
public const ZOMBIE_HORSE_SPAWN_EGG = "minecraft:zombie_horse_spawn_egg";
|
||||
public const ZOMBIE_PIGMAN_SPAWN_EGG = "minecraft:zombie_pigman_spawn_egg";
|
||||
|
@ -60,6 +60,7 @@ use pocketmine\player\Player;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use pocketmine\utils\Limits;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\VersionInfo;
|
||||
use pocketmine\world\format\Chunk;
|
||||
@ -76,6 +77,7 @@ use function floatval;
|
||||
use function floor;
|
||||
use function fmod;
|
||||
use function get_class;
|
||||
use function min;
|
||||
use function sin;
|
||||
use function spl_object_id;
|
||||
use const M_PI_2;
|
||||
@ -700,9 +702,16 @@ abstract class Entity{
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function setFireTicks(int $fireTicks) : void{
|
||||
if($fireTicks < 0 || $fireTicks > 0x7fff){
|
||||
throw new \InvalidArgumentException("Fire ticks must be in range 0 ... " . 0x7fff . ", got $fireTicks");
|
||||
if($fireTicks < 0){
|
||||
throw new \InvalidArgumentException("Fire ticks cannot be negative");
|
||||
}
|
||||
|
||||
//Since the max value is not externally obvious or intuitive, many plugins use this without being aware that
|
||||
//reasonably large values are not accepted. We even have such usages within PM itself. It doesn't make sense
|
||||
//to force all those calls to be aware of this limitation, as it's not a functional limit but a limitation of
|
||||
//the Mojang save format. Truncating this to the max acceptable value is the next best thing we can do.
|
||||
$fireTicks = min($fireTicks, Limits::INT16_MAX);
|
||||
|
||||
if(!$this->isFireProof()){
|
||||
$this->fireTicks = $fireTicks;
|
||||
$this->networkPropertiesDirty = true;
|
||||
@ -1495,7 +1504,7 @@ abstract class Entity{
|
||||
$this->getId(), //TODO: actor unique ID
|
||||
$this->getId(),
|
||||
static::getNetworkTypeId(),
|
||||
$this->location->asVector3(),
|
||||
$this->getOffsetPosition($this->location->asVector3()),
|
||||
$this->getMotion(),
|
||||
$this->location->pitch,
|
||||
$this->location->yaw,
|
||||
|
@ -1,86 +0,0 @@
|
||||
<?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\event\player;
|
||||
|
||||
use pocketmine\event\Cancellable;
|
||||
use pocketmine\event\CancellableTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
/**
|
||||
* Called when a player uses an anvil (renaming, repairing, combining items).
|
||||
* This event is called once per action even if multiple tasks are performed at once.
|
||||
*/
|
||||
class PlayerUseAnvilEvent extends PlayerEvent implements Cancellable{
|
||||
use CancellableTrait;
|
||||
|
||||
public function __construct(
|
||||
Player $player,
|
||||
private Item $baseItem,
|
||||
private ?Item $materialItem,
|
||||
private Item $resultItem,
|
||||
private ?string $customName,
|
||||
private int $xpCost
|
||||
){
|
||||
$this->player = $player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item that the player is using as the base item (left slot).
|
||||
*/
|
||||
public function getBaseItem() : Item{
|
||||
return $this->baseItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item that the player is using as the material item (right slot), or null if there is no material item
|
||||
* (e.g. when renaming an item).
|
||||
*/
|
||||
public function getMaterialItem() : ?Item{
|
||||
return $this->materialItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item that the player will receive as a result of the anvil operation.
|
||||
*/
|
||||
public function getResultItem() : Item{
|
||||
return $this->resultItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the custom name that the player is setting on the item, or null if the player is not renaming the item.
|
||||
*
|
||||
* This value is defined when the base item is already renamed.
|
||||
*/
|
||||
public function getCustomName() : ?string{
|
||||
return $this->customName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of XP levels that the player will spend on this anvil operation.
|
||||
*/
|
||||
public function getXpCost() : int{
|
||||
return $this->xpCost;
|
||||
}
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\inventory\transaction;
|
||||
|
||||
use pocketmine\block\Anvil;
|
||||
use pocketmine\block\inventory\AnvilInventory;
|
||||
use pocketmine\block\utils\AnvilHelper;
|
||||
use pocketmine\block\VanillaBlocks;
|
||||
use pocketmine\crafting\AnvilCraftResult;
|
||||
use pocketmine\event\player\PlayerUseAnvilEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\world\sound\AnvilBreakSound;
|
||||
use pocketmine\world\sound\AnvilUseSound;
|
||||
use function count;
|
||||
use function mt_rand;
|
||||
|
||||
class AnvilTransaction extends InventoryTransaction{
|
||||
private ?Item $baseItem = null;
|
||||
private ?Item $materialItem = null;
|
||||
|
||||
public function __construct(
|
||||
Player $source,
|
||||
private readonly AnvilCraftResult $expectedResult,
|
||||
private readonly ?string $customName
|
||||
){
|
||||
parent::__construct($source);
|
||||
}
|
||||
|
||||
private function validateFiniteResources(int $xpSpent) : void{
|
||||
$expectedXpCost = $this->expectedResult->getXpCost();
|
||||
if($xpSpent !== $expectedXpCost){
|
||||
throw new TransactionValidationException("Expected the amount of xp spent to be $expectedXpCost, but received $xpSpent");
|
||||
}
|
||||
|
||||
$xpLevel = $this->source->getXpManager()->getXpLevel();
|
||||
if($xpLevel < $expectedXpCost){
|
||||
throw new TransactionValidationException("Player's XP level $xpLevel is less than the required XP level $expectedXpCost");
|
||||
}
|
||||
}
|
||||
|
||||
private function validateInputs(Item $base, Item $material, Item $expectedOutput) : ?int{
|
||||
$calculAttempt = AnvilHelper::calculateResult($base, $material, $this->customName, $this->source->isCreative());
|
||||
if($calculAttempt === null){
|
||||
return null;
|
||||
}
|
||||
$result = $calculAttempt->getOutput();
|
||||
if(!$result->equalsExact($expectedOutput)){
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->baseItem = $base;
|
||||
$this->materialItem = $material;
|
||||
|
||||
return $calculAttempt->getXpCost();
|
||||
}
|
||||
|
||||
public function validate() : void{
|
||||
if(count($this->actions) < 1){
|
||||
throw new TransactionValidationException("Transaction must have at least one action to be executable");
|
||||
}
|
||||
|
||||
/** @var Item[] $inputs */
|
||||
$inputs = [];
|
||||
/** @var Item[] $outputs */
|
||||
$outputs = [];
|
||||
$this->matchItems($outputs, $inputs);
|
||||
|
||||
if(($outputCount = count($outputs)) !== 1){
|
||||
throw new TransactionValidationException("Expected 1 output item, but received $outputCount");
|
||||
}
|
||||
$outputItem = $outputs[0];
|
||||
|
||||
if(($inputCount = count($inputs)) < 1){
|
||||
throw new TransactionValidationException("Expected at least 1 input item, but received $inputCount");
|
||||
}
|
||||
if($inputCount > 2){
|
||||
throw new TransactionValidationException("Expected at most 2 input items, but received $inputCount");
|
||||
}
|
||||
|
||||
if(count($inputs) < 2){
|
||||
$xpCost = $this->validateInputs($inputs[0], VanillaItems::AIR(), $outputItem) ??
|
||||
throw new TransactionValidationException("Inputs do not match expected result");
|
||||
}else{
|
||||
$xpCost = $this->validateInputs($inputs[0], $inputs[1], $outputItem) ??
|
||||
$this->validateInputs($inputs[1], $inputs[0], $outputItem) ??
|
||||
throw new TransactionValidationException("Inputs do not match expected result");
|
||||
}
|
||||
|
||||
if($this->source->hasFiniteResources()){
|
||||
$this->validateFiniteResources($xpCost);
|
||||
}
|
||||
}
|
||||
|
||||
public function execute() : void{
|
||||
parent::execute();
|
||||
|
||||
if($this->source->hasFiniteResources()){
|
||||
$this->source->getXpManager()->subtractXpLevels($this->expectedResult->getXpCost());
|
||||
}
|
||||
|
||||
$inventory = $this->source->getCurrentWindow();
|
||||
if($inventory instanceof AnvilInventory){
|
||||
$world = $inventory->getHolder()->getWorld();
|
||||
if(mt_rand(0, 12) === 0){
|
||||
$anvilBlock = $world->getBlock($inventory->getHolder());
|
||||
if($anvilBlock instanceof Anvil){
|
||||
$newDamage = $anvilBlock->getDamage() + 1;
|
||||
if($newDamage > Anvil::VERY_DAMAGED){
|
||||
$newBlock = VanillaBlocks::AIR();
|
||||
$world->addSound($inventory->getHolder(), new AnvilBreakSound());
|
||||
}else{
|
||||
$newBlock = $anvilBlock->setDamage($newDamage);
|
||||
}
|
||||
$world->setBlock($inventory->getHolder(), $newBlock);
|
||||
}
|
||||
|
||||
}
|
||||
$world->addSound($inventory->getHolder(), new AnvilUseSound());
|
||||
}
|
||||
}
|
||||
|
||||
protected function callExecuteEvent() : bool{
|
||||
if($this->baseItem === null){
|
||||
throw new AssumptionFailedError("Expected that baseItem are not null before executing the event");
|
||||
}
|
||||
|
||||
$ev = new PlayerUseAnvilEvent($this->source, $this->baseItem, $this->materialItem, $this->expectedResult->getOutput(), $this->customName, $this->expectedResult->getXpCost());
|
||||
$ev->call();
|
||||
return !$ev->isCancelled();
|
||||
}
|
||||
}
|
@ -69,7 +69,6 @@ class Item implements \JsonSerializable{
|
||||
|
||||
public const TAG_DISPLAY_NAME = "Name";
|
||||
public const TAG_DISPLAY_LORE = "Lore";
|
||||
public const TAG_REPAIR_COST = "RepairCost";
|
||||
|
||||
public const TAG_KEEP_ON_DEATH = "minecraft:keep_on_death";
|
||||
|
||||
@ -85,7 +84,6 @@ class Item implements \JsonSerializable{
|
||||
protected string $customName = "";
|
||||
/** @var string[] */
|
||||
protected array $lore = [];
|
||||
protected int $anvilRepairCost = 0;
|
||||
/** TODO: this needs to die in a fire */
|
||||
protected ?CompoundTag $blockEntityTag = null;
|
||||
|
||||
@ -284,30 +282,6 @@ class Item implements \JsonSerializable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the anvil repair cost of the item.
|
||||
* This value is used in anvil to determine the XP cost of repairing the item.
|
||||
*
|
||||
* In vanilla, this value is stored in the "RepairCost" tag.
|
||||
*/
|
||||
public function getAnvilRepairCost() : int{
|
||||
return $this->anvilRepairCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the anvil repair cost value of the item.
|
||||
* This value is used in anvil to determine the XP cost of repairing the item.
|
||||
* Higher cost means more XP is required to repair the item.
|
||||
*
|
||||
* In vanilla, this value is stored in the "RepairCost" tag.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAnvilRepairCost(int $cost) : self{
|
||||
$this->anvilRepairCost = $cost;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NbtException
|
||||
*/
|
||||
@ -364,7 +338,6 @@ class Item implements \JsonSerializable{
|
||||
}
|
||||
|
||||
$this->keepOnDeath = $tag->getByte(self::TAG_KEEP_ON_DEATH, 0) !== 0;
|
||||
$this->anvilRepairCost = $tag->getInt(self::TAG_REPAIR_COST, 0);
|
||||
}
|
||||
|
||||
protected function serializeCompoundTag(CompoundTag $tag) : void{
|
||||
@ -433,12 +406,6 @@ class Item implements \JsonSerializable{
|
||||
}else{
|
||||
$tag->removeTag(self::TAG_KEEP_ON_DEATH);
|
||||
}
|
||||
|
||||
if($this->anvilRepairCost > 0){
|
||||
$tag->setInt(self::TAG_REPAIR_COST, $this->anvilRepairCost);
|
||||
}else{
|
||||
$tag->removeTag(self::TAG_REPAIR_COST);
|
||||
}
|
||||
}
|
||||
|
||||
public function getCount() : int{
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\item\enchantment\ItemEnchantmentTags as Tags;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments as Enchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_filter;
|
||||
use function array_values;
|
||||
use function count;
|
||||
@ -129,6 +130,7 @@ final class AvailableEnchantmentRegistry{
|
||||
if(!$this->isRegistered($enchantment)){
|
||||
throw new \LogicException("Cannot set primary item tags for non-registered enchantment");
|
||||
}
|
||||
Utils::validateArrayValueType($tags, fn(string $v) => 1);
|
||||
$this->primaryItemTags[spl_object_id($enchantment)] = array_values($tags);
|
||||
}
|
||||
|
||||
@ -152,6 +154,7 @@ final class AvailableEnchantmentRegistry{
|
||||
if(!$this->isRegistered($enchantment)){
|
||||
throw new \LogicException("Cannot set secondary item tags for non-registered enchantment");
|
||||
}
|
||||
Utils::validateArrayValueType($tags, fn(string $v) => 1);
|
||||
$this->secondaryItemTags[spl_object_id($enchantment)] = array_values($tags);
|
||||
}
|
||||
|
||||
|
63
src/network/mcpe/cache/StaticPacketCache.php
vendored
63
src/network/mcpe/cache/StaticPacketCache.php
vendored
@ -23,13 +23,22 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\cache;
|
||||
|
||||
use pocketmine\color\Color;
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\data\SavedDataLoadingException;
|
||||
use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket;
|
||||
use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket;
|
||||
use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer;
|
||||
use pocketmine\network\mcpe\protocol\types\biome\BiomeDefinitionEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\SingletonTrait;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\biome\model\BiomeDefinitionEntryData;
|
||||
use function count;
|
||||
use function get_debug_type;
|
||||
use function is_array;
|
||||
use function json_decode;
|
||||
|
||||
class StaticPacketCache{
|
||||
use SingletonTrait;
|
||||
@ -41,9 +50,61 @@ class StaticPacketCache{
|
||||
return new CacheableNbt((new NetworkNbtSerializer())->read(Filesystem::fileGetContents($filePath))->mustGetCompoundTag());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<BiomeDefinitionEntry>
|
||||
*/
|
||||
private static function loadBiomeDefinitionModel(string $filePath) : array{
|
||||
$biomeEntries = json_decode(Filesystem::fileGetContents($filePath), associative: true);
|
||||
if(!is_array($biomeEntries)){
|
||||
throw new SavedDataLoadingException("$filePath root should be an array, got " . get_debug_type($biomeEntries));
|
||||
}
|
||||
|
||||
$jsonMapper = new \JsonMapper();
|
||||
$jsonMapper->bExceptionOnMissingData = true;
|
||||
$jsonMapper->bStrictObjectTypeChecking = true;
|
||||
$jsonMapper->bEnforceMapType = false;
|
||||
|
||||
$entries = [];
|
||||
foreach(Utils::promoteKeys($biomeEntries) as $biomeName => $entry){
|
||||
if(!is_array($entry)){
|
||||
throw new SavedDataLoadingException("$filePath should be an array of objects, got " . get_debug_type($entry));
|
||||
}
|
||||
|
||||
try{
|
||||
$biomeDefinition = $jsonMapper->map($entry, new BiomeDefinitionEntryData());
|
||||
|
||||
$mapWaterColour = $biomeDefinition->mapWaterColour;
|
||||
$entries[] = new BiomeDefinitionEntry(
|
||||
(string) $biomeName,
|
||||
$biomeDefinition->id,
|
||||
$biomeDefinition->temperature,
|
||||
$biomeDefinition->downfall,
|
||||
$biomeDefinition->redSporeDensity,
|
||||
$biomeDefinition->blueSporeDensity,
|
||||
$biomeDefinition->ashDensity,
|
||||
$biomeDefinition->whiteAshDensity,
|
||||
$biomeDefinition->depth,
|
||||
$biomeDefinition->scale,
|
||||
new Color(
|
||||
$mapWaterColour->r,
|
||||
$mapWaterColour->g,
|
||||
$mapWaterColour->b,
|
||||
$mapWaterColour->a
|
||||
),
|
||||
$biomeDefinition->rain,
|
||||
count($biomeDefinition->tags) > 0 ? $biomeDefinition->tags : null,
|
||||
);
|
||||
}catch(\JsonMapper_Exception $e){
|
||||
throw new \RuntimeException($e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
private static function make() : self{
|
||||
return new self(
|
||||
BiomeDefinitionListPacket::create(self::loadCompoundFromFile(BedrockDataFiles::BIOME_DEFINITIONS_NBT)),
|
||||
BiomeDefinitionListPacket::fromDefinitions(self::loadBiomeDefinitionModel(BedrockDataFiles::BIOME_DEFINITIONS_JSON)),
|
||||
AvailableActorIdentifiersPacket::create(self::loadCompoundFromFile(BedrockDataFiles::ENTITY_IDENTIFIERS_NBT))
|
||||
);
|
||||
}
|
||||
|
@ -64,7 +64,6 @@ use pocketmine\network\mcpe\protocol\ItemStackResponsePacket;
|
||||
use pocketmine\network\mcpe\protocol\LabTablePacket;
|
||||
use pocketmine\network\mcpe\protocol\LecternUpdatePacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
|
||||
use pocketmine\network\mcpe\protocol\LevelSoundEventPacketV1;
|
||||
use pocketmine\network\mcpe\protocol\MapInfoRequestPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
|
||||
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
|
||||
@ -74,7 +73,6 @@ use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerActionPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerHotbarPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerInputPacket;
|
||||
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||
use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket;
|
||||
use pocketmine\network\mcpe\protocol\serializer\BitSet;
|
||||
@ -296,10 +294,6 @@ class InGamePacketHandler extends PacketHandler{
|
||||
return $packetHandled;
|
||||
}
|
||||
|
||||
public function handleLevelSoundEventPacketV1(LevelSoundEventPacketV1 $packet) : bool{
|
||||
return true; //useless leftover from 1.8
|
||||
}
|
||||
|
||||
public function handleActorEvent(ActorEventPacket $packet) : bool{
|
||||
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)
|
||||
@ -786,10 +780,6 @@ class InGamePacketHandler extends PacketHandler{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handlePlayerInput(PlayerInputPacket $packet) : bool{
|
||||
return false; //TODO
|
||||
}
|
||||
|
||||
public function handleSetPlayerGameType(SetPlayerGameTypePacket $packet) : bool{
|
||||
$gameMode = $this->session->getTypeConverter()->protocolGameModeToCore($packet->gamemode);
|
||||
if($gameMode !== $this->player->getGamemode()){
|
||||
|
@ -23,14 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\network\mcpe\handler;
|
||||
|
||||
use pocketmine\block\inventory\AnvilInventory;
|
||||
use pocketmine\block\inventory\EnchantInventory;
|
||||
use pocketmine\block\utils\AnvilHelper;
|
||||
use pocketmine\inventory\Inventory;
|
||||
use pocketmine\inventory\transaction\action\CreateItemAction;
|
||||
use pocketmine\inventory\transaction\action\DestroyItemAction;
|
||||
use pocketmine\inventory\transaction\action\DropItemAction;
|
||||
use pocketmine\inventory\transaction\AnvilTransaction;
|
||||
use pocketmine\inventory\transaction\CraftingTransaction;
|
||||
use pocketmine\inventory\transaction\EnchantingTransaction;
|
||||
use pocketmine\inventory\transaction\InventoryTransaction;
|
||||
@ -42,7 +39,6 @@ use pocketmine\network\mcpe\protocol\types\inventory\ContainerUIIds;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\CraftingConsumeInputStackRequestAction;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\CraftingCreateSpecificResultStackRequestAction;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\CraftRecipeAutoStackRequestAction;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\CraftRecipeOptionalStackRequestAction;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\CraftRecipeStackRequestAction;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\CreativeCreateStackRequestAction;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\DeprecatedCraftingResultsStackRequestAction;
|
||||
@ -294,7 +290,7 @@ class ItemStackRequestExecutor{
|
||||
* @throws ItemStackRequestProcessException
|
||||
*/
|
||||
private function assertDoingCrafting() : void{
|
||||
if(!$this->specialTransaction instanceof CraftingTransaction && !$this->specialTransaction instanceof EnchantingTransaction && !$this->specialTransaction instanceof AnvilTransaction){
|
||||
if(!$this->specialTransaction instanceof CraftingTransaction && !$this->specialTransaction instanceof EnchantingTransaction){
|
||||
if($this->specialTransaction === null){
|
||||
throw new ItemStackRequestProcessException("Expected CraftRecipe or CraftRecipeAuto action to precede this action");
|
||||
}else{
|
||||
@ -352,15 +348,6 @@ class ItemStackRequestExecutor{
|
||||
}
|
||||
}elseif($action instanceof CraftRecipeAutoStackRequestAction){
|
||||
$this->beginCrafting($action->getRecipeId(), $action->getRepetitions());
|
||||
}elseif($action instanceof CraftRecipeOptionalStackRequestAction){
|
||||
$window = $this->player->getCurrentWindow();
|
||||
if($window instanceof AnvilInventory){
|
||||
$result = AnvilHelper::calculateResult($window->getInput(), $window->getMaterial(), $this->request->getFilterStrings()[0] ?? null, $this->player->isCreative());
|
||||
if($result !== null){
|
||||
$this->specialTransaction = new AnvilTransaction($this->player, $result, $this->request->getFilterStrings()[0] ?? null);
|
||||
$this->setNextCreatedItem($result->getOutput());
|
||||
}
|
||||
}
|
||||
}elseif($action instanceof CraftingConsumeInputStackRequestAction){
|
||||
$this->assertDoingCrafting();
|
||||
$this->removeItemFromSlot($action->getSource(), $action->getCount()); //output discarded - we allow CraftingTransaction to verify the balance
|
||||
|
@ -84,6 +84,6 @@ final class ThreadCrashInfo extends ThreadSafe{
|
||||
public function getThreadName() : string{ return $this->threadName; }
|
||||
|
||||
public function makePrettyMessage() : string{
|
||||
return sprintf("%s: \"%s\" in \"%s\" on line %d", $this->type ?? "Fatal error", $this->message, Filesystem::cleanPath($this->file), $this->line);
|
||||
return sprintf("%s: \"%s\" in \"%s\" on line %d", $this->type, $this->message, Filesystem::cleanPath($this->file), $this->line);
|
||||
}
|
||||
}
|
||||
|
@ -584,7 +584,7 @@ final class Utils{
|
||||
/**
|
||||
* @phpstan-template TMemberType
|
||||
* @phpstan-param array<mixed, TMemberType> $array
|
||||
* @phpstan-param \Closure(TMemberType) : void $validator
|
||||
* @phpstan-param \Closure(TMemberType) : mixed $validator
|
||||
*/
|
||||
public static function validateArrayValueType(array $array, \Closure $validator) : void{
|
||||
foreach(Utils::promoteKeys($array) as $k => $v){
|
||||
|
@ -360,7 +360,7 @@ class World implements ChunkManager{
|
||||
|
||||
private bool $doingTick = false;
|
||||
|
||||
/** @phpstan-var class-string<\pocketmine\world\generator\Generator> */
|
||||
/** @phpstan-var class-string<generator\Generator> */
|
||||
private string $generator;
|
||||
|
||||
private bool $unloaded = false;
|
||||
|
@ -21,24 +21,49 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
namespace pocketmine\world\biome\model;
|
||||
|
||||
/**
|
||||
* Represent a recipe that repair an item with a material in an anvil.
|
||||
* Model for loading biome definition entries data from JSON.
|
||||
*/
|
||||
class ItemSelfCombineRecipe extends ItemCombineRecipe{
|
||||
/**
|
||||
* @param RecipeIngredient $target The item that will be concerned by the combinaison.
|
||||
* The input and material have to be accepted by this ingredient to be able to combine them.
|
||||
*/
|
||||
public function __construct(
|
||||
private RecipeIngredient $target
|
||||
){
|
||||
}
|
||||
final class BiomeDefinitionEntryData{
|
||||
/** @required */
|
||||
public ?int $id;
|
||||
|
||||
protected function validate(Item $input, Item $material) : bool{
|
||||
return $this->target->accepts($input) && $this->target->accepts($material);
|
||||
}
|
||||
/** @required */
|
||||
public float $temperature;
|
||||
|
||||
/** @required */
|
||||
public float $downfall;
|
||||
|
||||
/** @required */
|
||||
public float $redSporeDensity;
|
||||
|
||||
/** @required */
|
||||
public float $blueSporeDensity;
|
||||
|
||||
/** @required */
|
||||
public float $ashDensity;
|
||||
|
||||
/** @required */
|
||||
public float $whiteAshDensity;
|
||||
|
||||
/** @required */
|
||||
public float $depth;
|
||||
|
||||
/** @required */
|
||||
public float $scale;
|
||||
|
||||
/** @required */
|
||||
public ColorData $mapWaterColour;
|
||||
|
||||
/** @required */
|
||||
public bool $rain;
|
||||
|
||||
/**
|
||||
* @required
|
||||
* @var string[]
|
||||
* @phpstan-var list<string>
|
||||
*/
|
||||
public array $tags;
|
||||
}
|
@ -21,10 +21,21 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\crafting;
|
||||
namespace pocketmine\world\biome\model;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
/**
|
||||
* Model for loading color data from JSON.
|
||||
*/
|
||||
final class ColorData{
|
||||
/** @required */
|
||||
public int $r;
|
||||
|
||||
interface AnvilRecipe{
|
||||
public function getResultFor(Item $input, Item $material) : ?AnvilCraftResult;
|
||||
/** @required */
|
||||
public int $g;
|
||||
|
||||
/** @required */
|
||||
public int $b;
|
||||
|
||||
/** @required */
|
||||
public int $a;
|
||||
}
|
@ -51,12 +51,12 @@ use function time;
|
||||
class BedrockWorldData extends BaseNbtWorldData{
|
||||
|
||||
public const CURRENT_STORAGE_VERSION = 10;
|
||||
public const CURRENT_STORAGE_NETWORK_VERSION = 776;
|
||||
public const CURRENT_STORAGE_NETWORK_VERSION = 800;
|
||||
public const CURRENT_CLIENT_VERSION_TARGET = [
|
||||
1, //major
|
||||
21, //minor
|
||||
60, //patch
|
||||
33, //revision
|
||||
80, //patch
|
||||
3, //revision
|
||||
0 //is beta
|
||||
];
|
||||
|
||||
|
@ -39,7 +39,8 @@ class EntityAttackNoDamageSound implements Sound{
|
||||
-1,
|
||||
"minecraft:player",
|
||||
false,
|
||||
false
|
||||
false,
|
||||
-1
|
||||
)];
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,8 @@ class EntityAttackSound implements Sound{
|
||||
-1,
|
||||
"minecraft:player",
|
||||
false,
|
||||
false
|
||||
false,
|
||||
-1
|
||||
)];
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,8 @@ class EntityLandSound implements Sound{
|
||||
TypeConverter::getInstance()->getBlockTranslator()->internalIdToNetworkId($this->blockLandedOn->getStateId()),
|
||||
$this->entity::getNetworkTypeId(),
|
||||
false, //TODO: does isBaby have any relevance here?
|
||||
false
|
||||
false,
|
||||
$this->entity->getId()
|
||||
)];
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,8 @@ class EntityLongFallSound implements Sound{
|
||||
-1,
|
||||
$this->entity::getNetworkTypeId(),
|
||||
false, //TODO: is isBaby relevant here?
|
||||
false
|
||||
false,
|
||||
$this->entity->getId()
|
||||
)];
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,8 @@ class EntityShortFallSound implements Sound{
|
||||
-1,
|
||||
$this->entity::getNetworkTypeId(),
|
||||
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{
|
||||
|
||||
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),
|
||||
":",
|
||||
false,
|
||||
false
|
||||
false,
|
||||
-1
|
||||
)];
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ use function sprintf;
|
||||
/**
|
||||
* @implements Rule<Foreach_>
|
||||
*/
|
||||
final class UnsafeForeachArrayOfStringRule implements Rule{
|
||||
final class UnsafeForeachRule implements Rule{
|
||||
|
||||
public function getNodeType() : string{
|
||||
return Foreach_::class;
|
||||
@ -73,7 +73,7 @@ final class UnsafeForeachArrayOfStringRule implements Rule{
|
||||
$benevolentUnionDepth--;
|
||||
return $result;
|
||||
}
|
||||
if($type instanceof IntegerType && $benevolentUnionDepth === 0){
|
||||
if($type instanceof IntegerType){
|
||||
$expectsIntKeyTypes = true;
|
||||
return $type;
|
||||
}
|
||||
@ -87,24 +87,31 @@ final class UnsafeForeachArrayOfStringRule implements Rule{
|
||||
$hasCastableKeyTypes = true;
|
||||
return $type;
|
||||
});
|
||||
if($hasCastableKeyTypes && !$expectsIntKeyTypes){
|
||||
$tip = $implicitType ?
|
||||
sprintf(
|
||||
"Declare a key type using @phpstan-var or @phpstan-param, or use %s() to promote the key type to get proper error reporting",
|
||||
$errors = [];
|
||||
if($implicitType){
|
||||
$errors[] = RuleErrorBuilder::message("Possible unreported errors in foreach on array with unspecified key type.")
|
||||
->tip(sprintf(
|
||||
<<<TIP
|
||||
PHPStan might not be reporting some type errors if the key type is not specified.
|
||||
Declare a key type using @phpstan-var or @phpstan-param, or use %s() to force PHPStan to report proper errors.
|
||||
TIP,
|
||||
Utils::getNiceClosureName(Utils::promoteKeys(...))
|
||||
) :
|
||||
sprintf(
|
||||
"Use %s() to get a \Generator that will force the keys to string",
|
||||
Utils::getNiceClosureName(Utils::stringifyKeys(...)),
|
||||
);
|
||||
return [
|
||||
RuleErrorBuilder::message(sprintf(
|
||||
"Unsafe foreach on array with key type %s (they might be casted to int).",
|
||||
$iterableType->getIterableKeyType()->describe(VerbosityLevel::value())
|
||||
))->tip($tip)->identifier('pocketmine.foreach.stringKeys')->build()
|
||||
];
|
||||
))->identifier('pocketmine.foreach.implicitKeys')->build();
|
||||
}
|
||||
return [];
|
||||
if($hasCastableKeyTypes && !$expectsIntKeyTypes){
|
||||
$errors[] = RuleErrorBuilder::message(sprintf(
|
||||
"Unsafe foreach on array with key type %s.",
|
||||
$iterableType->getIterableKeyType()->describe(VerbosityLevel::value())
|
||||
))
|
||||
->tip(sprintf(
|
||||
<<<TIP
|
||||
PHP coerces numeric strings to integers when used as array keys, which can lead to unexpected type errors when passing the key to a function.
|
||||
Use %s() to wrap the array in a \Generator that will force the keys back to string during iteration.
|
||||
TIP,
|
||||
Utils::getNiceClosureName(Utils::stringifyKeys(...))
|
||||
))->identifier('pocketmine.foreach.stringKeys')->build();
|
||||
}
|
||||
return $errors;
|
||||
}
|
||||
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
<?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\crafting;
|
||||
|
||||
use Generator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use pocketmine\item\enchantment\EnchantmentInstance;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function floor;
|
||||
|
||||
class AnvilCraftTest extends TestCase{
|
||||
public static function materialRepairRecipeProvider() : Generator{
|
||||
yield "No repair available" => [
|
||||
VanillaItems::DIAMOND_PICKAXE(),
|
||||
VanillaItems::DIAMOND(),
|
||||
null
|
||||
];
|
||||
|
||||
yield "Repair one damage" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->setDamage(1),
|
||||
VanillaItems::DIAMOND(),
|
||||
new AnvilCraftResult(1, VanillaItems::DIAMOND_PICKAXE(), null)
|
||||
];
|
||||
|
||||
yield "Repair one damage with more materials than expected" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->setDamage(1),
|
||||
VanillaItems::DIAMOND()->setCount(2),
|
||||
new AnvilCraftResult(1, VanillaItems::DIAMOND_PICKAXE(), VanillaItems::DIAMOND())
|
||||
];
|
||||
|
||||
$diamondPickaxeQuarter = (int) floor(VanillaItems::DIAMOND_PICKAXE()->getMaxDurability() / 4);
|
||||
yield "Repair one quarter" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->setDamage($diamondPickaxeQuarter),
|
||||
VanillaItems::DIAMOND()->setCount(1),
|
||||
new AnvilCraftResult(1, VanillaItems::DIAMOND_PICKAXE(), null)
|
||||
];
|
||||
|
||||
yield "Repair one quarter plus 1" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->setDamage($diamondPickaxeQuarter + 1),
|
||||
VanillaItems::DIAMOND()->setCount(1),
|
||||
new AnvilCraftResult(1, VanillaItems::DIAMOND_PICKAXE()->setDamage(1), null)
|
||||
];
|
||||
|
||||
yield "Repair more than one quarter" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->setDamage($diamondPickaxeQuarter * 2),
|
||||
VanillaItems::DIAMOND()->setCount(2),
|
||||
new AnvilCraftResult(2, VanillaItems::DIAMOND_PICKAXE(), null)
|
||||
];
|
||||
|
||||
yield "Repair more than one quarter with more materials than expected" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->setDamage($diamondPickaxeQuarter * 2),
|
||||
VanillaItems::DIAMOND()->setCount(3),
|
||||
new AnvilCraftResult(2, VanillaItems::DIAMOND_PICKAXE(), VanillaItems::DIAMOND()->setCount(1))
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider materialRepairRecipeProvider
|
||||
*/
|
||||
public function testMaterialRepairRecipe(Item $base, Item $material, ?AnvilCraftResult $expected) : void{
|
||||
$recipe = new MaterialRepairRecipe(
|
||||
new WildcardRecipeIngredient(),
|
||||
new WildcardRecipeIngredient()
|
||||
);
|
||||
self::assertAnvilCraftResultEquals($expected, $recipe->getResultFor($base, $material));
|
||||
}
|
||||
|
||||
public static function itemSelfCombineRecipeProvider() : Generator{
|
||||
yield "Combine two identical items without damage and enchants" => [
|
||||
VanillaItems::DIAMOND_PICKAXE(),
|
||||
VanillaItems::DIAMOND_PICKAXE(),
|
||||
null
|
||||
];
|
||||
|
||||
yield "Enchant on base item and no enchants on material with no damage" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::UNBREAKING(), 1)),
|
||||
VanillaItems::DIAMOND_PICKAXE(),
|
||||
null
|
||||
];
|
||||
|
||||
yield "No enchant on base item and one enchant on material" => [
|
||||
VanillaItems::DIAMOND_PICKAXE(),
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::UNBREAKING(), 1)),
|
||||
new AnvilCraftResult(2, VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::UNBREAKING(), 1)), null)
|
||||
];
|
||||
|
||||
yield "Combine two identical items with damage" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->setDamage(10),
|
||||
VanillaItems::DIAMOND_PICKAXE(),
|
||||
new AnvilCraftResult(1, VanillaItems::DIAMOND_PICKAXE()->setDamage(0), null)
|
||||
];
|
||||
|
||||
yield "Combine two identical items with damage for material" => [
|
||||
VanillaItems::DIAMOND_PICKAXE(),
|
||||
VanillaItems::DIAMOND_PICKAXE()->setDamage(10),
|
||||
null
|
||||
];
|
||||
|
||||
yield "Combine two identical items with different enchantments" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::EFFICIENCY(), 2)),
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::UNBREAKING(), 1)),
|
||||
new AnvilCraftResult(2, VanillaItems::DIAMOND_PICKAXE()
|
||||
->addEnchantment(new EnchantmentInstance(VanillaEnchantments::EFFICIENCY(), 2))
|
||||
->addEnchantment(new EnchantmentInstance(VanillaEnchantments::UNBREAKING(), 1)),
|
||||
null)
|
||||
];
|
||||
|
||||
yield "Combine two identical items with different enchantments with damage" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::EFFICIENCY(), 2))->setDamage(10),
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::UNBREAKING(), 1)),
|
||||
new AnvilCraftResult(4, VanillaItems::DIAMOND_PICKAXE()
|
||||
->addEnchantment(new EnchantmentInstance(VanillaEnchantments::EFFICIENCY(), 2))
|
||||
->addEnchantment(new EnchantmentInstance(VanillaEnchantments::UNBREAKING(), 1)),
|
||||
null)
|
||||
];
|
||||
|
||||
yield "Combine two identical items with different enchantments with damage for material" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::EFFICIENCY(), 2)),
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::UNBREAKING(), 1))->setDamage(10),
|
||||
new AnvilCraftResult(2, VanillaItems::DIAMOND_PICKAXE()
|
||||
->addEnchantment(new EnchantmentInstance(VanillaEnchantments::EFFICIENCY(), 2))
|
||||
->addEnchantment(new EnchantmentInstance(VanillaEnchantments::UNBREAKING(), 1)),
|
||||
null)
|
||||
];
|
||||
|
||||
yield "Combine two identical items with same enchantment level" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::FORTUNE(), 1)),
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::FORTUNE(), 1)),
|
||||
new AnvilCraftResult(8, VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::FORTUNE(), 2)), null)
|
||||
];
|
||||
|
||||
yield "Combine two identical items with same enchantment level and damage" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::FORTUNE(), 1))->setDamage(10),
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::FORTUNE(), 1)),
|
||||
new AnvilCraftResult(10, VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::FORTUNE(), 2))->setDamage(0), null)
|
||||
];
|
||||
|
||||
yield "Combine two identical items with same enchantment level and damage for material" => [
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::FORTUNE(), 1)),
|
||||
VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::FORTUNE(), 1))->setDamage(10),
|
||||
new AnvilCraftResult(8, VanillaItems::DIAMOND_PICKAXE()->addEnchantment(new EnchantmentInstance(VanillaEnchantments::FORTUNE(), 2)), null)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider itemSelfCombineRecipeProvider
|
||||
*/
|
||||
public function testItemSelfCombineRecipe(Item $base, Item $combined, ?AnvilCraftResult $expected) : void{
|
||||
$recipe = new ItemSelfCombineRecipe(new WildcardRecipeIngredient());
|
||||
self::assertAnvilCraftResultEquals($expected, $recipe->getResultFor($base, $combined));
|
||||
}
|
||||
|
||||
private static function assertAnvilCraftResultEquals(?AnvilCraftResult $expected, ?AnvilCraftResult $actual) : void{
|
||||
if($expected === null){
|
||||
self::assertNull($actual, "Recipe did not match expected result");
|
||||
return;
|
||||
}else{
|
||||
self::assertNotNull($actual, "Recipe did not match expected result");
|
||||
}
|
||||
self::assertEquals($expected->getXpCost(), $actual->getXpCost(), "XP cost did not match expected result");
|
||||
self::assertTrue($expected->getOutput()->equalsExact($actual->getOutput()), "Recipe output did not match expected result");
|
||||
$sacrificeResult = $expected->getSacrificeResult();
|
||||
if($sacrificeResult !== null){
|
||||
$resultExpected = $actual->getSacrificeResult();
|
||||
self::assertNotNull($resultExpected, "Recipe sacrifice result did not match expected result");
|
||||
self::assertTrue($sacrificeResult->equalsExact($resultExpected), "Recipe sacrifice result did not match expected result");
|
||||
}else{
|
||||
self::assertNull($actual->getSacrificeResult(), "Recipe sacrifice result did not match expected result");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
<?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\crafting;
|
||||
|
||||
use pocketmine\item\Item;
|
||||
|
||||
final class WildcardRecipeIngredient implements RecipeIngredient{
|
||||
|
||||
public function __toString() : string{
|
||||
return "WildcardRecipeIngredient()";
|
||||
}
|
||||
|
||||
public function accepts(Item $item) : bool{
|
||||
return true;
|
||||
}
|
||||
}
|
@ -54,7 +54,6 @@ use pocketmine\network\mcpe\protocol\PacketPool;
|
||||
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
|
||||
use pocketmine\network\mcpe\protocol\serializer\PacketSerializer;
|
||||
use pocketmine\network\mcpe\protocol\StartGamePacket;
|
||||
use pocketmine\network\mcpe\protocol\types\CacheableNbt;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\CreativeGroupEntry;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStack;
|
||||
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackExtraData;
|
||||
@ -76,6 +75,8 @@ use pocketmine\network\PacketHandlingException;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\biome\model\BiomeDefinitionEntryData;
|
||||
use pocketmine\world\biome\model\ColorData;
|
||||
use pocketmine\world\format\io\GlobalBlockStateHandlers;
|
||||
use Ramsey\Uuid\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
@ -100,6 +101,7 @@ use function json_encode;
|
||||
use function ksort;
|
||||
use function mkdir;
|
||||
use function ord;
|
||||
use function round;
|
||||
use function strlen;
|
||||
use const FILE_IGNORE_NEW_LINES;
|
||||
use const JSON_PRETTY_PRINT;
|
||||
@ -572,34 +574,34 @@ class ParserPacketHandler extends PacketHandler{
|
||||
public function handleBiomeDefinitionList(BiomeDefinitionListPacket $packet) : bool{
|
||||
echo "storing biome definitions" . PHP_EOL;
|
||||
|
||||
file_put_contents($this->bedrockDataPath . '/biome_definitions_full.nbt', $packet->definitions->getEncodedNbt());
|
||||
$definitions = [];
|
||||
foreach($packet->buildDefinitionsFromData() as $entry){
|
||||
$mapWaterColor = new ColorData();
|
||||
$mapWaterColor->r = $entry->getMapWaterColor()->getR();
|
||||
$mapWaterColor->g = $entry->getMapWaterColor()->getG();
|
||||
$mapWaterColor->b = $entry->getMapWaterColor()->getB();
|
||||
$mapWaterColor->a = $entry->getMapWaterColor()->getA();
|
||||
|
||||
$nbt = $packet->definitions->getRoot();
|
||||
if(!$nbt instanceof CompoundTag){
|
||||
throw new AssumptionFailedError();
|
||||
}
|
||||
$strippedNbt = clone $nbt;
|
||||
foreach($strippedNbt as $compound){
|
||||
if($compound instanceof CompoundTag){
|
||||
foreach([
|
||||
"minecraft:capped_surface",
|
||||
"minecraft:consolidated_features",
|
||||
"minecraft:frozen_ocean_surface",
|
||||
"minecraft:legacy_world_generation_rules",
|
||||
"minecraft:mesa_surface",
|
||||
"minecraft:mountain_parameters",
|
||||
"minecraft:multinoise_generation_rules",
|
||||
"minecraft:overworld_generation_rules",
|
||||
"minecraft:surface_material_adjustments",
|
||||
"minecraft:surface_parameters",
|
||||
"minecraft:swamp_surface",
|
||||
] as $remove){
|
||||
$compound->removeTag($remove);
|
||||
}
|
||||
}
|
||||
$data = new BiomeDefinitionEntryData();
|
||||
$data->id = $entry->getId();
|
||||
$data->temperature = round($entry->getTemperature(), 3);
|
||||
$data->downfall = round($entry->getDownfall(), 3);
|
||||
$data->redSporeDensity = round($entry->getRedSporeDensity(), 3);
|
||||
$data->blueSporeDensity = round($entry->getBlueSporeDensity(), 3);
|
||||
$data->ashDensity = round($entry->getAshDensity(), 3);
|
||||
$data->whiteAshDensity = round($entry->getWhiteAshDensity(), 3);
|
||||
$data->depth = round($entry->getDepth(), 3);
|
||||
$data->scale = round($entry->getScale(), 3);
|
||||
$data->mapWaterColour = $mapWaterColor;
|
||||
$data->rain = $entry->hasRain();
|
||||
$data->tags = $entry->getTags() ?? [];
|
||||
|
||||
$definitions[$entry->getBiomeName()] = self::objectToOrderedArray($data);
|
||||
}
|
||||
|
||||
file_put_contents($this->bedrockDataPath . '/biome_definitions.nbt', (new CacheableNbt($strippedNbt))->getEncodedNbt());
|
||||
ksort($definitions, SORT_STRING);
|
||||
|
||||
file_put_contents($this->bedrockDataPath . '/biome_definitions.json', json_encode($definitions, JSON_PRETTY_PRINT) . "\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
Reference in New Issue
Block a user