Compare commits

..

180 Commits
5.4.0 ... 5.7.0

Author SHA1 Message Date
22b9e70372 Release 5.7.0 2023-10-26 12:51:45 +01:00
a222636476 Merge branch 'legacy/pm4' into stable 2023-10-26 12:47:19 +01:00
fb586cc562 4.25.1 is next 2023-10-26 12:43:16 +01:00
f3f22ba48b Release 4.25.0 2023-10-26 12:43:16 +01:00
a2e6e2e5b9 Update PHPStan 2023-10-26 12:39:45 +01:00
1aaaadb909 1.20.40 changes (PM4) 2023-10-26 12:36:12 +01:00
53a740433f Changes for 1.20.40 2023-10-26 12:32:59 +01:00
9fcc9f4338 StringToItemParser: added missing blocks
closes #6108
2023-10-23 12:24:02 +01:00
73b1fba53c Fixed Promise<null> calling rejection handler given after being successfully resolved
closes #6110

this is a weird use case, but it should work nonetheless.
2023-10-23 11:46:08 +01:00
e4888d7102 ÂCONTRIBUTING.md: restructure, reword and reorganize
[ci skip]
2023-10-20 12:12:14 +01:00
450ad42202 Added some new recommendations to CONTRIBUTING.md 2023-10-20 11:37:58 +01:00
1c5d3b43be 5.6.2 is next 2023-10-20 10:30:50 +01:00
decc188302 Release 5.6.1 2023-10-20 10:30:50 +01:00
8fa5c7cdab World: do not apply fake state properties from tile if the block doesn't expect this tile type
This was causing a variety of crashes due to incorrect tiles, presumably from PM3 worlds.
2023-10-20 10:28:46 +01:00
7dd3a70d2e Revert "World: discard tiles on load if they aren't the correct type or no tile is expected"
This reverts commit 8f804f6f34.

This change is too disruptive, since popular plugins like
ExtendedBlocks and ExtendedBlocksConverter relied on custom tiles.
Deleting them at this stage would prevent these plugins from working,
making it impossible to upgrade old data.

An alternative solution to this problem will need to be developed.
2023-10-20 10:16:49 +01:00
b3390458b4 Bump phpstan/phpstan from 1.10.38 to 1.10.39 (#6103)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.10.38 to 1.10.39.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.11.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.10.38...1.10.39)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-19 11:58:27 +01:00
b4d55e4384 Fixed dirt and grass block interactions when clicking on sides other than the top (#6071) 2023-10-18 10:40:01 +01:00
932116fa52 Server: re-added @see reference that somehow got deleted
this is useful when clicking through references in the call stack.
2023-10-18 10:23:02 +01:00
7b5c30bc2c WoodenDoor can be a fuel (#6101) 2023-10-17 22:10:08 +01:00
c14eb63f9b Wooden Button can be a fuel (#6099) 2023-10-17 16:30:35 +01:00
224a69b11a Sign can be a fuel (#6095) 2023-10-17 12:22:20 +01:00
15ba642258 Merge branch 'legacy/pm4' into stable 2023-10-16 21:28:48 +01:00
edea793a98 Downgrade PHPUnit to 10.3 until sebastianbergmann/phpunit#5539 is fixed 2023-10-16 21:25:53 +01:00
1da7e3586b Updated composer dependencies 2023-10-16 20:45:44 +01:00
7d200247f8 Cactus: do not update if only age changed
I'd prefer a smarter solution for this that automatically disables updates depending on which type of property was changed, but for now, this will significantly improve the performance of cactus farms.
The newly placed cactus block at the top cannot have updates disabled, though, since it needs to check its surroundings in case it grew into a space with a solid block next to it.

Thanks @KingOfTurkey38 for bringing this to light.
2023-10-13 12:45:11 +01:00
2d697c5f04 A random change that Composer 2.6 wanted to make 2023-10-09 18:27:20 +01:00
364f408eb1 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2023-10-09 18:22:54 +01:00
660e2b8173 Update build/php to pmmp/php-build-scripts@a34e48e7da 2023-10-09 18:22:28 +01:00
9facb98327 Bump phpunit/phpunit from 10.3.5 to 10.4.1 (#6082)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.3.5 to 10.4.1.
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.4.1/ChangeLog-10.4.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/10.3.5...10.4.1)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-09 17:16:15 +01:00
7e42a03db3 Bump phpstan/phpstan from 1.10.37 to 1.10.38 (#6081)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.10.37 to 1.10.38.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.11.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.10.37...1.10.38)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-09 17:15:50 +01:00
94a17f59d2 fix(Entity): broadcastSound() not firing WorldSoundEvent (#6069) 2023-10-08 19:25:19 +01:00
ed4088755f Bump phpstan/phpstan from 1.10.35 to 1.10.37 (#6073)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.10.35 to 1.10.37.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.11.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.10.35...1.10.37)

---
updated-dependencies:
- dependency-name: phpstan/phpstan
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-05 22:23:13 +01:00
ff89d4d055 Updated composer dependencies 2023-09-28 14:55:55 +01:00
8f804f6f34 World: discard tiles on load if they aren't the correct type or no tile is expected
in many instances, remnants of improperly removed blocks from PM3 have been causing problems, such as flower pot tiles where there are no flower pots.

this change might break some plugins which are using tiles for custom purposes, but this is a misuse that was never supported properly in the first place.
2023-09-27 14:57:06 +01:00
c3bca9e172 tools/generate-bedrock-data-from-packets: fixed interpreting item metadata as blockstates when the item ID could be interpreted as a block ID
this broke crafting recipes which accepted skulls as inputs, as well as nether wart and bed recipes.
2023-09-27 12:37:26 +01:00
c028bb9055 Bump docker/setup-buildx-action from 2 to 3 (#6049)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-21 14:50:57 +01:00
f151047b5e Bump docker/login-action from 2 to 3 (#6050)
Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-21 14:50:40 +01:00
77566db766 Bump docker/build-push-action from 4.1.1 to 5.0.0 (#6051)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4.1.1 to 5.0.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v4.1.1...v5.0.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-21 14:50:17 +01:00
dd2e6ea33f Bump shivammathur/setup-php from 2.25.5 to 2.26.0 (#6055)
Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.25.5 to 2.26.0.
- [Release notes](https://github.com/shivammathur/setup-php/releases)
- [Commits](https://github.com/shivammathur/setup-php/compare/2.25.5...2.26.0)

---
updated-dependencies:
- dependency-name: shivammathur/setup-php
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-21 14:49:38 +01:00
d138a15a32 Merge branch 'legacy/pm4' into stable 2023-09-21 13:27:04 +01:00
7a2cfa92b6 Update composer dependencies 2023-09-21 13:23:09 +01:00
912fd3f5c6 PHPStan 1.10.35, plus workarounds 2023-09-21 13:22:14 +01:00
5eca90d478 5.6.1 is next 2023-09-20 19:00:51 +01:00
338bb3fe6d Release 5.6.0 2023-09-20 19:00:51 +01:00
f485f7fb46 Updated composer dependencies 2023-09-20 18:57:36 +01:00
63eba3eb53 Merge branch 'legacy/pm4' into stable 2023-09-20 18:40:58 +01:00
914eb62e94 4.24.1 is next 2023-09-20 18:40:07 +01:00
a85814d0c9 Release 4.24.0 2023-09-20 18:40:07 +01:00
eb2e472b01 Merge branch 'legacy/pm4' into stable 2023-09-20 18:36:41 +01:00
6553852d99 Updated for 1.20.30 release 2023-09-20 18:34:12 +01:00
540476365f Updated for 1.20.30 release 2023-09-20 18:14:59 +01:00
efafc2c6ca DeadBush: updated support requirements
since 1.20 they can now be placed on grass and mud.
2023-09-08 16:41:06 +01:00
d7f69c5e24 CaveVines: fixed incorrect support condition 2023-09-08 12:47:46 +01:00
0e87ee1e0e ÂHangingRoots: fixed incorrect support face 2023-09-08 12:22:00 +01:00
03ecc98a24 HangingRoots: fixed support conditions 2023-09-08 12:16:45 +01:00
a5aeabd836 RegistryTrait: fixed mishandling of self::$members
Since PHPStan doesn't warn about potential nulls on untyped properties, this flew under the radar.
2023-09-08 12:16:16 +01:00
fe94379a93 Fixed connection requirements for fences, glass, bars and walls
these connect to the back faces of stairs and to glass, for example.
2023-09-06 12:56:47 +01:00
79acc4fed4 5.5.1 is next 2023-09-06 12:13:26 +01:00
c8d357f4eb Release 5.5.0 2023-09-06 12:13:26 +01:00
ec1cd5967d Added private constructors for new internal classes 2023-09-06 12:12:11 +01:00
5a010e8213 Merge branch 'minor-next' into stable 2023-09-06 12:06:15 +01:00
73a44d50ee 5.4.5 is next 2023-09-06 11:53:04 +01:00
6aab07debd Release 5.4.4 2023-09-06 11:53:01 +01:00
b160b87e24 Server: stop discriminating against crashes caused by folder plugins
these are the de facto standard, which means that a lot of crashes aren't getting reported from servers with folder plugins.
2023-09-06 11:34:03 +01:00
690ee4c574 CrashDump: fixed empty elements in lastError trace
as shown by #6010
2023-09-06 11:24:08 +01:00
a0c7587b68 Update composer dependencies 2023-09-06 11:09:28 +01:00
be4e091d40 Update draft release notice 2023-09-06 11:03:15 +01:00
857c2edc2c Server: update obsoletion notice with new announcement and cutoff date 2023-09-06 10:58:41 +01:00
b1ab69ac6c Updated build/php submodule to pmmp/PHP-Binaries@3331f8c0d5 2023-09-06 10:51:22 +01:00
e95a920fb8 Update composer dependencies 2023-09-06 10:49:54 +01:00
67f399b238 Bump phpstan/phpstan-phpunit from 1.3.13 to 1.3.14 (#6021)
Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 1.3.13 to 1.3.14.
- [Release notes](https://github.com/phpstan/phpstan-phpunit/releases)
- [Commits](https://github.com/phpstan/phpstan-phpunit/compare/1.3.13...1.3.14)

---
updated-dependencies:
- dependency-name: phpstan/phpstan-phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-06 10:24:41 +01:00
a7c806d549 Bump phpunit/phpunit from 10.3.2 to 10.3.3 (#6033)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.3.2 to 10.3.3.
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.3.3/ChangeLog-10.3.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/10.3.2...10.3.3)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-06 10:24:23 +01:00
0920c76a35 Bump build/php from 8884039 to 3331f8c (#6031)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `8884039` to `3331f8c`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](8884039bee...3331f8c0d5)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-06 08:37:05 +01:00
a91ca999fe Bump actions/checkout from 3 to 4 (#6032)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-06 08:32:33 +01:00
ce04478395 Fix SmithingTableInventory size (#6035)
Since 1.20 SmithingTable has a new Template slot, size is now 3

Fix debug error from InventoryManager
2023-09-06 08:15:27 +01:00
28ce7ac5fd Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2023-09-04 18:10:41 +01:00
540f088eda tools/generate-bedrock-data-from-packets: make duplicate reporting less spammy 2023-09-01 20:51:45 +01:00
19e3d339f6 InGamePacketHandler: subtract from raw position before rounding it (#6022)
This allows better compensation for floating point errors introduced by the subtraction of the 1.62 height offset.

For example, if the player is at y=7 exactly, their Y coordinate will be reported as 8.62, which, because of floating point errors, will be something like `8.619999999`. Subtracting `1.62` from this (really something like `1.62000000000005...`) leads to the calculated Y coordinate being slightly below 7.

Rounding after subtracting this offset allows this to be rounded to 7 sharp. Similar errors appear in various other coordinates.
2023-08-29 11:43:21 +01:00
9fdb6ba5aa Mark some new things as internal 2023-08-25 14:02:49 +01:00
4a0a538278 CS 2023-08-25 13:27:40 +01:00
2912e7ca29 ... 2023-08-25 13:27:11 +01:00
31d8cc1cb5 Generate and use constants for pocketmine.yml constant names
a couple of usages of properties that no longer exist couldn't be migrated.
in addition, this revealed a couple of dead properties in the default file.

this is not an ideal solution (I'd much rather model the configs using classes and map them) but in the absence of a good and reliable library to do that, this is the next best thing.
2023-08-25 13:23:38 +01:00
506d8d1064 CS 2023-08-25 12:49:56 +01:00
d1a7c1d453 Constify server.properties references 2023-08-25 12:49:39 +01:00
b56f1b679e Deduplicate a bunch of repeated type ID map code 2023-08-25 12:30:54 +01:00
1a18e32011 Bump ncipollo/release-action from 1.12.0 to 1.13.0 (#6019)
Bumps [ncipollo/release-action](https://github.com/ncipollo/release-action) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/ncipollo/release-action/releases)
- [Commits](https://github.com/ncipollo/release-action/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: ncipollo/release-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-25 09:43:31 +01:00
09c9dfb576 Bump build/php from d75f83e to 8884039 (#6018)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `d75f83e` to `8884039`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](d75f83e7ef...8884039bee)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-25 09:43:05 +01:00
f2b710c083 Bump build/php from a053f65 to d75f83e (#6017)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `a053f65` to `d75f83e`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](a053f65e18...d75f83e7ef)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 08:31:31 +01:00
c7a311c17a COPILOT 2023-08-23 17:14:56 +01:00
ce53a221a5 5.5.0-BETA2 is next 2023-08-23 17:09:34 +01:00
c8100480ac Release 5.5.0-BETA1 2023-08-23 17:09:34 +01:00
8814d06dfd Fix CS 2023-08-23 17:00:18 +01:00
923f7561fb Enchantment: added @see tags to @deprecated methods 2023-08-23 16:53:09 +01:00
f4e1c31dcf Change some weird constant names 2023-08-23 16:52:47 +01:00
998fcf20db Remove useless Cancellable from PressurePlateUpdateEvent 2023-08-23 16:52:22 +01:00
1504fdca24 Use 'enchanting' terminology
'enchant' just didn't feel right, being a verb.
All these things pertain to the act of enchanting.

This is now also consistent with CraftingTransaction etc. The ship already sailed on EnchantInventory, which will have to be renamed at a later datte. However, that was already inconsistent with 'enchanting table', so that's the odd one out here.
2023-08-23 16:14:17 +01:00
bf668c0f6c Rename EnchantHelper related stuff
Perhaps this and EnchantOption should be called EnchantingHelper and EnchantingOption respectively. The terminology used is rather inconsistent, but 'enchantment' definitely isn't the right word here.
2023-08-23 16:07:02 +01:00
d942748203 Move enchanting seed generation to EnchantmentHelper 2023-08-23 15:52:49 +01:00
29fdc8b08d Private constructor for EnchantmentHelper 2023-08-23 15:49:31 +01:00
20a41b00ba StringToTParser: added registerAlias() 2023-08-23 15:24:29 +01:00
df96e023dc Require pocketmine/nbt 1.0.0 2023-08-23 14:42:50 +01:00
f4d5605de1 Use hasHandlers() on more warm-hot events 2023-08-23 14:35:53 +01:00
d03e4d17ec Use hasHandlers() for events in player movement processing pathway
this should offer a minor performance improvement.
2023-08-23 14:26:17 +01:00
4cc858829f 5.4.4 is next 2023-08-21 18:31:45 +01:00
e852a43821 Release 5.4.3 2023-08-21 18:31:45 +01:00
05f40b1315 Merge branch 'legacy/pm4' into stable 2023-08-21 18:27:18 +01:00
7aaef8cb89 4.23.7 is next 2023-08-21 18:26:50 +01:00
9d4c37fc3a Release 4.23.6 2023-08-21 18:26:47 +01:00
cd6abbe0bb BaseSign: remove redundant condition 2023-08-21 16:30:16 +01:00
22778583cf Sign: implement waxing using honeycomb 2023-08-21 16:28:17 +01:00
d44e0e87d0 BaseSign: implement sign editing
this was originally submitted by #6000, but considering the overcomplicated PR and the triviality of the feature, I figured it would be quicker to do it myself instead of having a bunch of back-and-forth bikeshedding over it.
2023-08-21 16:14:43 +01:00
47b448965d Merge branch 'stable' into minor-next 2023-08-21 16:08:27 +01:00
cfa2df82eb Merge branch 'legacy/pm4' into stable 2023-08-21 16:07:56 +01:00
7f78ec0a32 Include PHP binary URLs in GitHub releases and build info 2023-08-21 16:05:59 +01:00
8572311bf4 Remove dead PHPStan stub
closes #6003
2023-08-21 14:57:26 +01:00
18ca3a37d9 CrashDump: fixed crashdump generation failure on fatal error
closes #6007
2023-08-21 14:51:54 +01:00
b2414b4c29 EnchantTransaction: cleanup XP cost checking logic 2023-08-18 12:33:07 +01:00
b3c740081e Merge branch 'stable' into minor-next 2023-08-18 12:28:45 +01:00
4b41fca991 Merge branch 'legacy/pm4' into stable 2023-08-18 12:28:29 +01:00
9f09acc079 Workaround for slot IDs not changing client side when old item == new item
this is a really dumb bug and seems similar to the armor bug I fixed a while ago.

fixes #5987

it's unlikely that #5727 will be solved by this, but one can hope...
2023-08-18 12:27:27 +01:00
beaca8bb6d EnchantTransaction: fixed XP level costs when minimum level is less than the XP cost
this can happen and happens in vanilla too. In these cases, as much of the XP cost as possible is deducted.
2023-08-16 14:51:47 +01:00
e323c5dd76 Implement pressure plate activation logic and events (#5991)
closes #5936

This implements all of the basic activation logic for pressure plates.
It also introduces a PressurePlateUpdateEvent, which is called in pulses when entities are standing on top of the plate and when it deactivates. Deactivation can be detected by checking if the list of activating entities is empty.

---------

Co-authored-by: Javier León <58715544+JavierLeon9966@users.noreply.github.com>
2023-08-16 13:00:23 +01:00
b65b7a7f74 Bump tests/plugins/DevTools from 83f0db3 to 411fd5b (#5998)
Bumps [tests/plugins/DevTools](https://github.com/pmmp/DevTools) from `83f0db3` to `411fd5b`.
- [Release notes](https://github.com/pmmp/DevTools/releases)
- [Commits](83f0db3f9e...411fd5bdc0)

---
updated-dependencies:
- dependency-name: tests/plugins/DevTools
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-16 09:38:16 +01:00
f516c3c502 EnchantCommand: ensure that books are turned into enchanted book items 2023-08-15 19:10:48 +01:00
5afbb9d807 Allow enchanted books to be enchanted
if an enchanted book is obtained via /give without enchantments, it should be able to receive enchantments in an enchanting table, exactly the same as regular books.
2023-08-15 19:10:03 +01:00
b330cbe8e2 Merge remote-tracking branch 'origin/stable' into minor-next 2023-08-15 17:41:41 +01:00
39867b97c5 Implement enchanting using enchanting tables (#5953)
Co-authored-by: Dylan K. Taylor <dktapps@pmmp.io>
2023-08-15 17:28:26 +01:00
4c25d38b44 Bump phpunit/phpunit from 10.3.1 to 10.3.2 (#5995)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.3.1 to 10.3.2.
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.3.2/ChangeLog-10.3.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/10.3.1...10.3.2)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-15 12:05:23 +01:00
983aa79a0b Bump build/php from ed0bc4d to a053f65 (#5993)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `ed0bc4d` to `a053f65`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](ed0bc4d2af...a053f65e18)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-15 09:30:51 +01:00
af9ae445fc Fix cake drops (#5985)
closes #5984
2023-08-10 17:42:32 +01:00
91d5a3ddfe PotionCauldron: fixed setPotionItem() not validating the given item
we should probably remove this API and have enums for potion container and type tbh... this API was a mistake
2023-08-10 16:06:41 +01:00
e48b5b2ec0 GeneratorManager: allow aliasing existing generators 2023-08-10 13:07:03 +01:00
f03e708f64 Fix chorus not working if the destination would be below y=0 (#5979) 2023-08-10 09:42:58 +01:00
37f2dafae1 PluginBase: make saveResource() use copy() instead of overengineered streams garbage 2023-08-09 16:16:11 +01:00
7826e0a11e Merge branch 'stable' into minor-next 2023-08-09 16:14:05 +01:00
97700636c6 PluginBase: added getResourceFolder() and getResourcePath(), deprecate getResource() (#5961)
This is a step towards #5958.

While it's not actually necessary to add these functions (since people could just use getFile() . "/resources/whatever.yml" instead), this helps preserve the convention of using the `resources` folder, which might be helpful for external tools.

As an example:
stream_get_contents($this->getResource("lang/eng.ini"));
(which is actually incorrect, since it leaks a resource)
can now be replaced by
file_get_contents($this->getResourcePath("lang/eng.ini"));
quite trivially.

getResourceFolder() can be used with scandir() to enumerate resources instead of using getResources(), although getResources() still provides utility in the relativized resource paths.
2023-08-09 16:09:16 +01:00
447f061566 Use Event::hasHandlers() for a few more hot events 2023-08-09 15:46:20 +01:00
b86b389fc5 changelog: fix link
[ci skip]
this is not technically wrong, but it's inconsistent with other changelogs
2023-08-09 15:33:02 +01:00
e27121a437 5.4.3 is next 2023-08-09 14:04:57 +01:00
2d5c9e64ce Release 5.4.2 2023-08-09 14:04:57 +01:00
78f5fbddf3 Merge branch 'legacy/pm4' into stable 2023-08-09 13:58:14 +01:00
aa3f4f2545 4.23.6 is next 2023-08-09 13:56:19 +01:00
f7279b6672 Release 4.23.5 2023-08-09 13:56:19 +01:00
2711ab4f00 Update composer dependencies 2023-08-09 13:49:19 +01:00
b4c5f5d58d PluginBase: fixed resource leak
all this time we've been harping at plugin devs to fix their own leaks, and here's one right under our noses that no one spotted for 10 years ...

this leak is rather common, since it will occur whenever a plugin attempts to save a resource which already exists in the data folder.

This bug was introduced in 2014 by commit 6328834681.
2023-08-09 13:28:05 +01:00
a5d8ef7a6c Add FarmlandHydrationChangeEvent (#5916) 2023-08-09 12:33:25 +01:00
59c88fe7f7 Added WorldDifficultyChangeEvent 2023-08-09 12:22:03 +01:00
735d9a5bf4 CandleTrait: allow candle to be lit by fire charges 2023-08-09 12:04:02 +01:00
f4a06605b1 Cake: only accept candle when no slices have been taken
otherwise, cake slices can be regenerated using candle
2023-08-09 11:42:08 +01:00
77dfbc4e23 Implemented pink petals (#5940) 2023-08-09 11:33:33 +01:00
662f2495e9 5.4.2 is next 2023-08-08 18:41:09 +01:00
b8a4ca45e4 Release 5.4.1 2023-08-08 18:41:06 +01:00
ebcd6a0bb2 CraftItemEvent: fixed inputs and outputs not being cloned 2023-08-08 18:29:49 +01:00
baefbce863 Merge branch 'stable' into minor-next 2023-08-08 18:27:50 +01:00
b45b4b5edf Update translations 2023-08-08 18:27:07 +01:00
9f14901820 Merge branch 'stable' into minor-next 2023-08-08 17:48:12 +01:00
dd79d4c463 Updated build/php submodule to pmmp/PHP-Binaries@ed0bc4d2af 2023-08-08 17:44:13 +01:00
9c1ab943bc Bump ext-pmmpthread min version to 6.0.7 2023-08-08 17:43:31 +01:00
2c74124e2e Update composer dependencies 2023-08-08 17:43:01 +01:00
514fc1ebb5 Bump phpunit/phpunit from 10.2.7 to 10.3.1 (#5965)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.2.7 to 10.3.1.
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.3.1/ChangeLog-10.3.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/10.2.7...10.3.1)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-08 17:33:16 +01:00
c1638ffaab Ban foreach by-reference at the PHPStan level 2023-08-08 17:08:13 +01:00
710177ceb5 CS
this mistake actually hasn't happened for a while
2023-08-08 15:10:31 +01:00
2559d1719f All pocketmine\thread\Thread now log uncaught exceptions and fatal errors by default 2023-08-08 14:56:54 +01:00
2e58387a43 Fixed thread error capture fail in shutdown function
the shutdown handler currently isn't called until join(), which sets isKilled to true and stops the error information from being recorded.
2023-08-08 14:55:53 +01:00
515f8eae4c ÂResourcePackManager: allow setting force_resources from a plugin 2023-08-07 17:05:45 +01:00
35a28300f6 Podzol should be affected by silk touch (#5969) 2023-08-07 11:47:29 +01:00
1cf508abdb World: use Facing::OFFSET in getHighestAdjacentLight() 2023-08-03 16:51:09 +01:00
6ac45526f9 Use new features in pocketmine/math 1.0.0 2023-08-03 16:46:16 +01:00
c91c8c2f9e Improving performance of small moving entities (e.g. dropped items) (#5954)
* World: cache block AABBs directly in the world
this removes some indirection when fetching the AABBs, and also allows the AABB cache to live longer than the block cache.

In local testing this showed a 10-20% performance improvement, but it was difficult to properly measure.

* World: eliminate padding block checks in getCollisionBoxes()
this substantially improves the function's performance for small entities.

The padding of 1 block in each direction was previously necessary to account for blocks like fences, which might have an AABB larger than the cell containing them. However, by tracking this information in the collisionBoxCache directly, we can avoid the need to check this at the expense of slightly more complex code. This reduces the number of blocks checked for a moving item entity from 27-64 all the way down to 1-8, which is a major improvement.

Locally, this change allowed me to simulate 2100 item entities without lag, compared with 1500 on the previous commit.
2023-08-03 14:51:51 +01:00
81941ae9e5 Bump phpunit/phpunit from 10.2.6 to 10.2.7 (#5957)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 10.2.6 to 10.2.7.
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.2.7/ChangeLog-10.2.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/10.2.6...10.2.7)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 18:05:30 +01:00
1a2c10e844 World: Fixed getSafeSpawn() not accepting seed positions below y=1 (#5955)
this should have been changed during the introduction of y=-64 minimum world height, but it got missed.
2023-08-02 18:05:16 +01:00
d88c3d8ced Fixed coral block killing itself when calling getDropsForCompatibleTool()
this might be called by plugins without actually breaking the block, in which case the block will glitch.
2023-08-02 13:43:36 +01:00
82f87cc2da Reduce repeated block-change-event related code
the new helper code reveals even more repetition, but this is at least consistent now.
2023-08-02 13:40:12 +01:00
bb0e648276 Fixed BlockDeathEvent usages showing an oldState which is already dead 2023-08-02 13:36:54 +01:00
6000bcccdd Merge pull request #5707 from pmmp/hot-events-optimisation
Avoid unnecessary event-related work in hot paths when the events have no registered handlers
2023-08-01 18:19:10 +01:00
0b86fafafb Hot path optimisation for DataPacketSendEvent 2023-08-01 17:41:53 +01:00
2608637210 HandlerListManager: track RegisteredListenerCache directly
This change improves the performance of calling an event with 0 handlers by about 10% with no other changes.

Since we have to access the list eventually anyway, we can cut out some unnecessary work by returning the handlers from the cache directly, instead of fetching the HandlerList for no reason.

This also improves the performance of Event::hasHandlers() by about 40%, which is pretty significant (120 ns -> 80 ns).
2023-08-01 17:37:49 +01:00
442d65143d Merge branch 'minor-next' into hot-events-optimisation 2023-08-01 17:01:52 +01:00
53de55dcde 5.4.1 is next 2023-08-01 12:46:56 +01:00
0629d11e13 Avoid unnecessary events work in handleDataPacket if the events have no registered handlers
this particular optimisation became possible thanks to changes in 4.19.

I observed that the allocation of Event objects and calling ->call() was costing us a significant percentage of the time taken in PlayerAuthInputPacket handlers. This change produces a measurable 2 microsecond reduction in overhead for PlayerAuthInputPacket handling when players are not moving (10.7 -> 8.7 microseconds). On a server with 200 players, this translates into a 1% reduction in CPU load for PlayerAuthInputPacket alone. It will also benefit other packets, but not to the extent that PlayerAuthInputPacket benefits.
2023-04-16 20:51:55 +01:00
181 changed files with 4948 additions and 1295 deletions

View File

@ -12,23 +12,23 @@ jobs:
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Clone pmmp/PocketMine-Docker repository
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: pmmp/PocketMine-Docker
fetch-depth: 1
@ -53,7 +53,7 @@ jobs:
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
- name: Build image for tag
uses: docker/build-push-action@v4.1.1
uses: docker/build-push-action@v5.0.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@v4.1.1
uses: docker/build-push-action@v5.0.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@v4.1.1
uses: docker/build-push-action@v5.0.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@v4.1.1
uses: docker/build-push-action@v5.0.0
with:
push: true
context: ./pocketmine-mp

View File

@ -18,7 +18,12 @@ require dirname(__DIR__, 2) . '/vendor/autoload.php';
/**
* @phpstan-return array<string, mixed>
*/
function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl, int $newsPingRoleId) : array{
function generateDiscordEmbed(string $version, string $channel, string $description, string $detailsUrl, string $sourceUrl, string $pharDownloadUrl, string $buildLogUrl, int $newsPingRoleId, ?string $phpDownloadUrl) : array{
if($phpDownloadUrl !== null){
$phpEmbedLink = " | [PHP Binaries]($phpDownloadUrl)";
}else{
$phpEmbedLink = "";
}
return [
"content" => "<@&$newsPingRoleId> New PocketMine-MP release: $version ($channel)",
"embeds" => [
@ -27,7 +32,7 @@ function generateDiscordEmbed(string $version, string $channel, string $descript
"description" => <<<DESCRIPTION
$description
[Details]($detailsUrl) | [Source Code]($sourceUrl) | [Build Log]($buildLogUrl) | [Download]($pharDownloadUrl)
[Details]($detailsUrl) | [Source Code]($sourceUrl) | [Build Log]($buildLogUrl) | [Download]($pharDownloadUrl)$phpEmbedLink
DESCRIPTION,
"url" => $detailsUrl,
"color" => $channel === "stable" ? 0x57ab5a : 0xc69026
@ -84,10 +89,21 @@ $detailsUrl = $buildInfoJson["details_url"];
$sourceUrl = $buildInfoJson["source_url"];
$pharDownloadUrl = $buildInfoJson["download_url"];
$buildLogUrl = $buildInfoJson["build_log_url"];
$phpBinaryUrl = $buildInfoJson["php_download_url"] ?? null;
$description = $releaseInfoJson["body"];
$discordPayload = generateDiscordEmbed($buildInfoJson["base_version"], $buildInfoJson["channel"], $description, $detailsUrl, $sourceUrl, $pharDownloadUrl, $buildLogUrl, (int) $newsPingRoleId);
$discordPayload = generateDiscordEmbed(
$buildInfoJson["base_version"],
$buildInfoJson["channel"],
$description,
$detailsUrl,
$sourceUrl,
$pharDownloadUrl,
$buildLogUrl,
(int) $newsPingRoleId,
$phpBinaryUrl
);
$response = Internet::postURL(
$hookURL,

View File

@ -10,10 +10,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.25.5
uses: shivammathur/setup-php@2.26.0
with:
php-version: 8.1

View File

@ -11,16 +11,18 @@ jobs:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
php-version: [8.1]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: true
- name: Setup PHP
uses: shivammathur/setup-php@2.25.5
uses: shivammathur/setup-php@2.26.0
with:
php-version: 8.1
php-version: ${{ matrix.php-version }}
- name: Restore Composer package cache
uses: actions/cache@v3
@ -58,8 +60,21 @@ jobs:
echo CHANGELOG_SUFFIX=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;') >> $GITHUB_OUTPUT
echo PRERELEASE=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "false" : "true";') >> $GITHUB_OUTPUT
- name: Generate PHP binary download URL
id: php-binary-url
run: |
echo PHP_BINARY_URL="${{ github.server_url }}/${{ github.repository_owner }}/PHP-Binaries/releases/tag/php-${{ matrix.php-version }}-latest" >> $GITHUB_OUTPUT
- name: Generate build info
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} ${{ github.run_id }} > build_info.json
run: |
php build/generate-build-info-json.php \
${{ github.sha }} \
${{ steps.get-pm-version.outputs.PM_VERSION }} \
${{ github.repository }} \
${{ steps.build-number.outputs.BUILD_NUMBER }} \
${{ github.run_id }} \
${{ steps.php-binary-url.outputs.PHP_BINARY_URL }} \
> build_info.json
- name: Upload release artifacts
uses: actions/upload-artifact@v3
@ -71,7 +86,7 @@ jobs:
${{ github.workspace }}/build_info.json
- name: Create draft release
uses: ncipollo/release-action@v1.12.0
uses: ncipollo/release-action@v1.13.0
with:
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json
commit: ${{ github.sha }}
@ -84,3 +99,5 @@ jobs:
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}${{ steps.get-pm-version.outputs.CHANGELOG_SUFFIX }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
:information_source: Download the recommended PHP binary [here](${{ steps.php-binary-url.outputs.PHP_BINARY_URL }}).

View File

@ -17,7 +17,7 @@ jobs:
php: ["8.1", "8.2"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP
uses: pmmp/setup-php-action@2.0.0
@ -52,7 +52,7 @@ jobs:
php: ["8.1", "8.2"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP
uses: pmmp/setup-php-action@2.0.0
@ -87,7 +87,7 @@ jobs:
php: ["8.1", "8.2"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: true
@ -124,7 +124,7 @@ jobs:
php: ["8.1", "8.2"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP
uses: pmmp/setup-php-action@2.0.0
@ -158,6 +158,9 @@ jobs:
- name: Regenerate BedrockData available files constants
run: php build/generate-bedrockdata-path-consts.php
- name: Regenerate YmlServerProperties constants
run: php build/generate-pocketmine-yml-property-consts.php
- name: Verify code is unchanged
run: |
git diff
@ -170,10 +173,10 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.25.5
uses: shivammathur/setup-php@2.26.0
with:
php-version: 8.1
tools: php-cs-fixer:3.17

View File

@ -14,7 +14,7 @@ jobs:
- name: Install jq
run: sudo apt update && sudo apt install jq -y
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
repository: ${{ github.repository_owner }}/update.pmmp.io
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}

View File

@ -88,45 +88,58 @@ Depending on the changes, maintainers might ask you to make changes to the PR to
### Requirements
The following are required as a minimum for pull requests. PRs that don't meet these requirements will be declined unless updated to meet them.
#### Licensing
PocketMine-MP is licensed under [LGPLv3 license](LICENSE).
By proposing a pull request, you agree to your code being distributed within PocketMine-MP under the same license.
If you take code from other projects, that code MUST be licensed under an LGPL-compatible license.
#### PRs should be about exactly ONE thing
If you want to make multiple changes, those changes should each be contributed as separate pull requests. **DO NOT** mix unrelated changes.
#### PRs must not include unnecessary/unrelated changes
Do not include changes which aren't strictly necessary. This makes it harder to review a PR, because the code diff becomes larger and harder to review.
This means:
- don't reformat or rearrange existing code
- don't change things that aren't related to the PR's objective
- don't rewrite existing code just to make it "look nicer"
- don't change PhpDocs to native types in code you didn't write
#### Tests must be provided
Where possible, PHPUnit tests should be written for new or changed code.
If that's not possible (e.g. for in-game functionality), the code must be tested manually and details of the tests done must be provided.
**Simply saying "Tested" is not acceptable** and will lead to your PR being declined.
#### Comments and documentation must be written in American English
English is the shared languages of all current maintainers.
#### Code must be in the PocketMine-MP style
It's your responsibility to ensure your code matches the formatting and styling of the rest of the code.
If you use PhpStorm, a `Project` code style is provided, which you can use to automatically format new code.
You can also use [`php-cs-fixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to format your code.
- **All code must be licensed under the [LGPLv3 license](LICENSE)** as per PocketMine-MP's own license, or a compatible license.
- By proposing a pull request, you agree to your code being distributed within PocketMine-MP under the same license.
- If you take code from other projects, that code MUST be licensed under an LGPL-compatible license.
- **PRs should be about ONE thing**
- If you want to make multiple changes, those changes should each be contributed as separate pull requests. **DO NOT** mix unrelated changes.
- **Do not include unnecessary changes.** This makes the code diff larger and more noisy, making it harder to review.
- Don't change things that aren't related to the PR's objective
- Don't reformat or rearrange existing code without a good reason related to the PR's objective
- Don't rewrite existing code just to make it "look nicer"
- Don't change PhpDocs to native types in code you didn't write, unless that's the objective of the PR
- **Test code changes, and tell us what tests have been done.**
- Where possible, PHPUnit tests should be written for new or changed code. If that's not possible (e.g. for in-game functionality), the code must be tested manually and details of the tests done must be provided.
- **Simply saying "Tested" is not acceptable** and could lead to your PR being declined.
- **Code, comments and documentation must be written in American English.** English is the shared languages of all current maintainers.
- **Code must be in the PocketMine-MP style.**
- It's your responsibility to ensure your code matches the formatting and styling of the rest of the code.
- If you use PhpStorm, a `Project` code style is provided, which you can use to automatically format new code.
- You can also use [`php-cs-fixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to format your code.
- **Use `final` and `private` wherever possible**.
- Changing from `private` to `protected` or `final` to non-`final` doesn't break backwards compatibility, but the opposite does.
- `private` and `final` also enable certain performance optimizations which are otherwise not possible.
- `private` members can be freely changed, added and removed in the future, so it's ideal for internal functions. Abusing `protected` makes internal improvements inconvenient.
- "Let's leave it protected/public in case someone needs it for ... idk what" is **not a valid reason to expose things**. If there isn't a clear reason for something to be accessible from the outside, don't expose it.
- **This is a lesson learned through years of experience.** You may not like it, but it's for the best.
- **Immutable things are almost always preferred.**
- Do not add unnecessary setters or public writable properties to classes. As above, "Let's leave it in case someone needs it" is **not a valid reason to expose things**.
- Mutable classes and properties are unpredictable, since code has no way to know if the object it's working with might be randomly modified by another part of the code. This makes it harder to maintain code and debug issues.
- Most classes exist only to hold some data. These are called "data transfer objects" (DTOs). These types of classes should pretty much always be immutable.
- Make use of `final`, `private` and `readonly` modifiers.
### Recommendations
- **Be patient.** Reviewing pull requests takes a lot of time and energy, and maintainers are often unavailable or busy. Your PR might not receive attention for a while.
- Remember, PRs with small diffs are much easier to review. Small PRs are generally reviewed and merged much faster than large ones.
- **Start small.** Try fixing minor bugs or doing something isolated (e.g. adding a new block or item) before attempting larger changes.
- This helps you get familiar with the codebase, the contribution process, and the expectations of maintainers.
- Check out the [issues page]() for something that you could tackle without too much effort.
- **Do not copy-paste other people's code**. Many PRs involve discussion about the changes, and changes are often requested by reviewers. If you don't understand the code you're copy-pasting, your PR is likely to fail.
- **Do not edit code directly on github.com.** We recommend learning how to use [`git`](https://git-scm.com). `git` allows you to "clone" a repository onto your computer, so that you can make changes using an IDE.
- **Use an IDE, not a text editor.** We recommend PhpStorm or VSCode.
- **Do not make large pull requests without an RFC.**
- Large changes should be discussed beforehand using the [RFC / Change Proposal](#rfcs--change-proposals) process.
- Large changes are much harder to review, and are more likely to be declined if maintainers don't have a good idea what you're trying to do in advance.
- **Create a new branch on your fork for each pull request.** This allows you to use the same fork to make multiple pull requests at the same time.
- **Make your PR diff as small as possible.** Smaller PRs are **much more likely** to be accepted, as they are easier to review.
- Avoid moving code around in files if possible.
- Don't make random CS changes. This makes the diff noisier and harder to review.
- **Use descriptive commit titles.** You can see an example [here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
- **Do not include multiple unrelated changes in one commit.** An atomic style for commits is preferred - this means that changes included in a commit should be part of a single distinct change set. See [this link](https://www.freshconsulting.com/atomic-commits/) for more information on atomic commits. See the [documentation on `git add`](https://git-scm.com/docs/git-add) for information on how to isolate local changes for committing.
- **Your pull request will be checked and discussed in due time.** Since the team is scattered all around the world, your PR may not receive any attention for some time.
- **Do not make large pull requests without an RFC.** Large changes should be discussed beforehand using the [RFC / Change Proposal](#rfcs--change-proposals) process. Large changes are much harder to review and are more likely to be declined if maintainers don't have a good idea what you're trying to do in advance.
- **Do not copy-paste code**. There are potential license issues implicit with copy-pasting, and copy-paste usually indicates a lack of understanding of the actual code. Copy-pasted code is obvious a mile off and **any PR like this is likely to be closed**. If you want to use somebody else's code from a Git repository, **use [GIT's cherry-pick feature](https://git-scm.com/docs/git-cherry-pick)** to cherry-pick the commit.
- **Split unrelated changes into multiple commits.**
- An atomic style for commits is preferred - this means that changes included in a commit should be part of a single distinct change set.
- If you need to use "and" or "multiple changes" in your commit message, the commit probably needs to be split up. There are exceptions, but this is a good rule of thumb.
- See [this link](https://www.freshconsulting.com/atomic-commits/) for more information on atomic commits.
- See the [documentation on `git add -i` or `git add -p`](https://git-scm.com/docs/git-add) for information on how to split up local changes for committing.
**Thanks for contributing to PocketMine-MP!**

View File

@ -23,13 +23,13 @@ declare(strict_types=1);
require dirname(__DIR__) . '/vendor/autoload.php';
if(count($argv) !== 6){
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number> <github actions run ID>\n");
if(count($argv) !== 7){
fwrite(STDERR, "required args: <git hash> <tag name> <github repo (owner/name)> <build number> <github actions run ID> <PHP binary download URL>\n");
exit(1);
}
echo json_encode([
"php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION),
"php_version" => sprintf("%d.%d", PHP_MAJOR_VERSION, PHP_MINOR_VERSION), //deprecated
"base_version" => \pocketmine\VersionInfo::BASE_VERSION,
"build" => (int) $argv[4],
"is_dev" => \pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD,
@ -41,4 +41,5 @@ echo json_encode([
"download_url" => "https://github.com/$argv[3]/releases/download/$argv[2]/PocketMine-MP.phar",
"source_url" => "https://github.com/$argv[3]/tree/$argv[2]",
"build_log_url" => "https://github.com/$argv[3]/actions/runs/$argv[5]",
"php_download_url" => $argv[6],
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n";

View File

@ -0,0 +1,120 @@
<?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);
use pocketmine\utils\Filesystem;
use pocketmine\utils\Utils;
require dirname(__DIR__) . '/vendor/autoload.php';
$defaultConfig = yaml_parse(Filesystem::fileGetContents(dirname(__DIR__) . '/resources/pocketmine.yml'));
if(!is_array($defaultConfig)){
fwrite(STDERR, "Invalid default pocketmine.yml\n");
exit(1);
}
$constants = [];
/**
* @param mixed[] $properties
* @param string[] $constants
* @phpstan-param array<string, string> $constants
* @phpstan-param-out array<string, string> $constants
*/
function collectProperties(string $prefix, array $properties, array &$constants) : void{
foreach($properties as $propertyName => $property){
$fullPropertyName = ($prefix !== "" ? $prefix . "." : "") . $propertyName;
$constName = str_replace([".", "-"], "_", strtoupper($fullPropertyName));
$constants[$constName] = $fullPropertyName;
if(is_array($property)){
collectProperties($fullPropertyName, $property, $constants);
}
}
}
collectProperties("", $defaultConfig, $constants);
ksort($constants, SORT_STRING);
$file = fopen(dirname(__DIR__) . '/src/YmlServerProperties.php', 'wb');
if($file === false){
fwrite(STDERR, "Failed to open output file\n");
exit(1);
}
fwrite($file, "<?php\n");
fwrite($file, <<<'HEADER'
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* 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/
*
*
*/
HEADER
);
fwrite($file, "declare(strict_types=1);\n\n");
fwrite($file, "namespace pocketmine;\n\n");
fwrite($file, <<<'DOC'
/**
* @internal
* Constants for all properties available in pocketmine.yml.
* This is generated by build/generate-pocketmine-yml-property-consts.php.
* Do not edit this file manually.
*/
DOC
);
fwrite($file, "final class YmlServerProperties{\n");
fwrite($file, <<<'CONSTRUCTOR'
private function __construct(){
//NOOP
}
CONSTRUCTOR
);
foreach(Utils::stringifyKeys($constants) as $constName => $propertyName){
fwrite($file, "\tpublic const $constName = '$propertyName';\n");
}
fwrite($file, "}\n");
fclose($file);
echo "Done. Don't forget to run CS fixup after generating code.\n";

View File

@ -49,3 +49,20 @@ Released 1st August 2023.
## Fixes
- Fixed exponentially increasing lag when many hundreds of non-mergeable dropped items occupied the same space. This disproportionately affected SkyBlock servers due to large cactus farms using water to collect items together.
# 4.23.5
Released 9th August 2023.
## General
- Updated translation data to [pmmp/Language 2.19.6](https://github.com/pmmp/Language/releases/tag/2.19.6).
## Fixes
- Fixed `PluginBase->saveResource()` leaking file resources when the data file already exists in the plugin's data folder. This bug existed since 2014 and was only discovered recently.
- Fixed coral blocks becoming dead after calling `getDropsForCompatibleTool()` on them.
- Fixed `BlockDeathEvent->getOldState()` returning a block which is already dead.
# 4.23.6
Released 21st August 2023.
## Fixes
- Added a workaround for armor and other inventories not working correctly after inventory sync. This is caused by a client bug.

17
changelogs/4.24.md Normal file
View File

@ -0,0 +1,17 @@
# 4.24.0
Released 20th September 2023.
**For Minecraft: Bedrock Edition 1.20.30**
This is a support release for Minecraft: Bedrock Edition 1.20.30.
**Plugin compatibility:** Plugins for previous 4.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.20.30.
- Removed support for older versions.
- Updated 4.x obsoletion message.

16
changelogs/4.25.md Normal file
View File

@ -0,0 +1,16 @@
# 4.25.0
Released 26th October 2023.
**For Minecraft: Bedrock Edition 1.20.40**
This is a support release for Minecraft: Bedrock Edition 1.20.40.
**Plugin compatibility:** Plugins for previous 4.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.20.40.
- Removed support for older versions.

View File

@ -81,3 +81,53 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
- In addition, this change facilitates the use of the newly introduced `Block->getAdjacentSupportType()` API method, reducing boilerplate support-type checking code.
- Bell block code has been simplified and cleaned up.
- `TallGrass` and `DoubleTallGrass` now use a shared `TallGrassTrait` to reduce code duplication.
# 5.4.1
Released 8th August 2023.
## General
- Updated translation data to [pmmp/Language 2.19.6](https://github.com/pmmp/Language/releases/tag/2.19.6).
- [`ext-pmmpthread` 6.0.7](https://github.com/pmmp/ext-pmmpthread/releases/tag/6.0.7) is now required (needed for bug fixes).
## Fixes
- Fixed Podzol not dropping itself when mined with Silk Touch.
- Fixed `World->getSafeSpawn()` not accepting positions below `y=0` (world height limit change).
- Fixed `pocketmine\thread\Thread` and `pocketmine\thread\Worker` instances not logging any information when they crash.
- Fixed `CraftItemEvent` not cloning returned items.
## Internals
- Foreach by-reference is now disallowed via a custom PHPStan rule.
# 5.4.2
Released 9th August 2023.
## Included releases
- [4.23.5](https://github.com/pmmp/PocketMine-MP/blob/4.23.5/changelogs/4.23.md#4235) - Minor bug fixes
## Fixes
- Fixed cake accepting candle placement when slices have already been eaten.
- Fixed fire charges not lighting candles.
# 5.4.3
Released 21st August 2023.
## Included releases
- [4.23.6](https://github.com/pmmp/PocketMine-MP/blob/4.23.6/changelogs/4.23.md#4236) - Armor inventory client bug workaround
## Fixes
- Fixed crashdumps not generating correctly on fatal errors.
- Fixed `PotionCauldron::setPotionItem()` not validating the item type.
- Fixed chorus fruit not considering teleport destinations below y=0.
- Fixed cake dropping itself when mined.
# 5.4.4
Released 6th September 2023.
## General
- Crashdumps caused by non-phar plugins are now submitted to the Crash Archive, the same as other plugins. Previously, non-phar plugin crashes would not be submitted, causing maintainers to potentially miss important issues.
## Fixes
- Fixed player Y coordinates sometimes being slightly below the top of the block they were standing on (floating point error due to subtracting eye height).
- Fixed template slot of smithing tables not accepting any items.
- `tools/generate-bedrock-data-from-packets.php` is now significantly less spammy when warning about duplicated recipes.
- Fixed empty stack traces in `lastError` data of crashdumps.

156
changelogs/5.5-beta.md Normal file
View File

@ -0,0 +1,156 @@
# 5.5.0-BETA1
Released 23rd August 2023.
**For Minecraft: Bedrock Edition 1.20.10**
This is a minor feature release, including performance improvements, new API methods, and new gameplay features.
**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.
## Dependencies
- Updated `pocketmine/math` dependency to [`1.0.0`](https://github.com/pmmp/Math/releases/tag/1.0.0).
- Updated `pocketmine/nbt` dependency to [`1.0.0`](https://github.com/pmmp/NBT/releases/tag/1.0.0).
## Performance
- Some events are now no longer fired if no handlers are registered.
- This improves performance by avoiding unnecessary object allocations and function calls.
- Events such as `DataPacketReceiveEvent`, `DataPacketSendEvent` and `PlayerMoveEvent` are optimized away almost completely by this change, offering some much-needed performance gains.
- Significantly improved performance of small moving entities, such as dropped items.
- This was achieved by a combination of changes, which together improved observed performance with 2000 item entities moving in water by 30-40%.
- The benefit of this will be most noticeable in SkyBlock servers, where large cactus farms can generate thousands of dropped items.
- `World->getCollisionBoxes()` now uses an improved search method, which reduces the work done by the function by almost 90% for small entities.
- This improves performance of collision detection for small entities, such as dropped items.
## Gameplay
### General
- Implemented enchanting using an enchanting table (yes, finally!)
- Thanks to [@S3v3Nice](https://github.com/S3v3Nice) for investing lots of time and effort into developing this.
- Since this feature is quite complex, it's possible there may be bugs. Please be vigilant and report any issues you find.
### Blocks
- The following new blocks have been implemented:
- Pink Petals
- Pressure plates are now functional, in the sense that they react when entities stand on them and perform the correct logic.
- Note that since redstone is not yet implemented, pressure plates do not activate any redstone devices, similar to buttons and levers.
- Signs can now be edited by right-clicking them.
- Signs can now be waxed using a honeycomb, which prevents them from being edited.
### Items
- The following new items have been implemented:
- Enchanted Book
## API
### `pocketmine\block`
- The following new API methods have been added:
- `public Block->getEnchantmentTags() : list<string>` returns a list of strings indicating which types of enchantment can be applied to the block when in item form
- `public BlockTypeInfo->getEnchantmentTags() : list<string>`
- `protected PressurePlate->getActivationBox() : AxisAlignedBB` - returns the AABB entities must intersect with in order to activate the pressure plate (not the same as the visual shape)
- `protected PressurePlate->hasOutputSignal() : bool` - returns whether the pressure plate has an output signal - this should be implemented by subclasses
- `protected PressurePlate->calculatePlateState() : array{Block, ?bool}` - returns the state the pressure plate will change to if the given list of entities are standing on it, and a bool indicating whether the plate activated or deactivated this tick
- `protected PressurePlate->filterIrrelevantEntities(list<Entity> $entities) : list<Entity>` - returns the given list filtered of entities that don't affect the plate's state (e.g. dropped items don't affect stone pressure plates)
- `public BaseSign->isWaxed() : bool`
- `public BaseSign->setWaxed(bool $waxed) : $this`
- `public inventory\EnchantInventory->getInput() : Item`
- `public inventory\EnchantInventory->getLapis() : Item`
- `public inventory\EnchantInventory->getOutput(int $optionId) : ?Item` - returns the item that would be produced if the input item was enchanted with the selected option, or `null` if the option is invalid
- `public inventory\EnchantInventory->getOption(int $optionId) : EnchantOption` - returns the enchanting option at the given index
- The following API methods have signature changes:
- `BlockTypeInfo->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
- `PressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
- `WeightedPressurePlate->__construct()` now accepts optional `int $deactivationDelayTicks` and `float $signalStrengthFactor` parameters
- `SimplePressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
- The following new classes have been added:
- `PinkPetals`
- `utils\BlockEventHelper` - provides helper methods for calling block-related events
- The following classes have been deprecated:
- `WeightedPressurePlateLight`
- `WeightedPressurePlateHeavy`
### `pocketmine\entity`
- The following new API methods have been added:
- `public Human->getEnchantmentSeed() : int` - returns the current seed used to randomize options shown on the enchanting table for this human
- `public Human->setEnchantmentSeed(int $seed) : void`
- `public Human->regenerateEnchantmentSeed() : void` - returns a new randomly generated seed which can be set with `setEnchantmentSeed()`
### `pocketmine\event`
- The following new classes have been added:
- `block\FarmlandHydrationChangeEvent` - called when farmland is hydrated or dehydrated
- `block\PressurePlateUpdateEvent` - called when a pressure plate is activated or changes its power output
- `player\PlayerEnchantingOptionsRequestEvent` - called when a player puts an item to be enchanted into an enchanting table, to allow plugins to modify the enchanting options shown
- `player\PlayerItemEnchantEvent` - called when a player enchants an item in an enchanting table
- `world\WorldDifficultyChangeEvent` - called when a world's difficulty is changed
- The following new API methods have been added:
- `public static Event::hasHandlers() : bool` - returns whether the event class has any registered handlers - used like `SomeEvent::hasHandlers()`
- `public HandlerListManager->getHandlersFor(class-string<? extends Event> $event) : list<RegisteredListener>` - returns a list of all registered listeners for the given event class, using cache if available
### `pocketmine\inventory\transaction`
- The following new classes have been added:
- `EnchantingTransaction` - used when a player enchants an item in an enchanting table
### `pocketmine\item`
- The following new API methods have been added:
- `public Armor->getMaterial() : ArmorMaterial` - returns an object containing properties shared by all items of the same armor material
- `public ArmorTypeInfo->getMaterial() : ArmorMaterial`
- `public Item->getEnchantability() : int` - returns the enchantability value of the item - higher values increase the chance of more powerful enchantments being offered by an enchanting table
- `public Item->getEnchantmentTags() : list<string>` - returns a list of strings indicating which types of enchantment can be applied to the item
- `public ToolTier->getEnchantability() : int`
- The following API methods have signature changes:
- `Item->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
- `ArmorTypeInfo->__construct()` now accepts an optional `?ArmorMaterial $material` parameter
- The following new classes have been added:
- `ArmorMaterial` - container for shared armor properties
- `VanillaArmorMaterials` - all vanilla armor materials
- `EnchantedBook` - represents an enchanted book item
### `pocketmine\item\enchantment`
- The following new classes have been added:
- `AvailableEnchantmentRegistry` - enchantments to be displayed on the enchanting table are selected from here - custom enchantments may be added
- `EnchantingHelper` - static class containing various helper methods for enchanting tables
- `EnchantingOption` - represents an option on the enchanting table menu
- `IncompatibleEnchantmentGroups` - list of constants naming groups of enchantments that are incompatible with each other - custom enchantments may be added using these group names to make them incompatible with existing enchantments in the same group
- `IncompatibleEnchantmentRegistry` - manages which enchantments are considered incompatible with each other - custom enchantments may be added using existing group names to make them incompatible with existing enchantments in the same group, or to entirely new groups
- `ItemEnchantmentTagRegistry` - manages item enchantment compatibility tags and which tags include which other tags
- `ItemEnchantmentTags` - list of constants naming item types for enchantment compatibility checks
- The following classes have been deprecated
- `ItemFlags`
- The following API methods have been added:
- `public Enchantment->isCompatibleWith(Enchantment $other) : bool`
- `public Enchantment->getMinEnchantingPower()` - returns the minimum enchanting power (derived from enchantability and number of bookshelves) needed to allow this enchantment to show on the enchanting table with a given level
- `public Enchantment->getMaxEnchantingPower()` - upper limit of enchanting power for this enchantment to be offered on the enchanting table with a given level
- The following API methods have signature changes:
- `Enchantment->__construct()` now accepts optional `(\Closure(int $level) : int)|null $minEnchantingPower` and `int $enchantingPowerRange` parameters
- `Enchantment->__construct()` parameters `$primaryItemFlags` and `$secondaryItemFlags` are now deprecated and no longer used
- `ProtectionEnchantment->__construct()` has extra parameters to reflect `Enchantment->__construct()` changes
- The following API methods have been deprecated:
- `Enchantment->getPrimaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
- `Enchantment->getSecondaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
- `Enchantment->hasPrimaryItemType()`
- `Enchantment->hasSecondaryItemType()`
### `pocketmine\plugin`
- The following new API methods have been added:
- `public PluginBase->getResourcePath(string $filename) : string` - returns a URI to an embedded resource file that can be used with `file_get_contents()` and similar functions
- `public PluginBase->getResourceFolder() : string` - returns a URI to the plugin's folder of embedded resources
- The following API methods have been deprecated:
- `PluginBase->getResource()` - prefer using `getResourcePath()` with `file_get_contents()` or other PHP built-in functions instead
### `pocketmine\resourcepacks`
- The following new API methods have been added:
- `public ResourcePackManager->setResourcePacksRequired(bool $value) : void` - sets whether players must accept resource packs in order to join
### `pocketmine\world\generator`
- The following new API methods have been added:
- `public GeneratorManager->addAlias(string $name, string $alias) : void` - allows registering a generator alias without copying the generator registration parameters
### `pocketmine\world\sound`
- The following new classes have been added:
- `PressurePlateActivateSound`
- `PressurePlateDeactivateSound`
### `pocketmine\utils`
- The following new API methods have been added:
- `public StringToTParser->registerAlias(string $existing, string $alias) : void` - allows registering a string alias without copying registration parameters

162
changelogs/5.5.md Normal file
View File

@ -0,0 +1,162 @@
# 5.5.0
Released 6th September 2023.
**For Minecraft: Bedrock Edition 1.20.10**
This is a minor feature release, including performance improvements, new API methods, and new gameplay features.
**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.
## Dependencies
- Updated `pocketmine/math` dependency to [`1.0.0`](https://github.com/pmmp/Math/releases/tag/1.0.0).
- Updated `pocketmine/nbt` dependency to [`1.0.0`](https://github.com/pmmp/NBT/releases/tag/1.0.0).
## Performance
- Some events are now no longer fired if no handlers are registered.
- This improves performance by avoiding unnecessary object allocations and function calls.
- Events such as `DataPacketReceiveEvent`, `DataPacketSendEvent` and `PlayerMoveEvent` are optimized away almost completely by this change, offering some much-needed performance gains.
- Significantly improved performance of small moving entities, such as dropped items.
- This was achieved by a combination of changes, which together improved observed performance with 2000 item entities moving in water by 30-40%.
- The benefit of this will be most noticeable in SkyBlock servers, where large cactus farms can generate thousands of dropped items.
- `World->getCollisionBoxes()` now uses an improved search method, which reduces the work done by the function by almost 90% for small entities.
- This improves performance of collision detection for small entities, such as dropped items.
## Gameplay
### General
- Implemented enchanting using an enchanting table (yes, finally!)
- Thanks to [@S3v3Nice](https://github.com/S3v3Nice) for investing lots of time and effort into developing this.
- Since this feature is quite complex, it's possible there may be bugs. Please be vigilant and report any issues you find.
### Blocks
- The following new blocks have been implemented:
- Pink Petals
- Pressure plates are now functional, in the sense that they react when entities stand on them and perform the correct logic.
- Note that since redstone is not yet implemented, pressure plates do not activate any redstone devices, similar to buttons and levers.
- Signs can now be edited by right-clicking them.
- Signs can now be waxed using a honeycomb, which prevents them from being edited.
### Items
- The following new items have been implemented:
- Enchanted Book
## API
### `pocketmine\block`
- The following new API methods have been added:
- `public Block->getEnchantmentTags() : list<string>` returns a list of strings indicating which types of enchantment can be applied to the block when in item form
- `public BlockTypeInfo->getEnchantmentTags() : list<string>`
- `protected PressurePlate->getActivationBox() : AxisAlignedBB` - returns the AABB entities must intersect with in order to activate the pressure plate (not the same as the visual shape)
- `protected PressurePlate->hasOutputSignal() : bool` - returns whether the pressure plate has an output signal - this should be implemented by subclasses
- `protected PressurePlate->calculatePlateState() : array{Block, ?bool}` - returns the state the pressure plate will change to if the given list of entities are standing on it, and a bool indicating whether the plate activated or deactivated this tick
- `protected PressurePlate->filterIrrelevantEntities(list<Entity> $entities) : list<Entity>` - returns the given list filtered of entities that don't affect the plate's state (e.g. dropped items don't affect stone pressure plates)
- `public BaseSign->isWaxed() : bool`
- `public BaseSign->setWaxed(bool $waxed) : $this`
- `public inventory\EnchantInventory->getInput() : Item`
- `public inventory\EnchantInventory->getLapis() : Item`
- `public inventory\EnchantInventory->getOutput(int $optionId) : ?Item` - returns the item that would be produced if the input item was enchanted with the selected option, or `null` if the option is invalid
- `public inventory\EnchantInventory->getOption(int $optionId) : EnchantOption` - returns the enchanting option at the given index
- The following API methods have signature changes:
- `BlockTypeInfo->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
- `PressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
- `WeightedPressurePlate->__construct()` now accepts optional `int $deactivationDelayTicks` and `float $signalStrengthFactor` parameters
- `SimplePressurePlate->__construct()` now accepts an optional `int $deactivationDelayTicks` parameter
- The following new classes have been added:
- `PinkPetals`
- `utils\BlockEventHelper` - provides helper methods for calling block-related events
- The following classes have been deprecated:
- `WeightedPressurePlateLight`
- `WeightedPressurePlateHeavy`
### `pocketmine\entity`
- The following new API methods have been added:
- `public Human->getEnchantmentSeed() : int` - returns the current seed used to randomize options shown on the enchanting table for this human
- `public Human->setEnchantmentSeed(int $seed) : void`
- `public Human->regenerateEnchantmentSeed() : void` - returns a new randomly generated seed which can be set with `setEnchantmentSeed()`
### `pocketmine\event`
- The following new classes have been added:
- `block\FarmlandHydrationChangeEvent` - called when farmland is hydrated or dehydrated
- `block\PressurePlateUpdateEvent` - called when a pressure plate is activated or changes its power output
- `player\PlayerEnchantingOptionsRequestEvent` - called when a player puts an item to be enchanted into an enchanting table, to allow plugins to modify the enchanting options shown
- `player\PlayerItemEnchantEvent` - called when a player enchants an item in an enchanting table
- `world\WorldDifficultyChangeEvent` - called when a world's difficulty is changed
- The following new API methods have been added:
- `public static Event::hasHandlers() : bool` - returns whether the event class has any registered handlers - used like `SomeEvent::hasHandlers()`
- `public HandlerListManager->getHandlersFor(class-string<? extends Event> $event) : list<RegisteredListener>` - returns a list of all registered listeners for the given event class, using cache if available
### `pocketmine\inventory\transaction`
- The following new classes have been added:
- `EnchantingTransaction` - used when a player enchants an item in an enchanting table
### `pocketmine\item`
- The following new API methods have been added:
- `public Armor->getMaterial() : ArmorMaterial` - returns an object containing properties shared by all items of the same armor material
- `public ArmorTypeInfo->getMaterial() : ArmorMaterial`
- `public Item->getEnchantability() : int` - returns the enchantability value of the item - higher values increase the chance of more powerful enchantments being offered by an enchanting table
- `public Item->getEnchantmentTags() : list<string>` - returns a list of strings indicating which types of enchantment can be applied to the item
- `public ToolTier->getEnchantability() : int`
- The following API methods have signature changes:
- `Item->__construct()` now accepts an optional `list<string> $enchantmentTags` parameter
- `ArmorTypeInfo->__construct()` now accepts an optional `?ArmorMaterial $material` parameter
- The following new classes have been added:
- `ArmorMaterial` - container for shared armor properties
- `VanillaArmorMaterials` - all vanilla armor materials
- `EnchantedBook` - represents an enchanted book item
### `pocketmine\item\enchantment`
- The following new classes have been added:
- `AvailableEnchantmentRegistry` - enchantments to be displayed on the enchanting table are selected from here - custom enchantments may be added
- `EnchantingHelper` - static class containing various helper methods for enchanting tables
- `EnchantingOption` - represents an option on the enchanting table menu
- `IncompatibleEnchantmentGroups` - list of constants naming groups of enchantments that are incompatible with each other - custom enchantments may be added using these group names to make them incompatible with existing enchantments in the same group
- `IncompatibleEnchantmentRegistry` - manages which enchantments are considered incompatible with each other - custom enchantments may be added using existing group names to make them incompatible with existing enchantments in the same group, or to entirely new groups
- `ItemEnchantmentTagRegistry` - manages item enchantment compatibility tags and which tags include which other tags
- `ItemEnchantmentTags` - list of constants naming item types for enchantment compatibility checks
- The following classes have been deprecated
- `ItemFlags`
- The following API methods have been added:
- `public Enchantment->isCompatibleWith(Enchantment $other) : bool`
- `public Enchantment->getMinEnchantingPower()` - returns the minimum enchanting power (derived from enchantability and number of bookshelves) needed to allow this enchantment to show on the enchanting table with a given level
- `public Enchantment->getMaxEnchantingPower()` - upper limit of enchanting power for this enchantment to be offered on the enchanting table with a given level
- The following API methods have signature changes:
- `Enchantment->__construct()` now accepts optional `(\Closure(int $level) : int)|null $minEnchantingPower` and `int $enchantingPowerRange` parameters
- `Enchantment->__construct()` parameters `$primaryItemFlags` and `$secondaryItemFlags` are now deprecated and no longer used
- `ProtectionEnchantment->__construct()` has extra parameters to reflect `Enchantment->__construct()` changes
- The following API methods have been deprecated:
- `Enchantment->getPrimaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
- `Enchantment->getSecondaryItemFlags()` - use API methods provided by `AvailableEnchantmentRegistry` instead
- `Enchantment->hasPrimaryItemType()`
- `Enchantment->hasSecondaryItemType()`
### `pocketmine\plugin`
- The following new API methods have been added:
- `public PluginBase->getResourcePath(string $filename) : string` - returns a URI to an embedded resource file that can be used with `file_get_contents()` and similar functions
- `public PluginBase->getResourceFolder() : string` - returns a URI to the plugin's folder of embedded resources
- The following API methods have been deprecated:
- `PluginBase->getResource()` - prefer using `getResourcePath()` with `file_get_contents()` or other PHP built-in functions instead
### `pocketmine\resourcepacks`
- The following new API methods have been added:
- `public ResourcePackManager->setResourcePacksRequired(bool $value) : void` - sets whether players must accept resource packs in order to join
### `pocketmine\world\generator`
- The following new API methods have been added:
- `public GeneratorManager->addAlias(string $name, string $alias) : void` - allows registering a generator alias without copying the generator registration parameters
### `pocketmine\world\sound`
- The following new classes have been added:
- `PressurePlateActivateSound`
- `PressurePlateDeactivateSound`
### `pocketmine\utils`
- The following new API methods have been added:
- `public StringToTParser->registerAlias(string $existing, string $alias) : void` - allows registering a string alias without copying registration parameters
## Internals
- Various `TypeIdMap` classes in the `pocketmine\data\bedrock` package now use the new `IntSaveIdMapTrait` to reduce code duplication.
- Added a new `ServerProperties` class containing constants for all known `server.properties` keys.
- Added a new `YmlServerProperties` class containing generated constants for all known `pocketmine.yml` keys. These keys can be used with `Config->getNested()`.

34
changelogs/5.6.md Normal file
View File

@ -0,0 +1,34 @@
# 5.6.0
Released 20th September 2023.
**For Minecraft: Bedrock Edition 1.20.30**
This is a support release for Minecraft: Bedrock Edition 1.20.30.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.20.30.
- Removed support for older versions.
## Fixes
- Fixed support conditions for hanging roots, cave vines and dead bushes.
- Fixed connection conditions for fences, glass panes, iron bars, and walls.
# 5.6.1
Released 20th October 2023.
## Performance
- Improved performance of cactus growth by disabling neighbour updates when only the age property was updated. While this isn't a perfect solution, it provides significant performance gains for servers with large cactus farms.
## Fixes
- Fixed `tools/generate-bedrock-data-from-packets.php` incorrectly interpreting network meta as blockstates in some cases (broken crafting recipes).
- Fixed crafting recipes involving beds, skulls and some other items not working correctly (incorrectly interpreted data).
- Fixed crashes when flower pot or cauldron blockentities exist in places where they shouldn't (leftovers from upgraded PM3 worlds).
- Fixed `Entity->broadcastSound()` not firing `WorldSoundEvent` (bypassing internal sound system).
- Fixed wooden signs, buttons and doors not being able to be used as furnace fuel.
- Fixed bone meal and tools only working when used on the top side of dirt and grass. Bone meal now works from any side, and tools work on any side except the bottom.

20
changelogs/5.7.md Normal file
View File

@ -0,0 +1,20 @@
# 5.7.0
Released 26th October 2023.
**For Minecraft: Bedrock Edition 1.20.40**
This is a support release for Minecraft: Bedrock Edition 1.20.40.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.20.40.
- Removed support for older versions.
## Fixes
- Fixed `cartography_table`, `smithing_table`, `stripped_cherry_log` and `stripped_cherry_wood` not working in `StringToItemParser`.
- Fixed `Promise<null>::onCompletion()` always calling the reject handler if the promise was already completed.

View File

@ -22,7 +22,7 @@
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pmmpthread": "^6.0.4",
"ext-pmmpthread": "^6.0.7",
"ext-reflection": "*",
"ext-simplexml": "*",
"ext-sockets": "*",
@ -33,18 +33,18 @@
"composer-runtime-api": "^2.0",
"adhocore/json-comment": "~1.2.0",
"pocketmine/netresearch-jsonmapper": "~v4.2.1000",
"pocketmine/bedrock-block-upgrade-schema": "~3.1.0+bedrock-1.20.10",
"pocketmine/bedrock-data": "~2.4.0+bedrock-1.20.10",
"pocketmine/bedrock-item-upgrade-schema": "~1.4.0+bedrock-1.20.10",
"pocketmine/bedrock-protocol": "~23.0.2+bedrock-1.20.10",
"pocketmine/bedrock-block-upgrade-schema": "~3.3.0+bedrock-1.20.40",
"pocketmine/bedrock-data": "~2.6.0+bedrock-1.20.40",
"pocketmine/bedrock-item-upgrade-schema": "~1.5.0+bedrock-1.20.30",
"pocketmine/bedrock-protocol": "~25.0.0+bedrock-1.20.40",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.6.0",
"pocketmine/locale-data": "~2.19.0",
"pocketmine/log": "^0.4.0",
"pocketmine/math": "^0.4.0",
"pocketmine/nbt": "^0.3.2",
"pocketmine/math": "~1.0.0",
"pocketmine/nbt": "~1.0.0",
"pocketmine/raklib": "^0.15.0",
"pocketmine/raklib-ipc": "^0.2.0",
"pocketmine/snooze": "^0.5.0",
@ -52,10 +52,10 @@
"symfony/filesystem": "~6.3.0"
},
"require-dev": {
"phpstan/phpstan": "1.10.16",
"phpstan/phpstan": "1.10.39",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "^10.1"
"phpunit/phpunit": "~10.3.0 || ~10.2.0 || ~10.1.0"
},
"autoload": {
"psr-4": {

281
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "ccd20e7656bc05ec2acd8e28aad9fcf2",
"content-hash": "feefde772166966ee8065e613fe9a56e",
"packages": [
{
"name": "adhocore/json-comment",
@ -122,16 +122,16 @@
},
{
"name": "pocketmine/bedrock-block-upgrade-schema",
"version": "3.1.0",
"version": "3.3.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
"reference": "6d4ae416043337946a22fc31e8065ca2c21f472d"
"reference": "ee46b9367af262bbddd9f122d4d5b5b495b892e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/6d4ae416043337946a22fc31e8065ca2c21f472d",
"reference": "6d4ae416043337946a22fc31e8065ca2c21f472d",
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/ee46b9367af262bbddd9f122d4d5b5b495b892e7",
"reference": "ee46b9367af262bbddd9f122d4d5b5b495b892e7",
"shasum": ""
},
"type": "library",
@ -142,22 +142,22 @@
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
"support": {
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/3.1.0"
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/3.3.0"
},
"time": "2023-07-12T12:05:36+00:00"
"time": "2023-10-16T16:11:02+00:00"
},
{
"name": "pocketmine/bedrock-data",
"version": "2.4.0+bedrock-1.20.10",
"version": "2.6.0+bedrock-1.20.40",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
"reference": "f98bd1cae46d2920058acf3b23c0bedeac79f4ab"
"reference": "37e780d28b470230bda3579b04cb50d406e3fbe6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/f98bd1cae46d2920058acf3b23c0bedeac79f4ab",
"reference": "f98bd1cae46d2920058acf3b23c0bedeac79f4ab",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/37e780d28b470230bda3579b04cb50d406e3fbe6",
"reference": "37e780d28b470230bda3579b04cb50d406e3fbe6",
"shasum": ""
},
"type": "library",
@ -168,22 +168,22 @@
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/BedrockData/issues",
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.10"
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.40"
},
"time": "2023-07-12T11:51:54+00:00"
"time": "2023-10-26T10:39:13+00:00"
},
{
"name": "pocketmine/bedrock-item-upgrade-schema",
"version": "1.4.0",
"version": "1.5.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
"reference": "60d199afe5e371fd189b21d685ec1fed6ba54230"
"reference": "3edc9ebbad9a4f2d9c8f53b3a5ba44d4a792ad93"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/60d199afe5e371fd189b21d685ec1fed6ba54230",
"reference": "60d199afe5e371fd189b21d685ec1fed6ba54230",
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/3edc9ebbad9a4f2d9c8f53b3a5ba44d4a792ad93",
"reference": "3edc9ebbad9a4f2d9c8f53b3a5ba44d4a792ad93",
"shasum": ""
},
"type": "library",
@ -194,36 +194,36 @@
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
"support": {
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.4.0"
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.5.0"
},
"time": "2023-07-12T12:08:37+00:00"
"time": "2023-09-01T19:58:57+00:00"
},
{
"name": "pocketmine/bedrock-protocol",
"version": "23.0.2+bedrock-1.20.10",
"version": "25.0.0+bedrock-1.20.40",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "69a309a2dd7dcf3ec8c316385b866397e8c2cbfd"
"reference": "69c36c96f6835e93fc278071aa2bb9829abe5cf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/69a309a2dd7dcf3ec8c316385b866397e8c2cbfd",
"reference": "69a309a2dd7dcf3ec8c316385b866397e8c2cbfd",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/69c36c96f6835e93fc278071aa2bb9829abe5cf8",
"reference": "69c36c96f6835e93fc278071aa2bb9829abe5cf8",
"shasum": ""
},
"require": {
"ext-json": "*",
"netresearch/jsonmapper": "^4.0",
"php": "^8.0",
"php": "^8.1",
"pocketmine/binaryutils": "^0.2.0",
"pocketmine/color": "^0.2.0 || ^0.3.0",
"pocketmine/math": "^0.3.0 || ^0.4.0",
"pocketmine/nbt": "^0.3.0",
"pocketmine/math": "^0.3.0 || ^0.4.0 || ^1.0.0",
"pocketmine/nbt": "^1.0.0",
"ramsey/uuid": "^4.1"
},
"require-dev": {
"phpstan/phpstan": "1.10.7",
"phpstan/phpstan": "1.10.33",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.0.0",
"phpunit/phpunit": "^9.5"
@ -241,9 +241,9 @@
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
"support": {
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
"source": "https://github.com/pmmp/BedrockProtocol/tree/23.0.2+bedrock-1.20.10"
"source": "https://github.com/pmmp/BedrockProtocol/tree/25.0.0+bedrock-1.20.40"
},
"time": "2023-07-24T15:35:36+00:00"
"time": "2023-10-26T11:03:10+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -416,16 +416,16 @@
},
{
"name": "pocketmine/locale-data",
"version": "2.19.5",
"version": "2.19.6",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Language.git",
"reference": "71af5f9bd23b4e4bad8920dac7f4fe08e5205f7d"
"reference": "93e473e20e7f4515ecf45c5ef0f9155b9247a86e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Language/zipball/71af5f9bd23b4e4bad8920dac7f4fe08e5205f7d",
"reference": "71af5f9bd23b4e4bad8920dac7f4fe08e5205f7d",
"url": "https://api.github.com/repos/pmmp/Language/zipball/93e473e20e7f4515ecf45c5ef0f9155b9247a86e",
"reference": "93e473e20e7f4515ecf45c5ef0f9155b9247a86e",
"shasum": ""
},
"type": "library",
@ -433,9 +433,9 @@
"description": "Language resources used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Language/issues",
"source": "https://github.com/pmmp/Language/tree/2.19.5"
"source": "https://github.com/pmmp/Language/tree/2.19.6"
},
"time": "2023-03-19T16:45:15+00:00"
"time": "2023-08-08T16:53:23+00:00"
},
{
"name": "pocketmine/log",
@ -480,16 +480,16 @@
},
{
"name": "pocketmine/math",
"version": "0.4.3",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Math.git",
"reference": "47a243d320b01c8099d65309967934c188111549"
"reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Math/zipball/47a243d320b01c8099d65309967934c188111549",
"reference": "47a243d320b01c8099d65309967934c188111549",
"url": "https://api.github.com/repos/pmmp/Math/zipball/dc132d93595b32e9f210d78b3c8d43c662a5edbf",
"reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf",
"shasum": ""
},
"require": {
@ -498,7 +498,7 @@
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "1.8.2",
"phpstan/phpstan": "~1.10.3",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^8.5 || ^9.5"
},
@ -515,22 +515,22 @@
"description": "PHP library containing math related code used in PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Math/issues",
"source": "https://github.com/pmmp/Math/tree/0.4.3"
"source": "https://github.com/pmmp/Math/tree/1.0.0"
},
"time": "2022-08-25T18:43:37+00:00"
"time": "2023-08-03T12:56:33+00:00"
},
{
"name": "pocketmine/nbt",
"version": "0.3.4",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/NBT.git",
"reference": "62c02464c6708b2467c1e1a2af01af09d5114eda"
"reference": "20540271cb59e04672cb163dca73366f207974f1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/62c02464c6708b2467c1e1a2af01af09d5114eda",
"reference": "62c02464c6708b2467c1e1a2af01af09d5114eda",
"url": "https://api.github.com/repos/pmmp/NBT/zipball/20540271cb59e04672cb163dca73366f207974f1",
"reference": "20540271cb59e04672cb163dca73366f207974f1",
"shasum": ""
},
"require": {
@ -540,7 +540,7 @@
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "1.10.3",
"phpstan/phpstan": "1.10.25",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5"
},
@ -557,9 +557,9 @@
"description": "PHP library for working with Named Binary Tags",
"support": {
"issues": "https://github.com/pmmp/NBT/issues",
"source": "https://github.com/pmmp/NBT/tree/0.3.4"
"source": "https://github.com/pmmp/NBT/tree/1.0.0"
},
"time": "2023-04-10T11:31:20+00:00"
"time": "2023-07-14T13:01:49+00:00"
},
{
"name": "pocketmine/netresearch-jsonmapper",
@ -985,16 +985,16 @@
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb",
"shasum": ""
},
"require": {
@ -1009,7 +1009,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1047,7 +1047,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0"
},
"funding": [
{
@ -1063,20 +1063,20 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-01-26T09:26:14+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"version": "v1.28.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
@ -1091,7 +1091,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.27-dev"
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
@ -1130,7 +1130,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
@ -1146,7 +1146,7 @@
"type": "tidelift"
}
],
"time": "2022-11-03T14:55:06+00:00"
"time": "2023-07-28T09:04:16+00:00"
}
],
"packages-dev": [
@ -1211,16 +1211,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.16.0",
"version": "v4.17.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "19526a33fb561ef417e822e85f08a00db4059c17"
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17",
"reference": "19526a33fb561ef417e822e85f08a00db4059c17",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"shasum": ""
},
"require": {
@ -1261,9 +1261,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
},
"time": "2023-06-25T14:52:30+00:00"
"time": "2023-08-13T19:53:39+00:00"
},
{
"name": "phar-io/manifest",
@ -1378,16 +1378,16 @@
},
{
"name": "phpstan/phpstan",
"version": "1.10.16",
"version": "1.10.39",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "352bdbb960bb523e3d71b834862589f910921c23"
"reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/352bdbb960bb523e3d71b834862589f910921c23",
"reference": "352bdbb960bb523e3d71b834862589f910921c23",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/d9dedb0413f678b4d03cbc2279a48f91592c97c4",
"reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4",
"shasum": ""
},
"require": {
@ -1436,20 +1436,20 @@
"type": "tidelift"
}
],
"time": "2023-06-05T08:21:46+00:00"
"time": "2023-10-17T15:46:26+00:00"
},
{
"name": "phpstan/phpstan-phpunit",
"version": "1.3.13",
"version": "1.3.15",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-phpunit.git",
"reference": "d8bdab0218c5eb0964338d24a8511b65e9c94fa5"
"reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d8bdab0218c5eb0964338d24a8511b65e9c94fa5",
"reference": "d8bdab0218c5eb0964338d24a8511b65e9c94fa5",
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/70ecacc64fe8090d8d2a33db5a51fe8e88acd93a",
"reference": "70ecacc64fe8090d8d2a33db5a51fe8e88acd93a",
"shasum": ""
},
"require": {
@ -1462,7 +1462,7 @@
"require-dev": {
"nikic/php-parser": "^4.13.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/phpstan-strict-rules": "^1.0",
"phpstan/phpstan-strict-rules": "^1.5.1",
"phpunit/phpunit": "^9.5"
},
"type": "phpstan-extension",
@ -1486,9 +1486,9 @@
"description": "PHPUnit extensions and rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.13"
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.15"
},
"time": "2023-05-26T11:05:59+00:00"
"time": "2023-10-09T18:58:39+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
@ -1541,16 +1541,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "10.1.2",
"version": "10.1.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "db1497ec8dd382e82c962f7abbe0320e4882ee4e"
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/db1497ec8dd382e82c962f7abbe0320e4882ee4e",
"reference": "db1497ec8dd382e82c962f7abbe0320e4882ee4e",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/355324ca4980b8916c18b9db29f3ef484078f26e",
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e",
"shasum": ""
},
"require": {
@ -1607,7 +1607,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.2"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.7"
},
"funding": [
{
@ -1615,20 +1615,20 @@
"type": "github"
}
],
"time": "2023-05-22T09:04:27+00:00"
"time": "2023-10-04T15:34:17+00:00"
},
{
"name": "phpunit/php-file-iterator",
"version": "4.0.2",
"version": "4.1.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "5647d65443818959172645e7ed999217360654b6"
"reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/5647d65443818959172645e7ed999217360654b6",
"reference": "5647d65443818959172645e7ed999217360654b6",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
"reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
"shasum": ""
},
"require": {
@ -1668,7 +1668,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.0.2"
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
},
"funding": [
{
@ -1676,7 +1676,7 @@
"type": "github"
}
],
"time": "2023-05-07T09:13:23+00:00"
"time": "2023-08-31T06:24:48+00:00"
},
{
"name": "phpunit/php-invoker",
@ -1743,16 +1743,16 @@
},
{
"name": "phpunit/php-text-template",
"version": "3.0.0",
"version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
"reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d"
"reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/9f3d3709577a527025f55bcf0f7ab8052c8bb37d",
"reference": "9f3d3709577a527025f55bcf0f7ab8052c8bb37d",
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
"reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
"shasum": ""
},
"require": {
@ -1790,7 +1790,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.0"
"security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
},
"funding": [
{
@ -1798,7 +1799,7 @@
"type": "github"
}
],
"time": "2023-02-03T06:56:46+00:00"
"time": "2023-08-31T14:07:24+00:00"
},
{
"name": "phpunit/php-timer",
@ -1861,16 +1862,16 @@
},
{
"name": "phpunit/phpunit",
"version": "10.2.6",
"version": "10.3.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "1c17815c129f133f3019cc18e8d0c8622e6d9bcd"
"reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c17815c129f133f3019cc18e8d0c8622e6d9bcd",
"reference": "1c17815c129f133f3019cc18e8d0c8622e6d9bcd",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/747c3b2038f1139e3dcd9886a3f5a948648b7503",
"reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503",
"shasum": ""
},
"require": {
@ -1884,7 +1885,7 @@
"phar-io/manifest": "^2.0.3",
"phar-io/version": "^3.0.2",
"php": ">=8.1",
"phpunit/php-code-coverage": "^10.1.1",
"phpunit/php-code-coverage": "^10.1.5",
"phpunit/php-file-iterator": "^4.0",
"phpunit/php-invoker": "^4.0",
"phpunit/php-text-template": "^3.0",
@ -1894,8 +1895,8 @@
"sebastian/comparator": "^5.0",
"sebastian/diff": "^5.0",
"sebastian/environment": "^6.0",
"sebastian/exporter": "^5.0",
"sebastian/global-state": "^6.0",
"sebastian/exporter": "^5.1",
"sebastian/global-state": "^6.0.1",
"sebastian/object-enumerator": "^5.0",
"sebastian/recursion-context": "^5.0",
"sebastian/type": "^4.0",
@ -1910,7 +1911,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "10.2-dev"
"dev-main": "10.3-dev"
}
},
"autoload": {
@ -1942,7 +1943,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.2.6"
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.5"
},
"funding": [
{
@ -1958,7 +1959,7 @@
"type": "tidelift"
}
],
"time": "2023-07-17T12:08:28+00:00"
"time": "2023-09-19T05:42:37+00:00"
},
{
"name": "sebastian/cli-parser",
@ -2129,16 +2130,16 @@
},
{
"name": "sebastian/comparator",
"version": "5.0.0",
"version": "5.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "72f01e6586e0caf6af81297897bd112eb7e9627c"
"reference": "2db5010a484d53ebf536087a70b4a5423c102372"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/72f01e6586e0caf6af81297897bd112eb7e9627c",
"reference": "72f01e6586e0caf6af81297897bd112eb7e9627c",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372",
"reference": "2db5010a484d53ebf536087a70b4a5423c102372",
"shasum": ""
},
"require": {
@ -2149,7 +2150,7 @@
"sebastian/exporter": "^5.0"
},
"require-dev": {
"phpunit/phpunit": "^10.0"
"phpunit/phpunit": "^10.3"
},
"type": "library",
"extra": {
@ -2193,7 +2194,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/5.0.0"
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
"source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1"
},
"funding": [
{
@ -2201,20 +2203,20 @@
"type": "github"
}
],
"time": "2023-02-03T07:07:16+00:00"
"time": "2023-08-14T13:18:12+00:00"
},
{
"name": "sebastian/complexity",
"version": "3.0.0",
"version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/complexity.git",
"reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6"
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/e67d240970c9dc7ea7b2123a6d520e334dd61dc6",
"reference": "e67d240970c9dc7ea7b2123a6d520e334dd61dc6",
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957",
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957",
"shasum": ""
},
"require": {
@ -2227,7 +2229,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.0-dev"
"dev-main": "3.1-dev"
}
},
"autoload": {
@ -2250,7 +2252,8 @@
"homepage": "https://github.com/sebastianbergmann/complexity",
"support": {
"issues": "https://github.com/sebastianbergmann/complexity/issues",
"source": "https://github.com/sebastianbergmann/complexity/tree/3.0.0"
"security": "https://github.com/sebastianbergmann/complexity/security/policy",
"source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0"
},
"funding": [
{
@ -2258,7 +2261,7 @@
"type": "github"
}
],
"time": "2023-02-03T06:59:47+00:00"
"time": "2023-09-28T11:50:59+00:00"
},
{
"name": "sebastian/diff",
@ -2393,16 +2396,16 @@
},
{
"name": "sebastian/exporter",
"version": "5.0.0",
"version": "5.1.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0"
"reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0",
"reference": "f3ec4bf931c0b31e5b413f5b4fc970a7d03338c0",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/64f51654862e0f5e318db7e9dcc2292c63cdbddc",
"reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc",
"shasum": ""
},
"require": {
@ -2416,7 +2419,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "5.0-dev"
"dev-main": "5.1-dev"
}
},
"autoload": {
@ -2458,7 +2461,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/5.0.0"
"security": "https://github.com/sebastianbergmann/exporter/security/policy",
"source": "https://github.com/sebastianbergmann/exporter/tree/5.1.1"
},
"funding": [
{
@ -2466,7 +2470,7 @@
"type": "github"
}
],
"time": "2023-02-03T07:06:49+00:00"
"time": "2023-09-24T13:22:09+00:00"
},
{
"name": "sebastian/global-state",
@ -2532,16 +2536,16 @@
},
{
"name": "sebastian/lines-of-code",
"version": "2.0.0",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
"reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130"
"reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/17c4d940ecafb3d15d2cf916f4108f664e28b130",
"reference": "17c4d940ecafb3d15d2cf916f4108f664e28b130",
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/649e40d279e243d985aa8fb6e74dd5bb28dc185d",
"reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d",
"shasum": ""
},
"require": {
@ -2577,7 +2581,8 @@
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
"support": {
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.0"
"security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.1"
},
"funding": [
{
@ -2585,7 +2590,7 @@
"type": "github"
}
],
"time": "2023-02-03T07:08:02+00:00"
"time": "2023-08-31T09:25:50+00:00"
},
{
"name": "sebastian/object-enumerator",
@ -2945,7 +2950,7 @@
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pmmpthread": "^6.0.4",
"ext-pmmpthread": "^6.0.7",
"ext-reflection": "*",
"ext-simplexml": "*",
"ext-sockets": "*",
@ -2959,5 +2964,5 @@
"platform-overrides": {
"php": "8.1.0"
},
"plugin-api-version": "2.3.0"
"plugin-api-version": "2.6.0"
}

View File

@ -11,6 +11,7 @@ includes:
rules:
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
@ -43,7 +44,6 @@ parameters:
stubFiles:
- tests/phpstan/stubs/JsonMapper.stub
- tests/phpstan/stubs/leveldb.stub
- tests/phpstan/stubs/phpasn1.stub
- tests/phpstan/stubs/pmmpthread.stub
reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
staticReflectionClassNamePatterns:

View File

@ -30,6 +30,7 @@ use pocketmine\scheduler\GarbageCollectionTask;
use pocketmine\timings\Timings;
use pocketmine\utils\Process;
use pocketmine\utils\Utils;
use pocketmine\YmlServerProperties as Yml;
use Symfony\Component\Filesystem\Path;
use function arsort;
use function count;
@ -109,7 +110,7 @@ class MemoryManager{
}
private function init(ServerConfigGroup $config) : void{
$this->memoryLimit = $config->getPropertyInt("memory.main-limit", 0) * 1024 * 1024;
$this->memoryLimit = $config->getPropertyInt(Yml::MEMORY_MAIN_LIMIT, 0) * 1024 * 1024;
$defaultMemory = 1024;
@ -127,7 +128,7 @@ class MemoryManager{
}
}
$hardLimit = $config->getPropertyInt("memory.main-hard-limit", $defaultMemory);
$hardLimit = $config->getPropertyInt(Yml::MEMORY_MAIN_HARD_LIMIT, $defaultMemory);
if($hardLimit <= 0){
ini_set("memory_limit", '-1');
@ -135,22 +136,22 @@ class MemoryManager{
ini_set("memory_limit", $hardLimit . "M");
}
$this->globalMemoryLimit = $config->getPropertyInt("memory.global-limit", 0) * 1024 * 1024;
$this->checkRate = $config->getPropertyInt("memory.check-rate", self::DEFAULT_CHECK_RATE);
$this->continuousTrigger = $config->getPropertyBool("memory.continuous-trigger", true);
$this->continuousTriggerRate = $config->getPropertyInt("memory.continuous-trigger-rate", self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
$this->globalMemoryLimit = $config->getPropertyInt(Yml::MEMORY_GLOBAL_LIMIT, 0) * 1024 * 1024;
$this->checkRate = $config->getPropertyInt(Yml::MEMORY_CHECK_RATE, self::DEFAULT_CHECK_RATE);
$this->continuousTrigger = $config->getPropertyBool(Yml::MEMORY_CONTINUOUS_TRIGGER, true);
$this->continuousTriggerRate = $config->getPropertyInt(Yml::MEMORY_CONTINUOUS_TRIGGER_RATE, self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
$this->garbageCollectionPeriod = $config->getPropertyInt("memory.garbage-collection.period", self::DEFAULT_TICKS_PER_GC);
$this->garbageCollectionTrigger = $config->getPropertyBool("memory.garbage-collection.low-memory-trigger", true);
$this->garbageCollectionAsync = $config->getPropertyBool("memory.garbage-collection.collect-async-worker", true);
$this->garbageCollectionPeriod = $config->getPropertyInt(Yml::MEMORY_GARBAGE_COLLECTION_PERIOD, self::DEFAULT_TICKS_PER_GC);
$this->garbageCollectionTrigger = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER, true);
$this->garbageCollectionAsync = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER, true);
$this->lowMemChunkRadiusOverride = $config->getPropertyInt("memory.max-chunks.chunk-radius", 4);
$this->lowMemChunkGC = $config->getPropertyBool("memory.max-chunks.trigger-chunk-collect", true);
$this->lowMemChunkRadiusOverride = $config->getPropertyInt(Yml::MEMORY_MAX_CHUNKS_CHUNK_RADIUS, 4);
$this->lowMemChunkGC = $config->getPropertyBool(Yml::MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT, true);
$this->lowMemDisableChunkCache = $config->getPropertyBool("memory.world-caches.disable-chunk-cache", true);
$this->lowMemClearWorldCache = $config->getPropertyBool("memory.world-caches.low-memory-trigger", true);
$this->lowMemDisableChunkCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE, true);
$this->lowMemClearWorldCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER, true);
$this->dumpWorkers = $config->getPropertyBool("memory.memory-dump.dump-async-worker", true);
$this->dumpWorkers = $config->getPropertyBool(Yml::MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER, true);
gc_enable();
}
@ -359,7 +360,7 @@ class MemoryManager{
'_SESSION' => true
];
foreach(Utils::stringifyKeys($GLOBALS) as $varName => $value){
foreach($GLOBALS as $varName => $value){
if(isset($ignoredGlobals[$varName])){
continue;
}

View File

@ -120,8 +120,8 @@ namespace pocketmine {
}
if(($pmmpthread_version = phpversion("pmmpthread")) !== false){
if(version_compare($pmmpthread_version, "6.0.4") < 0 || version_compare($pmmpthread_version, "7.0.0") >= 0){
$messages[] = "pmmpthread ^6.0.4 is required, while you have $pmmpthread_version.";
if(version_compare($pmmpthread_version, "6.0.7") < 0 || version_compare($pmmpthread_version, "7.0.0") >= 0){
$messages[] = "pmmpthread ^6.0.7 is required, while you have $pmmpthread_version.";
}
}

View File

@ -80,7 +80,6 @@ use pocketmine\player\PlayerDataProvider;
use pocketmine\player\PlayerDataSaveException;
use pocketmine\player\PlayerInfo;
use pocketmine\plugin\PharPluginLoader;
use pocketmine\plugin\Plugin;
use pocketmine\plugin\PluginEnableOrder;
use pocketmine\plugin\PluginGraylist;
use pocketmine\plugin\PluginManager;
@ -120,6 +119,7 @@ use pocketmine\world\Position;
use pocketmine\world\World;
use pocketmine\world\WorldCreationOptions;
use pocketmine\world\WorldManager;
use pocketmine\YmlServerProperties as Yml;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Filesystem\Path;
use function array_fill;
@ -357,15 +357,15 @@ class Server{
}
public function getPort() : int{
return $this->configGroup->getConfigInt("server-port", self::DEFAULT_PORT_IPV4);
return $this->configGroup->getConfigInt(ServerProperties::SERVER_PORT_IPV4, self::DEFAULT_PORT_IPV4);
}
public function getPortV6() : int{
return $this->configGroup->getConfigInt("server-portv6", self::DEFAULT_PORT_IPV6);
return $this->configGroup->getConfigInt(ServerProperties::SERVER_PORT_IPV6, self::DEFAULT_PORT_IPV6);
}
public function getViewDistance() : int{
return max(2, $this->configGroup->getConfigInt("view-distance", self::DEFAULT_MAX_VIEW_DISTANCE));
return max(2, $this->configGroup->getConfigInt(ServerProperties::VIEW_DISTANCE, self::DEFAULT_MAX_VIEW_DISTANCE));
}
/**
@ -376,12 +376,12 @@ class Server{
}
public function getIp() : string{
$str = $this->configGroup->getConfigString("server-ip");
$str = $this->configGroup->getConfigString(ServerProperties::SERVER_IPV4);
return $str !== "" ? $str : "0.0.0.0";
}
public function getIpV6() : string{
$str = $this->configGroup->getConfigString("server-ipv6");
$str = $this->configGroup->getConfigString(ServerProperties::SERVER_IPV6);
return $str !== "" ? $str : "::";
}
@ -390,30 +390,30 @@ class Server{
}
public function getGamemode() : GameMode{
return GameMode::fromString($this->configGroup->getConfigString("gamemode", GameMode::SURVIVAL()->name())) ?? GameMode::SURVIVAL();
return GameMode::fromString($this->configGroup->getConfigString(ServerProperties::GAME_MODE, GameMode::SURVIVAL()->name())) ?? GameMode::SURVIVAL();
}
public function getForceGamemode() : bool{
return $this->configGroup->getConfigBool("force-gamemode", false);
return $this->configGroup->getConfigBool(ServerProperties::FORCE_GAME_MODE, false);
}
/**
* Returns Server global difficulty. Note that this may be overridden in individual worlds.
*/
public function getDifficulty() : int{
return $this->configGroup->getConfigInt("difficulty", World::DIFFICULTY_NORMAL);
return $this->configGroup->getConfigInt(ServerProperties::DIFFICULTY, World::DIFFICULTY_NORMAL);
}
public function hasWhitelist() : bool{
return $this->configGroup->getConfigBool("white-list", false);
return $this->configGroup->getConfigBool(ServerProperties::WHITELIST, false);
}
public function isHardcore() : bool{
return $this->configGroup->getConfigBool("hardcore", false);
return $this->configGroup->getConfigBool(ServerProperties::HARDCORE, false);
}
public function getMotd() : string{
return $this->configGroup->getConfigString("motd", self::DEFAULT_SERVER_NAME);
return $this->configGroup->getConfigString(ServerProperties::MOTD, self::DEFAULT_SERVER_NAME);
}
public function getLoader() : ThreadSafeClassLoader{
@ -496,7 +496,7 @@ class Server{
}
public function shouldSavePlayerData() : bool{
return $this->configGroup->getPropertyBool("player.save-player-data", true);
return $this->configGroup->getPropertyBool(Yml::PLAYER_SAVE_PLAYER_DATA, true);
}
public function getOfflinePlayer(string $name) : Player|OfflinePlayer|null{
@ -570,6 +570,7 @@ class Server{
$playerPromiseResolver = new PromiseResolver();
$createPlayer = function(Location $location) use ($playerPromiseResolver, $class, $session, $playerInfo, $authenticated, $offlinePlayerData) : void{
/** @see Player::__construct() */
$player = new $class($this, $session, $playerInfo, $authenticated, $location, $offlinePlayerData);
if(!$player->hasPlayedBefore()){
$player->onGround = true; //TODO: this hack is needed for new players in-air ticks - they don't get detected as on-ground until they move
@ -736,7 +737,7 @@ class Server{
* @return string[][]
*/
public function getCommandAliases() : array{
$section = $this->configGroup->getProperty("aliases");
$section = $this->configGroup->getProperty(YmlServerProperties::ALIASES);
$result = [];
if(is_array($section)){
foreach($section as $key => $value){
@ -811,36 +812,36 @@ class Server{
$this->configGroup = new ServerConfigGroup(
new Config($pocketmineYmlPath, Config::YAML, []),
new Config(Path::join($this->dataPath, "server.properties"), Config::PROPERTIES, [
"motd" => self::DEFAULT_SERVER_NAME,
"server-port" => self::DEFAULT_PORT_IPV4,
"server-portv6" => self::DEFAULT_PORT_IPV6,
"enable-ipv6" => true,
"white-list" => false,
"max-players" => self::DEFAULT_MAX_PLAYERS,
"gamemode" => GameMode::SURVIVAL()->name(),
"force-gamemode" => false,
"hardcore" => false,
"pvp" => true,
"difficulty" => World::DIFFICULTY_NORMAL,
"generator-settings" => "",
"level-name" => "world",
"level-seed" => "",
"level-type" => "DEFAULT",
"enable-query" => true,
"auto-save" => true,
"view-distance" => self::DEFAULT_MAX_VIEW_DISTANCE,
"xbox-auth" => true,
"language" => "eng"
ServerProperties::MOTD => self::DEFAULT_SERVER_NAME,
ServerProperties::SERVER_PORT_IPV4 => self::DEFAULT_PORT_IPV4,
ServerProperties::SERVER_PORT_IPV6 => self::DEFAULT_PORT_IPV6,
ServerProperties::ENABLE_IPV6 => true,
ServerProperties::WHITELIST => false,
ServerProperties::MAX_PLAYERS => self::DEFAULT_MAX_PLAYERS,
ServerProperties::GAME_MODE => GameMode::SURVIVAL()->name(),
ServerProperties::FORCE_GAME_MODE => false,
ServerProperties::HARDCORE => false,
ServerProperties::PVP => true,
ServerProperties::DIFFICULTY => World::DIFFICULTY_NORMAL,
ServerProperties::DEFAULT_WORLD_GENERATOR_SETTINGS => "",
ServerProperties::DEFAULT_WORLD_NAME => "world",
ServerProperties::DEFAULT_WORLD_SEED => "",
ServerProperties::DEFAULT_WORLD_GENERATOR => "DEFAULT",
ServerProperties::ENABLE_QUERY => true,
ServerProperties::AUTO_SAVE => true,
ServerProperties::VIEW_DISTANCE => self::DEFAULT_MAX_VIEW_DISTANCE,
ServerProperties::XBOX_AUTH => true,
ServerProperties::LANGUAGE => "eng"
])
);
$debugLogLevel = $this->configGroup->getPropertyInt("debug.level", 1);
$debugLogLevel = $this->configGroup->getPropertyInt(Yml::DEBUG_LEVEL, 1);
if($this->logger instanceof MainLogger){
$this->logger->setLogDebug($debugLogLevel > 1);
}
$this->forceLanguage = $this->configGroup->getPropertyBool("settings.force-language", false);
$selectedLang = $this->configGroup->getConfigString("language", $this->configGroup->getPropertyString("settings.language", Language::FALLBACK_LANGUAGE));
$this->forceLanguage = $this->configGroup->getPropertyBool(Yml::SETTINGS_FORCE_LANGUAGE, false);
$selectedLang = $this->configGroup->getConfigString(ServerProperties::LANGUAGE, $this->configGroup->getPropertyString("settings.language", Language::FALLBACK_LANGUAGE));
try{
$this->language = new Language($selectedLang);
}catch(LanguageNotFoundException $e){
@ -856,11 +857,11 @@ class Server{
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::language_selected($this->getLanguage()->getName(), $this->getLanguage()->getLang())));
if(VersionInfo::IS_DEVELOPMENT_BUILD){
if(!$this->configGroup->getPropertyBool("settings.enable-dev-builds", false)){
if(!$this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_DEV_BUILDS, false)){
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error1(VersionInfo::NAME)));
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error2()));
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error3()));
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4("settings.enable-dev-builds")));
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error4(YmlServerProperties::SETTINGS_ENABLE_DEV_BUILDS)));
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_devBuild_error5("https://github.com/pmmp/PocketMine-MP/releases")));
$this->forceShutdownExit();
@ -878,7 +879,7 @@ class Server{
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_start(TextFormat::AQUA . $this->getVersion() . TextFormat::RESET)));
if(($poolSize = $this->configGroup->getPropertyString("settings.async-workers", "auto")) === "auto"){
if(($poolSize = $this->configGroup->getPropertyString(Yml::SETTINGS_ASYNC_WORKERS, "auto")) === "auto"){
$poolSize = 2;
$processors = Utils::getCoreCount() - 2;
@ -889,32 +890,32 @@ class Server{
$poolSize = max(1, (int) $poolSize);
}
$this->asyncPool = new AsyncPool($poolSize, max(-1, $this->configGroup->getPropertyInt("memory.async-worker-hard-limit", 256)), $this->autoloader, $this->logger, $this->tickSleeper);
$this->asyncPool = new AsyncPool($poolSize, max(-1, $this->configGroup->getPropertyInt(Yml::MEMORY_ASYNC_WORKER_HARD_LIMIT, 256)), $this->autoloader, $this->logger, $this->tickSleeper);
$netCompressionThreshold = -1;
if($this->configGroup->getPropertyInt("network.batch-threshold", 256) >= 0){
$netCompressionThreshold = $this->configGroup->getPropertyInt("network.batch-threshold", 256);
if($this->configGroup->getPropertyInt(Yml::NETWORK_BATCH_THRESHOLD, 256) >= 0){
$netCompressionThreshold = $this->configGroup->getPropertyInt(Yml::NETWORK_BATCH_THRESHOLD, 256);
}
if($netCompressionThreshold < 0){
$netCompressionThreshold = null;
}
$netCompressionLevel = $this->configGroup->getPropertyInt("network.compression-level", 6);
$netCompressionLevel = $this->configGroup->getPropertyInt(Yml::NETWORK_COMPRESSION_LEVEL, 6);
if($netCompressionLevel < 1 || $netCompressionLevel > 9){
$this->logger->warning("Invalid network compression level $netCompressionLevel set, setting to default 6");
$netCompressionLevel = 6;
}
ZlibCompressor::setInstance(new ZlibCompressor($netCompressionLevel, $netCompressionThreshold, ZlibCompressor::DEFAULT_MAX_DECOMPRESSION_SIZE));
$this->networkCompressionAsync = $this->configGroup->getPropertyBool("network.async-compression", true);
$this->networkCompressionAsync = $this->configGroup->getPropertyBool(Yml::NETWORK_ASYNC_COMPRESSION, true);
$this->networkCompressionAsyncThreshold = max(
$this->configGroup->getPropertyInt("network.async-compression-threshold", self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD),
$this->configGroup->getPropertyInt(Yml::NETWORK_ASYNC_COMPRESSION_THRESHOLD, self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD),
$netCompressionThreshold ?? self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD
);
EncryptionContext::$ENABLED = $this->configGroup->getPropertyBool("network.enable-encryption", true);
EncryptionContext::$ENABLED = $this->configGroup->getPropertyBool(Yml::NETWORK_ENABLE_ENCRYPTION, true);
$this->doTitleTick = $this->configGroup->getPropertyBool("console.title-tick", true) && Terminal::hasFormattingCodes();
$this->doTitleTick = $this->configGroup->getPropertyBool(Yml::CONSOLE_TITLE_TICK, true) && Terminal::hasFormattingCodes();
$this->operators = new Config(Path::join($this->dataPath, "ops.txt"), Config::ENUM);
$this->whitelist = new Config(Path::join($this->dataPath, "white-list.txt"), Config::ENUM);
@ -932,9 +933,9 @@ class Server{
$this->banByIP = new BanList($bannedIpsTxt);
$this->banByIP->load();
$this->maxPlayers = $this->configGroup->getConfigInt("max-players", self::DEFAULT_MAX_PLAYERS);
$this->maxPlayers = $this->configGroup->getConfigInt(ServerProperties::MAX_PLAYERS, self::DEFAULT_MAX_PLAYERS);
$this->onlineMode = $this->configGroup->getConfigBool("xbox-auth", true);
$this->onlineMode = $this->configGroup->getConfigBool(ServerProperties::XBOX_AUTH, true);
if($this->onlineMode){
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_auth_enabled()));
}else{
@ -943,8 +944,8 @@ class Server{
$this->logger->warning($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
}
if($this->configGroup->getConfigBool("hardcore", false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
$this->configGroup->setConfigInt("difficulty", World::DIFFICULTY_HARD);
if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
$this->configGroup->setConfigInt(ServerProperties::DIFFICULTY, World::DIFFICULTY_HARD);
}
@cli_set_process_title($this->getName() . " " . $this->getPocketMineVersion());
@ -963,8 +964,8 @@ class Server{
)));
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
TimingsHandler::setEnabled($this->configGroup->getPropertyBool("settings.enable-profiling", false));
$this->profilingTickRate = $this->configGroup->getPropertyInt("settings.profile-report-trigger", self::TARGET_TICKS_PER_SECOND);
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
DefaultPermissions::registerCorePermissions();
@ -986,13 +987,13 @@ class Server{
$this->forceShutdownExit();
return;
}
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool("plugins.legacy-data-dir", true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->getDataPath(), "plugin_data"), $pluginGraylist);
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
$this->pluginManager->registerInterface(new ScriptPluginLoader());
$providerManager = new WorldProviderManager();
if(
($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString("level-settings.default-format", ""))) !== null &&
($format = $providerManager->getProviderByName($formatName = $this->configGroup->getPropertyString(Yml::LEVEL_SETTINGS_DEFAULT_FORMAT, ""))) !== null &&
$format instanceof WritableWorldProviderManagerEntry
){
$providerManager->setDefault($format);
@ -1001,10 +1002,10 @@ class Server{
}
$this->worldManager = new WorldManager($this, Path::join($this->dataPath, "worlds"), $providerManager);
$this->worldManager->setAutoSave($this->configGroup->getConfigBool("auto-save", $this->worldManager->getAutoSave()));
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt("ticks-per.autosave", $this->worldManager->getAutoSaveInterval()));
$this->worldManager->setAutoSave($this->configGroup->getConfigBool(ServerProperties::AUTO_SAVE, $this->worldManager->getAutoSave()));
$this->worldManager->setAutoSaveInterval($this->configGroup->getPropertyInt(Yml::TICKS_PER_AUTOSAVE, $this->worldManager->getAutoSaveInterval()));
$this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString("auto-updater.host", "update.pmmp.io"));
$this->updater = new UpdateChecker($this, $this->configGroup->getPropertyString(Yml::AUTO_UPDATER_HOST, "update.pmmp.io"));
$this->queryInfo = new QueryInfo($this);
@ -1041,7 +1042,7 @@ class Server{
return;
}
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
if($this->configGroup->getPropertyBool(Yml::ANONYMOUS_STATISTICS_ENABLED, true)){
$this->sendUsageTicker = self::TICKS_PER_STATS_REPORT;
$this->sendUsage(SendUsageTask::TYPE_OPEN);
}
@ -1057,7 +1058,7 @@ class Server{
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_USERS, $forwarder);
//TODO: move console parts to a separate component
if($this->configGroup->getPropertyBool("console.enable-input", true)){
if($this->configGroup->getPropertyBool(Yml::CONSOLE_ENABLE_INPUT, true)){
$this->console = new ConsoleReaderChildProcessDaemon($this->logger);
}
@ -1092,7 +1093,7 @@ class Server{
$anyWorldFailedToLoad = false;
foreach((array) $this->configGroup->getProperty("worlds", []) as $name => $options){
foreach((array) $this->configGroup->getProperty(Yml::WORLDS, []) as $name => $options){
if($options === null){
$options = [];
}elseif(!is_array($options)){
@ -1136,11 +1137,11 @@ class Server{
}
if($this->worldManager->getDefaultWorld() === null){
$default = $this->configGroup->getConfigString("level-name", "world");
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
if(trim($default) == ""){
$this->getLogger()->warning("level-name cannot be null, using default");
$default = "world";
$this->configGroup->setConfigString("level-name", "world");
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
}
if(!$this->worldManager->loadWorld($default, true)){
if($this->worldManager->isWorldGenerated($default)){
@ -1148,8 +1149,8 @@ class Server{
return false;
}
$generatorName = $this->configGroup->getConfigString("level-type");
$generatorOptions = $this->configGroup->getConfigString("generator-settings");
$generatorName = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_GENERATOR);
$generatorOptions = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_GENERATOR_SETTINGS);
$generatorClass = $getGenerator($generatorName, $generatorOptions, $default);
if($generatorClass === null){
@ -1159,7 +1160,7 @@ class Server{
$creationOptions = WorldCreationOptions::create()
->setGeneratorClass($generatorClass)
->setGeneratorOptions($generatorOptions);
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString("level-seed"));
$convertedSeed = Generator::convertSeed($this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_SEED));
if($convertedSeed !== null){
$creationOptions->setSeed($convertedSeed);
}
@ -1213,7 +1214,7 @@ class Server{
}
private function startupPrepareNetworkInterfaces() : bool{
$useQuery = $this->configGroup->getConfigBool("enable-query", true);
$useQuery = $this->configGroup->getConfigBool(ServerProperties::ENABLE_QUERY, true);
$typeConverter = TypeConverter::getInstance();
$packetSerializerContext = new PacketSerializerContext($typeConverter->getItemTypeDictionary());
@ -1223,7 +1224,7 @@ class Server{
if(
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter) ||
(
$this->configGroup->getConfigBool("enable-ipv6", true) &&
$this->configGroup->getConfigBool(ServerProperties::ENABLE_IPV6, true) &&
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext, $typeConverter)
)
){
@ -1238,7 +1239,7 @@ class Server{
$this->network->blockAddress($entry->getName(), -1);
}
if($this->configGroup->getPropertyBool("network.upnp-forwarding", false)){
if($this->configGroup->getPropertyBool(Yml::NETWORK_UPNP_FORWARDING, false)){
$this->network->registerInterface(new UPnPNetworkInterface($this->logger, Internet::getInternalIP(), $this->getPort()));
}
@ -1458,7 +1459,7 @@ class Server{
}
if(isset($this->network)){
$this->network->getSessionManager()->close($this->configGroup->getPropertyString("settings.shutdown-message", "Server closed"));
$this->network->getSessionManager()->close($this->configGroup->getPropertyString(YmlServerProperties::SETTINGS_SHUTDOWN_MESSAGE, "Server closed"));
}
if(isset($this->worldManager)){
@ -1595,7 +1596,7 @@ class Server{
$this->logger->emergency($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_crash_submit($crashDumpPath)));
if($this->configGroup->getPropertyBool("auto-report.enabled", true)){
if($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_ENABLED, true)){
$report = true;
$stamp = Path::join($this->getDataPath(), "crashdumps", ".last_crash");
@ -1606,15 +1607,6 @@ class Server{
}
@touch($stamp); //update file timestamp
$plugin = $dump->getData()->plugin;
if($plugin !== ""){
$p = $this->pluginManager->getPlugin($plugin);
if($p instanceof Plugin && !($p->getPluginLoader() instanceof PharPluginLoader)){
$this->logger->debug("Not sending crashdump due to caused by non-phar plugin");
$report = false;
}
}
if($dump->getData()->error["type"] === \ParseError::class){
$report = false;
}
@ -1625,7 +1617,7 @@ class Server{
}
if($report){
$url = ($this->configGroup->getPropertyBool("auto-report.use-https", true) ? "https" : "http") . "://" . $this->configGroup->getPropertyString("auto-report.host", "crash.pmmp.io") . "/submit/api";
$url = ($this->configGroup->getPropertyBool(Yml::AUTO_REPORT_USE_HTTPS, true) ? "https" : "http") . "://" . $this->configGroup->getPropertyString(Yml::AUTO_REPORT_HOST, "crash.pmmp.io") . "/submit/api";
$postUrlError = "Unknown error";
$reply = Internet::postURL($url, [
"report" => "yes",
@ -1736,7 +1728,7 @@ class Server{
}
public function sendUsage(int $type = SendUsageTask::TYPE_STATUS) : void{
if($this->configGroup->getPropertyBool("anonymous-statistics.enabled", true)){
if($this->configGroup->getPropertyBool(Yml::ANONYMOUS_STATISTICS_ENABLED, true)){
$this->asyncPool->submitTask(new SendUsageTask($this, $type, $this->uniquePlayers));
}
$this->uniquePlayers = [];

58
src/ServerProperties.php Normal file
View File

@ -0,0 +1,58 @@
<?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;
/**
* @internal
* Constants for all properties available in server.properties.
*/
final class ServerProperties{
private function __construct(){
//NOOP
}
public const AUTO_SAVE = "auto-save";
public const DEFAULT_WORLD_GENERATOR = "level-type";
public const DEFAULT_WORLD_GENERATOR_SETTINGS = "generator-settings";
public const DEFAULT_WORLD_NAME = "level-name";
public const DEFAULT_WORLD_SEED = "level-seed";
public const DIFFICULTY = "difficulty";
public const ENABLE_IPV6 = "enable-ipv6";
public const ENABLE_QUERY = "enable-query";
public const FORCE_GAME_MODE = "force-gamemode";
public const GAME_MODE = "gamemode";
public const HARDCORE = "hardcore";
public const LANGUAGE = "language";
public const MAX_PLAYERS = "max-players";
public const MOTD = "motd";
public const PVP = "pvp";
public const SERVER_IPV4 = "server-ip";
public const SERVER_IPV6 = "server-ipv6";
public const SERVER_PORT_IPV4 = "server-port";
public const SERVER_PORT_IPV6 = "server-portv6";
public const VIEW_DISTANCE = "view-distance";
public const WHITELIST = "white-list";
public const XBOX_AUTH = "xbox-auth";
}

View File

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

118
src/YmlServerProperties.php Normal file
View File

@ -0,0 +1,118 @@
<?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;
/**
* @internal
* Constants for all properties available in pocketmine.yml.
* This is generated by build/generate-pocketmine-yml-property-consts.php.
* Do not edit this file manually.
*/
final class YmlServerProperties{
private function __construct(){
//NOOP
}
public const ALIASES = 'aliases';
public const ANONYMOUS_STATISTICS = 'anonymous-statistics';
public const ANONYMOUS_STATISTICS_ENABLED = 'anonymous-statistics.enabled';
public const ANONYMOUS_STATISTICS_HOST = 'anonymous-statistics.host';
public const AUTO_REPORT = 'auto-report';
public const AUTO_REPORT_ENABLED = 'auto-report.enabled';
public const AUTO_REPORT_HOST = 'auto-report.host';
public const AUTO_REPORT_SEND_CODE = 'auto-report.send-code';
public const AUTO_REPORT_SEND_PHPINFO = 'auto-report.send-phpinfo';
public const AUTO_REPORT_SEND_SETTINGS = 'auto-report.send-settings';
public const AUTO_REPORT_USE_HTTPS = 'auto-report.use-https';
public const AUTO_UPDATER = 'auto-updater';
public const AUTO_UPDATER_ENABLED = 'auto-updater.enabled';
public const AUTO_UPDATER_HOST = 'auto-updater.host';
public const AUTO_UPDATER_ON_UPDATE = 'auto-updater.on-update';
public const AUTO_UPDATER_ON_UPDATE_WARN_CONSOLE = 'auto-updater.on-update.warn-console';
public const AUTO_UPDATER_PREFERRED_CHANNEL = 'auto-updater.preferred-channel';
public const AUTO_UPDATER_SUGGEST_CHANNELS = 'auto-updater.suggest-channels';
public const CHUNK_GENERATION = 'chunk-generation';
public const CHUNK_GENERATION_POPULATION_QUEUE_SIZE = 'chunk-generation.population-queue-size';
public const CHUNK_SENDING = 'chunk-sending';
public const CHUNK_SENDING_PER_TICK = 'chunk-sending.per-tick';
public const CHUNK_SENDING_SPAWN_RADIUS = 'chunk-sending.spawn-radius';
public const CHUNK_TICKING = 'chunk-ticking';
public const CHUNK_TICKING_BLOCKS_PER_SUBCHUNK_PER_TICK = 'chunk-ticking.blocks-per-subchunk-per-tick';
public const CHUNK_TICKING_DISABLE_BLOCK_TICKING = 'chunk-ticking.disable-block-ticking';
public const CHUNK_TICKING_TICK_RADIUS = 'chunk-ticking.tick-radius';
public const CONSOLE = 'console';
public const CONSOLE_ENABLE_INPUT = 'console.enable-input';
public const CONSOLE_TITLE_TICK = 'console.title-tick';
public const DEBUG = 'debug';
public const DEBUG_LEVEL = 'debug.level';
public const LEVEL_SETTINGS = 'level-settings';
public const LEVEL_SETTINGS_DEFAULT_FORMAT = 'level-settings.default-format';
public const MEMORY = 'memory';
public const MEMORY_ASYNC_WORKER_HARD_LIMIT = 'memory.async-worker-hard-limit';
public const MEMORY_CHECK_RATE = 'memory.check-rate';
public const MEMORY_CONTINUOUS_TRIGGER = 'memory.continuous-trigger';
public const MEMORY_CONTINUOUS_TRIGGER_RATE = 'memory.continuous-trigger-rate';
public const MEMORY_GARBAGE_COLLECTION = 'memory.garbage-collection';
public const MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER = 'memory.garbage-collection.collect-async-worker';
public const MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER = 'memory.garbage-collection.low-memory-trigger';
public const MEMORY_GARBAGE_COLLECTION_PERIOD = 'memory.garbage-collection.period';
public const MEMORY_GLOBAL_LIMIT = 'memory.global-limit';
public const MEMORY_MAIN_HARD_LIMIT = 'memory.main-hard-limit';
public const MEMORY_MAIN_LIMIT = 'memory.main-limit';
public const MEMORY_MAX_CHUNKS = 'memory.max-chunks';
public const MEMORY_MAX_CHUNKS_CHUNK_RADIUS = 'memory.max-chunks.chunk-radius';
public const MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT = 'memory.max-chunks.trigger-chunk-collect';
public const MEMORY_MEMORY_DUMP = 'memory.memory-dump';
public const MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER = 'memory.memory-dump.dump-async-worker';
public const MEMORY_WORLD_CACHES = 'memory.world-caches';
public const MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE = 'memory.world-caches.disable-chunk-cache';
public const MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER = 'memory.world-caches.low-memory-trigger';
public const NETWORK = 'network';
public const NETWORK_ASYNC_COMPRESSION = 'network.async-compression';
public const NETWORK_ASYNC_COMPRESSION_THRESHOLD = 'network.async-compression-threshold';
public const NETWORK_BATCH_THRESHOLD = 'network.batch-threshold';
public const NETWORK_COMPRESSION_LEVEL = 'network.compression-level';
public const NETWORK_ENABLE_ENCRYPTION = 'network.enable-encryption';
public const NETWORK_MAX_MTU_SIZE = 'network.max-mtu-size';
public const NETWORK_UPNP_FORWARDING = 'network.upnp-forwarding';
public const PLAYER = 'player';
public const PLAYER_SAVE_PLAYER_DATA = 'player.save-player-data';
public const PLAYER_VERIFY_XUID = 'player.verify-xuid';
public const PLUGINS = 'plugins';
public const PLUGINS_LEGACY_DATA_DIR = 'plugins.legacy-data-dir';
public const SETTINGS = 'settings';
public const SETTINGS_ASYNC_WORKERS = 'settings.async-workers';
public const SETTINGS_ENABLE_DEV_BUILDS = 'settings.enable-dev-builds';
public const SETTINGS_ENABLE_PROFILING = 'settings.enable-profiling';
public const SETTINGS_FORCE_LANGUAGE = 'settings.force-language';
public const SETTINGS_PROFILE_REPORT_TRIGGER = 'settings.profile-report-trigger';
public const SETTINGS_QUERY_PLUGINS = 'settings.query-plugins';
public const SETTINGS_SHUTDOWN_MESSAGE = 'settings.shutdown-message';
public const TICKS_PER = 'ticks-per';
public const TICKS_PER_AUTOSAVE = 'ticks-per.autosave';
public const TIMINGS = 'timings';
public const TIMINGS_HOST = 'timings.host';
public const WORLDS = 'worlds';
}

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\BlockDeathEvent;
use pocketmine\item\Item;
use function mt_rand;
@ -46,11 +46,7 @@ abstract class BaseCoral extends Transparent{
public function onScheduledUpdate() : void{
if(!$this->dead && !$this->isCoveredWithWater()){
$ev = new BlockDeathEvent($this, $this->setDead(true));
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::die($this, (clone $this)->setDead(true));
}
}

View File

@ -49,6 +49,8 @@ abstract class BaseSign extends Transparent{
use WoodTypeTrait;
protected SignText $text;
private bool $waxed = false;
protected ?int $editorEntityRuntimeId = null;
/** @var \Closure() : Item */
@ -69,6 +71,7 @@ abstract class BaseSign extends Transparent{
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileSign){
$this->text = $tile->getText();
$this->waxed = $tile->isWaxed();
$this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId();
}
@ -80,6 +83,7 @@ abstract class BaseSign extends Transparent{
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileSign);
$tile->setText($this->text);
$tile->setWaxed($this->waxed);
$tile->setEditorEntityRuntimeId($this->editorEntityRuntimeId);
}
@ -147,10 +151,26 @@ abstract class BaseSign extends Transparent{
return false;
}
private function wax(Player $player, Item $item) : bool{
if($this->waxed){
return false;
}
$this->waxed = true;
$this->position->getWorld()->setBlock($this->position, $this);
$item->pop();
return true;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player === null){
return false;
}
if($this->waxed){
return true;
}
$dyeColor = $item instanceof Dye ? $item->getColor() : match($item->getTypeId()){
ItemTypeIds::BONE_MEAL => DyeColor::WHITE(),
ItemTypeIds::LAPIS_LAZULI => DyeColor::BLUE(),
@ -159,20 +179,25 @@ abstract class BaseSign extends Transparent{
};
if($dyeColor !== null){
$color = $dyeColor->equals(DyeColor::BLACK()) ? new Color(0, 0, 0) : $dyeColor->getRgbValue();
if($color->toARGB() === $this->text->getBaseColor()->toARGB()){
return false;
}
if($this->doSignChange(new SignText($this->text->getLines(), $color, $this->text->isGlowing()), $player, $item)){
if(
$color->toARGB() !== $this->text->getBaseColor()->toARGB() &&
$this->doSignChange(new SignText($this->text->getLines(), $color, $this->text->isGlowing()), $player, $item)
){
$this->position->getWorld()->addSound($this->position, new DyeUseSound());
return true;
}
}elseif($item->getTypeId() === ItemTypeIds::INK_SAC){
return $this->changeSignGlowingState(false, $player, $item);
}elseif($item->getTypeId() === ItemTypeIds::GLOW_INK_SAC){
return $this->changeSignGlowingState(true, $player, $item);
}elseif(match($item->getTypeId()){
ItemTypeIds::INK_SAC => $this->changeSignGlowingState(false, $player, $item),
ItemTypeIds::GLOW_INK_SAC => $this->changeSignGlowingState(true, $player, $item),
ItemTypeIds::HONEYCOMB => $this->wax($player, $item),
default => false
}){
return true;
}
return false;
$player->openSignEditor($this->position);
return true;
}
/**
@ -188,6 +213,17 @@ abstract class BaseSign extends Transparent{
return $this;
}
/**
* Returns whether the sign has been waxed using a honeycomb. If true, the sign cannot be edited by a player.
*/
public function isWaxed() : bool{ return $this->waxed; }
/** @return $this */
public function setWaxed(bool $waxed) : self{
$this->waxed = $waxed;
return $this;
}
/**
* Sets the runtime entity ID of the player editing this sign. Only this player will be able to edit the sign.
* This is used to prevent multiple players from editing the same sign at the same time, and to prevent players
@ -217,8 +253,8 @@ abstract class BaseSign extends Transparent{
}
$ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) : string{
return TextFormat::clean($line, false);
}, $text->getLines())));
if($this->editorEntityRuntimeId === null || $this->editorEntityRuntimeId !== $author->getId()){
}, $text->getLines()), $this->text->getBaseColor(), $this->text->isGlowing()));
if($this->waxed || $this->editorEntityRuntimeId !== $author->getId()){
$ev->cancel();
}
$ev->call();
@ -235,4 +271,8 @@ abstract class BaseSign extends Transparent{
public function asItem() : Item{
return ($this->asItemCallback)();
}
public function getFuelTime() : int{
return $this->woodType->isFlammable() ? 200 : 0;
}
}

View File

@ -36,6 +36,9 @@ use pocketmine\data\runtime\RuntimeDataSizeCalculator;
use pocketmine\data\runtime\RuntimeDataWriter;
use pocketmine\entity\Entity;
use pocketmine\entity\projectile\Projectile;
use pocketmine\item\enchantment\AvailableEnchantmentRegistry;
use pocketmine\item\enchantment\ItemEnchantmentTagRegistry;
use pocketmine\item\enchantment\ItemEnchantmentTags;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\item\Item;
use pocketmine\item\ItemBlock;
@ -422,6 +425,19 @@ class Block{
return $this->typeInfo->getBreakInfo();
}
/**
* Returns tags that represent the type of item being enchanted and are used to determine
* what enchantments can be applied to the item of this block during in-game enchanting (enchanting table, anvil, fishing, etc.).
* @see ItemEnchantmentTags
* @see ItemEnchantmentTagRegistry
* @see AvailableEnchantmentRegistry
*
* @return string[]
*/
public function getEnchantmentTags() : array{
return $this->typeInfo->getEnchantmentTags();
}
/**
* Do the actions needed so the block is broken with the Item
*

View File

@ -736,8 +736,9 @@ final class BlockTypeIds{
public const SMALL_DRIPLEAF = 10706;
public const BIG_DRIPLEAF_HEAD = 10707;
public const BIG_DRIPLEAF_STEM = 10708;
public const PINK_PETALS = 10709;
public const FIRST_UNUSED_BLOCK_ID = 10709;
public const FIRST_UNUSED_BLOCK_ID = 10710;
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;

View File

@ -35,10 +35,12 @@ final class BlockTypeInfo{
/**
* @param string[] $typeTags
* @param string[] $enchantmentTags
*/
public function __construct(
private BlockBreakInfo $breakInfo,
array $typeTags = []
array $typeTags = [],
private array $enchantmentTags = []
){
$this->typeTags = array_fill_keys($typeTags, true);
}
@ -49,4 +51,17 @@ final class BlockTypeInfo{
public function getTypeTags() : array{ return array_keys($this->typeTags); }
public function hasTypeTag(string $tag) : bool{ return isset($this->typeTags[$tag]); }
/**
* Returns tags that represent the type of item being enchanted and are used to determine
* what enchantments can be applied to the item of this block during in-game enchanting (enchanting table, anvil, fishing, etc.).
* @see ItemEnchantmentTags
* @see ItemEnchantmentTagRegistry
* @see AvailableEnchantmentRegistry
*
* @return string[]
*/
public function getEnchantmentTags() : array{
return $this->enchantmentTags;
}
}

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
@ -111,21 +111,16 @@ class Cactus extends Transparent{
}
$b = $world->getBlockAt($this->position->x, $this->position->y + $y, $this->position->z);
if($b->getTypeId() === BlockTypeIds::AIR){
$ev = new BlockGrowEvent($b, VanillaBlocks::CACTUS());
$ev->call();
if($ev->isCancelled()){
break;
}
$world->setBlock($b->position, $ev->getNewState());
BlockEventHelper::grow($b, VanillaBlocks::CACTUS(), null);
}else{
break;
}
}
$this->age = 0;
$world->setBlock($this->position, $this);
$world->setBlock($this->position, $this, update: false);
}else{
++$this->age;
$world->setBlock($this->position, $this);
$world->setBlock($this->position, $this, update: false);
}
}
}

View File

@ -64,7 +64,7 @@ class Cake extends BaseCake{
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof ItemBlock){
if($this->bites === 0 && $item instanceof ItemBlock){
$block = $item->getBlock();
$resultBlock = null;
if($block->getTypeId() === BlockTypeIds::CANDLE){
@ -83,6 +83,10 @@ class Cake extends BaseCake{
return parent::onInteract($item, $face, $clickVector, $player, $returnedItems);
}
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function getResidue() : Block{
$clone = clone $this;
$clone->bites++;

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
@ -88,7 +88,8 @@ class CaveVines extends Flowable{
}
private function canBeSupportedAt(Block $block) : bool{
return $block->getAdjacentSupportType(Facing::UP)->equals(SupportType::FULL()) || $block->hasSameTypeId($this);
$supportBlock = $block->getSide(Facing::UP);
return $supportBlock->getSupportType(Facing::DOWN)->equals(SupportType::FULL()) || $supportBlock->hasSameTypeId($this);
}
public function onNearbyBlockChange() : void{
@ -114,16 +115,12 @@ class CaveVines extends Flowable{
return true;
}
if($item instanceof Fertilizer){
$ev = new BlockGrowEvent($this, (clone $this)
$newState = (clone $this)
->setBerries(true)
->setHead(!$this->getSide(Facing::DOWN)->hasSameTypeId($this))
);
$ev->call();
if($ev->isCancelled()){
return false;
->setHead(!$this->getSide(Facing::DOWN)->hasSameTypeId($this));
if(BlockEventHelper::grow($this, $newState, $player)){
$item->pop();
}
$item->pop();
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
return true;
}
return false;
@ -141,16 +138,10 @@ class CaveVines extends Flowable{
if($world->isInWorld($growthPos->getFloorX(), $growthPos->getFloorY(), $growthPos->getFloorZ())){
$block = $world->getBlock($growthPos);
if($block->getTypeId() === BlockTypeIds::AIR){
$ev = new BlockGrowEvent($block, VanillaBlocks::CAVE_VINES()
$newState = VanillaBlocks::CAVE_VINES()
->setAge($this->age + 1)
->setBerries(mt_rand(1, 9) === 1)
);
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($growthPos, $ev->getNewState());
}
->setBerries(mt_rand(1, 9) === 1);
BlockEventHelper::grow($block, $newState, null);
}
}
}

View File

@ -23,11 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\WoodType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
@ -123,12 +123,7 @@ class CocoaBlock extends Transparent{
if($this->age < self::MAX_AGE){
$block = clone $this;
$block->age++;
$ev = new BlockGrowEvent($this, $block, $player);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
return true;
}
return BlockEventHelper::grow($this, $block, $player);
}
return false;
}

View File

@ -23,11 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\Fallable;
use pocketmine\block\utils\FallableTrait;
use pocketmine\event\block\BlockFormEvent;
use pocketmine\math\Facing;
class ConcretePowder extends Opaque implements Fallable{
@ -43,11 +43,7 @@ class ConcretePowder extends Opaque implements Fallable{
public function onNearbyBlockChange() : void{
if(($water = $this->getAdjacentWater()) !== null){
$ev = new BlockFormEvent($this, VanillaBlocks::CONCRETE()->setColor($this->color), $water);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::form($this, VanillaBlocks::CONCRETE()->setColor($this->color), $water);
}else{
$this->startFalling();
}

View File

@ -23,9 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\event\block\BlockDeathEvent;
use pocketmine\item\Item;
use function mt_rand;
@ -55,17 +55,13 @@ final class CoralBlock extends Opaque{
}
}
if(!$hasWater){
$ev = new BlockDeathEvent($this, $this->setDead(true));
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::die($this, (clone $this)->setDead(true));
}
}
}
public function getDropsForCompatibleTool(Item $item) : array{
return [$this->setDead(true)->asItem()];
return [(clone $this)->setDead(true)->asItem()];
}
public function isAffectedBySilkTouch() : bool{

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\math\Facing;
@ -68,11 +68,7 @@ abstract class Crops extends Flowable{
if($block->age > self::MAX_AGE){
$block->age = self::MAX_AGE;
}
$ev = new BlockGrowEvent($this, $block, $player);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
if(BlockEventHelper::grow($this, $block, $player)){
$item->pop();
}
@ -96,11 +92,7 @@ abstract class Crops extends Flowable{
if($this->age < self::MAX_AGE && mt_rand(0, 2) === 1){
$block = clone $this;
++$block->age;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::grow($this, $block, null);
}
}
}

View File

@ -66,13 +66,19 @@ class DeadBush extends Flowable{
}
private function canBeSupportedBy(Block $block) : bool{
$blockId = $block->getTypeId();
return $blockId === BlockTypeIds::SAND
|| $blockId === BlockTypeIds::RED_SAND
|| $blockId === BlockTypeIds::PODZOL
|| $blockId === BlockTypeIds::MYCELIUM
|| $blockId === BlockTypeIds::DIRT
|| $blockId === BlockTypeIds::HARDENED_CLAY
|| $blockId === BlockTypeIds::STAINED_CLAY;
return
$block->hasTypeTag(BlockTypeTags::SAND) ||
$block->hasTypeTag(BlockTypeTags::MUD) ||
match($block->getTypeId()){
//can't use DIRT tag here because it includes farmland
BlockTypeIds::PODZOL,
BlockTypeIds::MYCELIUM,
BlockTypeIds::DIRT,
BlockTypeIds::GRASS,
BlockTypeIds::HARDENED_CLAY,
BlockTypeIds::STAINED_CLAY => true,
//TODO: moss block
default => false,
};
}
}

View File

@ -59,7 +59,12 @@ class Dirt extends Opaque{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
$world = $this->position->getWorld();
if($face === Facing::UP && $item instanceof Hoe){
if($face !== Facing::DOWN && $item instanceof Hoe){
$up = $this->getSide(Facing::UP);
if($up->getTypeId() !== BlockTypeIds::AIR){
return true;
}
$item->applyDamage(1);
$newBlock = $this->dirtType->equals(DirtType::NORMAL()) ? VanillaBlocks::FARMLAND() : VanillaBlocks::DIRT();

View File

@ -26,6 +26,7 @@ namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\entity\Living;
use pocketmine\event\block\FarmlandHydrationChangeEvent;
use pocketmine\event\entity\EntityTrampleFarmlandEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
@ -73,14 +74,22 @@ class Farmland extends Transparent{
$world = $this->position->getWorld();
if(!$this->canHydrate()){
if($this->wetness > 0){
$this->wetness--;
$world->setBlock($this->position, $this, false);
$event = new FarmlandHydrationChangeEvent($this, $this->wetness, $this->wetness - 1);
$event->call();
if(!$event->isCancelled()){
$this->wetness = $event->getNewHydration();
$world->setBlock($this->position, $this, false);
}
}else{
$world->setBlock($this->position, VanillaBlocks::DIRT());
}
}elseif($this->wetness < self::MAX_WETNESS){
$this->wetness = self::MAX_WETNESS;
$world->setBlock($this->position, $this, false);
$event = new FarmlandHydrationChangeEvent($this, $this->wetness, self::MAX_WETNESS);
$event->call();
if(!$event->isCancelled()){
$this->wetness = $event->getNewHydration();
$world->setBlock($this->position, $this, false);
}
}
}

View File

@ -42,7 +42,7 @@ class Fence extends Transparent{
foreach(Facing::HORIZONTAL as $facing){
$block = $this->getSide($facing);
if($block instanceof static || $block instanceof FenceGate || ($block->isSolid() && !$block->isTransparent())){
if($block instanceof static || $block instanceof FenceGate || $block->getSupportType(Facing::opposite($facing))->equals(SupportType::FULL())){
$this->connections[$facing] = true;
}else{
unset($this->connections[$facing]);

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockBurnEvent;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\math\Facing;
use pocketmine\world\format\Chunk;
use pocketmine\world\World;
@ -145,9 +145,13 @@ class Fire extends BaseFire{
private function burnBlock(Block $block, int $chanceBound) : void{
if(mt_rand(0, $chanceBound) < $block->getFlammability()){
$ev = new BlockBurnEvent($block, $this);
$ev->call();
if(!$ev->isCancelled()){
$cancelled = false;
if(BlockBurnEvent::hasHandlers()){
$ev = new BlockBurnEvent($block, $this);
$ev->call();
$cancelled = $ev->isCancelled();
}
if(!$cancelled){
$block->onIncinerate();
$world = $this->position->getWorld();
@ -225,13 +229,6 @@ class Fire extends BaseFire{
}
private function spreadBlock(Block $block, Block $newState) : bool{
$ev = new BlockSpreadEvent($block, $this, $newState);
$ev->call();
if(!$ev->isCancelled()){
$block->position->getWorld()->setBlock($block->position, $ev->getNewState());
return true;
}
return false;
return BlockEventHelper::spread($block, $newState, $this);
}
}

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockMeltEvent;
use function mt_rand;
class FrostedIce extends Ice{
@ -97,11 +97,7 @@ class FrostedIce extends Ice{
private function tryMelt() : bool{
$world = $this->position->getWorld();
if($this->age >= self::MAX_AGE){
$ev = new BlockMeltEvent($this, VanillaBlocks::WATER());
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::melt($this, VanillaBlocks::WATER());
return true;
}

View File

@ -23,9 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
@ -166,14 +166,7 @@ class GlowLichen extends Transparent{
return false;
}
$ev = new BlockSpreadEvent($replacedBlock, $this, $replacementBlock);
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($replacedBlock->getPosition(), $ev->getNewState());
return true;
}
return false;
return BlockEventHelper::spread($replacedBlock, $replacementBlock, $this);
}
/**

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\DirtType;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Hoe;
use pocketmine\item\Item;
@ -58,11 +58,7 @@ class Grass extends Opaque{
$lightAbove = $world->getFullLightAt($this->position->x, $this->position->y + 1, $this->position->z);
if($lightAbove < 4 && $world->getBlockAt($this->position->x, $this->position->y + 1, $this->position->z)->getLightFilter() >= 2){
//grass dies
$ev = new BlockSpreadEvent($this, $this, VanillaBlocks::DIRT());
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState(), false);
}
BlockEventHelper::spread($this, VanillaBlocks::DIRT(), $this);
}elseif($lightAbove >= 9){
//try grass spread
for($i = 0; $i < 4; ++$i){
@ -80,17 +76,13 @@ class Grass extends Opaque{
continue;
}
$ev = new BlockSpreadEvent($b, $this, VanillaBlocks::GRASS());
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($b->position, $ev->getNewState(), false);
}
BlockEventHelper::spread($b, VanillaBlocks::GRASS(), $this);
}
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($face !== Facing::UP){
if($this->getSide(Facing::UP)->getTypeId() !== BlockTypeIds::AIR){
return false;
}
$world = $this->position->getWorld();
@ -99,20 +91,23 @@ class Grass extends Opaque{
TallGrassObject::growGrass($world, $this->position, new Random(mt_rand()), 8, 2);
return true;
}elseif($item instanceof Hoe){
$item->applyDamage(1);
$newBlock = VanillaBlocks::FARMLAND();
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
$world->setBlock($this->position, $newBlock);
}
if($face !== Facing::DOWN){
if($item instanceof Hoe){
$item->applyDamage(1);
$newBlock = VanillaBlocks::FARMLAND();
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
$world->setBlock($this->position, $newBlock);
return true;
}elseif($item instanceof Shovel && $this->getSide(Facing::UP)->getTypeId() === BlockTypeIds::AIR){
$item->applyDamage(1);
$newBlock = VanillaBlocks::GRASS_PATH();
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
$world->setBlock($this->position, $newBlock);
return true;
}elseif($item instanceof Shovel){
$item->applyDamage(1);
$newBlock = VanillaBlocks::GRASS_PATH();
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
$world->setBlock($this->position, $newBlock);
return true;
return true;
}
}
return false;

View File

@ -32,19 +32,19 @@ use pocketmine\world\BlockTransaction;
final class HangingRoots extends Flowable{
private function canBeSupportedBy(Block $block) : bool{
return $block->isSolid(); //TODO: not sure if this is the correct logic
private function canBeSupportedAt(Block $block) : bool{
return $block->getAdjacentSupportType(Facing::UP)->hasCenterSupport(); //weird I know, but they can be placed on the bottom of fences
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$blockReplace->getSide(Facing::UP)->isSolid()){
if(!$this->canBeSupportedAt($blockReplace)){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide(Facing::UP))){
if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position);
}
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\event\block\BlockMeltEvent;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\item\Item;
use pocketmine\player\Player;
@ -53,11 +53,7 @@ class Ice extends Transparent{
public function onRandomTick() : void{
$world = $this->position->getWorld();
if($world->getHighestAdjacentBlockLight($this->position->x, $this->position->y, $this->position->z) >= 12){
$ev = new BlockMeltEvent($this, VanillaBlocks::WATER());
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::melt($this, VanillaBlocks::WATER());
}
}

View File

@ -116,10 +116,15 @@ class Leaves extends Transparent{
public function onRandomTick() : void{
if(!$this->noDecay && $this->checkDecay){
$ev = new LeavesDecayEvent($this);
$ev->call();
$cancelled = false;
if(LeavesDecayEvent::hasHandlers()){
$ev = new LeavesDecayEvent($this);
$ev->call();
$cancelled = $ev->isCancelled();
}
$world = $this->position->getWorld();
if($ev->isCancelled() || $this->findLog($this->position)){
if($cancelled || $this->findLog($this->position)){
$this->checkDecay = false;
$world->setBlock($this->position, $this, false);
}else{

View File

@ -23,11 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\MinimumCostFlowCalculator;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockFormEvent;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
@ -363,12 +363,8 @@ abstract class Liquid extends Transparent{
}
protected function liquidCollide(Block $cause, Block $result) : bool{
$ev = new BlockFormEvent($this, $result, $cause);
$ev->call();
if(!$ev->isCancelled()){
$world = $this->position->getWorld();
$world->setBlock($this->position, $ev->getNewState());
$world->addSound($this->position->add(0.5, 0.5, 0.5), new FizzSound(2.6 + (lcg_value() - lcg_value()) * 0.8));
if(BlockEventHelper::form($this, $result, $cause)){
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new FizzSound(2.6 + (lcg_value() - lcg_value()) * 0.8));
}
return true;
}

View File

@ -113,14 +113,15 @@ class MobHead extends Flowable{
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$collisionBox = AxisAlignedBB::one()->contract(0.25, 0, 0.25)->trim(Facing::UP, 0.5);
return match($this->facing){
Facing::NORTH => [$collisionBox->offset(0, 0.25, 0.25)],
Facing::SOUTH => [$collisionBox->offset(0, 0.25, -0.25)],
Facing::WEST => [$collisionBox->offset(0.25, 0.25, 0)],
Facing::EAST => [$collisionBox->offset(-0.25, 0.25, 0)],
default => [$collisionBox]
};
$collisionBox = AxisAlignedBB::one()
->contract(0.25, 0, 0.25)
->trim(Facing::UP, 0.5);
if($this->facing !== Facing::UP){
$collisionBox = $collisionBox
->offsetTowards(Facing::opposite($this->facing), 0.25)
->offsetTowards(Facing::UP, 0.25);
}
return [$collisionBox];
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\DirtType;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use function mt_rand;
@ -54,11 +54,7 @@ class Mycelium extends Opaque{
$block = $world->getBlockAt($x, $y, $z);
if($block instanceof Dirt && $block->getDirtType()->equals(DirtType::NORMAL())){
if($block->getSide(Facing::UP) instanceof Transparent){
$ev = new BlockSpreadEvent($block, $this, VanillaBlocks::MYCELIUM());
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($block->position, $ev->getNewState());
}
BlockEventHelper::spread($block, VanillaBlocks::MYCELIUM(), $this);
}
}
}

View File

@ -23,9 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\FortuneDropHelper;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
@ -76,11 +76,7 @@ class NetherWartPlant extends Flowable{
if($this->age < self::MAX_AGE && mt_rand(0, 10) === 0){ //Still growing
$block = clone $this;
$block->age++;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::grow($this, $block, null);
}
}

119
src/block/PinkPetals.php Normal file
View File

@ -0,0 +1,119 @@
<?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;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class PinkPetals extends Flowable{
use HorizontalFacingTrait;
public const MIN_COUNT = 1;
public const MAX_COUNT = 4;
protected int $count = self::MIN_COUNT;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->boundedInt(2, self::MIN_COUNT, self::MAX_COUNT, $this->count);
}
public function getCount() : int{
return $this->count;
}
/** @return $this */
public function setCount(int $count) : self{
if($count < self::MIN_COUNT || $count > self::MAX_COUNT){
throw new \InvalidArgumentException("Count must be in range " . self::MIN_COUNT . " ... " . self::MAX_COUNT);
}
$this->count = $count;
return $this;
}
private function canBeSupportedAt(Block $block) : bool{
$supportBlock = $block->getSide(Facing::DOWN);
//TODO: Moss block
return $supportBlock->hasTypeTag(BlockTypeTags::DIRT) || $supportBlock->hasTypeTag(BlockTypeTags::MUD);
}
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
return ($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT) || parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedAt($this)){
return false;
}
if($blockReplace instanceof PinkPetals && $blockReplace->getCount() < self::MAX_COUNT){
$this->count = $blockReplace->getCount() + 1;
$this->facing = $blockReplace->getFacing();
}elseif($player !== null){
$this->facing = Facing::opposite($player->getHorizontalFacing());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof Fertilizer){
$grew = false;
if($this->count < self::MAX_COUNT){
$grew = BlockEventHelper::grow($this, (clone $this)->setCount($this->count + 1), $player);
}else{
$this->position->getWorld()->dropItem($this->position->add(0, 0.5, 0), $this->asItem());
$grew = true;
}
if($grew){
$item->pop();
return true;
}
}
return false;
}
public function getFlameEncouragement() : int{
return 60;
}
public function getFlammability() : int{
return 100;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [$this->asItem()->setCount($this->count)];
}
}

View File

@ -27,6 +27,10 @@ use pocketmine\item\Item;
class Podzol extends Opaque{
public function isAffectedBySilkTouch() : bool{
return true;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaBlocks::DIRT()->asItem()

View File

@ -63,6 +63,14 @@ final class PotionCauldron extends FillableCauldron{
/** @return $this */
public function setPotionItem(?Item $potionItem) : self{
if($potionItem !== null && !match($potionItem->getTypeId()){
ItemTypeIds::POTION,
ItemTypeIds::SPLASH_POTION,
ItemTypeIds::LINGERING_POTION => true,
default => false,
}){
throw new \InvalidArgumentException("Item must be a POTION, SPLASH_POTION or LINGERING_POTION");
}
$this->potionItem = $potionItem !== null ? (clone $potionItem)->setCount(1) : null;
return $this;
}

View File

@ -24,14 +24,33 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\entity\Entity;
use pocketmine\event\block\PressurePlateUpdateEvent;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\PressurePlateActivateSound;
use pocketmine\world\sound\PressurePlateDeactivateSound;
use function count;
abstract class PressurePlate extends Transparent{
private readonly int $deactivationDelayTicks;
public function __construct(
BlockIdentifier $idInfo,
string $name,
BlockTypeInfo $typeInfo,
int $deactivationDelayTicks = 20 //TODO: make this mandatory in PM6
){
parent::__construct($idInfo, $name, $typeInfo);
$this->deactivationDelayTicks = $deactivationDelayTicks;
}
public function isSolid() : bool{
return false;
}
@ -61,5 +80,89 @@ abstract class PressurePlate extends Transparent{
}
}
//TODO
public function hasEntityCollision() : bool{
return true;
}
public function onEntityInside(Entity $entity) : bool{
if(!$this->hasOutputSignal()){
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 0);
}
return true;
}
/**
* Returns the AABB that entities must intersect to activate the pressure plate.
* Note that this is not the same as the collision box (pressure plate doesn't have one), nor the visual bounding
* box. The activation area has a height of 0.25 blocks.
*/
protected function getActivationBox() : AxisAlignedBB{
return AxisAlignedBB::one()
->squash(Axis::X, 1 / 8)
->squash(Axis::Z, 1 / 8)
->trim(Facing::UP, 3 / 4)
->offset($this->position->x, $this->position->y, $this->position->z);
}
/**
* TODO: make this abstract in PM6
*/
protected function hasOutputSignal() : bool{
return false;
}
/**
* TODO: make this abstract in PM6
*
* @param Entity[] $entities
*
* @return mixed[]
* @phpstan-return array{Block, ?bool}
*/
protected function calculatePlateState(array $entities) : array{
return [$this, null];
}
/**
* Filters entities which don't affect the pressure plate state from the given list.
*
* @param Entity[] $entities
* @return Entity[]
*/
protected function filterIrrelevantEntities(array $entities) : array{
return $entities;
}
public function onScheduledUpdate() : void{
$world = $this->position->getWorld();
$intersectionAABB = $this->getActivationBox();
$activatingEntities = $this->filterIrrelevantEntities($world->getNearbyEntities($intersectionAABB));
//if an irrelevant entity is inside the full cube space of the pressure plate but not activating the plate,
//it will cause scheduled updates on the plate every tick. We don't want to fire events in this case if the
//plate is already deactivated.
if(count($activatingEntities) > 0 || $this->hasOutputSignal()){
[$newState, $pressedChange] = $this->calculatePlateState($activatingEntities);
//always call this, in case there are new entities on the plate
if(PressurePlateUpdateEvent::hasHandlers()){
$ev = new PressurePlateUpdateEvent($this, $newState, $activatingEntities);
$ev->call();
$newState = $ev->isCancelled() ? null : $ev->getNewState();
}
if($newState !== null){
$world->setBlock($this->position, $newState);
if($pressedChange !== null){
$world->addSound($this->position, $pressedChange ?
new PressurePlateActivateSound($this) :
new PressurePlateDeactivateSound($this)
);
}
}
if($pressedChange ?? $this->hasOutputSignal()){
$world->scheduleDelayedBlockUpdate($this->position, $this->deactivationDelayTicks);
}
}
}
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use function count;
abstract class SimplePressurePlate extends PressurePlate{
protected bool $pressed = false;
@ -39,4 +40,19 @@ abstract class SimplePressurePlate extends PressurePlate{
$this->pressed = $pressed;
return $this;
}
protected function hasOutputSignal() : bool{
return $this->pressed;
}
protected function calculatePlateState(array $entities) : array{
$newPressed = count($entities) > 0;
if($newPressed === $this->pressed){
return [$this, null];
}
return [
(clone $this)->setPressed($newPressed),
$newPressed
];
}
}

View File

@ -23,11 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\Fallable;
use pocketmine\block\utils\FallableTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockMeltEvent;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
@ -105,11 +105,7 @@ class SnowLayer extends Flowable implements Fallable{
public function onRandomTick() : void{
$world = $this->position->getWorld();
if($world->getBlockLightAt($this->position->x, $this->position->y, $this->position->z) >= 12){
$ev = new BlockMeltEvent($this, VanillaBlocks::AIR());
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::melt($this, VanillaBlocks::AIR());
}
}

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use function array_rand;
@ -64,11 +64,7 @@ abstract class Stem extends Crops{
if($this->age < self::MAX_AGE){
$block = clone $this;
++$block->age;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::grow($this, $block, null);
}else{
$grow = $this->getPlant();
foreach(Facing::HORIZONTAL as $side){
@ -80,12 +76,7 @@ abstract class Stem extends Crops{
$facing = Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)];
$side = $this->getSide($facing);
if($side->getTypeId() === BlockTypeIds::AIR && $side->getSide(Facing::DOWN)->hasTypeTag(BlockTypeTags::DIRT)){
$ev = new BlockGrowEvent($side, $grow);
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $this->setFacing($facing));
$world->setBlock($side->position, $ev->getNewState());
}
BlockEventHelper::grow($side, $grow, null);
}
}
}

View File

@ -23,6 +23,13 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\entity\Living;
use function array_filter;
class StonePressurePlate extends SimplePressurePlate{
protected function filterIrrelevantEntities(array $entities) : array{
return array_filter($entities, fn(Entity $e) => $e instanceof Living); //TODO: armor stands should activate stone plates too
}
}

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\math\Facing;
@ -60,13 +60,11 @@ class Sugarcane extends Flowable{
}
$b = $world->getBlockAt($pos->x, $pos->y + $y, $pos->z);
if($b->getTypeId() === BlockTypeIds::AIR){
$ev = new BlockGrowEvent($b, VanillaBlocks::SUGARCANE(), $player);
$ev->call();
if($ev->isCancelled()){
if(BlockEventHelper::grow($b, VanillaBlocks::SUGARCANE(), $player)){
$grew = true;
}else{
break;
}
$world->setBlock($b->position, $ev->getNewState());
$grew = true;
}elseif(!$b->hasSameTypeId($this)){
break;
}

View File

@ -23,11 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\FortuneDropHelper;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\entity\Living;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
@ -87,15 +87,9 @@ class SweetBerryBush extends Flowable{
if($this->age < self::STAGE_MATURE && $item instanceof Fertilizer){
$block = clone $this;
$block->age++;
$ev = new BlockGrowEvent($this, $block, $player);
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
if(BlockEventHelper::grow($this, $block, $player)){
$item->pop();
}
}elseif(($dropAmount = $this->getBerryDropAmount()) > 0){
$world->setBlock($this->position, $this->setAge(self::STAGE_BUSH_NO_BERRIES));
$world->dropItem($this->position, $this->asItem()->setCount($dropAmount));
@ -133,11 +127,7 @@ class SweetBerryBush extends Flowable{
if($this->age < self::STAGE_MATURE && mt_rand(0, 2) === 1){
$block = clone $this;
++$block->age;
$ev = new BlockGrowEvent($this, $block);
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
}
BlockEventHelper::grow($this, $block, null);
}
}

View File

@ -41,7 +41,7 @@ class Thin extends Transparent{
foreach(Facing::HORIZONTAL as $facing){
$side = $this->getSide($facing);
if($side instanceof Thin || $side instanceof Wall || $side->isFullCube()){
if($side instanceof Thin || $side instanceof Wall || $side->getSupportType(Facing::opposite($facing))->equals(SupportType::FULL())){
$this->connections[$facing] = true;
}else{
unset($this->connections[$facing]);

View File

@ -59,6 +59,7 @@ use pocketmine\block\utils\SaplingType;
use pocketmine\block\utils\WoodType;
use pocketmine\crafting\FurnaceType;
use pocketmine\entity\projectile\Projectile;
use pocketmine\item\enchantment\ItemEnchantmentTags as EnchantmentTags;
use pocketmine\item\Item;
use pocketmine\item\ToolTier;
use pocketmine\math\Facing;
@ -573,6 +574,7 @@ use function mb_strtolower;
* @method static PackedIce PACKED_ICE()
* @method static Opaque PACKED_MUD()
* @method static DoublePlant PEONY()
* @method static PinkPetals PINK_PETALS()
* @method static Flower PINK_TULIP()
* @method static Podzol PODZOL()
* @method static Opaque POLISHED_ANDESITE()
@ -840,6 +842,7 @@ final class VanillaBlocks{
self::register("lilac", new DoublePlant(new BID(Ids::LILAC), "Lilac", new Info(BreakInfo::instant())));
self::register("rose_bush", new DoublePlant(new BID(Ids::ROSE_BUSH), "Rose Bush", new Info(BreakInfo::instant())));
self::register("peony", new DoublePlant(new BID(Ids::PEONY), "Peony", new Info(BreakInfo::instant())));
self::register("pink_petals", new PinkPetals(new BID(Ids::PINK_PETALS), "Pink Petals", new Info(BreakInfo::instant())));
self::register("double_tallgrass", new DoubleTallGrass(new BID(Ids::DOUBLE_TALLGRASS), "Double Tallgrass", new Info(BreakInfo::instant(ToolType::SHEARS, 1))));
self::register("large_fern", new DoubleTallGrass(new BID(Ids::LARGE_FERN), "Large Fern", new Info(BreakInfo::instant(ToolType::SHEARS, 1))));
self::register("dragon_egg", new DragonEgg(new BID(Ids::DRAGON_EGG), "Dragon Egg", new Info(BreakInfo::pickaxe(3.0, ToolTier::WOOD()))));
@ -964,7 +967,7 @@ final class VanillaBlocks{
$pumpkinBreakInfo = new Info(BreakInfo::axe(1.0));
self::register("pumpkin", new Pumpkin(new BID(Ids::PUMPKIN), "Pumpkin", $pumpkinBreakInfo));
self::register("carved_pumpkin", new CarvedPumpkin(new BID(Ids::CARVED_PUMPKIN), "Carved Pumpkin", $pumpkinBreakInfo));
self::register("carved_pumpkin", new CarvedPumpkin(new BID(Ids::CARVED_PUMPKIN), "Carved Pumpkin", new Info(BreakInfo::axe(1.0), enchantmentTags: [EnchantmentTags::MASK])));
self::register("lit_pumpkin", new LitPumpkin(new BID(Ids::LIT_PUMPKIN), "Jack o'Lantern", $pumpkinBreakInfo));
self::register("pumpkin_stem", new PumpkinStem(new BID(Ids::PUMPKIN_STEM), "Pumpkin Stem", new Info(BreakInfo::instant())));
@ -1000,7 +1003,7 @@ final class VanillaBlocks{
self::register("sea_lantern", new SeaLantern(new BID(Ids::SEA_LANTERN), "Sea Lantern", new Info(new BreakInfo(0.3))));
self::register("sea_pickle", new SeaPickle(new BID(Ids::SEA_PICKLE), "Sea Pickle", new Info(BreakInfo::instant())));
self::register("mob_head", new MobHead(new BID(Ids::MOB_HEAD, TileMobHead::class), "Mob Head", new Info(new BreakInfo(1.0))));
self::register("mob_head", new MobHead(new BID(Ids::MOB_HEAD, TileMobHead::class), "Mob Head", new Info(new BreakInfo(1.0), enchantmentTags: [EnchantmentTags::MASK])));
self::register("slime", new Slime(new BID(Ids::SLIME), "Slime Block", new Info(BreakInfo::instant())));
self::register("snow", new Snow(new BID(Ids::SNOW), "Snow Block", new Info(BreakInfo::shovel(0.2, ToolTier::WOOD()))));
self::register("snow_layer", new SnowLayer(new BID(Ids::SNOW_LAYER), "Snow Layer", new Info(BreakInfo::shovel(0.1, ToolTier::WOOD()))));
@ -1111,8 +1114,20 @@ final class VanillaBlocks{
self::register("lily_pad", new WaterLily(new BID(Ids::LILY_PAD), "Lily Pad", new Info(BreakInfo::instant())));
$weightedPressurePlateBreakInfo = new Info(BreakInfo::pickaxe(0.5, ToolTier::WOOD()));
self::register("weighted_pressure_plate_heavy", new WeightedPressurePlateHeavy(new BID(Ids::WEIGHTED_PRESSURE_PLATE_HEAVY), "Weighted Pressure Plate Heavy", $weightedPressurePlateBreakInfo));
self::register("weighted_pressure_plate_light", new WeightedPressurePlateLight(new BID(Ids::WEIGHTED_PRESSURE_PLATE_LIGHT), "Weighted Pressure Plate Light", $weightedPressurePlateBreakInfo));
self::register("weighted_pressure_plate_heavy", new WeightedPressurePlateHeavy(
new BID(Ids::WEIGHTED_PRESSURE_PLATE_HEAVY),
"Weighted Pressure Plate Heavy",
$weightedPressurePlateBreakInfo,
deactivationDelayTicks: 10,
signalStrengthFactor: 0.1
));
self::register("weighted_pressure_plate_light", new WeightedPressurePlateLight(
new BID(Ids::WEIGHTED_PRESSURE_PLATE_LIGHT),
"Weighted Pressure Plate Light",
$weightedPressurePlateBreakInfo,
deactivationDelayTicks: 10,
signalStrengthFactor: 1.0
));
self::register("wheat", new Wheat(new BID(Ids::WHEAT), "Wheat Block", new Info(BreakInfo::instant())));
$leavesBreakInfo = new Info(new class(0.2, ToolType::HOE) extends BreakInfo{
@ -1263,7 +1278,7 @@ final class VanillaBlocks{
self::register($idName("door"), new WoodenDoor(WoodLikeBlockIdHelper::getDoorIdentifier($woodType), $name . " Door", $woodenDoorBreakInfo, $woodType));
self::register($idName("button"), new WoodenButton(WoodLikeBlockIdHelper::getButtonIdentifier($woodType), $name . " Button", $woodenButtonBreakInfo, $woodType));
self::register($idName("pressure_plate"), new WoodenPressurePlate(WoodLikeBlockIdHelper::getPressurePlateIdentifier($woodType), $name . " Pressure Plate", $woodenPressurePlateBreakInfo, $woodType));
self::register($idName("pressure_plate"), new WoodenPressurePlate(WoodLikeBlockIdHelper::getPressurePlateIdentifier($woodType), $name . " Pressure Plate", $woodenPressurePlateBreakInfo, $woodType, 20));
self::register($idName("trapdoor"), new WoodenTrapdoor(WoodLikeBlockIdHelper::getTrapdoorIdentifier($woodType), $name . " Trapdoor", $woodenDoorBreakInfo, $woodType));
[$floorSignId, $wallSignId, $signAsItem] = WoodLikeBlockIdHelper::getSignInfo($woodType);
@ -1488,7 +1503,7 @@ final class VanillaBlocks{
$prefix = fn(string $thing) => "Polished Blackstone" . ($thing !== "" ? " $thing" : "");
self::register("polished_blackstone", new Opaque(new BID(Ids::POLISHED_BLACKSTONE), $prefix(""), $blackstoneBreakInfo));
self::register("polished_blackstone_button", new StoneButton(new BID(Ids::POLISHED_BLACKSTONE_BUTTON), $prefix("Button"), new Info(BreakInfo::pickaxe(0.5))));
self::register("polished_blackstone_pressure_plate", new StonePressurePlate(new BID(Ids::POLISHED_BLACKSTONE_PRESSURE_PLATE), $prefix("Pressure Plate"), new Info(BreakInfo::pickaxe(0.5, ToolTier::WOOD()))));
self::register("polished_blackstone_pressure_plate", new StonePressurePlate(new BID(Ids::POLISHED_BLACKSTONE_PRESSURE_PLATE), $prefix("Pressure Plate"), new Info(BreakInfo::pickaxe(0.5, ToolTier::WOOD())), 20));
self::register("polished_blackstone_slab", new Slab(new BID(Ids::POLISHED_BLACKSTONE_SLAB), $prefix(""), $slabBreakInfo));
self::register("polished_blackstone_stairs", new Stair(new BID(Ids::POLISHED_BLACKSTONE_STAIRS), $prefix("Stairs"), $blackstoneBreakInfo));
self::register("polished_blackstone_wall", new Wall(new BID(Ids::POLISHED_BLACKSTONE_WALL), $prefix("Wall"), $blackstoneBreakInfo));

View File

@ -101,7 +101,7 @@ class Wall extends Transparent{
foreach(Facing::HORIZONTAL as $facing){
$block = $this->getSide($facing);
if($block instanceof static || $block instanceof FenceGate || $block instanceof Thin || ($block->isSolid() && !$block->isTransparent())){
if($block instanceof static || $block instanceof FenceGate || $block instanceof Thin || $block->getSupportType(Facing::opposite($facing))->equals(SupportType::FULL())){
if(!isset($this->connections[$facing])){
$this->connections[$facing] = WallConnectionType::SHORT();
$changed++;

View File

@ -24,7 +24,40 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait;
use function ceil;
use function count;
use function max;
use function min;
abstract class WeightedPressurePlate extends PressurePlate{
class WeightedPressurePlate extends PressurePlate{
use AnalogRedstoneSignalEmitterTrait;
private readonly float $signalStrengthFactor;
/**
* @param float $signalStrengthFactor Number of entities on the plate is divided by this value to get signal strength
*/
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, int $deactivationDelayTicks, float $signalStrengthFactor = 1.0){
parent::__construct($idInfo, $name, $typeInfo, $deactivationDelayTicks);
$this->signalStrengthFactor = $signalStrengthFactor;
}
protected function hasOutputSignal() : bool{
return $this->signalStrength > 0;
}
protected function calculatePlateState(array $entities) : array{
$newSignalStrength = min(15, max(0,
(int) ceil(count($entities) * $this->signalStrengthFactor)
));
if($newSignalStrength === $this->signalStrength){
return [$this, null];
}
$wasActive = $this->signalStrength !== 0;
$isActive = $newSignalStrength !== 0;
return [
(clone $this)->setOutputSignalStrength($newSignalStrength),
$wasActive !== $isActive ? $isActive : null
];
}
}

View File

@ -23,6 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
/**
* @deprecated
*/
class WeightedPressurePlateHeavy extends WeightedPressurePlate{
}

View File

@ -23,6 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
/**
* @deprecated
*/
class WeightedPressurePlateLight extends WeightedPressurePlate{
}

View File

@ -35,4 +35,8 @@ class WoodenButton extends Button{
public function hasEntityCollision() : bool{
return false; //TODO: arrows activate wooden buttons
}
public function getFuelTime() : int{
return $this->woodType->isFlammable() ? 100 : 0;
}
}

View File

@ -27,4 +27,8 @@ use pocketmine\block\utils\WoodTypeTrait;
class WoodenDoor extends Door{
use WoodTypeTrait;
public function getFuelTime() : int{
return $this->woodType->isFlammable() ? 200 : 0;
}
}

View File

@ -23,11 +23,23 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\WoodType;
use pocketmine\block\utils\WoodTypeTrait;
class WoodenPressurePlate extends SimplePressurePlate{
use WoodTypeTrait;
public function __construct(
BlockIdentifier $idInfo,
string $name,
BlockTypeInfo $typeInfo,
WoodType $woodType,
int $deactivationDelayTicks = 20 //TODO: make this mandatory in PM6
){
$this->woodType = $woodType;
parent::__construct($idInfo, $name, $typeInfo, $deactivationDelayTicks);
}
public function getFuelTime() : int{
return 300;
}

View File

@ -23,9 +23,15 @@ declare(strict_types=1);
namespace pocketmine\block\inventory;
use pocketmine\event\player\PlayerEnchantingOptionsRequestEvent;
use pocketmine\inventory\SimpleInventory;
use pocketmine\inventory\TemporaryInventory;
use pocketmine\item\enchantment\EnchantingHelper as Helper;
use pocketmine\item\enchantment\EnchantingOption;
use pocketmine\item\Item;
use pocketmine\world\Position;
use function array_values;
use function count;
class EnchantInventory extends SimpleInventory implements BlockInventory, TemporaryInventory{
use BlockInventoryTrait;
@ -33,8 +39,47 @@ class EnchantInventory extends SimpleInventory implements BlockInventory, Tempor
public const SLOT_INPUT = 0;
public const SLOT_LAPIS = 1;
/** @var EnchantingOption[] $options */
private array $options = [];
public function __construct(Position $holder){
$this->holder = $holder;
parent::__construct(2);
}
protected function onSlotChange(int $index, Item $before) : void{
if($index === self::SLOT_INPUT){
foreach($this->viewers as $viewer){
$this->options = [];
$item = $this->getInput();
$options = Helper::generateOptions($this->holder, $item, $viewer->getEnchantmentSeed());
$event = new PlayerEnchantingOptionsRequestEvent($viewer, $this, $options);
$event->call();
if(!$event->isCancelled() && count($event->getOptions()) > 0){
$this->options = array_values($event->getOptions());
$viewer->getNetworkSession()->getInvManager()?->syncEnchantingTableOptions($this->options);
}
}
}
parent::onSlotChange($index, $before);
}
public function getInput() : Item{
return $this->getItem(self::SLOT_INPUT);
}
public function getLapis() : Item{
return $this->getItem(self::SLOT_LAPIS);
}
public function getOutput(int $optionId) : ?Item{
$option = $this->getOption($optionId);
return $option === null ? null : Helper::enchantItem($this->getInput(), $option->getEnchantments());
}
public function getOption(int $optionId) : ?EnchantingOption{
return $this->options[$optionId] ?? null;
}
}

View File

@ -32,6 +32,6 @@ final class SmithingTableInventory extends SimpleInventory implements BlockInven
public function __construct(Position $holder){
$this->holder = $holder;
parent::__construct(2);
parent::__construct(3);
}
}

View File

@ -68,6 +68,8 @@ class Sign extends Spawnable{
}
protected SignText $text;
private bool $waxed = false;
protected ?int $editorEntityRuntimeId = null;
public function __construct(World $world, Vector3 $pos){
@ -101,6 +103,7 @@ class Sign extends Spawnable{
}
$this->text = new SignText($text);
}
$this->waxed = $nbt->getByte(self::TAG_WAXED, 0) !== 0;
}
protected function writeSaveData(CompoundTag $nbt) : void{
@ -113,6 +116,7 @@ class Sign extends Spawnable{
$nbt->setInt(self::TAG_TEXT_COLOR, Binary::signInt($this->text->getBaseColor()->toARGB()));
$nbt->setByte(self::TAG_GLOWING_TEXT, $this->text->isGlowing() ? 1 : 0);
$nbt->setByte(self::TAG_LEGACY_BUG_RESOLVE, 1);
$nbt->setByte(self::TAG_WAXED, $this->waxed ? 1 : 0);
}
public function getText() : SignText{
@ -123,6 +127,10 @@ class Sign extends Spawnable{
$this->text = $text;
}
public function isWaxed() : bool{ return $this->waxed; }
public function setWaxed(bool $waxed) : void{ $this->waxed = $waxed; }
/**
* Returns the entity runtime ID of the player who placed this sign. Only the player whose entity ID matches this
* one may edit the sign text.
@ -153,7 +161,7 @@ class Sign extends Spawnable{
->setByte(self::TAG_GLOWING_TEXT, 0)
->setByte(self::TAG_PERSIST_FORMATTING, 1)
);
$nbt->setByte(self::TAG_WAXED, 0);
$nbt->setByte(self::TAG_WAXED, $this->waxed ? 1 : 0);
$nbt->setLong(self::TAG_LOCKED_FOR_EDITING_BY, $this->editorEntityRuntimeId ?? -1);
}
}

View File

@ -0,0 +1,115 @@
<?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\block\Block;
use pocketmine\event\block\BlockDeathEvent;
use pocketmine\event\block\BlockFormEvent;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\block\BlockMeltEvent;
use pocketmine\event\block\BlockSpreadEvent;
use pocketmine\player\Player;
/**
* Helper class to call block changing events and apply the results to the world.
* TODO: try to further reduce the amount of code duplication here - while this is much better than before, it's still
* very repetitive.
*/
final class BlockEventHelper{
public static function grow(Block $oldState, Block $newState, ?Player $causingPlayer) : bool{
if(BlockGrowEvent::hasHandlers()){
$ev = new BlockGrowEvent($oldState, $newState, $causingPlayer);
$ev->call();
if($ev->isCancelled()){
return false;
}
$newState = $ev->getNewState();
}
$position = $oldState->getPosition();
$position->getWorld()->setBlock($position, $newState);
return true;
}
public static function spread(Block $oldState, Block $newState, Block $source) : bool{
if(BlockSpreadEvent::hasHandlers()){
$ev = new BlockSpreadEvent($oldState, $source, $newState);
$ev->call();
if($ev->isCancelled()){
return false;
}
$newState = $ev->getNewState();
}
$position = $oldState->getPosition();
$position->getWorld()->setBlock($position, $newState);
return true;
}
public static function form(Block $oldState, Block $newState, Block $cause) : bool{
if(BlockFormEvent::hasHandlers()){
$ev = new BlockFormEvent($oldState, $newState, $cause);
$ev->call();
if($ev->isCancelled()){
return false;
}
$newState = $ev->getNewState();
}
$position = $oldState->getPosition();
$position->getWorld()->setBlock($position, $newState);
return true;
}
public static function melt(Block $oldState, Block $newState) : bool{
if(BlockMeltEvent::hasHandlers()){
$ev = new BlockMeltEvent($oldState, $newState);
$ev->call();
if($ev->isCancelled()){
return false;
}
$newState = $ev->getNewState();
}
$position = $oldState->getPosition();
$position->getWorld()->setBlock($position, $newState);
return true;
}
public static function die(Block $oldState, Block $newState) : bool{
if(BlockDeathEvent::hasHandlers()){
$ev = new BlockDeathEvent($oldState, $newState);
$ev->call();
if($ev->isCancelled()){
return false;
}
$newState = $ev->getNewState();
}
$position = $oldState->getPosition();
$position->getWorld()->setBlock($position, $newState);
return true;
}
}

View File

@ -33,6 +33,7 @@ use pocketmine\item\ItemTypeIds;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\BlazeShootSound;
use pocketmine\world\sound\FireExtinguishSound;
use pocketmine\world\sound\FlintSteelSound;
@ -57,12 +58,16 @@ trait CandleTrait{
/** @see Block::onInteract() */
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE || $item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
if($this->lit){
return true;
}
if($item instanceof Durable){
$item->applyDamage(1);
}elseif($item->getTypeId() === ItemTypeIds::FIRE_CHARGE){
$item->pop();
//TODO: not sure if this is intentional, but it's what Bedrock currently does as of 1.20.10
$this->position->getWorld()->addSound($this->position, new BlazeShootSound());
}
$this->position->getWorld()->addSound($this->position, new FlintSteelSound());
$this->position->getWorld()->setBlock($this->position, $this->setLit(true));

View File

@ -28,6 +28,7 @@ use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\GameMode;
use pocketmine\ServerProperties;
use function count;
class DefaultGamemodeCommand extends VanillaCommand{
@ -52,7 +53,7 @@ class DefaultGamemodeCommand extends VanillaCommand{
return true;
}
$sender->getServer()->getConfigGroup()->setConfigString("gamemode", $gameMode->name());
$sender->getServer()->getConfigGroup()->setConfigString(ServerProperties::GAME_MODE, $gameMode->name());
$sender->sendMessage(KnownTranslationFactory::commands_defaultgamemode_success($gameMode->getTranslatableName()));
return true;
}

View File

@ -28,6 +28,7 @@ use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\ServerProperties;
use pocketmine\world\World;
use function count;
@ -54,7 +55,7 @@ class DifficultyCommand extends VanillaCommand{
}
if($difficulty !== -1){
$sender->getServer()->getConfigGroup()->setConfigInt("difficulty", $difficulty);
$sender->getServer()->getConfigGroup()->setConfigInt(ServerProperties::DIFFICULTY, $difficulty);
//TODO: add per-world support
foreach($sender->getServer()->getWorldManager()->getWorlds() as $world){

View File

@ -25,6 +25,7 @@ namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender;
use pocketmine\command\utils\InvalidCommandSyntaxException;
use pocketmine\item\enchantment\EnchantingHelper;
use pocketmine\item\enchantment\EnchantmentInstance;
use pocketmine\item\enchantment\StringToEnchantmentParser;
use pocketmine\lang\KnownTranslationFactory;
@ -76,8 +77,9 @@ class EnchantCommand extends VanillaCommand{
}
}
$item->addEnchantment(new EnchantmentInstance($enchantment, $level));
$player->getInventory()->setItemInHand($item);
//this is necessary to deal with enchanted books, which are a different item type than regular books
$enchantedItem = EnchantingHelper::enchantItem($item, [new EnchantmentInstance($enchantment, $level)]);
$player->getInventory()->setItemInHand($enchantedItem);
self::broadcastCommandMessage($sender, KnownTranslationFactory::commands_enchant_success($player->getName()));
return true;

View File

@ -35,6 +35,7 @@ use pocketmine\timings\TimingsHandler;
use pocketmine\utils\InternetException;
use pocketmine\utils\InternetRequestResult;
use pocketmine\utils\Utils;
use pocketmine\YmlServerProperties;
use Symfony\Component\Filesystem\Path;
use function count;
use function fclose;
@ -130,7 +131,7 @@ class TimingsCommand extends VanillaCommand{
];
fclose($fileTimings);
$host = $sender->getServer()->getConfigGroup()->getPropertyString("timings.host", "timings.pmmp.io");
$host = $sender->getServer()->getConfigGroup()->getPropertyString(YmlServerProperties::TIMINGS_HOST, "timings.pmmp.io");
$sender->getServer()->getAsyncPool()->submitTask(new BulkCurlTask(
[new BulkCurlTaskOperation(

View File

@ -30,6 +30,7 @@ use pocketmine\lang\KnownTranslationFactory;
use pocketmine\permission\DefaultPermissionNames;
use pocketmine\player\Player;
use pocketmine\Server;
use pocketmine\ServerProperties;
use function count;
use function implode;
use function sort;
@ -71,7 +72,7 @@ class WhitelistCommand extends VanillaCommand{
case "on":
if($this->testPermission($sender, DefaultPermissionNames::COMMAND_WHITELIST_ENABLE)){
$server = $sender->getServer();
$server->getConfigGroup()->setConfigBool("white-list", true);
$server->getConfigGroup()->setConfigBool(ServerProperties::WHITELIST, true);
$this->kickNonWhitelistedPlayers($server);
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_whitelist_enabled());
}
@ -79,7 +80,7 @@ class WhitelistCommand extends VanillaCommand{
return true;
case "off":
if($this->testPermission($sender, DefaultPermissionNames::COMMAND_WHITELIST_DISABLE)){
$sender->getServer()->getConfigGroup()->setConfigBool("white-list", false);
$sender->getServer()->getConfigGroup()->setConfigBool(ServerProperties::WHITELIST, false);
Command::broadcastCommandMessage($sender, KnownTranslationFactory::commands_whitelist_disabled());
}

View File

@ -34,6 +34,7 @@ use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Filesystem;
use pocketmine\utils\Utils;
use pocketmine\VersionInfo;
use pocketmine\YmlServerProperties;
use Symfony\Component\Filesystem\Path;
use function array_map;
use function base64_encode;
@ -152,7 +153,7 @@ class CrashDump{
private function extraData() : void{
global $argv;
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-settings", true)){
if($this->server->getConfigGroup()->getPropertyBool(YmlServerProperties::AUTO_REPORT_SEND_SETTINGS, true)){
$this->data->parameters = (array) $argv;
if(($serverDotProperties = @file_get_contents(Path::join($this->server->getDataPath(), "server.properties"))) !== false){
$this->data->serverDotProperties = preg_replace("#^rcon\\.password=(.*)$#m", "rcon.password=******", $serverDotProperties) ?? throw new AssumptionFailedError("Pattern is valid");
@ -170,7 +171,7 @@ class CrashDump{
$this->data->jit_mode = Utils::getOpcacheJitMode();
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-phpinfo", true)){
if($this->server->getConfigGroup()->getPropertyBool(YmlServerProperties::AUTO_REPORT_SEND_PHPINFO, true)){
ob_start();
phpinfo();
$this->data->phpinfo = ob_get_contents(); // @phpstan-ignore-line
@ -199,12 +200,14 @@ class CrashDump{
if(($pos = strpos($error["message"], "\n")) !== false){
$error["message"] = substr($error["message"], 0, $pos);
}
$error["thread"] = "Main";
}
$error["message"] = mb_scrub($error["message"], 'UTF-8');
if(isset($lastError)){
$this->data->lastError = $lastError;
$this->data->lastError["message"] = mb_scrub($this->data->lastError["message"], 'UTF-8');
$this->data->lastError["trace"] = array_map(array: $lastError["trace"], callback: fn(ThreadCrashInfoFrame $frame) => $frame->getPrintableFrame());
}
$this->data->error = $error;
@ -224,7 +227,7 @@ class CrashDump{
}
}
if($this->server->getConfigGroup()->getPropertyBool("auto-report.send-code", true) && file_exists($error["fullFile"])){
if($this->server->getConfigGroup()->getPropertyBool(YmlServerProperties::AUTO_REPORT_SEND_CODE, true) && file_exists($error["fullFile"])){
$file = @file($error["fullFile"], FILE_IGNORE_NEW_LINES);
if($file !== false){
for($l = max(0, $error["line"] - 10); $l < $error["line"] + 10 && isset($file[$l]); ++$l){

View File

@ -29,18 +29,10 @@ use pocketmine\utils\SingletonTrait;
final class DyeColorIdMap{
use SingletonTrait;
/**
* @var DyeColor[]
* @phpstan-var array<int, DyeColor>
*/
private array $idToEnum = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enumToId = [];
/** @phpstan-use IntSaveIdMapTrait<DyeColor> */
use IntSaveIdMapTrait {
register as registerInt;
}
/**
* @var DyeColor[]
@ -74,16 +66,11 @@ final class DyeColorIdMap{
}
private function register(int $id, string $itemId, DyeColor $color) : void{
$this->idToEnum[$id] = $color;
$this->enumToId[$color->id()] = $id;
$this->registerInt($id, $color);
$this->itemIdToEnum[$itemId] = $color;
$this->enumToItemId[$color->id()] = $itemId;
}
public function toId(DyeColor $color) : int{
return $this->enumToId[$color->id()]; //TODO: is it possible for this to be missing?
}
public function toInvertedId(DyeColor $color) : int{
return ~$this->toId($color) & 0xf;
}
@ -92,10 +79,6 @@ final class DyeColorIdMap{
return $this->enumToItemId[$color->id()];
}
public function fromId(int $id) : ?DyeColor{
return $this->idToEnum[$id] ?? null;
}
public function fromInvertedId(int $id) : ?DyeColor{
return $this->fromId(~$id & 0xf);
}

View File

@ -26,23 +26,11 @@ namespace pocketmine\data\bedrock;
use pocketmine\entity\effect\Effect;
use pocketmine\entity\effect\VanillaEffects;
use pocketmine\utils\SingletonTrait;
use function array_key_exists;
use function spl_object_id;
final class EffectIdMap{
use SingletonTrait;
/**
* @var Effect[]
* @phpstan-var array<int, Effect>
*/
private array $idToEffect = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $effectToId = [];
/** @phpstan-use IntSaveIdMapTrait<Effect> */
use IntSaveIdMapTrait;
private function __construct(){
$this->register(EffectIds::SPEED, VanillaEffects::SPEED());
@ -76,24 +64,4 @@ final class EffectIdMap{
//TODO: VILLAGE_HERO
$this->register(EffectIds::DARKNESS, VanillaEffects::DARKNESS());
}
//TODO: not a big fan of the code duplication here :(
public function register(int $mcpeId, Effect $effect) : void{
$this->idToEffect[$mcpeId] = $effect;
$this->effectToId[spl_object_id($effect)] = $mcpeId;
}
public function fromId(int $id) : ?Effect{
//we might not have all the effect IDs registered
return $this->idToEffect[$id] ?? null;
}
public function toId(Effect $effect) : int{
if(!array_key_exists(spl_object_id($effect), $this->effectToId)){
//this should never happen, so we treat it as an exceptional condition
throw new \InvalidArgumentException("Effect does not have a mapped ID");
}
return $this->effectToId[spl_object_id($effect)];
}
}

View File

@ -26,25 +26,14 @@ namespace pocketmine\data\bedrock;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\utils\SingletonTrait;
use function array_key_exists;
use function spl_object_id;
/**
* Handles translation of internal enchantment types to and from Minecraft: Bedrock IDs.
*/
final class EnchantmentIdMap{
use SingletonTrait;
/**
* @var Enchantment[]
* @phpstan-var array<int, Enchantment>
*/
private array $idToEnch = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enchToId = [];
/** @phpstan-use IntSaveIdMapTrait<Enchantment> */
use IntSaveIdMapTrait;
private function __construct(){
$this->register(EnchantmentIds::PROTECTION, VanillaEnchantments::PROTECTION());
@ -77,22 +66,4 @@ final class EnchantmentIdMap{
$this->register(EnchantmentIds::SWIFT_SNEAK, VanillaEnchantments::SWIFT_SNEAK());
}
public function register(int $mcpeId, Enchantment $enchantment) : void{
$this->idToEnch[$mcpeId] = $enchantment;
$this->enchToId[spl_object_id($enchantment)] = $mcpeId;
}
public function fromId(int $id) : ?Enchantment{
//we might not have all the enchantment IDs registered
return $this->idToEnch[$id] ?? null;
}
public function toId(Enchantment $enchantment) : int{
if(!array_key_exists(spl_object_id($enchantment), $this->enchToId)){
//this should never happen, so we treat it as an exceptional condition
throw new \InvalidArgumentException("Enchantment does not have a mapped ID");
}
return $this->enchToId[spl_object_id($enchantment)];
}
}

View File

@ -0,0 +1,81 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock;
use function array_key_exists;
use function spl_object_id;
/**
* @phpstan-template TObject of object
*/
trait IntSaveIdMapTrait{
/**
* @var object[]
* @phpstan-var array<int, TObject>
*/
private array $idToEnum = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enumToId = [];
/**
* @phpstan-param TObject $enum
*/
protected function getRuntimeId(object $enum) : int{
//this is fine for enums and non-cloning object registries
return spl_object_id($enum);
}
/**
* @phpstan-param TObject $enum
*/
public function register(int $saveId, object $enum) : void{
$this->idToEnum[$saveId] = $enum;
$this->enumToId[$this->getRuntimeId($enum)] = $saveId;
}
/**
* @phpstan-return TObject|null
*/
public function fromId(int $id) : ?object{
//we might not have all the effect IDs registered
return $this->idToEnum[$id] ?? null;
}
/**
* @phpstan-param TObject $enum
*/
public function toId(object $enum) : int{
$runtimeId = $this->getRuntimeId($enum);
if(!array_key_exists($runtimeId, $this->enumToId)){
//this should never happen, so we treat it as an exceptional condition
throw new \InvalidArgumentException("Object does not have a mapped save ID");
}
return $this->enumToId[$runtimeId];
}
}

View File

@ -28,18 +28,8 @@ use pocketmine\utils\SingletonTrait;
final class MedicineTypeIdMap{
use SingletonTrait;
/**
* @var MedicineType[]
* @phpstan-var array<int, MedicineType>
*/
private array $idToEnum = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enumToId = [];
/** @phpstan-use IntSaveIdMapTrait<MedicineType> */
use IntSaveIdMapTrait;
private function __construct(){
$this->register(MedicineTypeIds::ANTIDOTE, MedicineType::ANTIDOTE());
@ -47,20 +37,4 @@ final class MedicineTypeIdMap{
$this->register(MedicineTypeIds::EYE_DROPS, MedicineType::EYE_DROPS());
$this->register(MedicineTypeIds::TONIC, MedicineType::TONIC());
}
private function register(int $id, MedicineType $type) : void{
$this->idToEnum[$id] = $type;
$this->enumToId[$type->id()] = $id;
}
public function fromId(int $id) : ?MedicineType{
return $this->idToEnum[$id] ?? null;
}
public function toId(MedicineType $type) : int{
if(!isset($this->enumToId[$type->id()])){
throw new \InvalidArgumentException("Type does not have a mapped ID");
}
return $this->enumToId[$type->id()];
}
}

View File

@ -28,18 +28,8 @@ use pocketmine\utils\SingletonTrait;
final class MobHeadTypeIdMap{
use SingletonTrait;
/**
* @var MobHeadType[]
* @phpstan-var array<int, MobHeadType>
*/
private array $idToEnum = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enumToId = [];
/** @phpstan-use IntSaveIdMapTrait<MobHeadType> */
use IntSaveIdMapTrait;
private function __construct(){
$this->register(0, MobHeadType::SKELETON());
@ -50,20 +40,4 @@ final class MobHeadTypeIdMap{
$this->register(5, MobHeadType::DRAGON());
$this->register(6, MobHeadType::PIGLIN());
}
private function register(int $id, MobHeadType $type) : void{
$this->idToEnum[$id] = $type;
$this->enumToId[$type->id()] = $id;
}
public function fromId(int $id) : ?MobHeadType{
return $this->idToEnum[$id] ?? null;
}
public function toId(MobHeadType $type) : int{
if(!isset($this->enumToId[$type->id()])){
throw new \InvalidArgumentException("Type does not have a mapped ID");
}
return $this->enumToId[$type->id()];
}
}

View File

@ -26,21 +26,11 @@ namespace pocketmine\data\bedrock;
use pocketmine\block\utils\MushroomBlockType;
use pocketmine\data\bedrock\block\BlockLegacyMetadata as LegacyMeta;
use pocketmine\utils\SingletonTrait;
use function array_key_exists;
final class MushroomBlockTypeIdMap{
use SingletonTrait;
/**
* @var MushroomBlockType[]
* @phpstan-var array<int, MushroomBlockType>
*/
private array $idToEnum = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enumToId = [];
/** @phpstan-use IntSaveIdMapTrait<MushroomBlockType> */
use IntSaveIdMapTrait;
public function __construct(){
$this->register(LegacyMeta::MUSHROOM_BLOCK_ALL_PORES, MushroomBlockType::PORES());
@ -55,20 +45,4 @@ final class MushroomBlockTypeIdMap{
$this->register(LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER, MushroomBlockType::CAP_SOUTHEAST());
$this->register(LegacyMeta::MUSHROOM_BLOCK_ALL_CAP, MushroomBlockType::ALL_CAP());
}
public function register(int $id, MushroomBlockType $type) : void{
$this->idToEnum[$id] = $type;
$this->enumToId[$type->id()] = $id;
}
public function fromId(int $id) : ?MushroomBlockType{
return $this->idToEnum[$id] ?? null;
}
public function toId(MushroomBlockType $type) : int{
if(!array_key_exists($type->id(), $this->enumToId)){
throw new \InvalidArgumentException("Mushroom block type does not have a mapped ID"); //this should never happen
}
return $this->enumToId[$type->id()];
}
}

View File

@ -28,18 +28,8 @@ use pocketmine\world\sound\NoteInstrument;
final class NoteInstrumentIdMap{
use SingletonTrait;
/**
* @var NoteInstrument[]
* @phpstan-var array<int, NoteInstrument>
*/
private array $idToEnum = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enumToId = [];
/** @phpstan-use IntSaveIdMapTrait<NoteInstrument> */
use IntSaveIdMapTrait;
private function __construct(){
$this->register(0, NoteInstrument::PIANO());
@ -59,20 +49,4 @@ final class NoteInstrumentIdMap{
$this->register(14, NoteInstrument::BANJO());
$this->register(15, NoteInstrument::PLING());
}
private function register(int $id, NoteInstrument $instrument) : void{
$this->idToEnum[$id] = $instrument;
$this->enumToId[$instrument->id()] = $id;
}
public function fromId(int $id) : ?NoteInstrument{
return $this->idToEnum[$id] ?? null;
}
public function toId(NoteInstrument $instrument) : int{
if(!isset($this->enumToId[$instrument->id()])){
throw new \InvalidArgumentException("Type does not have a mapped ID");
}
return $this->enumToId[$instrument->id()];
}
}

View File

@ -28,18 +28,8 @@ use pocketmine\utils\SingletonTrait;
final class PotionTypeIdMap{
use SingletonTrait;
/**
* @var PotionType[]
* @phpstan-var array<int, PotionType>
*/
private array $idToEnum = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enumToId = [];
/** @phpstan-use IntSaveIdMapTrait<PotionType> */
use IntSaveIdMapTrait;
private function __construct(){
$this->register(PotionTypeIds::WATER, PotionType::WATER());
@ -86,20 +76,4 @@ final class PotionTypeIdMap{
$this->register(PotionTypeIds::LONG_SLOW_FALLING, PotionType::LONG_SLOW_FALLING());
$this->register(PotionTypeIds::STRONG_SLOWNESS, PotionType::STRONG_SLOWNESS());
}
private function register(int $id, PotionType $type) : void{
$this->idToEnum[$id] = $type;
$this->enumToId[$type->id()] = $id;
}
public function fromId(int $id) : ?PotionType{
return $this->idToEnum[$id] ?? null;
}
public function toId(PotionType $type) : int{
if(!isset($this->enumToId[$type->id()])){
throw new \InvalidArgumentException("Type does not have a mapped ID");
}
return $this->enumToId[$type->id()];
}
}

View File

@ -28,18 +28,8 @@ use pocketmine\utils\SingletonTrait;
final class SuspiciousStewTypeIdMap{
use SingletonTrait;
/**
* @var SuspiciousStewType[]
* @phpstan-var array<int, SuspiciousStewType>
*/
private array $idToEnum = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private array $enumToId = [];
/** @phpstan-use IntSaveIdMapTrait<SuspiciousStewType> */
use IntSaveIdMapTrait;
private function __construct(){
$this->register(SuspiciousStewTypeIds::POPPY, SuspiciousStewType::POPPY());
@ -53,20 +43,4 @@ final class SuspiciousStewTypeIdMap{
$this->register(SuspiciousStewTypeIds::OXEYE_DAISY, SuspiciousStewType::OXEYE_DAISY());
$this->register(SuspiciousStewTypeIds::WITHER_ROSE, SuspiciousStewType::WITHER_ROSE());
}
private function register(int $id, SuspiciousStewType $type) : void{
$this->idToEnum[$id] = $type;
$this->enumToId[$type->id()] = $id;
}
public function fromId(int $id) : ?SuspiciousStewType{
return $this->idToEnum[$id] ?? null;
}
public function toId(SuspiciousStewType $type) : int{
if(!isset($this->enumToId[$type->id()])){
throw new \InvalidArgumentException("Type does not have a mapped ID");
}
return $this->enumToId[$type->id()];
}
}

View File

@ -42,8 +42,8 @@ final class BlockStateData{
public const CURRENT_VERSION =
(1 << 24) | //major
(20 << 16) | //minor
(10 << 8) | //patch
(32); //revision
(40 << 8) | //patch
(3); //revision
public const TAG_NAME = "name";
public const TAG_STATES = "states";

View File

@ -98,8 +98,10 @@ final class BlockStateNames{
public const LEVER_DIRECTION = "lever_direction";
public const LIQUID_DEPTH = "liquid_depth";
public const LIT = "lit";
public const MC_BLOCK_FACE = "minecraft:block_face";
public const MC_CARDINAL_DIRECTION = "minecraft:cardinal_direction";
public const MC_FACING_DIRECTION = "minecraft:facing_direction";
public const MC_VERTICAL_HALF = "minecraft:vertical_half";
public const MOISTURIZED_AMOUNT = "moisturized_amount";
public const MONSTER_EGG_STONE_TYPE = "monster_egg_stone_type";
public const MULTI_FACE_DIRECTION_BITS = "multi_face_direction_bits";
@ -141,7 +143,6 @@ final class BlockStateNames{
public const SUSPENDED_BIT = "suspended_bit";
public const TALL_GRASS_TYPE = "tall_grass_type";
public const TOGGLE_BIT = "toggle_bit";
public const TOP_SLOT_BIT = "top_slot_bit";
public const TORCH_FACING_DIRECTION = "torch_facing_direction";
public const TRIGGERED_BIT = "triggered_bit";
public const TURTLE_EGG_COUNT = "turtle_egg_count";

View File

@ -131,6 +131,13 @@ final class BlockStateStringValues{
public const LEVER_DIRECTION_UP_NORTH_SOUTH = "up_north_south";
public const LEVER_DIRECTION_WEST = "west";
public const MC_BLOCK_FACE_DOWN = "down";
public const MC_BLOCK_FACE_EAST = "east";
public const MC_BLOCK_FACE_NORTH = "north";
public const MC_BLOCK_FACE_SOUTH = "south";
public const MC_BLOCK_FACE_UP = "up";
public const MC_BLOCK_FACE_WEST = "west";
public const MC_CARDINAL_DIRECTION_EAST = "east";
public const MC_CARDINAL_DIRECTION_NORTH = "north";
public const MC_CARDINAL_DIRECTION_SOUTH = "south";
@ -143,6 +150,9 @@ final class BlockStateStringValues{
public const MC_FACING_DIRECTION_UP = "up";
public const MC_FACING_DIRECTION_WEST = "west";
public const MC_VERTICAL_HALF_BOTTOM = "bottom";
public const MC_VERTICAL_HALF_TOP = "top";
public const MONSTER_EGG_STONE_TYPE_CHISELED_STONE_BRICK = "chiseled_stone_brick";
public const MONSTER_EGG_STONE_TYPE_COBBLESTONE = "cobblestone";
public const MONSTER_EGG_STONE_TYPE_CRACKED_STONE_BRICK = "cracked_stone_brick";

View File

@ -99,8 +99,12 @@ final class BlockTypeNames{
public const BLACK_CANDLE_CAKE = "minecraft:black_candle_cake";
public const BLACK_CARPET = "minecraft:black_carpet";
public const BLACK_CONCRETE = "minecraft:black_concrete";
public const BLACK_CONCRETE_POWDER = "minecraft:black_concrete_powder";
public const BLACK_GLAZED_TERRACOTTA = "minecraft:black_glazed_terracotta";
public const BLACK_SHULKER_BOX = "minecraft:black_shulker_box";
public const BLACK_STAINED_GLASS = "minecraft:black_stained_glass";
public const BLACK_STAINED_GLASS_PANE = "minecraft:black_stained_glass_pane";
public const BLACK_TERRACOTTA = "minecraft:black_terracotta";
public const BLACK_WOOL = "minecraft:black_wool";
public const BLACKSTONE = "minecraft:blackstone";
public const BLACKSTONE_DOUBLE_SLAB = "minecraft:blackstone_double_slab";
@ -112,9 +116,13 @@ final class BlockTypeNames{
public const BLUE_CANDLE_CAKE = "minecraft:blue_candle_cake";
public const BLUE_CARPET = "minecraft:blue_carpet";
public const BLUE_CONCRETE = "minecraft:blue_concrete";
public const BLUE_CONCRETE_POWDER = "minecraft:blue_concrete_powder";
public const BLUE_GLAZED_TERRACOTTA = "minecraft:blue_glazed_terracotta";
public const BLUE_ICE = "minecraft:blue_ice";
public const BLUE_SHULKER_BOX = "minecraft:blue_shulker_box";
public const BLUE_STAINED_GLASS = "minecraft:blue_stained_glass";
public const BLUE_STAINED_GLASS_PANE = "minecraft:blue_stained_glass_pane";
public const BLUE_TERRACOTTA = "minecraft:blue_terracotta";
public const BLUE_WOOL = "minecraft:blue_wool";
public const BONE_BLOCK = "minecraft:bone_block";
public const BOOKSHELF = "minecraft:bookshelf";
@ -127,10 +135,14 @@ final class BlockTypeNames{
public const BROWN_CANDLE_CAKE = "minecraft:brown_candle_cake";
public const BROWN_CARPET = "minecraft:brown_carpet";
public const BROWN_CONCRETE = "minecraft:brown_concrete";
public const BROWN_CONCRETE_POWDER = "minecraft:brown_concrete_powder";
public const BROWN_GLAZED_TERRACOTTA = "minecraft:brown_glazed_terracotta";
public const BROWN_MUSHROOM = "minecraft:brown_mushroom";
public const BROWN_MUSHROOM_BLOCK = "minecraft:brown_mushroom_block";
public const BROWN_SHULKER_BOX = "minecraft:brown_shulker_box";
public const BROWN_STAINED_GLASS = "minecraft:brown_stained_glass";
public const BROWN_STAINED_GLASS_PANE = "minecraft:brown_stained_glass_pane";
public const BROWN_TERRACOTTA = "minecraft:brown_terracotta";
public const BROWN_WOOL = "minecraft:brown_wool";
public const BUBBLE_COLUMN = "minecraft:bubble_column";
public const BUBBLE_CORAL = "minecraft:bubble_coral";
@ -194,7 +206,6 @@ final class BlockTypeNames{
public const COLORED_TORCH_RG = "minecraft:colored_torch_rg";
public const COMMAND_BLOCK = "minecraft:command_block";
public const COMPOSTER = "minecraft:composter";
public const CONCRETE_POWDER = "minecraft:concrete_powder";
public const CONDUIT = "minecraft:conduit";
public const COPPER_BLOCK = "minecraft:copper_block";
public const COPPER_ORE = "minecraft:copper_ore";
@ -235,8 +246,12 @@ final class BlockTypeNames{
public const CYAN_CANDLE_CAKE = "minecraft:cyan_candle_cake";
public const CYAN_CARPET = "minecraft:cyan_carpet";
public const CYAN_CONCRETE = "minecraft:cyan_concrete";
public const CYAN_CONCRETE_POWDER = "minecraft:cyan_concrete_powder";
public const CYAN_GLAZED_TERRACOTTA = "minecraft:cyan_glazed_terracotta";
public const CYAN_SHULKER_BOX = "minecraft:cyan_shulker_box";
public const CYAN_STAINED_GLASS = "minecraft:cyan_stained_glass";
public const CYAN_STAINED_GLASS_PANE = "minecraft:cyan_stained_glass_pane";
public const CYAN_TERRACOTTA = "minecraft:cyan_terracotta";
public const CYAN_WOOL = "minecraft:cyan_wool";
public const DARK_OAK_BUTTON = "minecraft:dark_oak_button";
public const DARK_OAK_DOOR = "minecraft:dark_oak_door";
@ -463,15 +478,23 @@ final class BlockTypeNames{
public const GRAY_CANDLE_CAKE = "minecraft:gray_candle_cake";
public const GRAY_CARPET = "minecraft:gray_carpet";
public const GRAY_CONCRETE = "minecraft:gray_concrete";
public const GRAY_CONCRETE_POWDER = "minecraft:gray_concrete_powder";
public const GRAY_GLAZED_TERRACOTTA = "minecraft:gray_glazed_terracotta";
public const GRAY_SHULKER_BOX = "minecraft:gray_shulker_box";
public const GRAY_STAINED_GLASS = "minecraft:gray_stained_glass";
public const GRAY_STAINED_GLASS_PANE = "minecraft:gray_stained_glass_pane";
public const GRAY_TERRACOTTA = "minecraft:gray_terracotta";
public const GRAY_WOOL = "minecraft:gray_wool";
public const GREEN_CANDLE = "minecraft:green_candle";
public const GREEN_CANDLE_CAKE = "minecraft:green_candle_cake";
public const GREEN_CARPET = "minecraft:green_carpet";
public const GREEN_CONCRETE = "minecraft:green_concrete";
public const GREEN_CONCRETE_POWDER = "minecraft:green_concrete_powder";
public const GREEN_GLAZED_TERRACOTTA = "minecraft:green_glazed_terracotta";
public const GREEN_SHULKER_BOX = "minecraft:green_shulker_box";
public const GREEN_STAINED_GLASS = "minecraft:green_stained_glass";
public const GREEN_STAINED_GLASS_PANE = "minecraft:green_stained_glass_pane";
public const GREEN_TERRACOTTA = "minecraft:green_terracotta";
public const GREEN_WOOL = "minecraft:green_wool";
public const GRINDSTONE = "minecraft:grindstone";
public const HANGING_ROOTS = "minecraft:hanging_roots";
@ -525,14 +548,22 @@ final class BlockTypeNames{
public const LIGHT_BLUE_CANDLE_CAKE = "minecraft:light_blue_candle_cake";
public const LIGHT_BLUE_CARPET = "minecraft:light_blue_carpet";
public const LIGHT_BLUE_CONCRETE = "minecraft:light_blue_concrete";
public const LIGHT_BLUE_CONCRETE_POWDER = "minecraft:light_blue_concrete_powder";
public const LIGHT_BLUE_GLAZED_TERRACOTTA = "minecraft:light_blue_glazed_terracotta";
public const LIGHT_BLUE_SHULKER_BOX = "minecraft:light_blue_shulker_box";
public const LIGHT_BLUE_STAINED_GLASS = "minecraft:light_blue_stained_glass";
public const LIGHT_BLUE_STAINED_GLASS_PANE = "minecraft:light_blue_stained_glass_pane";
public const LIGHT_BLUE_TERRACOTTA = "minecraft:light_blue_terracotta";
public const LIGHT_BLUE_WOOL = "minecraft:light_blue_wool";
public const LIGHT_GRAY_CANDLE = "minecraft:light_gray_candle";
public const LIGHT_GRAY_CANDLE_CAKE = "minecraft:light_gray_candle_cake";
public const LIGHT_GRAY_CARPET = "minecraft:light_gray_carpet";
public const LIGHT_GRAY_CONCRETE = "minecraft:light_gray_concrete";
public const LIGHT_GRAY_CONCRETE_POWDER = "minecraft:light_gray_concrete_powder";
public const LIGHT_GRAY_SHULKER_BOX = "minecraft:light_gray_shulker_box";
public const LIGHT_GRAY_STAINED_GLASS = "minecraft:light_gray_stained_glass";
public const LIGHT_GRAY_STAINED_GLASS_PANE = "minecraft:light_gray_stained_glass_pane";
public const LIGHT_GRAY_TERRACOTTA = "minecraft:light_gray_terracotta";
public const LIGHT_GRAY_WOOL = "minecraft:light_gray_wool";
public const LIGHT_WEIGHTED_PRESSURE_PLATE = "minecraft:light_weighted_pressure_plate";
public const LIGHTNING_ROD = "minecraft:lightning_rod";
@ -540,8 +571,12 @@ final class BlockTypeNames{
public const LIME_CANDLE_CAKE = "minecraft:lime_candle_cake";
public const LIME_CARPET = "minecraft:lime_carpet";
public const LIME_CONCRETE = "minecraft:lime_concrete";
public const LIME_CONCRETE_POWDER = "minecraft:lime_concrete_powder";
public const LIME_GLAZED_TERRACOTTA = "minecraft:lime_glazed_terracotta";
public const LIME_SHULKER_BOX = "minecraft:lime_shulker_box";
public const LIME_STAINED_GLASS = "minecraft:lime_stained_glass";
public const LIME_STAINED_GLASS_PANE = "minecraft:lime_stained_glass_pane";
public const LIME_TERRACOTTA = "minecraft:lime_terracotta";
public const LIME_WOOL = "minecraft:lime_wool";
public const LIT_BLAST_FURNACE = "minecraft:lit_blast_furnace";
public const LIT_DEEPSLATE_REDSTONE_ORE = "minecraft:lit_deepslate_redstone_ore";
@ -556,8 +591,12 @@ final class BlockTypeNames{
public const MAGENTA_CANDLE_CAKE = "minecraft:magenta_candle_cake";
public const MAGENTA_CARPET = "minecraft:magenta_carpet";
public const MAGENTA_CONCRETE = "minecraft:magenta_concrete";
public const MAGENTA_CONCRETE_POWDER = "minecraft:magenta_concrete_powder";
public const MAGENTA_GLAZED_TERRACOTTA = "minecraft:magenta_glazed_terracotta";
public const MAGENTA_SHULKER_BOX = "minecraft:magenta_shulker_box";
public const MAGENTA_STAINED_GLASS = "minecraft:magenta_stained_glass";
public const MAGENTA_STAINED_GLASS_PANE = "minecraft:magenta_stained_glass_pane";
public const MAGENTA_TERRACOTTA = "minecraft:magenta_terracotta";
public const MAGENTA_WOOL = "minecraft:magenta_wool";
public const MAGMA = "minecraft:magma";
public const MANGROVE_BUTTON = "minecraft:mangrove_button";
@ -620,8 +659,12 @@ final class BlockTypeNames{
public const ORANGE_CANDLE_CAKE = "minecraft:orange_candle_cake";
public const ORANGE_CARPET = "minecraft:orange_carpet";
public const ORANGE_CONCRETE = "minecraft:orange_concrete";
public const ORANGE_CONCRETE_POWDER = "minecraft:orange_concrete_powder";
public const ORANGE_GLAZED_TERRACOTTA = "minecraft:orange_glazed_terracotta";
public const ORANGE_SHULKER_BOX = "minecraft:orange_shulker_box";
public const ORANGE_STAINED_GLASS = "minecraft:orange_stained_glass";
public const ORANGE_STAINED_GLASS_PANE = "minecraft:orange_stained_glass_pane";
public const ORANGE_TERRACOTTA = "minecraft:orange_terracotta";
public const ORANGE_WOOL = "minecraft:orange_wool";
public const OXIDIZED_COPPER = "minecraft:oxidized_copper";
public const OXIDIZED_CUT_COPPER = "minecraft:oxidized_cut_copper";
@ -635,9 +678,13 @@ final class BlockTypeNames{
public const PINK_CANDLE_CAKE = "minecraft:pink_candle_cake";
public const PINK_CARPET = "minecraft:pink_carpet";
public const PINK_CONCRETE = "minecraft:pink_concrete";
public const PINK_CONCRETE_POWDER = "minecraft:pink_concrete_powder";
public const PINK_GLAZED_TERRACOTTA = "minecraft:pink_glazed_terracotta";
public const PINK_PETALS = "minecraft:pink_petals";
public const PINK_SHULKER_BOX = "minecraft:pink_shulker_box";
public const PINK_STAINED_GLASS = "minecraft:pink_stained_glass";
public const PINK_STAINED_GLASS_PANE = "minecraft:pink_stained_glass_pane";
public const PINK_TERRACOTTA = "minecraft:pink_terracotta";
public const PINK_WOOL = "minecraft:pink_wool";
public const PISTON = "minecraft:piston";
public const PISTON_ARM_COLLISION = "minecraft:piston_arm_collision";
@ -681,8 +728,12 @@ final class BlockTypeNames{
public const PURPLE_CANDLE_CAKE = "minecraft:purple_candle_cake";
public const PURPLE_CARPET = "minecraft:purple_carpet";
public const PURPLE_CONCRETE = "minecraft:purple_concrete";
public const PURPLE_CONCRETE_POWDER = "minecraft:purple_concrete_powder";
public const PURPLE_GLAZED_TERRACOTTA = "minecraft:purple_glazed_terracotta";
public const PURPLE_SHULKER_BOX = "minecraft:purple_shulker_box";
public const PURPLE_STAINED_GLASS = "minecraft:purple_stained_glass";
public const PURPLE_STAINED_GLASS_PANE = "minecraft:purple_stained_glass_pane";
public const PURPLE_TERRACOTTA = "minecraft:purple_terracotta";
public const PURPLE_WOOL = "minecraft:purple_wool";
public const PURPUR_BLOCK = "minecraft:purpur_block";
public const PURPUR_STAIRS = "minecraft:purpur_stairs";
@ -698,6 +749,7 @@ final class BlockTypeNames{
public const RED_CANDLE_CAKE = "minecraft:red_candle_cake";
public const RED_CARPET = "minecraft:red_carpet";
public const RED_CONCRETE = "minecraft:red_concrete";
public const RED_CONCRETE_POWDER = "minecraft:red_concrete_powder";
public const RED_FLOWER = "minecraft:red_flower";
public const RED_GLAZED_TERRACOTTA = "minecraft:red_glazed_terracotta";
public const RED_MUSHROOM = "minecraft:red_mushroom";
@ -707,6 +759,9 @@ final class BlockTypeNames{
public const RED_SANDSTONE = "minecraft:red_sandstone";
public const RED_SANDSTONE_STAIRS = "minecraft:red_sandstone_stairs";
public const RED_SHULKER_BOX = "minecraft:red_shulker_box";
public const RED_STAINED_GLASS = "minecraft:red_stained_glass";
public const RED_STAINED_GLASS_PANE = "minecraft:red_stained_glass_pane";
public const RED_TERRACOTTA = "minecraft:red_terracotta";
public const RED_WOOL = "minecraft:red_wool";
public const REDSTONE_BLOCK = "minecraft:redstone_block";
public const REDSTONE_LAMP = "minecraft:redstone_lamp";
@ -766,9 +821,6 @@ final class BlockTypeNames{
public const SPRUCE_STANDING_SIGN = "minecraft:spruce_standing_sign";
public const SPRUCE_TRAPDOOR = "minecraft:spruce_trapdoor";
public const SPRUCE_WALL_SIGN = "minecraft:spruce_wall_sign";
public const STAINED_GLASS = "minecraft:stained_glass";
public const STAINED_GLASS_PANE = "minecraft:stained_glass_pane";
public const STAINED_HARDENED_CLAY = "minecraft:stained_hardened_clay";
public const STANDING_BANNER = "minecraft:standing_banner";
public const STANDING_SIGN = "minecraft:standing_sign";
public const STICKY_PISTON = "minecraft:sticky_piston";
@ -883,8 +935,12 @@ final class BlockTypeNames{
public const WHITE_CANDLE_CAKE = "minecraft:white_candle_cake";
public const WHITE_CARPET = "minecraft:white_carpet";
public const WHITE_CONCRETE = "minecraft:white_concrete";
public const WHITE_CONCRETE_POWDER = "minecraft:white_concrete_powder";
public const WHITE_GLAZED_TERRACOTTA = "minecraft:white_glazed_terracotta";
public const WHITE_SHULKER_BOX = "minecraft:white_shulker_box";
public const WHITE_STAINED_GLASS = "minecraft:white_stained_glass";
public const WHITE_STAINED_GLASS_PANE = "minecraft:white_stained_glass_pane";
public const WHITE_TERRACOTTA = "minecraft:white_terracotta";
public const WHITE_WOOL = "minecraft:white_wool";
public const WITHER_ROSE = "minecraft:wither_rose";
public const WOOD = "minecraft:wood";
@ -896,8 +952,12 @@ final class BlockTypeNames{
public const YELLOW_CANDLE_CAKE = "minecraft:yellow_candle_cake";
public const YELLOW_CARPET = "minecraft:yellow_carpet";
public const YELLOW_CONCRETE = "minecraft:yellow_concrete";
public const YELLOW_CONCRETE_POWDER = "minecraft:yellow_concrete_powder";
public const YELLOW_FLOWER = "minecraft:yellow_flower";
public const YELLOW_GLAZED_TERRACOTTA = "minecraft:yellow_glazed_terracotta";
public const YELLOW_SHULKER_BOX = "minecraft:yellow_shulker_box";
public const YELLOW_STAINED_GLASS = "minecraft:yellow_stained_glass";
public const YELLOW_STAINED_GLASS_PANE = "minecraft:yellow_stained_glass_pane";
public const YELLOW_TERRACOTTA = "minecraft:yellow_terracotta";
public const YELLOW_WOOL = "minecraft:yellow_wool";
}

View File

@ -100,6 +100,7 @@ use pocketmine\block\MobHead;
use pocketmine\block\NetherPortal;
use pocketmine\block\NetherVines;
use pocketmine\block\NetherWartPlant;
use pocketmine\block\PinkPetals;
use pocketmine\block\Potato;
use pocketmine\block\PoweredRail;
use pocketmine\block\PumpkinStem;
@ -414,6 +415,86 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
DyeColor::YELLOW() => Ids::YELLOW_CONCRETE,
default => throw new AssumptionFailedError("Unhandled dye colour " . $color->name())
}));
$this->map(Blocks::CONCRETE_POWDER(), fn(ConcretePowder $block) => Writer::create(match($color = $block->getColor()){
DyeColor::BLACK() => Ids::BLACK_CONCRETE_POWDER,
DyeColor::BLUE() => Ids::BLUE_CONCRETE_POWDER,
DyeColor::BROWN() => Ids::BROWN_CONCRETE_POWDER,
DyeColor::CYAN() => Ids::CYAN_CONCRETE_POWDER,
DyeColor::GRAY() => Ids::GRAY_CONCRETE_POWDER,
DyeColor::GREEN() => Ids::GREEN_CONCRETE_POWDER,
DyeColor::LIGHT_BLUE() => Ids::LIGHT_BLUE_CONCRETE_POWDER,
DyeColor::LIGHT_GRAY() => Ids::LIGHT_GRAY_CONCRETE_POWDER,
DyeColor::LIME() => Ids::LIME_CONCRETE_POWDER,
DyeColor::MAGENTA() => Ids::MAGENTA_CONCRETE_POWDER,
DyeColor::ORANGE() => Ids::ORANGE_CONCRETE_POWDER,
DyeColor::PINK() => Ids::PINK_CONCRETE_POWDER,
DyeColor::PURPLE() => Ids::PURPLE_CONCRETE_POWDER,
DyeColor::RED() => Ids::RED_CONCRETE_POWDER,
DyeColor::WHITE() => Ids::WHITE_CONCRETE_POWDER,
DyeColor::YELLOW() => Ids::YELLOW_CONCRETE_POWDER,
default => throw new AssumptionFailedError("Unhandled dye colour " . $color->name())
}));
$this->map(Blocks::STAINED_CLAY(), fn(StainedHardenedClay $block) => Writer::create(match($color = $block->getColor()){
DyeColor::BLACK() => Ids::BLACK_TERRACOTTA,
DyeColor::BLUE() => Ids::BLUE_TERRACOTTA,
DyeColor::BROWN() => Ids::BROWN_TERRACOTTA,
DyeColor::CYAN() => Ids::CYAN_TERRACOTTA,
DyeColor::GRAY() => Ids::GRAY_TERRACOTTA,
DyeColor::GREEN() => Ids::GREEN_TERRACOTTA,
DyeColor::LIGHT_BLUE() => Ids::LIGHT_BLUE_TERRACOTTA,
DyeColor::LIGHT_GRAY() => Ids::LIGHT_GRAY_TERRACOTTA,
DyeColor::LIME() => Ids::LIME_TERRACOTTA,
DyeColor::MAGENTA() => Ids::MAGENTA_TERRACOTTA,
DyeColor::ORANGE() => Ids::ORANGE_TERRACOTTA,
DyeColor::PINK() => Ids::PINK_TERRACOTTA,
DyeColor::PURPLE() => Ids::PURPLE_TERRACOTTA,
DyeColor::RED() => Ids::RED_TERRACOTTA,
DyeColor::WHITE() => Ids::WHITE_TERRACOTTA,
DyeColor::YELLOW() => Ids::YELLOW_TERRACOTTA,
default => throw new AssumptionFailedError("Unhandled dye colour " . $color->name())
}));
$this->map(Blocks::STAINED_GLASS(), fn(StainedGlass $block) => Writer::create(match($color = $block->getColor()){
DyeColor::BLACK() => Ids::BLACK_STAINED_GLASS,
DyeColor::BLUE() => Ids::BLUE_STAINED_GLASS,
DyeColor::BROWN() => Ids::BROWN_STAINED_GLASS,
DyeColor::CYAN() => Ids::CYAN_STAINED_GLASS,
DyeColor::GRAY() => Ids::GRAY_STAINED_GLASS,
DyeColor::GREEN() => Ids::GREEN_STAINED_GLASS,
DyeColor::LIGHT_BLUE() => Ids::LIGHT_BLUE_STAINED_GLASS,
DyeColor::LIGHT_GRAY() => Ids::LIGHT_GRAY_STAINED_GLASS,
DyeColor::LIME() => Ids::LIME_STAINED_GLASS,
DyeColor::MAGENTA() => Ids::MAGENTA_STAINED_GLASS,
DyeColor::ORANGE() => Ids::ORANGE_STAINED_GLASS,
DyeColor::PINK() => Ids::PINK_STAINED_GLASS,
DyeColor::PURPLE() => Ids::PURPLE_STAINED_GLASS,
DyeColor::RED() => Ids::RED_STAINED_GLASS,
DyeColor::WHITE() => Ids::WHITE_STAINED_GLASS,
DyeColor::YELLOW() => Ids::YELLOW_STAINED_GLASS,
default => throw new AssumptionFailedError("Unhandled dye colour " . $color->name())
}));
$this->map(Blocks::STAINED_GLASS_PANE(), fn(StainedGlassPane $block) => Writer::create(match($color = $block->getColor()){
DyeColor::BLACK() => Ids::BLACK_STAINED_GLASS_PANE,
DyeColor::BLUE() => Ids::BLUE_STAINED_GLASS_PANE,
DyeColor::BROWN() => Ids::BROWN_STAINED_GLASS_PANE,
DyeColor::CYAN() => Ids::CYAN_STAINED_GLASS_PANE,
DyeColor::GRAY() => Ids::GRAY_STAINED_GLASS_PANE,
DyeColor::GREEN() => Ids::GREEN_STAINED_GLASS_PANE,
DyeColor::LIGHT_BLUE() => Ids::LIGHT_BLUE_STAINED_GLASS_PANE,
DyeColor::LIGHT_GRAY() => Ids::LIGHT_GRAY_STAINED_GLASS_PANE,
DyeColor::LIME() => Ids::LIME_STAINED_GLASS_PANE,
DyeColor::MAGENTA() => Ids::MAGENTA_STAINED_GLASS_PANE,
DyeColor::ORANGE() => Ids::ORANGE_STAINED_GLASS_PANE,
DyeColor::PINK() => Ids::PINK_STAINED_GLASS_PANE,
DyeColor::PURPLE() => Ids::PURPLE_STAINED_GLASS_PANE,
DyeColor::RED() => Ids::RED_STAINED_GLASS_PANE,
DyeColor::WHITE() => Ids::WHITE_STAINED_GLASS_PANE,
DyeColor::YELLOW() => Ids::YELLOW_STAINED_GLASS_PANE,
default => throw new AssumptionFailedError("Unhandled dye colour " . $color->name())
}));
}
private function registerFlatCoralSerializers() : void{
@ -904,7 +985,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::ANDESITE_WALL(), fn(Wall $block) => Helper::encodeLegacyWall($block, StringValues::WALL_BLOCK_TYPE_ANDESITE));
$this->map(Blocks::ANVIL(), function(Anvil $block) : Writer{
return Writer::create(Ids::ANVIL)
->writeLegacyHorizontalFacing($block->getFacing())
->writeCardinalHorizontalFacing($block->getFacing())
->writeString(StateNames::DAMAGE, match($damage = $block->getDamage()){
0 => StringValues::DAMAGE_UNDAMAGED,
1 => StringValues::DAMAGE_SLIGHTLY_DAMAGED,
@ -964,7 +1045,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
});
$this->map(Blocks::BIG_DRIPLEAF_HEAD(), function(BigDripleafHead $block) : Writer{
return Writer::create(Ids::BIG_DRIPLEAF)
->writeLegacyHorizontalFacing($block->getFacing())
->writeCardinalHorizontalFacing($block->getFacing())
->writeString(StateNames::BIG_DRIPLEAF_TILT, match($block->getLeafState()->id()){
DripleafState::STABLE()->id() => StringValues::BIG_DRIPLEAF_TILT_NONE,
DripleafState::UNSTABLE()->id() => StringValues::BIG_DRIPLEAF_TILT_UNSTABLE,
@ -976,7 +1057,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
});
$this->map(Blocks::BIG_DRIPLEAF_STEM(), function(BigDripleafStem $block) : Writer{
return Writer::create(Ids::BIG_DRIPLEAF)
->writeLegacyHorizontalFacing($block->getFacing())
->writeCardinalHorizontalFacing($block->getFacing())
->writeString(StateNames::BIG_DRIPLEAF_TILT, StringValues::BIG_DRIPLEAF_TILT_NONE)
->writeBool(StateNames::BIG_DRIPLEAF_HEAD, false);
});
@ -1032,7 +1113,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
});
$this->map(Blocks::CHEST(), function(Chest $block) : Writer{
return Writer::create(Ids::CHEST)
->writeHorizontalFacing($block->getFacing());
->writeCardinalHorizontalFacing($block->getFacing());
});
$this->map(Blocks::CHISELED_QUARTZ(), fn(SimplePillar $block) => Helper::encodeQuartz(StringValues::CHISEL_TYPE_CHISELED, $block->getAxis()));
$this->map(Blocks::CHISELED_RED_SANDSTONE(), fn() => Helper::encodeSandstone(Ids::RED_SANDSTONE, StringValues::SAND_STONE_TYPE_HEIROGLYPHS));
@ -1128,10 +1209,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeLegacyHorizontalFacing(Facing::opposite($block->getFacing()));
});
$this->map(Blocks::COMPOUND_CREATOR(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, StringValues::CHEMISTRY_TABLE_TYPE_COMPOUND_CREATOR, new Writer(Ids::CHEMISTRY_TABLE)));
$this->map(Blocks::CONCRETE_POWDER(), function(ConcretePowder $block) : Writer{
return Writer::create(Ids::CONCRETE_POWDER)
->writeColor($block->getColor());
});
$this->map(Blocks::CORAL_BLOCK(), function(CoralBlock $block) : Writer{
return Writer::create(Ids::CORAL_BLOCK)
->writeBool(StateNames::DEAD_BIT, $block->isDead())
@ -1197,12 +1274,12 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::ELEMENT_CONSTRUCTOR(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, StringValues::CHEMISTRY_TABLE_TYPE_ELEMENT_CONSTRUCTOR, new Writer(Ids::CHEMISTRY_TABLE)));
$this->map(Blocks::ENDER_CHEST(), function(EnderChest $block) : Writer{
return Writer::create(Ids::ENDER_CHEST)
->writeHorizontalFacing($block->getFacing());
->writeCardinalHorizontalFacing($block->getFacing());
});
$this->map(Blocks::END_PORTAL_FRAME(), function(EndPortalFrame $block) : Writer{
return Writer::create(Ids::END_PORTAL_FRAME)
->writeBool(StateNames::END_PORTAL_EYE_BIT, $block->hasEye())
->writeLegacyHorizontalFacing($block->getFacing());
->writeCardinalHorizontalFacing($block->getFacing());
});
$this->map(Blocks::END_ROD(), function(EndRod $block) : Writer{
return Writer::create(Ids::END_ROD)
@ -1290,7 +1367,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::LECTERN(), function(Lectern $block) : Writer{
return Writer::create(Ids::LECTERN)
->writeBool(StateNames::POWERED_BIT, $block->isProducingSignal())
->writeLegacyHorizontalFacing($block->getFacing());
->writeCardinalHorizontalFacing($block->getFacing());
});
$this->map(Blocks::LEVER(), function(Lever $block) : Writer{
return Writer::create(Ids::LEVER)
@ -1364,6 +1441,11 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
$this->map(Blocks::ORANGE_TULIP(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_TULIP_ORANGE));
$this->map(Blocks::OXEYE_DAISY(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_OXEYE));
$this->map(Blocks::PEONY(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, StringValues::DOUBLE_PLANT_TYPE_PAEONIA, Writer::create(Ids::DOUBLE_PLANT)));
$this->map(Blocks::PINK_PETALS(), function(PinkPetals $block) : Writer{
return Writer::create(Ids::PINK_PETALS)
->writeCardinalHorizontalFacing($block->getFacing())
->writeInt(StateNames::GROWTH, $block->getCount() - 1);
});
$this->map(Blocks::PINK_TULIP(), fn() => Helper::encodeRedFlower(StringValues::FLOWER_TYPE_TULIP_PINK));
$this->map(Blocks::POLISHED_ANDESITE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_ANDESITE_SMOOTH));
$this->map(Blocks::POLISHED_ANDESITE_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab3($block, StringValues::STONE_SLAB_TYPE_3_POLISHED_ANDESITE));
@ -1435,13 +1517,13 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
return Writer::create($block->isPowered() ? Ids::POWERED_COMPARATOR : Ids::UNPOWERED_COMPARATOR)
->writeBool(StateNames::OUTPUT_LIT_BIT, $block->isPowered())
->writeBool(StateNames::OUTPUT_SUBTRACT_BIT, $block->isSubtractMode())
->writeLegacyHorizontalFacing($block->getFacing());
->writeCardinalHorizontalFacing($block->getFacing());
});
$this->map(Blocks::REDSTONE_LAMP(), fn(RedstoneLamp $block) => new Writer($block->isPowered() ? Ids::LIT_REDSTONE_LAMP : Ids::REDSTONE_LAMP));
$this->map(Blocks::REDSTONE_ORE(), fn(RedstoneOre $block) => new Writer($block->isLit() ? Ids::LIT_REDSTONE_ORE : Ids::REDSTONE_ORE));
$this->map(Blocks::REDSTONE_REPEATER(), function(RedstoneRepeater $block) : Writer{
return Writer::create($block->isPowered() ? Ids::POWERED_REPEATER : Ids::UNPOWERED_REPEATER)
->writeLegacyHorizontalFacing($block->getFacing())
->writeCardinalHorizontalFacing($block->getFacing())
->writeInt(StateNames::REPEATER_DELAY, $block->getDelay() - 1);
});
$this->map(Blocks::REDSTONE_TORCH(), function(RedstoneTorch $block) : Writer{
@ -1478,7 +1560,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
});
$this->map(Blocks::SMALL_DRIPLEAF(), function(SmallDripleaf $block) : Writer{
return Writer::create(Ids::SMALL_DRIPLEAF_BLOCK)
->writeLegacyHorizontalFacing($block->getFacing())
->writeCardinalHorizontalFacing($block->getFacing())
->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop());
});
$this->map(Blocks::SMOKER(), fn(Furnace $block) => Helper::encodeFurnace($block, Ids::SMOKER, Ids::LIT_SMOKER));
@ -1514,18 +1596,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
->writeString(StateNames::SPONGE_TYPE, $block->isWet() ? StringValues::SPONGE_TYPE_WET : StringValues::SPONGE_TYPE_DRY);
});
$this->map(Blocks::SPRUCE_SAPLING(), fn(Sapling $block) => Helper::encodeSapling($block, StringValues::SAPLING_TYPE_SPRUCE));
$this->map(Blocks::STAINED_CLAY(), function(StainedHardenedClay $block) : Writer{
return Writer::create(Ids::STAINED_HARDENED_CLAY)
->writeColor($block->getColor());
});
$this->map(Blocks::STAINED_GLASS(), function(StainedGlass $block) : Writer{
return Writer::create(Ids::STAINED_GLASS)
->writeColor($block->getColor());
});
$this->map(Blocks::STAINED_GLASS_PANE(), function(StainedGlassPane $block) : Writer{
return Writer::create(Ids::STAINED_GLASS_PANE)
->writeColor($block->getColor());
});
$this->map(Blocks::STAINED_HARDENED_GLASS(), function(StainedHardenedGlass $block) : Writer{
return Writer::create(Ids::HARD_STAINED_GLASS)
->writeColor($block->getColor());
@ -1536,7 +1606,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
});
$this->map(Blocks::STONE(), fn() => Helper::encodeStone(StringValues::STONE_TYPE_STONE));
$this->map(Blocks::STONECUTTER(), fn(Stonecutter $block) => Writer::create(Ids::STONECUTTER_BLOCK)
->writeHorizontalFacing($block->getFacing()));
->writeCardinalHorizontalFacing($block->getFacing()));
$this->map(Blocks::STONE_BRICKS(), fn() => Helper::encodeStoneBricks(StringValues::STONE_BRICK_TYPE_DEFAULT));
$this->map(Blocks::STONE_BRICK_SLAB(), fn(Slab $block) => Helper::encodeStoneSlab1($block, StringValues::STONE_SLAB_TYPE_STONE_BRICK));
$this->mapStairs(Blocks::STONE_BRICK_STAIRS(), Ids::STONE_BRICK_STAIRS);
@ -1567,7 +1637,7 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{
});
$this->map(Blocks::TRAPPED_CHEST(), function(TrappedChest $block) : Writer{
return Writer::create(Ids::TRAPPED_CHEST)
->writeHorizontalFacing($block->getFacing());
->writeCardinalHorizontalFacing($block->getFacing());
});
$this->map(Blocks::TRIPWIRE(), function(Tripwire $block) : Writer{
return Writer::create(Ids::TRIP_WIRE)

View File

@ -93,7 +93,7 @@ final class BlockStateDeserializerHelper{
/** @throws BlockStateDeserializeException */
public static function decodeComparator(RedstoneComparator $block, BlockStateReader $in) : RedstoneComparator{
return $block
->setFacing($in->readLegacyHorizontalFacing())
->setFacing($in->readCardinalHorizontalFacing())
->setPowered($in->readBool(BlockStateNames::OUTPUT_LIT_BIT))
->setSubtractMode($in->readBool(BlockStateNames::OUTPUT_SUBTRACT_BIT));
}
@ -216,7 +216,7 @@ final class BlockStateDeserializerHelper{
/** @throws BlockStateDeserializeException */
public static function decodeRepeater(RedstoneRepeater $block, BlockStateReader $in) : RedstoneRepeater{
return $block
->setFacing($in->readLegacyHorizontalFacing())
->setFacing($in->readCardinalHorizontalFacing())
->setDelay($in->readBoundedInt(BlockStateNames::REPEATER_DELAY, 0, 3) + 1);
}

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