Compare commits

..

136 Commits

Author SHA1 Message Date
ee903cad1f Release 4.22.1 2023-06-09 01:33:35 +01:00
9a04481bec Entity: broadcast teleports as regular movements
fixes #5810

probably fixes #4986

#5810 was caused by the workaround for #4394, which broke in 1.20 for reasons I'm still unclear on.

As FLAG_TELEPORT does not work at all for non-player entities, and causes bugs with player entities, sending the teleport movement without the flag is the least buggy way to solve all of these issues. Having the client interpolate teleport movements is not ideal, but there doesn't seem to be a way to reliably prevent it without causing even more bugs, so this will have to do.
2023-06-09 01:24:57 +01:00
5d514a274f Merge branch 'legacy/pm4' of github.com:pmmp/PocketMine-MP into legacy/pm4 2023-06-07 21:24:13 +01:00
2220dc557e 4.22.1 is next 2023-06-07 21:23:57 +01:00
b5fc31a781 Release 4.22.0 2023-06-07 21:23:54 +01:00
179eec9754 PHP-CS-Fixer 3.17 2023-06-07 21:04:11 +01:00
441f1f534f Random change PHP-CS-Fixer wanted to make 2023-06-07 20:59:32 +01:00
e747478afd and one more 2023-06-07 20:58:15 +01:00
92c45dd7e1 Fixed PHPUnit deprecation warnings 2023-06-07 20:57:43 +01:00
2538880408 1.20.0 2023-06-07 20:56:59 +01:00
c715efb18e Jukebox: fix music not stopping when destroyed by explosion
closes #5794
2023-06-03 21:22:26 +01:00
6678360c00 Make changelogs less infuriating in PhpStorm 2023-06-02 13:34:16 +01:00
3db45b6a68 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2023-06-01 14:51:14 +01:00
3e87ad281f Use tagged fork of netresearch/jsonmapper
we need this for it to not be a huge pain in the ass to install PM as a composer dependency, which plugin CIs may do.
2023-06-01 14:51:04 +01:00
b72da777eb Bump tests/plugins/DevTools from a67f9af to a2f36e8 (#5785)
Bumps [tests/plugins/DevTools](https://github.com/pmmp/DevTools) from `a67f9af` to `a2f36e8`.
- [Release notes](https://github.com/pmmp/DevTools/releases)
- [Commits](a67f9af8d6...a2f36e8dbf)

---
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-06-01 13:45:20 +01:00
1101f35c17 Update setup-php-action to 2.0.0
this version vastly improves build time by using optimized prebuilts
instead of building the binaries on the runner.
2023-05-31 22:09:33 +01:00
3948dc4f75 Remove calls to ReflectionProperty::setAccessible() (#5783)
This is a no-op in PHP 8.1 and up.
2023-05-31 14:03:14 +01:00
20942b37eb Update composer dependencies 2023-05-30 16:07:01 +01:00
d343db8750 4.21.2 is next 2023-05-30 14:42:59 +01:00
f2df702c67 Release 4.21.1 2023-05-30 14:42:59 +01:00
481270e6aa Merge tag '4.20.5' into stable 2023-05-30 14:42:11 +01:00
e7bdaa8579 Release 4.20.5 2023-05-30 14:35:17 +01:00
76749cbaa7 Use fork of JsonMapper to solve cweiske/jsonmapper#210 2023-05-30 14:30:28 +01:00
a897bdfaa0 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2023-05-30 14:17:21 +01:00
09668a37d6 Use fork of JsonMapper to solve cweiske/JsonMapper#210 2023-05-30 14:17:09 +01:00
ea92a23d0d Bump build/php from b1d5c0d to f2ece7b (#5765)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `b1d5c0d` to `f2ece7b`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](b1d5c0d737...f2ece7b30d)

---
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-05-29 21:37:18 +01:00
691e67018d Bump phpstan/phpstan-phpunit from 1.3.11 to 1.3.13 (#5772)
Bumps [phpstan/phpstan-phpunit](https://github.com/phpstan/phpstan-phpunit) from 1.3.11 to 1.3.13.
- [Release notes](https://github.com/phpstan/phpstan-phpunit/releases)
- [Commits](https://github.com/phpstan/phpstan-phpunit/compare/1.3.11...1.3.13)

---
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-05-29 21:36:58 +01:00
fe2140a716 Bump shivammathur/setup-php from 2.25.1 to 2.25.2 (#5766)
Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.25.1 to 2.25.2.
- [Release notes](https://github.com/shivammathur/setup-php/releases)
- [Commits](https://github.com/shivammathur/setup-php/compare/2.25.1...2.25.2)

---
updated-dependencies:
- dependency-name: shivammathur/setup-php
  dependency-type: direct:production
  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-05-29 21:36:46 +01:00
57330a7186 Bump build/php from f860ade to b1d5c0d (#5760)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `f860ade` to `b1d5c0d`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](f860ade30a...b1d5c0d737)

---
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-05-23 12:27:12 +01:00
9ddac21de0 Bump shivammathur/setup-php from 2.24.0 to 2.25.1 (#5711)
Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.24.0 to 2.25.1.
- [Release notes](https://github.com/shivammathur/setup-php/releases)
- [Commits](https://github.com/shivammathur/setup-php/compare/2.24.0...2.25.1)

---
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-05-21 00:13:22 +01:00
c91aa24daa Bump phpunit/phpunit from 9.6.8 to 10.1.3 (#5753)
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.8 to 10.1.3.
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/10.1.3/ChangeLog-10.1.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.8...10.1.3)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  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-05-19 15:09:24 +01:00
6186fc0bfe 4.21.1 is next 2023-05-17 16:45:35 +01:00
ef40934d24 Release 4.21.0 2023-05-17 16:45:32 +01:00
69b668355f Merge branch 'minor-next' into stable 2023-05-17 16:12:24 +01:00
0547383296 Update build/php submodule to pmmp/PHP-Binaries@f860ade30a 2023-05-17 15:08:05 +01:00
c7dff9ea40 bootstrap: remove ext-parallel bootstrapping code
I have no intention of using parallel, so this code is not necessary.
2023-05-17 14:11:43 +01:00
043350753b Drop PHP 8.0, 8.1 is now minimum version 2023-05-17 13:53:57 +01:00
5ad8016b99 Merge branch 'stable' into minor-next 2023-05-17 13:44:45 +01:00
2e5b2eed6e Update composer dependencies 2023-05-17 13:43:28 +01:00
5a0cde49cc AsyncPool: do not double-check progress updates on finished tasks
checkProgressUpdates is called directly before onCompletion, so we only need to call it again if the task isn't finished yet.
2023-05-16 23:37:58 +01:00
008a022ec1 Players now have finite resources in spectator mode
this seems like the logical solution for the block picking issues.
2023-05-16 23:02:33 +01:00
5c85a7c306 Merge remote-tracking branch 'origin/stable' into minor-next 2023-05-16 22:54:53 +01:00
599c4284f5 Introduce 10 KB threshold for async compression
due to the extremely large performance cost of instantiating AsyncTasks, it's usually not worth bothering with async compression except for very large packets.
While this large overhead can be significantly reduced by using specialized threads, it's early days in the testing stages for such improvements, and for now, we still have this to deal with.

Since async compression is always used prior to player spawn, this change may slightly improve the performance of the pre-join stage of the game.
2023-05-16 22:54:06 +01:00
9499e2e595 always the CS... 2023-05-16 14:22:03 +01:00
a4fea1444a Remove validateCallableSignature() calls from network hot paths
we rely on phpstan for validation of this internally, and plugins shouldn't be calling these methods anyway.
this significantly reduces the overhead of CompressBatchPromise.
2023-05-16 14:21:32 +01:00
1ba47802a8 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2023-05-15 14:59:02 +01:00
9d111e13f1 CONTRIBUTING: added table of in-house dependencies and which classes, functions or namespaces they contain 2023-05-15 14:58:31 +01:00
44bc4d8c7c Bump phpstan/phpstan from 1.10.14 to 1.10.15 (#5741)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.10.14 to 1.10.15.
- [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.14...1.10.15)

---
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-05-10 15:02:59 +01:00
d317347a9b WorldTimings: remove TODO
I tried this, and it didn't really provide any information that the tree table didn't already show.
2023-05-08 16:35:30 +01:00
077fac84bf Added aggregate timers for all world timings
this allows timings list view to display totals for these sections. It does make the tree view a bit more annoying in some cases though.
2023-05-08 16:27:46 +01:00
fdb3a5b121 Fixed incorrect implementation of peak timings 2023-05-07 18:29:37 +01:00
e3bc36ab5b Merge branch 'stable' into minor-next 2023-05-06 18:26:47 +01:00
283ff28aa9 4.20.5 is next 2023-05-06 18:20:19 +01:00
c3ceeeace7 Release 4.20.4 2023-05-06 18:20:18 +01:00
aac4f6c0e1 Fixed all game modes allowing flight
moral of the story: do not trust that mojang things do what they say they do - the spectator ability layer always applies, regardless of whether the player is actually in spectator mode or not ...
2023-05-06 18:18:05 +01:00
bb60a9057f Merge branch 'stable' into minor-next 2023-05-06 17:08:29 +01:00
3b893961e4 4.20.4 is next 2023-05-06 17:01:49 +01:00
325ffec1be Release 4.20.3 2023-05-06 17:01:49 +01:00
fa715a074a Fixed TimingsHandler depth not getting reset when timings is disabled
When timings was disabled, internalStopTiming is not called, and timer depth is not decremented.
If timings is later reenabled, the next call to internalStartTiming will think the timer is already running, and won't generate any new records for the timer.
This has led to broken timings reports with missing Full Server Tick entries, amongst other things.
2023-05-06 16:56:39 +01:00
4caa2c7690 NetworkSession: send FLYING flag on spectator ability layer
fixes #5722

I'm not very clear why this works. PM doesn't use real spectator mode yet (we're still using the faux spectator mode PM has had for years, because I haven't yet assessed how real spectator mode will affect stuff like block interactions), so this ability layer shouldn't have any effect.

thank you @Alemiz112
2023-05-06 15:54:23 +01:00
d04da9b1d8 Reuse timings handlers for event handlers of the same events
due to direct repeated usage of registerEvent() with closures, we've seen some libraries like muqsit/SimplePacketHandler generate very large timings reports, because a new timings handler gets created every time a plugin registers or unregisters a new packet handler callback.

This change fixes the problem by ensuring that any handlers derived from the same function, handling the same event class, will share the same timer.
2023-05-06 15:42:52 +01:00
02cf5ed388 RuntimeBlockMapping: lazy-load NBT blockstates
this saves a considerable amount of memory.

we don't actually need this state array in PM4 anyway, since we don't support the client-side chunk cache yet.
when the time comes to support it, it'll be much more practical to cache binary states and copy bytes anyway, instead of doing it the current way, which is both slow and memory-intensive.

Measured footprint change: 9 MB -> 400 KB.
2023-05-05 16:18:03 +01:00
6cad559dbe Merge branch 'stable' into minor-next 2023-05-05 16:08:30 +01:00
84a943bcec BaseInventory: slap a TODO on isSlotEmpty() 2023-05-05 16:06:37 +01:00
633e77a34c RuntimeBlockMapping: share states CompoundTags if they are the same
this allows saving about 4 MB of memory, because there are many blocks which have identical states, although they have different IDs.

this relies on a potentially risky assumption that the tags in knownStates won't be modified. If they are modified, the changes will influence all blockstates which share the tag.
However, I don't expect this to happen, and the 4 MB memory saving is substantial enough to be worth the risk.
2023-05-04 23:21:54 +01:00
092d130c96 RuntimeBlockMapping: borrow a hack from PM5 to reduce memory footprint
we can't change the internals of this on a patch release, but this hack provides a 12 MB memory usage reduction, which is very significant.
2023-05-04 23:01:10 +01:00
c09390d20f 4.20.3 is next 2023-05-04 21:06:30 +01:00
22f8623e17 Release 4.20.2 2023-05-04 21:06:27 +01:00
f04151dbe6 README: next-major branch was renamed (#5731)
[ci skip]
2023-05-01 14:08:20 +01:00
5dcd8bf289 Bump symfony/filesystem from 5.4.21 to 5.4.23 (#5730)
Bumps [symfony/filesystem](https://github.com/symfony/filesystem) from 5.4.21 to 5.4.23.
- [Release notes](https://github.com/symfony/filesystem/releases)
- [Changelog](https://github.com/symfony/filesystem/blob/6.2/CHANGELOG.md)
- [Commits](https://github.com/symfony/filesystem/compare/v5.4.21...v5.4.23)

---
updated-dependencies:
- dependency-name: symfony/filesystem
  dependency-type: direct:production
  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-05-01 13:30:02 +01:00
b70ff32548 ItemTranslator: Fixed log items not displaying correctly on the client
closes #5724

this uses a (potentially bogus) assumption that the lowest mapped meta value associated with an ID is valid. I don't want to break this during a patch release, and this works for now.

In the future it would probably make more sense to bypass ItemTranslator entirely, and rely solely on the blockstate returned by RuntimeBlockMapping to fetch the correct ID. This is similar to how we serialize items for saving on disk in PM5.
2023-04-28 13:54:40 +01:00
73bf5d4b29 DoubleChestInventory: specialize isSlotEmpty() and getMatchingItemCount() 2023-04-27 21:17:55 +01:00
eb136e60c8 BaseInventory: added getMatchingItemCount() helper
this eliminates the performance issues described by #5719.
closes #5719

we may want to consider exposing a public API for this in the future, since it might be useful for plugins.
2023-04-27 21:08:35 +01:00
4228880509 BaseInventory: change dumb variable names in internalAddItem() 2023-04-27 20:29:02 +01:00
709d874204 BaseInventory: clean up max stack size handling
we can safely assume that:
- the inventory's max stack size won't change during the operation
- two items which stack together have the same max stack size
- the item's max stack size won't change during the operation
2023-04-27 20:27:05 +01:00
07dc10d6e6 World: improve performance of tickChunks() selection process (#5721)
Since light population is required to make a chunk tickable, a chunk may not be tickable for some time if the async workers get backlogged.
The previous version of this system only cached the eligibility result if the result was a "yes", but we can also track it when it's a "no", rather than rechecking it every tick.

This change should improve performance in factions and similar gamemodes, which involve large maps with sparsely distributed players, where each player likely has an independent, non-overlapping ticking chunk circle.

We also ditch TickingChunkEntry in favour of multiple arrays to track the eligibility states. This allows us to avoid rechecking the (even cached) readiness of potentially thousands of chunks. If there are no ticking chunks to recheck, this reduces the cost of the selection process to zero.
2023-04-27 16:59:29 +01:00
7f6269c432 Introduce and use optimised versions of Inventory->isSlotEmpty()
this avoids useless cloning, improving the performance of several functions.
2023-04-27 16:52:52 +01:00
194714b448 Merge branch 'stable' into minor-next 2023-04-27 15:37:54 +01:00
023460db2c BaseInventory: fixed internalAddItem() doing useless canStackWith() checks on null items
if the item is null, it's never going to stack with anything given to this function, because addItem() already discards null items.
2023-04-27 14:53:54 +01:00
2910ffebf4 4.20.2 is next 2023-04-27 13:31:02 +01:00
fea820a99e Release 4.20.1 2023-04-27 13:31:02 +01:00
7c19f14cf5 Fixed up offhand handling for ItemStackRequest, fixes #5723 2023-04-27 13:25:08 +01:00
5a54d09869 InventoryManager: verify slot existence in locateWindowAndSlot()
previously, this would happily return invalid slot IDs, potentially leading to a crash.
2023-04-27 13:18:28 +01:00
4def4d52d9 Merge branch 'stable' into minor-next 2023-04-26 23:22:00 +01:00
1d10107024 4.20.1 is next 2023-04-26 23:15:38 +01:00
54ae4d0ea2 Release 4.20.0 2023-04-26 23:15:34 +01:00
0d21e591d1 Support sign editing UI in 1.19.80, with APIs to allow plugins to use it
this doesn't support editing the rear side of a sign, since the 1.12 format doesn't allow us to represent the rear text, and it would necessitate API breaks to support anyway.

However, we can quite trivially support APIs for the sign GUI, which plugins can use to enable editing signs. PocketMine-MP doesn't currently permit this, since it's currently an experimental feature in 1.20, but plugins can simply use Player->openSignEditor() to mimic it.

This is, however, a byproduct of the fact that APIs needed to be added in order to facilitate the use of OpenSignPacket in 1.19.80.
2023-04-26 22:55:05 +01:00
408616723c Changes for 1.19.80 2023-04-26 22:52:02 +01:00
9bfcd39f2a World: improve type info for getTickingChunks() 2023-04-26 17:06:52 +01:00
8102616ff4 Added ticking chunk count to /status
closes #5716
2023-04-26 17:05:31 +01:00
b162d688a3 CI: use php-cs-fixer 3.16 2023-04-26 16:05:06 +01:00
eb130f2906 Move primary version to PHP 8.1
8.0 is still supported for now, but won't be updated any longer.
2023-04-26 16:03:33 +01:00
3b09c3a48a actions: updated setup-php-action to pmmp/setup-php-action@c7fb29d835 2023-04-26 14:40:39 +01:00
87781cff4d Update GitHub Actions PHP versions 2023-04-26 14:38:40 +01:00
db0cf4bb5a Update composer dependencies 2023-04-26 14:35:05 +01:00
eb4679fefd Merge remote-tracking branch 'origin/stable' into minor-next 2023-04-26 14:28:29 +01:00
a4f2b99ed5 InGamePacketHandler: queue slots for syncing if they appear in requestChangedSlots
this is essentially a prediction without the actual predicted item. We have to sync these regardless of what happens.

fixes #5708
2023-04-24 14:06:29 +01:00
3ecc980bc4 ÂInventoryManagerEntry: fixed incorrect PHPDoc type 2023-04-24 13:42:11 +01:00
107b56154b ItemStackRequestExecutor: fixed stonecutter recipes
this uses the same dodgy hack used by CraftingTransaction, which assumes that getResultsFor() does not care about the crafting inputs.

While this is currently OK, since none of the currently-implemented recipes care about inputs anyway, it will become a problem when we implement shulker box recipes, so this needs to be addressed.

However, it can't be addressed without BC breaks, so this will have to be dealt with in PM5.

closes #5715
2023-04-24 13:35:00 +01:00
f86fde064d CraftingManager: fixed uninitialized field
I'm having deja vu about this ...
2023-04-24 12:34:34 +01:00
84a16ce69a HandlerList: fixed crash on getting unused priority
these sub-arrays are no longer allocated if no handlers are registered.

fixes #5713
2023-04-21 16:19:15 +01:00
d06d3bc871 4.19.4 is next 2023-04-21 15:53:05 +01:00
11e34b3e5c Release 4.19.3 2023-04-21 15:53:02 +01:00
f9318bf286 TimingsHandler: stop throwing exceptions when timers aren't stopped in the right order
this is usually because of an uncaught exception interacting with a try...finally block.
This will normally result in a crash anyway, and we don't want to obscure the real error.
2023-04-21 15:38:11 +01:00
71b78b02d3 Merge remote-tracking branch 'origin/stable' into minor-next 2023-04-19 23:57:26 +01:00
674b65f789 Item: optimise serializeCompoundTag() a little 2023-04-18 16:18:34 +01:00
a77fc8109f TypeConverter: avoid repeated calls to getId() and getMeta() 2023-04-18 15:02:52 +01:00
6102740ee3 TypeConverter: use a less slow hack to restore meta values on items sent by the client
this isn't even really needed anymore, since we don't decode items from the client since 4.18.

However, this may still be useful for tools.
2023-04-18 15:00:34 +01:00
40168a457e TypeConverter: fixed coreItemStackToNet() causing item NBT to be prepared twice
hasNamedTag() calls getNamedTag(), which calls serializeCompoundTag(), which writes the item's properties into the given NBT tag.
2023-04-18 14:43:25 +01:00
d07acd0013 RakLibInterface: split error ID into 4-character chunks
this makes it easier to read, since the error ID can't be copy-pasted from the disconnection screen on the client.
2023-04-17 14:05:46 +01:00
9561ae5af7 Entity: micro optimisation for checkBlockIntersections() 2023-04-16 17:57:51 +01:00
56fbd45dd5 Entity: avoid double-checking block intersections for moving entities
fixes #1824
2023-04-16 17:38:26 +01:00
b5dc72b0ee tools/simulate-chunk-selector: fixed the script being completely broken
getopt() behaviour is really, really dumb
2023-04-16 16:47:17 +01:00
4ba57f2b03 RegisteredListener: use try...finally to stop timings
While event handlers should not throw exceptions, we need to make sure the timings get stopped in the correct order, because the parent Event timer will be stopped due to using a finally block.
If this happens while the handler timing is still running, a second exception will occur, obscuring the real error.
2023-04-16 00:40:43 +01:00
84cb070d56 Merge branch 'stable' into minor-next 2023-04-14 20:12:33 +01:00
df0d72bf61 4.19.3 is next 2023-04-14 18:43:44 +01:00
a534ac759a Release 4.19.2 2023-04-14 18:43:41 +01:00
5ab954b7a0 Update composer dependencies 2023-04-14 18:31:57 +01:00
6c6f686f8e Timings: be more intelligent about shortening timer names
non-pocketmine classes may reuse the names of pocketmine core classes. We don't want timers to get erroneously reused in this case.
2023-04-14 18:24:53 +01:00
bf7975da57 Timings: use class to index packet timings, not IDs
on multi version servers, the same packet may have different IDs, or different packets might use the same ID. In these cases, we don't want the timings to get split up or erroneously reused.
2023-04-14 18:22:35 +01:00
7aeedd8220 Timings: fixed every player getting its own timings
we need a more consistent way to deal with this
2023-04-14 17:32:56 +01:00
3dd1ce2d02 4.19.2 is next 2023-04-14 16:47:46 +01:00
5a29d07021 Release 4.19.1 2023-04-14 16:47:43 +01:00
692e1253c6 Fixed AABB height for farmland and grass paths (fixed in 1.19.50) 2023-04-14 16:02:28 +01:00
ab0c444823 Player: fixed ticking chunks not being re-registered if they never left the view distance
closes #5699
2023-04-14 16:02:28 +01:00
e48a4aaa55 World: fixed chunk ticking not being disabled by setting chunk ticking radius to 0
I can't believe I missed this ...
2023-04-14 16:02:28 +01:00
6fc4ce0f86 ÂTimingsCommand: include HTTP response code in debug message
we should probably show this in the regular response message, but we need new translations for that.
2023-04-14 16:02:27 +01:00
10243c7b2c Bump phpstan/phpstan from 1.10.11 to 1.10.13 (#5697)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.10.11 to 1.10.13.
- [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.11...1.10.13)

---
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-04-13 13:19:24 +01:00
8102586ee0 Merge branch 'stable' into minor-next 2023-04-12 21:04:03 +01:00
18b528f72d ItemStackRequestExecutor: fixed borked taking of created items
closes #5695
2023-04-12 21:01:46 +01:00
0336394098 Human: remove useless NameTag tag
this is not written anywhere, so this code never does anything.
2023-04-12 16:44:10 +01:00
7e92da126d DelegateInventory: fixed slots being synced twice and breaking ItemStackRequests
the second time the slot is synced, there is no prediction, so the slot update isn't associated with a request anymore. This causes subsequent requests in the same packet to fail, since the dependency request ID isn't associated with the slot anymore.

This change fixes the problem by only allowing the backing inventory to trigger a call to DelegateInventory->on*Change(). While we could have removed and re-added the listener instead, this way is safer since it doesn't assume that the backing inventory won't modify the given item in setItem().

closes #5692
2023-04-12 15:43:51 +01:00
1569bed37a Merge branch 'stable' into minor-next 2023-04-11 23:56:22 +01:00
ba62e0f9cb WorldManager: fixed borked pre-generation for new worlds' spawn terrain
perhaps directly altering the behaviour of selectChunks() wasn't a good
idea? ...
2023-04-11 23:55:53 +01:00
a6e79c5004 TimingsHandler: remove useless paste metadata
these fields are not used by any version of timings, so this code is redundant.
2023-04-11 23:45:01 +01:00
858d4a2ed2 changelog: fixed indentation
I have no idea what happened here...
2023-04-11 23:35:14 +01:00
715 changed files with 69307 additions and 31094 deletions

View File

@ -13,9 +13,9 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP and tools - name: Setup PHP and tools
uses: shivammathur/setup-php@2.24.0 uses: shivammathur/setup-php@2.25.2
with: with:
php-version: 8.0 php-version: 8.1
- name: Restore Composer package cache - name: Restore Composer package cache
uses: actions/cache@v3 uses: actions/cache@v3

View File

@ -18,9 +18,9 @@ jobs:
submodules: true submodules: true
- name: Setup PHP - name: Setup PHP
uses: shivammathur/setup-php@2.24.0 uses: shivammathur/setup-php@2.25.2
with: with:
php-version: 8.0 php-version: 8.1
- name: Restore Composer package cache - name: Restore Composer package cache
uses: actions/cache@v3 uses: actions/cache@v3

View File

@ -6,46 +6,25 @@ on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
build-php:
name: Prepare PHP
runs-on: ${{ matrix.image }}
strategy:
matrix:
image: [ubuntu-20.04]
php: [8.0.28, 8.1.16, 8.2.3]
steps:
- name: Build and prepare PHP cache
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256
with:
php-version: ${{ matrix.php }}
install-path: "./bin"
pm-version-major: "5"
phpstan: phpstan:
name: PHPStan analysis name: PHPStan analysis
needs: build-php
runs-on: ${{ matrix.image }} runs-on: ${{ matrix.image }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
image: [ubuntu-20.04] image: [ubuntu-20.04]
php: [8.0.28, 8.1.16, 8.2.3] php: ["8.1", "8.2"]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP - name: Setup PHP
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256 uses: pmmp/setup-php-action@2.0.0
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
install-path: "./bin" install-path: "./bin"
pm-version-major: "5" pm-version-major: "4"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache - name: Restore Composer package cache
uses: actions/cache@v3 uses: actions/cache@v3
@ -58,33 +37,29 @@ jobs:
composer-v2-cache- composer-v2-cache-
- name: Install Composer dependencies - name: Install Composer dependencies
run: php composer.phar install --prefer-dist --no-interaction run: composer install --prefer-dist --no-interaction
- name: Run PHPStan - name: Run PHPStan
run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G run: ./vendor/bin/phpstan analyze --no-progress --memory-limit=2G
phpunit: phpunit:
name: PHPUnit tests name: PHPUnit tests
needs: build-php
runs-on: ${{ matrix.image }} runs-on: ${{ matrix.image }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
image: [ubuntu-20.04] image: [ubuntu-20.04]
php: [8.0.28, 8.1.16, 8.2.3] php: ["8.1", "8.2"]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP - name: Setup PHP
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256 uses: pmmp/setup-php-action@2.0.0
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
install-path: "./bin" install-path: "./bin"
pm-version-major: "5" pm-version-major: "4"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache - name: Restore Composer package cache
uses: actions/cache@v3 uses: actions/cache@v3
@ -97,20 +72,19 @@ jobs:
composer-v2-cache- composer-v2-cache-
- name: Install Composer dependencies - name: Install Composer dependencies
run: php composer.phar install --prefer-dist --no-interaction run: composer install --prefer-dist --no-interaction
- name: Run PHPUnit tests - name: Run PHPUnit tests
run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit run: ./vendor/bin/phpunit --bootstrap vendor/autoload.php --fail-on-warning tests/phpunit
integration: integration:
name: Integration tests name: Integration tests
needs: build-php
runs-on: ${{ matrix.image }} runs-on: ${{ matrix.image }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
image: [ubuntu-20.04] image: [ubuntu-20.04]
php: [8.0.28, 8.1.16, 8.2.3] php: ["8.1", "8.2"]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -118,14 +92,11 @@ jobs:
submodules: true submodules: true
- name: Setup PHP - name: Setup PHP
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256 uses: pmmp/setup-php-action@2.0.0
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
install-path: "./bin" install-path: "./bin"
pm-version-major: "5" pm-version-major: "4"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache - name: Restore Composer package cache
uses: actions/cache@v3 uses: actions/cache@v3
@ -138,33 +109,29 @@ jobs:
composer-v2-cache- composer-v2-cache-
- name: Install Composer dependencies - name: Install Composer dependencies
run: php composer.phar install --no-dev --prefer-dist --no-interaction run: composer install --no-dev --prefer-dist --no-interaction
- name: Run integration tests - name: Run integration tests
run: ./tests/travis.sh -t4 run: ./tests/travis.sh -t4
codegen: codegen:
name: Generated Code consistency checks name: Generated Code consistency checks
needs: build-php
runs-on: ${{ matrix.image }} runs-on: ${{ matrix.image }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
image: [ubuntu-20.04] image: [ubuntu-20.04]
php: [8.0.28, 8.1.16, 8.2.3] php: ["8.1", "8.2"]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP - name: Setup PHP
uses: pmmp/setup-php-action@6dd74c145250109942b08fc63cd5118edd2fd256 uses: pmmp/setup-php-action@2.0.0
with: with:
php-version: ${{ matrix.php }} php-version: ${{ matrix.php }}
install-path: "./bin" install-path: "./bin"
pm-version-major: "5" pm-version-major: "4"
- name: Install Composer
run: curl -sS https://getcomposer.org/installer | php
- name: Restore Composer package cache - name: Restore Composer package cache
uses: actions/cache@v3 uses: actions/cache@v3
@ -177,7 +144,7 @@ jobs:
composer-v2-cache- composer-v2-cache-
- name: Install Composer dependencies - name: Install Composer dependencies
run: php composer.phar install --no-dev --prefer-dist --no-interaction run: composer install --no-dev --prefer-dist --no-interaction
- name: Regenerate registry annotations - name: Regenerate registry annotations
run: php build/generate-registry-annotations.php src run: php build/generate-registry-annotations.php src
@ -185,9 +152,6 @@ jobs:
- name: Regenerate KnownTranslation APIs - name: Regenerate KnownTranslation APIs
run: php build/generate-known-translation-apis.php run: php build/generate-known-translation-apis.php
- name: Regenerate RuntimeEnum(De)serializer
run: php build/generate-runtime-enum-serializers.php
- name: Regenerate BedrockData available files constants - name: Regenerate BedrockData available files constants
run: php build/generate-bedrockdata-path-consts.php run: php build/generate-bedrockdata-path-consts.php
@ -206,10 +170,10 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup PHP and tools - name: Setup PHP and tools
uses: shivammathur/setup-php@2.24.0 uses: shivammathur/setup-php@2.25.2
with: with:
php-version: 8.0 php-version: 8.1
tools: php-cs-fixer:3.11 tools: php-cs-fixer:3.17
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,51 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
const VERSIONS = [
"8.0",
"8.1",
"8.2"
];
$workflowFile = file_get_contents(__DIR__ . '/main.yml');
$newWorkflowFile = $workflowFile;
foreach(VERSIONS as $v){
$releaseInfo = file_get_contents("https://secure.php.net/releases?json&version=$v");
if($releaseInfo === false){
throw new \RuntimeException("Failed to contact php.net API");
}
$data = json_decode($releaseInfo, true);
if(!is_array($data) || !isset($data["version"]) || !is_string($data["version"]) || preg_match('/^\d+\.\d+\.\d+(-[A-Za-z\d]+)?$/', $data["version"]) === 0){
throw new \RuntimeException("Invalid data returned by API");
}
$updated = preg_replace("/$v\.\d+/", $data["version"], $newWorkflowFile);
if($updated !== $newWorkflowFile){
echo "Updated $v revision to " . $data["version"] . "\n";
}
$newWorkflowFile = $updated;
}
if($workflowFile !== $newWorkflowFile){
echo "Writing modified workflow file\n";
file_put_contents(__DIR__ . '/main.yml', $newWorkflowFile);
}

View File

@ -30,6 +30,13 @@
<option name="USE_TAB_CHARACTER" value="true" /> <option name="USE_TAB_CHARACTER" value="true" />
</indentOptions> </indentOptions>
</codeStyleSettings> </codeStyleSettings>
<codeStyleSettings language="Markdown">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PHP"> <codeStyleSettings language="PHP">
<option name="CLASS_BRACE_STYLE" value="1" /> <option name="CLASS_BRACE_STYLE" value="1" />
<option name="METHOD_BRACE_STYLE" value="1" /> <option name="METHOD_BRACE_STYLE" value="1" />

View File

@ -2,13 +2,13 @@
## Pre-requisites ## Pre-requisites
- A bash shell (git bash is sufficient for Windows) - A bash shell (git bash is sufficient for Windows)
- [`git`](https://git-scm.com) available in your shell - [`git`](https://git-scm.com) available in your shell
- PHP 8.0 or newer available in your shell - PHP 8.1 or newer available in your shell
- [`composer`](https://getcomposer.org) available in your shell - [`composer`](https://getcomposer.org) available in your shell
## Custom PHP binaries ## Custom PHP binaries
Because PocketMine-MP requires several non-standard PHP extensions and configuration, PMMP provides scripts to build custom binaries for running PocketMine-MP, as well as prebuilt binaries. Because PocketMine-MP requires several non-standard PHP extensions and configuration, PMMP provides scripts to build custom binaries for running PocketMine-MP, as well as prebuilt binaries.
- [Prebuilt binaries](https://jenkins.pmmp.io/job/PHP-8.0-Aggregate) - [Prebuilt binaries](https://github.com/pmmp/PHP-Binaries/releases)
- [Compile scripts](https://github.com/pmmp/php-build-scripts) are provided as a submodule in the path `build/php` - [Compile scripts](https://github.com/pmmp/php-build-scripts) are provided as a submodule in the path `build/php`
If you use a custom binary, you'll need to replace `composer` usages in this guide with `path/to/your/php path/to/your/composer.phar`. If you use a custom binary, you'll need to replace `composer` usages in this guide with `path/to/your/php path/to/your/composer.phar`.
@ -29,11 +29,5 @@ Run `composer make-server` using your preferred PHP binary. It'll drop a `Pocket
You can also use the `--out` option to change the output filename. You can also use the `--out` option to change the output filename.
There is a bug in PHP that might cause an error which looks like this:
```
Fatal error: Uncaught BadMethodCallException: unable to create temporary file in PocketMine-MP/build/server-phar.php:119
```
You can work around it by setting `ulimit -n` to some bigger number, e.g. `8192`, or by updating your PHP version to at least 8.0.3.
## Running PocketMine-MP from source code ## Running PocketMine-MP from source code
Run `src/PocketMine.php` using your preferred PHP binary. Run `src/PocketMine.php` using your preferred PHP binary.

View File

@ -18,6 +18,30 @@ Larger contributions like feature additions should be preceded by a [Change Prop
## Other things you'll need ## Other things you'll need
- [git](https://git-scm.com/) - [git](https://git-scm.com/)
## List of `pocketmine` namespaces which are in other repos
PocketMine-MP has several dependencies which are independent from the main server code. Most of them use the `pocketmine` namespace.
Some of these add extra classes to packages which already exist in PocketMine-MP.
Take a look at the table below if you can't find the class or function you're looking for.
| Source URL | Namespace, class or function |
|:----------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------|
| [pmmp/BedrockProtocol](https://github.com/pmmp/BedrockProtocol) | `pocketmine\network\mcpe\protocol` |
| [pmmp/BinaryUtils](https://github.com/pmmp/BinaryUtils) | `pocketmine\utils\BinaryDataException`</br>`pocketmine\utils\BinaryStream`</br>`pocketmine\utils\Binary` |
| [pmmp/ClassLoader](https://github.com/pmmp/`ClassLoader`) | `BaseClassLoader`</br>`ClassLoader`</br>`DynamicClassLoader` |
| [pmmp/Color](https://github.com/pmmp/Color) | `pocketmine\color` |
| [pmmp/ErrorHandler](https://github.com/pmmp/ErrorHandler) | `pocketmine\errorhandler` |
| [pmmp/LogPthreads](https://github.com/pmmp/LogPthreads) | `ThreadedLoggerAttachment`</br>`ThreadedLogger`</br>`AttachableThreadedLogger` |
| [pmmp/Log](https://github.com/pmmp/Log) | `AttachableLogger`</br>`BufferedLogger`</br>`GlobalLogger`</br>`LogLevel`</br>`Logger`</br>`PrefixedLogger`</br>`SimpleLogger` |
| [pmmp/Math](https://github.com/pmmp/Math) | `pocketmine\math` |
| [pmmp/NBT](https://github.com/pmmp/NBT) | `pocketmine\nbt` |
| [pmmp/RakLibIpc](https://github.com/pmmp/RakLibIpc) | `raklib\server\ipc` |
| [pmmp/RakLib](https://github.com/pmmp/RakLib) | `raklib` |
| [pmmp/Snooze](https://github.com/pmmp/Snooze) | `pocketmine\snooze` |
| [pmmp/ext-chunkutils2](https://github.com/pmmp/ext-chunkutils2) | `pocketmine\world\format\LightArray`</br>`pocketmine\world\format\PalettedBlockArray`</br>`pocketmine\world\format\io\SubChunkConverter` |
| [pmmp/ext-morton](https://github.com/pmmp/ext-morton) | `morton2d_decode`</br>`morton2d_encode`</br>`morton3d_decode`</br>`morton3d_encode` |
| [pmmp/ext-libdeflate](https://github.com/pmmp/ext-libdeflate) | `libdeflate_deflate_compress`</br>`libdeflate_gzip_compress`</br>`libdeflate_zlib_compress` |
## Choosing a target branch ## Choosing a target branch
PocketMine-MP has three primary branches of development. PocketMine-MP has three primary branches of development.

View File

@ -35,7 +35,7 @@
* [Building and running from source](BUILDING.md) * [Building and running from source](BUILDING.md)
* [Developer documentation](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers * [Developer documentation](https://devdoc.pmmp.io) - General documentation for PocketMine-MP plugin developers
* [Latest release API documentation](https://apidoc.pmmp.io) - Doxygen API documentation generated for each release * [Latest release API documentation](https://apidoc.pmmp.io) - Doxygen API documentation generated for each release
* [Latest bleeding-edge API documentation](https://apidoc-dev.pmmp.io) - Doxygen API documentation generated weekly from `next-major` branch * [Latest bleeding-edge API documentation](https://apidoc-dev.pmmp.io) - Doxygen API documentation generated weekly from `major-next` branch
* [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins * [DevTools](https://github.com/pmmp/DevTools/) - Development tools plugin for creating plugins
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features * [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
* [Contributing Guidelines](CONTRIBUTING.md) * [Contributing Guidelines](CONTRIBUTING.md)

View File

@ -1,197 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\build\generate_block_serializer_consts;
use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\BlockStateNames;
use pocketmine\data\bedrock\block\BlockStateStringValues;
use pocketmine\data\bedrock\block\BlockTypeNames;
use pocketmine\errorhandler\ErrorToExceptionHandler;
use pocketmine\nbt\NbtException;
use pocketmine\network\mcpe\convert\BlockStateDictionary;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\Utils;
use function array_values;
use function asort;
use function count;
use function dirname;
use function explode;
use function fclose;
use function file_get_contents;
use function fopen;
use function fwrite;
use function is_string;
use function ksort;
use function mb_strtoupper;
use function sort;
use function strrpos;
use function strtoupper;
use function substr;
use const SORT_STRING;
use const STDERR;
require dirname(__DIR__) . '/vendor/autoload.php';
class BlockPaletteReport{
/**
* @var string[]
* @phpstan-var array<string, string>
*/
public array $seenTypes = [];
/**
* @var string[][]
* @phpstan-var array<string, array<mixed, mixed>>
*/
public array $seenStateValues = [];
}
/**
* @param BlockStateData[] $states
* @phpstan-param list<BlockStateData> $states
*/
function generateBlockPaletteReport(array $states) : BlockPaletteReport{
$result = new BlockPaletteReport();
foreach($states as $stateData){
$name = $stateData->getName();
$result->seenTypes[$name] = $name;
foreach(Utils::stringifyKeys($stateData->getStates()) as $k => $v){
$result->seenStateValues[$k][$v->getValue()] = $v->getValue();
asort($result->seenStateValues[$k]);
}
}
ksort($result->seenTypes, SORT_STRING);
ksort($result->seenStateValues, SORT_STRING);
return $result;
}
function constifyMcId(string $id) : string{
return strtoupper(explode(":", $id, 2)[1]);
}
function generateClassHeader(string $className) : string{
$backslashPos = strrpos($className, "\\");
if($backslashPos === false){
throw new AssumptionFailedError("Expected a namespaced class FQN");
}
$namespace = substr($className, 0, $backslashPos);
$shortName = substr($className, $backslashPos + 1);
return <<<HEADER
<?php
declare(strict_types=1);
namespace $namespace;
/**
* This class is generated automatically from the block palette for the current version. Do not edit it manually.
*/
final class $shortName{
private function __construct(){
//NOOP
}
HEADER;
}
/**
* @phpstan-param list<string> $seenIds
*/
function generateBlockIds(array $seenIds) : void{
$output = ErrorToExceptionHandler::trapAndRemoveFalse(fn() => fopen(dirname(__DIR__) . '/src/data/bedrock/block/BlockTypeNames.php', 'wb'));
fwrite($output, generateClassHeader(BlockTypeNames::class));
foreach($seenIds as $id){
fwrite($output, "\tpublic const " . constifyMcId($id) . " = \"" . $id . "\";\n");
}
fwrite($output, "}\n");
fclose($output);
}
function generateBlockStateNames(BlockPaletteReport $data) : void{
$output = ErrorToExceptionHandler::trapAndRemoveFalse(fn() => fopen(dirname(__DIR__) . '/src/data/bedrock/block/BlockStateNames.php', 'wb'));
fwrite($output, generateClassHeader(BlockStateNames::class));
foreach(Utils::stringifyKeys($data->seenStateValues) as $state => $values){
$constName = mb_strtoupper($state, 'US-ASCII');
fwrite($output, "\tpublic const $constName = \"$state\";\n");
}
fwrite($output, "}\n");
fclose($output);
}
function generateBlockStringValues(BlockPaletteReport $data) : void{
$output = ErrorToExceptionHandler::trapAndRemoveFalse(fn() => fopen(dirname(__DIR__) . '/src/data/bedrock/block/BlockStateStringValues.php', 'wb'));
fwrite($output, generateClassHeader(BlockStateStringValues::class));
foreach(Utils::stringifyKeys($data->seenStateValues) as $stateName => $values){
$anyWritten = false;
sort($values, SORT_STRING);
foreach($values as $value){
if(!is_string($value)){
continue;
}
$anyWritten = true;
$constName = mb_strtoupper($stateName . "_" . $value, 'US-ASCII');
fwrite($output, "\tpublic const $constName = \"$value\";\n");
}
if($anyWritten){
fwrite($output, "\n");
}
}
fwrite($output, "}\n");
fclose($output);
}
if(count($argv) !== 2){
fwrite(STDERR, "This script regenerates BlockTypeNames, BlockStateNames and BlockStateStringValues from a given palette file\n");
fwrite(STDERR, "Required arguments: path to block palette file\n");
exit(1);
}
$palettePath = $argv[1];
$paletteRaw = file_get_contents($palettePath);
if($paletteRaw === false){
fwrite(STDERR, "Failed to read block palette file\n");
exit(1);
}
try{
$states = BlockStateDictionary::loadPaletteFromString($paletteRaw);
}catch(NbtException){
fwrite(STDERR, "Invalid block palette file $argv[1]\n");
exit(1);
}
$report = generateBlockPaletteReport($states);
generateBlockIds(array_values($report->seenTypes));
generateBlockStateNames($report);
generateBlockStringValues($report);
echo "Done. Don't forget to run CS fixup after generating code.\n";

View File

@ -1,97 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\build\generate_item_serializer_ids;
use pocketmine\errorhandler\ErrorToExceptionHandler;
use pocketmine\network\mcpe\convert\ItemTypeDictionaryFromDataHelper;
use pocketmine\network\mcpe\protocol\serializer\ItemTypeDictionary;
use pocketmine\utils\Utils;
use function asort;
use function count;
use function dirname;
use function explode;
use function fclose;
use function file_get_contents;
use function fopen;
use function fwrite;
use function strtoupper;
use const SORT_STRING;
use const STDERR;
require dirname(__DIR__) . '/vendor/autoload.php';
function constifyMcId(string $id) : string{
return strtoupper(explode(":", $id, 2)[1]);
}
function generateItemIds(ItemTypeDictionary $dictionary) : void{
$ids = [];
foreach($dictionary->getEntries() as $entry){
if($entry->getNumericId() < 256){ //blockitems are serialized via BlockStateSerializer
continue;
}
$ids[$entry->getStringId()] = $entry->getStringId();
}
asort($ids, SORT_STRING);
$file = ErrorToExceptionHandler::trapAndRemoveFalse(fn() => fopen(dirname(__DIR__) . '/src/data/bedrock/item/ItemTypeNames.php', 'wb'));
fwrite($file, <<<'HEADER'
<?php
declare(strict_types=1);
namespace pocketmine\data\bedrock\item;
/**
* This class is generated automatically from the item type dictionary for the current version. Do not edit it manually.
*/
final class ItemTypeNames{
HEADER
);
foreach(Utils::stringifyKeys($ids) as $id){
fwrite($file, "\tpublic const " . constifyMcId($id) . " = \"" . $id . "\";\n");
}
fwrite($file, "}\n");
fclose($file);
}
if(count($argv) !== 2){
fwrite(STDERR, "This script regenerates ItemTypeNames from a given item dictionary file\n");
fwrite(STDERR, "Required argument: path to item type dictionary file\n");
exit(1);
}
$raw = file_get_contents($argv[1]);
if($raw === false){
fwrite(STDERR, "Failed to read item type dictionary file\n");
exit(1);
}
$dictionary = ItemTypeDictionaryFromDataHelper::loadFromString($raw);
generateItemIds($dictionary);
echo "Done. Don't forget to run CS fixup after generating code.\n";

View File

@ -1,263 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\build\generate_runtime_enum_serializers;
use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\CopperOxidation;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\DirtType;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\FroglightType;
use pocketmine\block\utils\LeverFacing;
use pocketmine\block\utils\MushroomBlockType;
use pocketmine\block\utils\SkullType;
use pocketmine\block\utils\SlabType;
use pocketmine\item\MedicineType;
use pocketmine\item\PotionType;
use pocketmine\item\SuspiciousStewType;
use function array_key_first;
use function array_keys;
use function array_map;
use function ceil;
use function count;
use function dirname;
use function file_put_contents;
use function implode;
use function ksort;
use function lcfirst;
use function log;
use function ob_get_clean;
use function ob_start;
use const SORT_STRING;
require dirname(__DIR__) . '/vendor/autoload.php';
/**
* @param string[] $memberNames
* @phpstan-param list<string> $memberNames
*
* @return string[]
* @phpstan-return list<string>
*/
function buildWriterFunc(string $virtualTypeName, string $nativeTypeName, array $memberNames, string $functionName) : array{
$bits = getBitsRequired($memberNames);
$lines = [];
$lines[] = "public function $functionName(\\$nativeTypeName &\$value) : void{";
$lines[] = "\t\$this->writeInt($bits, match(\$value){";
foreach($memberNames as $key => $memberName){
$lines[] = "\t\t$memberName => $key,";
}
$lines[] = "\t\tdefault => throw new \pocketmine\utils\AssumptionFailedError(\"All $virtualTypeName cases should be covered\")";
$lines[] = "\t});";
$lines[] = "}";
return $lines;
}
/**
* @param string[] $memberNames
* @phpstan-param list<string> $memberNames
*
* @return string[]
* @phpstan-return list<string>
*/
function buildReaderFunc(string $virtualTypeName, string $nativeTypeName, array $memberNames, string $functionName) : array{
$bits = getBitsRequired($memberNames);
$lines = [];
$lines[] = "public function $functionName(\\$nativeTypeName &\$value) : void{";
$lines[] = "\t\$value = match(\$this->readInt($bits)){";
foreach($memberNames as $key => $memberName){
$lines[] = "\t\t$key => $memberName,";
}
$lines[] = "\t\tdefault => throw new InvalidSerializedRuntimeDataException(\"Invalid serialized value for $virtualTypeName\")";
$lines[] = "\t};";
$lines[] = "}";
return $lines;
}
function buildInterfaceFunc(string $nativeTypeName, string $functionName) : string{
return "public function $functionName(\\$nativeTypeName &\$value) : void;";
}
/**
* @param string[] $memberNames
* @phpstan-param list<string> $memberNames
*
* @return string[]
* @phpstan-return list<string>
*/
function buildSizeCalculationFunc(string $nativeTypeName, string $functionName, array $memberNames) : array{
$lines = [];
$lines[] = "public function $functionName(\\$nativeTypeName &\$value) : void{";
$lines[] = "\t\$this->addBits(" . getBitsRequired($memberNames) . ");";
$lines[] = "}";
return $lines;
}
/**
* @param mixed[] $members
*/
function getBitsRequired(array $members) : int{
return (int) ceil(log(count($members), 2));
}
/**
* @param object[] $members
* @phpstan-param array<string, object> $members
*
* @return string[]
* @phpstan-return list<string>
*/
function stringifyEnumMembers(array $members, string $enumClass) : array{
ksort($members, SORT_STRING);
return array_map(fn(string $enumCaseName) => "\\$enumClass::$enumCaseName()", array_keys($members));
}
$enumsUsed = [
BellAttachmentType::getAll(),
CopperOxidation::getAll(),
CoralType::getAll(),
DirtType::getAll(),
DyeColor::getAll(),
FroglightType::getAll(),
LeverFacing::getAll(),
MedicineType::getAll(),
MushroomBlockType::getAll(),
SkullType::getAll(),
SlabType::getAll(),
SuspiciousStewType::getAll(),
PotionType::getAll()
];
$readerFuncs = [
"" => [
"abstract protected function readInt(int \$bits) : int;"
]
];
$writerFuncs = [
"" => [
"abstract protected function writeInt(int \$bits, int \$value) : void;"
]
];
$interfaceFuncs = [];
$sizeCalculationFuncs = [
"" => [
"abstract protected function addBits(int \$bits) : void;"
]
];
foreach($enumsUsed as $enumMembers){
if(count($enumMembers) === 0){
throw new \InvalidArgumentException("Enum members cannot be empty");
}
$reflect = new \ReflectionClass($enumMembers[array_key_first($enumMembers)]);
$virtualTypeName = $reflect->getShortName();
$nativeTypeName = $reflect->getName();
$functionName = lcfirst($virtualTypeName);
$stringifiedMembers = stringifyEnumMembers($enumMembers, $nativeTypeName);
$writerFuncs[$functionName] = buildWriterFunc(
$virtualTypeName,
$nativeTypeName,
$stringifiedMembers,
$functionName
);
$readerFuncs[$functionName] = buildReaderFunc(
$virtualTypeName,
$nativeTypeName,
$stringifiedMembers,
$functionName
);
$interfaceFuncs[$functionName] = [buildInterfaceFunc(
$nativeTypeName,
$functionName
)];
$sizeCalculationFuncs[$functionName] = buildSizeCalculationFunc(
$nativeTypeName,
$functionName,
$stringifiedMembers
);
}
/**
* @param string[][] $functions
* @phpstan-param array<string, list<string>> $functions
*/
function printFunctions(array $functions, string $className, string $classType) : void{
ksort($functions, SORT_STRING);
ob_start();
echo <<<'HEADER'
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\runtime;
/**
* This class is auto-generated. Do not edit it manually.
* @see build/generate-runtime-enum-serializers.php
*/
HEADER;
echo "$classType $className{\n\n";
echo implode("\n\n", array_map(fn(array $functionLines) => "\t" . implode("\n\t", $functionLines), $functions));
echo "\n\n}\n";
file_put_contents(dirname(__DIR__) . '/src/data/runtime/' . $className . '.php', ob_get_clean());
}
printFunctions($writerFuncs, "RuntimeEnumSerializerTrait", "trait");
printFunctions($readerFuncs, "RuntimeEnumDeserializerTrait", "trait");
printFunctions($interfaceFuncs, "RuntimeEnumDescriber", "interface");
printFunctions($sizeCalculationFuncs, "RuntimeEnumSizeCalculatorTrait", "trait");
echo "Done. Don't forget to run CS fixup after generating code.\n";

View File

@ -54,13 +54,13 @@ Released 11th April 2023.
### `pocketmine\timings` ### `pocketmine\timings`
- The following API constants have been deprecated: - The following API constants have been deprecated:
- `Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX` - this is superseded by timings group support (see `Timings::GROUP_BREAKDOWN`) - `Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX` - this is superseded by timings group support (see `Timings::GROUP_BREAKDOWN`)
- The following API constants have been added: - The following API constants have been added:
- `Timings::GROUP_BREAKDOWN` - this group makes a timer appear in the `Minecraft - Breakdown` section of a timings report - `Timings::GROUP_BREAKDOWN` - this group makes a timer appear in the `Minecraft - Breakdown` section of a timings report
- The following API methods have been added: - The following API methods have been added:
- `public TimingsHandler->getGroup() : string` - returns the name of the table in which this timer will appear in a timings report - `public TimingsHandler->getGroup() : string` - returns the name of the table in which this timer will appear in a timings report
- The following API methods have changed signatures: - The following API methods have changed signatures:
- `TimingsHandler->__construct()` now accepts an additional, optional `string $group` parameter, which defaults to `Minecraft`. - `TimingsHandler->__construct()` now accepts an additional, optional `string $group` parameter, which defaults to `Minecraft`.
### `pocketmine\world` ### `pocketmine\world`
#### Highlights #### Highlights
@ -75,3 +75,37 @@ It works similarly to the `ChunkLoader` system, in that chunks will be ticked as
- The following API methods have been added: - The following API methods have been added:
- `public World->registerTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - registers a chunk to be ticked by the given `ChunkTicker` - `public World->registerTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - registers a chunk to be ticked by the given `ChunkTicker`
- `public World->unregisterTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - unregisters a chunk from being ticked by the given `ChunkTicker` - `public World->unregisterTickingChunk(ChunkTicker $ticker, int $chunkX, int $chunkZ) : void` - unregisters a chunk from being ticked by the given `ChunkTicker`
# 4.19.1
Released 14th April 2023.
## Fixes
- Fixed inventory rollbacks when spreading items in ender chests.
- Fixed inventory rollbacks when shift-clicking to craft and the outputs would have been split across multiple inventory slots.
- Fixed incorrect spawn terrain generation for newly created worlds.
- Fixed `chunk-ticking.tick-radius` not disabling chunk ticking when set to `0`.
- Fixed chunks not being ticked if they previously left a player's simulation distance without leaving their view distance.
- Fixed height of collision boxes for Grass Path and Farmland blocks.
# 4.19.2
Released 14th April 2023.
## Fixes
- Fixed player timings duplication leading to extremely large timings reports when timings runs for a long time with many players.
- Packet timings are now indexed by class FQN instead of packet ID. This prevents erroneous timer reuse on packet ID reuse (e.g. multi version servers).
- Fixed entity timings being shared by different classes with the same short name. This led to incorrect timings being reported for some entities when custom entities were used.
# 4.19.3
Released 21st April 2023.
## General
- Error IDs for `Packet processing error` disconnects are now split into 4-character chunks to make them easier to type (since they can't be copied from the disconnection screen of a client).
## Fixes
- Fixed entity-block intersections being checked twice per tick. Besides wasting CPU time, this may have caused unexpected behaviour during entity-block interactions with blocks like water or cacti.
- Fixed performance issue in network inventory synchronization due item NBT being prepared twice.
- Fixed `tools/simulate-chunk-selector.php` argument parsing being completely broken (weird behaviour of PHP `getopt()`).
## Internals
- `TimingsHandler->stopTiming()` now logs an error message if a subtimer wasn't stopped, rather than throwing an exception.
- Due to interactions between `try...finally` and unexpected errors, throwing exceptions made it difficult for plugin developers to debug errors in their plugins, since it obscured the original error.

79
changelogs/4.20.md Normal file
View File

@ -0,0 +1,79 @@
**For Minecraft: Bedrock Edition 1.19.80**
### Note about API versions
Plugins which don't touch the `pocketmine\network\mcpe` namespace are compatible with any previous 4.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
### Interim releases
If you're upgrading from 4.17.x directly to 4.20.x, please also read the following changelogs, as the interim releases contain important changes:
- [4.18.0](https://github.com/pmmp/PocketMine-MP/blob/4.20.0/changelogs/4.18.md#4180) - major performance improvements, internal network changes, minor API additions
- [4.19.0](https://github.com/pmmp/PocketMine-MP/blob/4.20.0/changelogs/4.19.md#4190) - minor performance improvements, improved timings system, minor API additions
# 4.20.0
Released 26th April 2023.
## General
- Added support for Minecraft: Bedrock Edition 1.19.80.
- Removed support for older versions.
## Fixes
- Fixed packet processing error when attempting to use a stonecutter.
- Fixed armor slots containing ghost items when cancelling right-click to equip armor.
- Fixed crash in `HandlerList->getListenersByPriority()` when no listeners are registered at the given priority.
## API
### `pocketmine\block`
- The following API methods have been added:
- `public BaseSign->getEditorEntityRuntimeId() : int` - returns the entity runtime ID of the player currently editing this sign, or `null` if none
- `public BaseSign->setEditorEntityRuntimeId(?int $editorEntityRuntimeId) : $this` - sets the entity runtime ID of the player currently editing this sign
### `pocketmine\player`
- The following API methods have been added:
- `public Player->openSignEditor(Vector3 $position) : void` - opens the client-side sign editor GUI for the given position
# 4.20.1
Released 27th April 2023.
## Fixes
- Fixed server crash when firing a bow while holding arrows in the offhand slot.
## Internals
- `ItemStackContainerIdTranslator::translate()` now requires an additional `int $slotId` parameter and returns `array{int, int}` (translated window ID, translated slot ID) to be used with `InventoryManager->locateWindowAndSlot()`.
- `InventoryManager->locateWindowAndSlot()` now checks if the translated slot actually exists in the requested inventory, and returns `null` if not. Previously, it would return potentially invalid slot IDs without checking them, potentially leading to crashes.
# 4.20.2
Released 4th May 2023.
## Fixes
- Fixed all types of wooden logs appearing as oak in the inventory.
- Fixed a performance issue in `BaseInventory->canAddItem()` (missing `continue` causing useless logic to run).
# 4.20.3
Released 6th May 2023.
## Improvements
- Reduced memory usage of `RuntimeBlockMapping` from 25 MB to 9 MB. Since every thread has its own copy of the block map, this saves a substantial amount of memory.
## Fixes
- Fixed players falling through blocks in spectator mode.
- Fixed timings reports getting bloated by prolific usage of `PluginManager->registerEvent()`.
- This was caused by creating a new timings handler for each call, regardless of whether a timer already existed for the given event and callback.
- Fixed `Full Server Tick` and other records being missing from timings reports.
- This was caused by timings handler depth not getting reset when timings was disabled and later re-enabled.
# 4.20.4
Released 6th May 2023.
## Fixes
- Fixed players being forced into flight mode in every game mode.
- Moral of the story: do not assume anything in Mojang internals does what its name suggests...
# 4.20.5
Released 30th May 2023.
## Fixes
- Fixed server crash due to a bug in upstream dependency [`netresearch/jsonmapper`](https://github.com/cweiske/JsonMapper).

77
changelogs/4.21.md Normal file
View File

@ -0,0 +1,77 @@
**For Minecraft: Bedrock Edition 1.19.80**
### Note about API versions
Plugins which don't touch the `pocketmine\network\mcpe` namespace, and don't use reflection or any internal methods,
will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**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.
# 4.21.0
Released 17th May 2023.
## General
- PHP 8.1 is now required. Most plugins should run without changes, but some might need to be updated due to language-level deprecations.
- Ticking chunk count is now shown separately from loaded chunk count in the `/status` command, providing useful performance information.
- Further improved performance of ticking chunk selection.
- Improved performance of some inventory functions.
- Reduced server memory footprint in most cases by ~9 MB per thread.
- Due to large overhead, async network compression is now only used for packets larger than 10 KB by default.
## Configuration
- Added the following new `pocketmine.yml` configuration options:
- `network.async-compression-threshold` - minimum size of packet which will be compressed using `AsyncTask`
- Default is 10 KB, which means that very few packets will use async compression in practice. This is because the overhead of compressing async is currently so high that it's not worth it for smaller packets.
## Timings
- Timings reports no longer include the unused metadata fields `Entities` and `LivingEntities`.
- Timings reports now correctly calculate the peak time of a timer.
- Previously it was incorrectly recorded as the longest time spent in a single tick, rather than the longest time spent in a single activation.
- Timings report version has been bumped to `2` to reflect this change.
- All world-specific timers now have generic aggregate timings, making it much easier to locate performance patterns across all worlds.
## Gameplay
- Players in spectator mode are no longer able to pick blocks, and now have finite resources similar to survival mode.
## API
### `pocketmine\world`
- The following API methods have been added:
- `public World->getTickingChunks() : list<int>` - returns a list of chunk position hashes (a la `World::chunkHash()`) which are currently valid for random ticking
### `pocketmine\inventory`
- The following API methods have been added:
- `protected BaseInventory->getMatchingItemCount(int $slot, Item $test, bool $checkDamage, bool $checkTags) : int` - returns the number of items in the given stack if the content of the slot matches the test item, or zero otherwise
- This should be overridden if directly extending `BaseInventory` to provide a performance-optimised version. A slow default implementation is provided, but it will be removed in the future.
## Internals
### Entity
- Unused `NameTag` tag is no longer saved for `Human` entities.
### Inventory
- `BaseInventory` now uses a new internal method `getMatchingItemCount()` to locate items in the inventory without useless cloning. This improves performance of various API methods, such as `addItem()`, `contains()`, and more.
- Specialization of `Inventory->isSlotEmpty()` in `BaseInventory` subclasses has been added to improve performance of some API methods.
### Network
- `RuntimeBlockMapping` no longer keeps all block palette NBT data in memory.
- This significantly reduces server idle memory footprint.
- For multi-version implementations, this will have a significant impact on memory usage, since a different block palette is often required to support each version.
- NBT will be lazy-loaded into memory and cached if `getBedrockKnownStates()` is called. However, this is not used by PocketMine-MP under normal circumstances.
- Removed unnecessary usage of `Utils::validateCallableSignature()` from some internal network pathways, improving performance.
### Scheduler
- `AsyncPool` no longer double-checks progress updates on completed tasks.
### World
- Ticking chunks are now tracked in `World->validTickingChunks` and `World->recheckTickingChunks`.
- This allows avoiding rechecking every ticking chunk for validity during ticking chunk selection, improving performance.
- In some cases, this allows bypassing chunk selection entirely, reducing selection cost to zero.
- Registered but ineligible ticking chunks are no longer rechecked every tick.
- This was causing wasted cycles during async worker backlog.
- The internal system must call `markTickingChunkForRecheck()` whenever a ticking chunk's eligibility for ticking has potentially changed, rather than just when it has changed from a yes to a no.
# 4.21.1
Released 30th May 2023.
## Fixes
- Fixed server crash due to a bug in upstream dependency [`netresearch/jsonmapper`](https://github.com/cweiske/JsonMapper).

34
changelogs/4.22.md Normal file
View File

@ -0,0 +1,34 @@
# 4.22.0
Released 7th June 2023.
**For Minecraft: Bedrock Edition 1.20.0**
This is a support release for Minecraft: Bedrock Edition 1.20.0.
**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.
## Interim releases
If you're upgrading from 4.20.x directly to 4.22.x, please also read the following changelogs, as the interim releases contain important changes:
- [4.21.0](https://github.com/pmmp/PocketMine-MP/blob/4.22.0/changelogs/4.21.md#4210) - PHP 8.1 minimum version, minor performance improvements
## General
- Added support for Minecraft: Bedrock Edition 1.20.0.
- Removed support for older versions.
## Fixes
- Removed deprecated `ReflectionProperty::setAccessible()` calls.
- Fixed jukebox music not stopping when destroyed by an explosion.
# 4.22.1
Released 9th June 2023.
## Fixes
- Reokaced workaround for an old teleporting client bug:
- This workaround broke due to an additional client bug introduced by 1.20, causing players to become frozen to observers when teleported.
- The original client bug has still not been fixed, meaning a new workaround was needed, but no perfect solution could be found.
- The new workaround involves broadcasting teleport movements as regular movements, which causes unwanted interpolation between the old and new positions, but otherwise works correctly. This solution is not ideal, but it is the best we can do for now.
- See issues [#4394](https://github.com/pmmp/PocketMine-MP/issues/4394) and [#5810](https://github.com/pmmp/PocketMine-MP/issues/5810) for more details.

File diff suppressed because it is too large Load Diff

View File

@ -1,95 +0,0 @@
**For Minecraft: Bedrock Edition 1.19.62**
5.0.0 is a major update to PocketMine-MP, including many new features and API changes. It is **not** compatible with plugins written for previous versions of PocketMine-MP.
**During the beta phase, no new features will be added.**
This stage of development is focused on stability and cleaning up any major issues introduced during the alpha stage.
## WARNING
**This is a BETA release.** This means that it may be unstable, and is not yet ready for production use.
Since this version has undergone substantial changes compared to 4.x, plugins written for 4.x will need to be updated to work on this version.
Breaking API changes may still occur during the beta phase, but only if they are strictly necessary to fix a problem prior to full release.
**BACK UP your data before testing this.** This version will work with worlds and player data from 4.x,
BUT any world or player data loaded in 5.0.0 will not work in 4.x due to backwards-incompatible storage format changes.
# 5.0.0-BETA1
Released 7th March 2023.
**This release includes changes from the following releases:**
- [All 5.0.0 alpha releases](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA1/changelogs/5.0-alpha.md)
- [4.15.2](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA1/changelogs/4.15.md#4152)
- [4.15.3](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA1/changelogs/4.15.md#4153)
- [4.16.0](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA1/changelogs/4.16.md#4160)
## API
### `pocketmine\block`
- Improved documentation for the following methods:
- `Block->getTypeId()`
- `Block->getStateId()`
- `Block->describeType()`
- `Block->describeState()`
### `pocketmine\command`
- The following API methods have been renamed:
- `Command->getPermission()` -> `Command->getPermissions()`
## Internals
- The following methods have been renamed:
- `Block->computeStateData()` -> `Block->computeTypeAndStateData()`
- `Block->decodeStateData()` -> `Block->decodeTypeAndStateData()`
- Wall state data now packs connections into 7 bits instead of 8.
# 5.0.0-BETA2
Released 11th April 2023.
**This release includes changes from the following releases:**
- [4.17.0](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA2/changelogs/4.17.md#4170)
- [4.17.1](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA2/changelogs/4.17.md#4171)
- [4.17.2](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA2/changelogs/4.17.md#4172)
- [4.18.0](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA2/changelogs/4.18.md#4180)
- [4.18.1](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA2/changelogs/4.18.md#4181)
- [4.18.2](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA2/changelogs/4.18.md#4182)
- [4.18.3](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA2/changelogs/4.18.md#4183)
- [4.18.4](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA2/changelogs/4.18.md#4184)
- [4.19.0](https://github.com/pmmp/PocketMine-MP/blob/5.0.0-BETA2/changelogs/4.19.md#4190)
## Tools
- Added script `tools/generate-bedrock-data-from-packets.php`. This tool accepts a txt file containing base64-encoded packet dumps.
- This script has been used to generate data for [BedrockData](https://github.com/pmmp/BedrockData) for several years, but has only now been open-sourced.
- It's used to generate data such as crafting recipes, creative inventory data, and various other blobs of data needed to support the current version of Minecraft: Bedrock Edition.
## Gameplay
- Anvils now damage entities when they fall on top of them.
## API
### `pocketmine\block\utils`
- The following API interface requirements have been added (BC breaking):
- `public Fallable->getFallDamagePerBlock() : float` (default implementation provided by `FallableTrait`)
- `public Fallable->getMaxFallDamage() : float` (default implementation provided by `FallableTrait`)
### `pocketmine\data\bedrock\block`
- The following new API methods have been added:
- `public BlockStateData->getVersionAsString() : string`
#### `pocketmine\data\bedrock\block\upgrade\model`
- `BlockStateUpgradeSchemaModelBlockRemap` now accepts `null` for `oldState` and `newState`. This makes it easier to generate portable schemas for other languages to read.
### `pocketmine\event\entity`
- The following new API constants have been added:
- `EntityDamageEvent::CAUSE_FALLING_BLOCK`
- `EntityDamageEvent::MODIFIER_ARMOR_HELMET`
### `pocketmine\item`
- The following API methods have signature changes:
- `ItemTypeIds::toBlockTypeId()` may now return `null` if the item type ID is not a block.
### `pocketmine\player`
- The following classes have been removed:
- `PlayerChunkLoader` - deprecated in 4.19.0 (this was technically internal, but never marked as such)
## Internals
- Make use of `Item->canStackWith()` instead of `Item->equals()` wherever possible, to make the code more readable.

View File

@ -5,7 +5,7 @@
"homepage": "https://pmmp.io", "homepage": "https://pmmp.io",
"license": "LGPL-3.0", "license": "LGPL-3.0",
"require": { "require": {
"php": "^8.0", "php": "^8.1",
"php-64bit": "*", "php-64bit": "*",
"ext-chunkutils2": "^0.3.1", "ext-chunkutils2": "^0.3.1",
"ext-crypto": "^0.3.1", "ext-crypto": "^0.3.1",
@ -22,7 +22,7 @@
"ext-openssl": "*", "ext-openssl": "*",
"ext-pcre": "*", "ext-pcre": "*",
"ext-phar": "*", "ext-phar": "*",
"ext-pthreads": "^5.1", "ext-pthreads": "^4.0",
"ext-reflection": "*", "ext-reflection": "*",
"ext-simplexml": "*", "ext-simplexml": "*",
"ext-sockets": "*", "ext-sockets": "*",
@ -33,32 +33,33 @@
"composer-runtime-api": "^2.0", "composer-runtime-api": "^2.0",
"adhocore/json-comment": "^1.1", "adhocore/json-comment": "^1.1",
"fgrosse/phpasn1": "^2.3", "fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0", "pocketmine/netresearch-jsonmapper": "~v4.2.999",
"pocketmine/bedrock-block-upgrade-schema": "~1.1.1+bedrock-1.19.70", "pocketmine/bedrock-block-upgrade-schema": "~2.2.0+bedrock-1.20.0",
"pocketmine/bedrock-data": "~2.1.1+bedrock-1.19.70", "pocketmine/bedrock-data": "~2.3.0+bedrock-1.20.0",
"pocketmine/bedrock-item-upgrade-schema": "~1.1.0+bedrock-1.19.70", "pocketmine/bedrock-item-upgrade-schema": "~1.3.0+bedrock-1.20.0",
"pocketmine/bedrock-protocol": "~20.1.1+bedrock-1.19.70", "pocketmine/bedrock-protocol": "~22.0.0+bedrock-1.20.0",
"pocketmine/binaryutils": "^0.2.1", "pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2", "pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.3.0", "pocketmine/classloader": "^0.2.0",
"pocketmine/color": "^0.3.0", "pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.6.0", "pocketmine/errorhandler": "^0.6.0",
"pocketmine/locale-data": "~2.19.0", "pocketmine/locale-data": "~2.19.0",
"pocketmine/log": "^0.4.0", "pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.5.0", "pocketmine/log-pthreads": "^0.4.0",
"pocketmine/math": "^0.4.0", "pocketmine/math": "^0.4.0",
"pocketmine/nbt": "^0.3.2", "pocketmine/nbt": "^0.3.2",
"pocketmine/raklib": "^0.15.0", "pocketmine/raklib": "^0.14.2",
"pocketmine/raklib-ipc": "^0.2.0", "pocketmine/raklib-ipc": "^0.1.0",
"pocketmine/snooze": "^0.4.0", "pocketmine/snooze": "^0.3.0",
"ramsey/uuid": "^4.1", "ramsey/uuid": "^4.1",
"symfony/filesystem": "^5.4" "symfony/filesystem": "^5.4",
"webmozart/path-util": "^2.3"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "1.10.11", "phpstan/phpstan": "1.10.15",
"phpstan/phpstan-phpunit": "^1.1.0", "phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0", "phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "^9.2" "phpunit/phpunit": "^10.1"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -76,7 +77,7 @@
}, },
"config": { "config": {
"platform": { "platform": {
"php": "8.0.0" "php": "8.1.0"
}, },
"sort-packages": true "sort-packages": true
}, },

1007
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
includes: includes:
- tests/phpstan/analyse-for-current-php-version.neon.php - tests/phpstan/analyse-for-current-php-version.neon.php
- tests/phpstan/configs/actual-problems.neon - tests/phpstan/configs/actual-problems.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/impossible-generics.neon - tests/phpstan/configs/impossible-generics.neon
- tests/phpstan/configs/php-bugs.neon - tests/phpstan/configs/php-bugs.neon
- tests/phpstan/configs/phpstan-bugs.neon - tests/phpstan/configs/phpstan-bugs.neon

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

49988
resources/legacy_recipes.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -85,8 +85,11 @@ network:
batch-threshold: 256 batch-threshold: 256
#Compression level used when sending batched packets. Higher = more CPU, less bandwidth usage #Compression level used when sending batched packets. Higher = more CPU, less bandwidth usage
compression-level: 6 compression-level: 6
#Use AsyncTasks for compression. Adds half/one tick delay, less CPU load on main thread #Use AsyncTasks for compression during the main game session. Increases latency, but may reduce main thread load
async-compression: false async-compression: false
#Threshold for async compression, in bytes. Only packets larger than this will be compressed asynchronously
#Due to large overhead of AsyncTask, async compression isn't worth it except for large packets
async-compression-threshold: 10000
#Experimental. Use UPnP to automatically port forward #Experimental. Use UPnP to automatically port forward
upnp-forwarding: false upnp-forwarding: false
#Maximum size in bytes of packets sent over the network (default 1492 bytes). Packets larger than this will be #Maximum size in bytes of packets sent over the network (default 1492 bytes). Packets larger than this will be

View File

@ -282,8 +282,10 @@ class MemoryManager{
/** /**
* Static memory dumper accessible from any thread. * Static memory dumper accessible from any thread.
*
* @param mixed $startingObject
*/ */
public static function dumpMemory(mixed $startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{ public static function dumpMemory($startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
$hardLimit = Utils::assumeNotFalse(ini_get('memory_limit'), "memory_limit INI directive should always exist"); $hardLimit = Utils::assumeNotFalse(ini_get('memory_limit'), "memory_limit INI directive should always exist");
ini_set('memory_limit', '-1'); ini_set('memory_limit', '-1');
gc_disable(); gc_disable();
@ -314,9 +316,6 @@ class MemoryManager{
continue; continue;
} }
if(!$property->isPublic()){
$property->setAccessible(true);
}
if(!$property->isInitialized()){ if(!$property->isInitialized()){
continue; continue;
} }
@ -440,9 +439,6 @@ class MemoryManager{
continue; continue;
} }
} }
if(!$property->isPublic()){
$property->setAccessible(true);
}
if(!$property->isInitialized($object)){ if(!$property->isInitialized($object)){
continue; continue;
} }
@ -474,6 +470,7 @@ class MemoryManager{
} }
/** /**
* @param mixed $from
* @param object[] $objects reference parameter * @param object[] $objects reference parameter
* @param int[] $refCounts reference parameter * @param int[] $refCounts reference parameter
* *
@ -481,8 +478,10 @@ class MemoryManager{
* @phpstan-param array<string, int> $refCounts * @phpstan-param array<string, int> $refCounts
* @phpstan-param-out array<string, object> $objects * @phpstan-param-out array<string, object> $objects
* @phpstan-param-out array<string, int> $refCounts * @phpstan-param-out array<string, int> $refCounts
*
* @return mixed
*/ */
private static function continueDump(mixed $from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : mixed{ private static function continueDump($from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize){
if($maxNesting <= 0){ if($maxNesting <= 0){
return "(error) NESTING LIMIT REACHED"; return "(error) NESTING LIMIT REACHED";
} }

View File

@ -50,7 +50,7 @@ namespace pocketmine {
require_once __DIR__ . '/VersionInfo.php'; require_once __DIR__ . '/VersionInfo.php';
const MIN_PHP_VERSION = "8.0.0"; const MIN_PHP_VERSION = "8.1.0";
/** /**
* @param string $message * @param string $message
@ -122,8 +122,8 @@ namespace pocketmine {
if(substr_count($pthreads_version, ".") < 2){ if(substr_count($pthreads_version, ".") < 2){
$pthreads_version = "0.$pthreads_version"; $pthreads_version = "0.$pthreads_version";
} }
if(version_compare($pthreads_version, "5.1.0") < 0 || version_compare($pthreads_version, "6.0.0") >= 0){ if(version_compare($pthreads_version, "4.0.0") < 0 || version_compare($pthreads_version, "5.0.0") >= 0){
$messages[] = "pthreads ^5.0.0 is required, while you have $pthreads_version."; $messages[] = "pthreads ^4.0.0 is required, while you have $pthreads_version.";
} }
} }
@ -265,9 +265,6 @@ JIT_WARNING
exit(1); exit(1);
} }
} }
if(extension_loaded('parallel')){
\parallel\bootstrap(\pocketmine\COMPOSER_AUTOLOADER_PATH);
}
ErrorToExceptionHandler::set(); ErrorToExceptionHandler::set();

View File

@ -56,9 +56,12 @@ use pocketmine\network\mcpe\compression\ZlibCompressor;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary; use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\encryption\EncryptionContext; use pocketmine\network\mcpe\encryption\EncryptionContext;
use pocketmine\network\mcpe\EntityEventBroadcaster; use pocketmine\network\mcpe\EntityEventBroadcaster;
use pocketmine\network\mcpe\NetworkBroadcastUtils;
use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\PacketBroadcaster; use pocketmine\network\mcpe\PacketBroadcaster;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext; use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\network\mcpe\raklib\RakLibInterface; use pocketmine\network\mcpe\raklib\RakLibInterface;
use pocketmine\network\mcpe\StandardEntityEventBroadcaster; use pocketmine\network\mcpe\StandardEntityEventBroadcaster;
@ -205,6 +208,8 @@ class Server{
private const TICKS_PER_TPS_OVERLOAD_WARNING = 5 * self::TARGET_TICKS_PER_SECOND; private const TICKS_PER_TPS_OVERLOAD_WARNING = 5 * self::TARGET_TICKS_PER_SECOND;
private const TICKS_PER_STATS_REPORT = 300 * self::TARGET_TICKS_PER_SECOND; private const TICKS_PER_STATS_REPORT = 300 * self::TARGET_TICKS_PER_SECOND;
private const DEFAULT_ASYNC_COMPRESSION_THRESHOLD = 10_000;
private static ?Server $instance = null; private static ?Server $instance = null;
private TimeTrackingSleeperHandler $tickSleeper; private TimeTrackingSleeperHandler $tickSleeper;
@ -263,6 +268,7 @@ class Server{
private Network $network; private Network $network;
private bool $networkCompressionAsync = true; private bool $networkCompressionAsync = true;
private int $networkCompressionAsyncThreshold = self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD;
private Language $language; private Language $language;
private bool $forceLanguage = false; private bool $forceLanguage = false;
@ -493,7 +499,10 @@ class Server{
return $this->configGroup->getPropertyBool("player.save-player-data", true); return $this->configGroup->getPropertyBool("player.save-player-data", true);
} }
public function getOfflinePlayer(string $name) : Player|OfflinePlayer|null{ /**
* @return OfflinePlayer|Player
*/
public function getOfflinePlayer(string $name){
$name = strtolower($name); $name = strtolower($name);
$result = $this->getPlayerExact($name); $result = $this->getPlayerExact($name);
@ -582,7 +591,8 @@ class Server{
}, },
function() use ($playerPromiseResolver, $session) : void{ function() use ($playerPromiseResolver, $session) : void{
if($session->isConnected()){ if($session->isConnected()){
$session->disconnectWithError(KnownTranslationFactory::pocketmine_disconnect_error_respawn()); //TODO: this needs to be localized - this might be reached if the spawn world was unloaded while the player was logging in
$session->disconnect("Failed to find a safe spawn location");
} }
$playerPromiseResolver->reject(); $playerPromiseResolver->reject();
} }
@ -901,6 +911,10 @@ class Server{
ZlibCompressor::setInstance(new ZlibCompressor($netCompressionLevel, $netCompressionThreshold, ZlibCompressor::DEFAULT_MAX_DECOMPRESSION_SIZE)); 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("network.async-compression", true);
$this->networkCompressionAsyncThreshold = max(
$this->configGroup->getPropertyInt("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("network.enable-encryption", true);
@ -960,7 +974,7 @@ class Server{
$this->commandMap = new SimpleCommandMap($this); $this->commandMap = new SimpleCommandMap($this);
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes")); $this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\RESOURCE_PATH, "legacy_recipes.json"));
$this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger); $this->resourceManager = new ResourcePackManager(Path::join($this->getDataPath(), "resource_packs"), $this->logger);
@ -1341,23 +1355,34 @@ class Server{
return count($recipients); return count($recipients);
} }
/**
* @param Player[] $players
* @param ClientboundPacket[] $packets
* @deprecated
*/
public function broadcastPackets(array $players, array $packets) : bool{
return NetworkBroadcastUtils::broadcastPackets($players, $packets);
}
/** /**
* Broadcasts a list of packets in a batch to a list of players * Broadcasts a list of packets in a batch to a list of players
* *
* @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null). * @param bool|null $sync Compression on the main thread (true) or workers (false). Default is automatic (null).
*/ */
public function prepareBatch(string $buffer, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise{ public function prepareBatch(PacketBatch $stream, Compressor $compressor, ?bool $sync = null, ?TimingsHandler $timings = null) : CompressBatchPromise{
$timings ??= Timings::$playerNetworkSendCompress; $timings ??= Timings::$playerNetworkSendCompress;
try{ try{
$timings->startTiming(); $timings->startTiming();
$buffer = $stream->getBuffer();
if($sync === null){ if($sync === null){
$threshold = $compressor->getCompressionThreshold(); $threshold = $compressor->getCompressionThreshold();
$sync = !$this->networkCompressionAsync || $threshold === null || strlen($buffer) < $threshold; $sync = !$this->networkCompressionAsync || $threshold === null || strlen($stream->getBuffer()) < $threshold;
} }
$promise = new CompressBatchPromise(); $promise = new CompressBatchPromise();
if(!$sync){ if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
$task = new CompressBatchTask($buffer, $promise, $compressor); $task = new CompressBatchTask($buffer, $promise, $compressor);
$this->asyncPool->submitTask($task); $this->asyncPool->submitTask($task);
}else{ }else{
@ -1497,7 +1522,7 @@ class Server{
* @param mixed[][]|null $trace * @param mixed[][]|null $trace
* @phpstan-param list<array<string, mixed>>|null $trace * @phpstan-param list<array<string, mixed>>|null $trace
*/ */
public function exceptionHandler(\Throwable $e, ?array $trace = null) : void{ public function exceptionHandler(\Throwable $e, $trace = null) : void{
while(@ob_end_flush()){} while(@ob_end_flush()){}
global $lastError; global $lastError;

View File

@ -43,7 +43,12 @@ final class ServerConfigGroup{
private Config $serverProperties private Config $serverProperties
){} ){}
public function getProperty(string $variable, mixed $defaultValue = null) : mixed{ /**
* @param mixed $defaultValue
*
* @return mixed
*/
public function getProperty(string $variable, $defaultValue = null){
if(!array_key_exists($variable, $this->propertyCache)){ if(!array_key_exists($variable, $this->propertyCache)){
$v = getopt("", ["$variable::"]); $v = getopt("", ["$variable::"]);
if(isset($v[$variable])){ if(isset($v[$variable])){

View File

@ -31,10 +31,9 @@ use function str_repeat;
final class VersionInfo{ final class VersionInfo{
public const NAME = "PocketMine-MP"; public const NAME = "PocketMine-MP";
public const BASE_VERSION = "4.22.1";
public const BASE_VERSION = "5.0.0-BETA2";
public const IS_DEVELOPMENT_BUILD = false; public const IS_DEVELOPMENT_BUILD = false;
public const BUILD_CHANNEL = "beta"; public const BUILD_CHANNEL = "stable";
private function __construct(){ private function __construct(){
//NOOP //NOOP

View File

@ -24,22 +24,17 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\inventory\AnvilInventory; use pocketmine\block\inventory\AnvilInventory;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\Fallable; use pocketmine\block\utils\Fallable;
use pocketmine\block\utils\FallableTrait; use pocketmine\block\utils\FallableTrait;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\object\FallingBlock;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\world\BlockTransaction; use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\AnvilFallSound;
use pocketmine\world\sound\Sound;
use function lcg_value;
use function round;
class Anvil extends Transparent implements Fallable{ class Anvil extends Transparent implements Fallable{
use FallableTrait; use FallableTrait;
@ -51,12 +46,21 @@ class Anvil extends Transparent implements Fallable{
private int $damage = self::UNDAMAGED; private int $damage = self::UNDAMAGED;
protected function describeType(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->boundedInt(2, self::UNDAMAGED, self::VERY_DAMAGED, $this->damage); return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) | ($this->damage << 2);
} }
protected function describeState(RuntimeDataDescriber $w) : void{ public function readStateFromData(int $id, int $stateMeta) : void{
$w->horizontalFacing($this->facing); $this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x3);
$this->damage = BlockDataSerializer::readBoundedInt("damage", $stateMeta >> 2, self::UNDAMAGED, self::VERY_DAMAGED);
}
public function getStateBitmask() : int{
return 0b1111;
}
protected function writeStateToItemMeta() : int{
return $this->damage << 2;
} }
public function getDamage() : int{ return $this->damage; } public function getDamage() : int{ return $this->damage; }
@ -81,7 +85,7 @@ class Anvil extends Transparent implements Fallable{
return SupportType::NONE(); return SupportType::NONE();
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){ if($player instanceof Player){
$player->setCurrentWindow(new AnvilInventory($this->position)); $player->setCurrentWindow(new AnvilInventory($this->position));
} }
@ -96,26 +100,7 @@ class Anvil extends Transparent implements Fallable{
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
public function onHitGround(FallingBlock $blockEntity) : bool{ public function tickFalling() : ?Block{
if(lcg_value() < 0.05 + (round($blockEntity->getFallDistance()) - 1) * 0.05){ return null;
if($this->damage !== self::VERY_DAMAGED){
$this->damage = $this->damage + 1;
}else{
return false;
}
}
return true;
}
public function getFallDamagePerBlock() : float{
return 2.0;
}
public function getMaxFallDamage() : float{
return 40.0;
}
public function getLandSound() : ?Sound{
return new AnvilFallSound();
} }
} }

View File

@ -23,13 +23,12 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\StructureGrowEvent; use pocketmine\event\block\StructureGrowEvent;
use pocketmine\item\Bamboo as ItemBamboo; use pocketmine\item\Bamboo as ItemBamboo;
use pocketmine\item\Fertilizer; use pocketmine\item\Fertilizer;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
@ -55,10 +54,18 @@ class Bamboo extends Transparent{
protected bool $ready = false; protected bool $ready = false;
protected int $leafSize = self::NO_LEAVES; protected int $leafSize = self::NO_LEAVES;
protected function describeState(RuntimeDataDescriber $w) : void{ public function readStateFromData(int $id, int $stateMeta) : void{
$w->boundedInt(2, self::NO_LEAVES, self::LARGE_LEAVES, $this->leafSize); $this->thick = ($stateMeta & BlockLegacyMetadata::BAMBOO_FLAG_THICK) !== 0;
$w->bool($this->thick); $this->leafSize = BlockDataSerializer::readBoundedInt("leafSize", ($stateMeta >> BlockLegacyMetadata::BAMBOO_LEAF_SIZE_SHIFT) & BlockLegacyMetadata::BAMBOO_LEAF_SIZE_MASK, self::NO_LEAVES, self::LARGE_LEAVES);
$w->bool($this->ready); $this->ready = ($stateMeta & BlockLegacyMetadata::BAMBOO_FLAG_READY) !== 0;
}
public function writeStateToMeta() : int{
return ($this->thick ? BlockLegacyMetadata::BAMBOO_FLAG_THICK : 0) | ($this->leafSize << BlockLegacyMetadata::BAMBOO_LEAF_SIZE_SHIFT) | ($this->ready ? BlockLegacyMetadata::BAMBOO_FLAG_READY : 0);
}
public function getStateBitmask() : int{
return 0b1111;
} }
public function isThick() : bool{ return $this->thick; } public function isThick() : bool{ return $this->thick; }
@ -121,11 +128,14 @@ class Bamboo extends Transparent{
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedBy(Block $block) : bool{
//TODO: tags would be better for this
return return
$block->getTypeId() === BlockTypeIds::GRAVEL || $block instanceof Dirt ||
$block->hasTypeTag(BlockTypeTags::DIRT) || $block instanceof Grass ||
$block->hasTypeTag(BlockTypeTags::MUD) || $block instanceof Gravel ||
$block->hasTypeTag(BlockTypeTags::SAND); $block instanceof Sand ||
$block instanceof Mycelium ||
$block instanceof Podzol;
} }
private function seekToTop() : Bamboo{ private function seekToTop() : Bamboo{
@ -137,7 +147,7 @@ class Bamboo extends Transparent{
return $top; return $top;
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer){ if($item instanceof Fertilizer){
$top = $this->seekToTop(); $top = $this->seekToTop();
if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2), $player)){ if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2), $player)){
@ -233,8 +243,4 @@ class Bamboo extends Transparent{
$world->setBlock($this->position, $this); $world->setBlock($this->position, $this);
} }
} }
public function asItem() : Item{
return VanillaItems::BAMBOO();
}
} }

View File

@ -23,23 +23,28 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\StructureGrowEvent; use pocketmine\event\block\StructureGrowEvent;
use pocketmine\item\Bamboo as ItemBamboo; use pocketmine\item\Bamboo as ItemBamboo;
use pocketmine\item\Fertilizer; use pocketmine\item\Fertilizer;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\world\BlockTransaction; use pocketmine\world\BlockTransaction;
final class BambooSapling extends Flowable{ final class BambooSapling extends Flowable{
private bool $ready = false; private bool $ready = false;
protected function describeState(RuntimeDataDescriber $w) : void{ public function readStateFromData(int $id, int $stateMeta) : void{
$w->bool($this->ready); $this->ready = ($stateMeta & BlockLegacyMetadata::BAMBOO_SAPLING_FLAG_READY) !== 0;
} }
protected function writeStateToMeta() : int{
return $this->ready ? BlockLegacyMetadata::BAMBOO_SAPLING_FLAG_READY : 0;
}
public function getStateBitmask() : int{ return 0b1; }
public function isReady() : bool{ return $this->ready; } public function isReady() : bool{ return $this->ready; }
/** @return $this */ /** @return $this */
@ -49,11 +54,14 @@ final class BambooSapling extends Flowable{
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedBy(Block $block) : bool{
//TODO: tags would be better for this
return return
$block->getTypeId() === BlockTypeIds::GRAVEL || $block instanceof Dirt ||
$block->hasTypeTag(BlockTypeTags::DIRT) || $block instanceof Grass ||
$block->hasTypeTag(BlockTypeTags::MUD) || $block instanceof Gravel ||
$block->hasTypeTag(BlockTypeTags::SAND); $block instanceof Sand ||
$block instanceof Mycelium ||
$block instanceof Podzol;
} }
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
@ -63,7 +71,7 @@ final class BambooSapling extends Flowable{
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); 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{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer || $item instanceof ItemBamboo){ if($item instanceof Fertilizer || $item instanceof ItemBamboo){
if($this->grow($player)){ if($this->grow($player)){
$item->pop(); $item->pop();
@ -118,6 +126,6 @@ final class BambooSapling extends Flowable{
} }
public function asItem() : Item{ public function asItem() : Item{
return VanillaItems::BAMBOO(); return VanillaBlocks::BAMBOO()->asItem();
} }
} }

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Barrel as TileBarrel; use pocketmine\block\tile\Barrel as TileBarrel;
use pocketmine\block\utils\AnyFacingTrait; use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
@ -38,9 +38,17 @@ class Barrel extends Opaque{
protected bool $open = false; protected bool $open = false;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->facing($this->facing); return BlockDataSerializer::writeFacing($this->facing) | ($this->open ? BlockLegacyMetadata::BARREL_FLAG_OPEN : 0);
$w->bool($this->open); }
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readFacing($stateMeta & 0x07);
$this->open = ($stateMeta & BlockLegacyMetadata::BARREL_FLAG_OPEN) === BlockLegacyMetadata::BARREL_FLAG_OPEN;
}
public function getStateBitmask() : int{
return 0b1111;
} }
public function isOpen() : bool{ public function isOpen() : bool{
@ -73,7 +81,7 @@ class Barrel extends Opaque{
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); 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{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){ if($player instanceof Player){
$barrel = $this->position->getWorld()->getTile($this->position); $barrel = $this->position->getWorld()->getTile($this->position);
if($barrel instanceof TileBarrel){ if($barrel instanceof TileBarrel){

View File

@ -28,9 +28,9 @@ use pocketmine\block\utils\BannerPatternLayer;
use pocketmine\block\utils\ColoredTrait; use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\bedrock\DyeColorIdMap;
use pocketmine\item\Banner as ItemBanner; use pocketmine\item\Banner as ItemBanner;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
@ -48,20 +48,18 @@ abstract class BaseBanner extends Transparent{
*/ */
protected array $patterns = []; protected array $patterns = [];
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::BLACK(); $this->color = DyeColor::BLACK();
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
} }
public function readStateFromWorld() : Block{ public function readStateFromWorld() : void{
parent::readStateFromWorld(); parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position); $tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBanner){ if($tile instanceof TileBanner){
$this->color = $tile->getBaseColor(); $this->color = $tile->getBaseColor();
$this->setPatterns($tile->getPatterns()); $this->setPatterns($tile->getPatterns());
} }
return $this;
} }
public function writeStateToWorld() : void{ public function writeStateToWorld() : void{
@ -138,6 +136,10 @@ abstract class BaseBanner extends Transparent{
} }
} }
protected function writeStateToItemMeta() : int{
return DyeColorIdMap::getInstance()->toInvertedId($this->color);
}
public function getDropsForCompatibleTool(Item $item) : array{ public function getDropsForCompatibleTool(Item $item) : array{
$drop = $this->asItem(); $drop = $this->asItem();
if($drop instanceof ItemBanner && count($this->patterns) > 0){ if($drop instanceof ItemBanner && count($this->patterns) > 0){
@ -154,8 +156,4 @@ abstract class BaseBanner extends Transparent{
} }
return $result; return $result;
} }
public function asItem() : Item{
return VanillaItems::BANNER()->setColor($this->color);
}
} }

View File

@ -1,89 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\FoodSource;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
abstract class BaseCake extends Transparent implements FoodSource{
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $this->getSide(Facing::DOWN);
if($down->getTypeId() !== BlockTypeIds::AIR){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::AIR){ //Replace with common break method
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player !== null){
return $player->consumeObject($this);
}
return false;
}
public function getFoodRestore() : int{
return 2;
}
public function getSaturationRestore() : float{
return 0.4;
}
public function requiresHunger() : bool{
return true;
}
/**
* @return EffectInstance[]
*/
public function getAdditionalEffects() : array{
return [];
}
abstract public function getResidue() : Block;
public function onConsume(Living $consumer) : void{
$this->position->getWorld()->setBlock($this->position, $this->getResidue());
}
}

View File

@ -28,28 +28,34 @@ use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\event\block\BlockDeathEvent; use pocketmine\event\block\BlockDeathEvent;
use pocketmine\item\Item; use pocketmine\item\Item;
use function mt_rand;
abstract class BaseCoral extends Transparent{ abstract class BaseCoral extends Transparent{
use CoralTypeTrait; use CoralTypeTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
$this->coralType = CoralType::TUBE(); $this->coralType = CoralType::TUBE();
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(!$this->dead){ if(!$this->dead){
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(40, 200)); $world = $this->position->getWorld();
}
}
public function onScheduledUpdate() : void{ $hasWater = false;
if(!$this->dead && !$this->isCoveredWithWater()){ foreach($this->position->sides() as $vector3){
$ev = new BlockDeathEvent($this, $this->setDead(true)); if($world->getBlock($vector3) instanceof Water){
$ev->call(); $hasWater = true;
if(!$ev->isCancelled()){ break;
$this->position->getWorld()->setBlock($this->position, $ev->getNewState()); }
}
//TODO: check water inside the block itself (not supported on the API yet)
if(!$hasWater){
$ev = new BlockDeathEvent($this, $this->setDead(true));
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
}
} }
} }
} }
@ -64,21 +70,6 @@ abstract class BaseCoral extends Transparent{
public function isSolid() : bool{ return false; } public function isSolid() : bool{ return false; }
protected function isCoveredWithWater() : bool{
$world = $this->position->getWorld();
$hasWater = false;
foreach($this->position->sides() as $vector3){
if($world->getBlock($vector3) instanceof Water){
$hasWater = true;
break;
}
}
//TODO: check water inside the block itself (not supported on the API yet)
return $hasWater;
}
protected function recalculateCollisionBoxes() : array{ return []; } protected function recalculateCollisionBoxes() : array{ return []; }
public function getSupportType(int $facing) : SupportType{ public function getSupportType(int $facing) : SupportType{

View File

@ -1,63 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\entity\Entity;
use pocketmine\entity\projectile\Arrow;
use pocketmine\event\entity\EntityCombustByBlockEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
abstract class BaseFire extends Flowable{
public function hasEntityCollision() : bool{
return true;
}
public function canBeReplaced() : bool{
return true;
}
public function onEntityInside(Entity $entity) : bool{
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, $this->getFireDamage());
$entity->attack($ev);
$ev = new EntityCombustByBlockEvent($this, $entity, 8);
if($entity instanceof Arrow){
$ev->cancel();
}
$ev->call();
if(!$ev->isCancelled()){
$entity->setOnFire($ev->getDuration());
}
return true;
}
abstract protected function getFireDamage() : int;
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
}

View File

@ -24,55 +24,35 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\tile\Sign as TileSign; use pocketmine\block\tile\Sign as TileSign;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SignText; use pocketmine\block\utils\SignText;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\WoodType;
use pocketmine\block\utils\WoodTypeTrait;
use pocketmine\color\Color;
use pocketmine\event\block\SignChangeEvent; use pocketmine\event\block\SignChangeEvent;
use pocketmine\item\Dye;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
use pocketmine\world\BlockTransaction; use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\DyeUseSound;
use pocketmine\world\sound\InkSacUseSound;
use function array_map; use function array_map;
use function assert; use function assert;
use function strlen; use function strlen;
abstract class BaseSign extends Transparent{ abstract class BaseSign extends Transparent{
use WoodTypeTrait;
protected SignText $text; protected SignText $text;
protected ?int $editorEntityRuntimeId = null; protected ?int $editorEntityRuntimeId = null;
/** @var \Closure() : Item */ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
private \Closure $asItemCallback; parent::__construct($idInfo, $name, $breakInfo);
/**
* @param \Closure() : Item $asItemCallback
*/
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, WoodType $woodType, \Closure $asItemCallback){
$this->woodType = $woodType;
parent::__construct($idInfo, $name, $typeInfo);
$this->text = new SignText(); $this->text = new SignText();
$this->asItemCallback = $asItemCallback;
} }
public function readStateFromWorld() : Block{ public function readStateFromWorld() : void{
parent::readStateFromWorld(); parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position); $tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileSign){ if($tile instanceof TileSign){
$this->text = $tile->getText(); $this->text = $tile->getText();
$this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId(); $this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId();
} }
return $this;
} }
public function writeStateToWorld() : void{ public function writeStateToWorld() : void{
@ -105,7 +85,7 @@ abstract class BaseSign extends Transparent{
abstract protected function getSupportingFace() : int; abstract protected function getSupportingFace() : int;
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if($this->getSide($this->getSupportingFace())->getTypeId() === BlockTypeIds::AIR){ if($this->getSide($this->getSupportingFace())->getId() === BlockLegacyIds::AIR){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }
@ -117,53 +97,13 @@ abstract class BaseSign extends Transparent{
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
private function doSignChange(SignText $newText, Player $player, Item $item) : bool{ public function onPostPlace() : void{
$ev = new SignChangeEvent($this, $player, $newText); $player = $this->editorEntityRuntimeId !== null ?
$ev->call(); $this->position->getWorld()->getEntity($this->editorEntityRuntimeId) :
if(!$ev->isCancelled()){ null;
$this->text = $ev->getNewText(); if($player instanceof Player){
$this->position->getWorld()->setBlock($this->position, $this); $player->openSignEditor($this->position);
$item->pop();
return true;
} }
return false;
}
private function changeSignGlowingState(bool $glowing, Player $player, Item $item) : bool{
if($this->text->isGlowing() !== $glowing && $this->doSignChange(new SignText($this->text->getLines(), $this->text->getBaseColor(), $glowing), $player, $item)){
$this->position->getWorld()->addSound($this->position, new InkSacUseSound());
return true;
}
return false;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player === null){
return false;
}
$dyeColor = $item instanceof Dye ? $item->getColor() : match($item->getTypeId()){
ItemTypeIds::BONE_MEAL => DyeColor::WHITE(),
ItemTypeIds::LAPIS_LAZULI => DyeColor::BLUE(),
ItemTypeIds::COCOA_BEANS => DyeColor::BROWN(),
default => null
};
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)){
$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);
}
return false;
} }
/** /**
@ -179,6 +119,19 @@ abstract class BaseSign extends Transparent{
return $this; 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
* from editing signs they didn't place.
*/
public function getEditorEntityRuntimeId() : ?int{ return $this->editorEntityRuntimeId; }
/** @return $this */
public function setEditorEntityRuntimeId(?int $editorEntityRuntimeId) : self{
$this->editorEntityRuntimeId = $editorEntityRuntimeId;
return $this;
}
/** /**
* Called by the player controller (network session) to update the sign text, firing events as appropriate. * Called by the player controller (network session) to update the sign text, firing events as appropriate.
* *
@ -202,14 +155,11 @@ abstract class BaseSign extends Transparent{
$ev->call(); $ev->call();
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$this->setText($ev->getNewText()); $this->setText($ev->getNewText());
$this->setEditorEntityRuntimeId(null);
$this->position->getWorld()->setBlock($this->position, $this); $this->position->getWorld()->setBlock($this->position, $this);
return true; return true;
} }
return false; return false;
} }
public function asItem() : Item{
return ($this->asItemCallback)();
}
} }

View File

@ -24,11 +24,12 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\tile\Bed as TileBed; use pocketmine\block\tile\Bed as TileBed;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\ColoredTrait; use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\data\bedrock\DyeColorIdMap;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Living; use pocketmine\entity\Living;
use pocketmine\item\Item; use pocketmine\item\Item;
@ -48,26 +49,34 @@ class Bed extends Transparent{
protected bool $occupied = false; protected bool $occupied = false;
protected bool $head = false; protected bool $head = false;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::RED(); $this->color = DyeColor::RED();
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
} }
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->horizontalFacing($this->facing); return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) |
$w->bool($this->occupied); ($this->occupied ? BlockLegacyMetadata::BED_FLAG_OCCUPIED : 0) |
$w->bool($this->head); ($this->head ? BlockLegacyMetadata::BED_FLAG_HEAD : 0);
} }
public function readStateFromWorld() : Block{ public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
$this->occupied = ($stateMeta & BlockLegacyMetadata::BED_FLAG_OCCUPIED) !== 0;
$this->head = ($stateMeta & BlockLegacyMetadata::BED_FLAG_HEAD) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld(); parent::readStateFromWorld();
//read extra state information from the tile - this is an ugly hack //read extra state information from the tile - this is an ugly hack
$tile = $this->position->getWorld()->getTile($this->position); $tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBed){ if($tile instanceof TileBed){
$this->color = $tile->getColor(); $this->color = $tile->getColor();
} }
return $this;
} }
public function writeStateToWorld() : void{ public function writeStateToWorld() : void{
@ -123,7 +132,7 @@ class Bed extends Transparent{
return null; return null;
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){ if($player !== null){
$other = $this->getOtherHalf(); $other = $this->getOtherHalf();
$playerPos = $player->getPosition(); $playerPos = $player->getPosition();
@ -200,6 +209,10 @@ class Bed extends Transparent{
return []; return [];
} }
protected function writeStateToItemMeta() : int{
return DyeColorIdMap::getInstance()->toId($this->color);
}
public function getAffectedBlocks() : array{ public function getAffectedBlocks() : array{
if(($other = $this->getOtherHalf()) !== null){ if(($other = $this->getOtherHalf()) !== null){
return [$this, $other]; return [$this, $other];
@ -211,6 +224,4 @@ class Bed extends Transparent{
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedBy(Block $block) : bool{
return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE()); return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE());
} }
public function getMaxStackSize() : int{ return 1; }
} }

View File

@ -23,13 +23,20 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
class Bedrock extends Opaque{ class Bedrock extends Opaque{
private bool $burnsForever = false; private bool $burnsForever = false;
protected function describeState(RuntimeDataDescriber $w) : void{ public function readStateFromData(int $id, int $stateMeta) : void{
$w->bool($this->burnsForever); $this->burnsForever = ($stateMeta & BlockLegacyMetadata::BEDROCK_FLAG_INFINIBURN) !== 0;
}
protected function writeStateToMeta() : int{
return $this->burnsForever ? BlockLegacyMetadata::BEDROCK_FLAG_INFINIBURN : 0;
}
public function getStateBitmask() : int{
return 0b1;
} }
public function burnsForever() : bool{ public function burnsForever() : bool{

View File

@ -42,7 +42,7 @@ class Beetroot extends Crops{
]; ];
} }
public function asItem() : Item{ public function getPickedItem(bool $addUserData = false) : Item{
return VanillaItems::BEETROOT_SEEDS(); return VanillaItems::BEETROOT_SEEDS();
} }
} }

View File

@ -25,16 +25,16 @@ namespace pocketmine\block;
use pocketmine\block\tile\Bell as TileBell; use pocketmine\block\tile\Bell as TileBell;
use pocketmine\block\utils\BellAttachmentType; use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\projectile\Projectile;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction; use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\BellRingSound; use pocketmine\world\sound\BellRingSound;
@ -43,14 +43,41 @@ final class Bell extends Transparent{
private BellAttachmentType $attachmentType; private BellAttachmentType $attachmentType;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->attachmentType = BellAttachmentType::FLOOR(); $this->attachmentType = BellAttachmentType::FLOOR();
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
} }
protected function describeState(RuntimeDataDescriber $w) : void{ public function readStateFromData(int $id, int $stateMeta) : void{
$w->bellAttachmentType($this->attachmentType); $this->setFacing(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03));
$w->horizontalFacing($this->facing);
$attachmentType = [
BlockLegacyMetadata::BELL_ATTACHMENT_FLOOR => BellAttachmentType::FLOOR(),
BlockLegacyMetadata::BELL_ATTACHMENT_CEILING => BellAttachmentType::CEILING(),
BlockLegacyMetadata::BELL_ATTACHMENT_ONE_WALL => BellAttachmentType::ONE_WALL(),
BlockLegacyMetadata::BELL_ATTACHMENT_TWO_WALLS => BellAttachmentType::TWO_WALLS()
][($stateMeta >> 2) & 0b11] ?? null;
if($attachmentType === null){
throw new InvalidBlockStateException("No such attachment type");
}
$this->setAttachmentType($attachmentType);
}
public function writeStateToMeta() : int{
$attachmentTypeMeta = [
BellAttachmentType::FLOOR()->id() => BlockLegacyMetadata::BELL_ATTACHMENT_FLOOR,
BellAttachmentType::CEILING()->id() => BlockLegacyMetadata::BELL_ATTACHMENT_CEILING,
BellAttachmentType::ONE_WALL()->id() => BlockLegacyMetadata::BELL_ATTACHMENT_ONE_WALL,
BellAttachmentType::TWO_WALLS()->id() => BlockLegacyMetadata::BELL_ATTACHMENT_TWO_WALLS
][$this->getAttachmentType()->id()] ?? null;
if($attachmentTypeMeta === null){
throw new AssumptionFailedError("Mapping should cover all cases");
}
return BlockDataSerializer::writeLegacyHorizontalFacing($this->getFacing()) | ($attachmentTypeMeta << 2);
}
public function getStateBitmask() : int{
return 0b1111;
} }
protected function recalculateCollisionBoxes() : array{ protected function recalculateCollisionBoxes() : array{
@ -130,10 +157,17 @@ final class Bell extends Transparent{
} }
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){ if($player !== null){
$faceHit = Facing::opposite($player->getHorizontalFacing()); $faceHit = Facing::opposite($player->getHorizontalFacing());
if($this->isValidFaceToRing($faceHit)){ if(
$this->attachmentType->equals(BellAttachmentType::CEILING()) ||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)) ||
(
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
)
){
$this->ring($faceHit); $this->ring($faceHit);
return true; return true;
} }
@ -142,13 +176,6 @@ final class Bell extends Transparent{
return false; return false;
} }
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
$faceHit = Facing::opposite($projectile->getHorizontalFacing());
if($this->isValidFaceToRing($faceHit)){
$this->ring($faceHit);
}
}
public function ring(int $faceHit) : void{ public function ring(int $faceHit) : void{
$world = $this->position->getWorld(); $world = $this->position->getWorld();
$world->addSound($this->position, new BellRingSound()); $world->addSound($this->position, new BellRingSound());
@ -157,15 +184,4 @@ final class Bell extends Transparent{
$world->broadcastPacketToViewers($this->position, $tile->createFakeUpdatePacket($faceHit)); $world->broadcastPacketToViewers($this->position, $tile->createFakeUpdatePacket($faceHit));
} }
} }
private function isValidFaceToRing(int $faceHit) : bool{
return (
$this->attachmentType->equals(BellAttachmentType::CEILING()) ||
($this->attachmentType->equals(BellAttachmentType::FLOOR()) && Facing::axis($faceHit) === Facing::axis($this->facing)) ||
(
($this->attachmentType->equals(BellAttachmentType::ONE_WALL()) || $this->attachmentType->equals(BellAttachmentType::TWO_WALLS())) &&
($faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true))
)
);
}
} }

View File

@ -28,61 +28,49 @@ namespace pocketmine\block;
use pocketmine\block\tile\Spawnable; use pocketmine\block\tile\Spawnable;
use pocketmine\block\tile\Tile; use pocketmine\block\tile\Tile;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\data\runtime\RuntimeDataReader;
use pocketmine\data\runtime\RuntimeDataSizeCalculator;
use pocketmine\data\runtime\RuntimeDataWriter;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\projectile\Projectile;
use pocketmine\item\enchantment\VanillaEnchantments; use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\ItemBlock; use pocketmine\item\ItemFactory;
use pocketmine\math\Axis; use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\RayTraceResult; use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction; use pocketmine\world\BlockTransaction;
use pocketmine\world\format\Chunk; use pocketmine\world\format\Chunk;
use pocketmine\world\Position; use pocketmine\world\Position;
use pocketmine\world\World; use pocketmine\world\World;
use function assert;
use function count; use function count;
use function get_class; use function dechex;
use const PHP_INT_MAX; use const PHP_INT_MAX;
class Block{ class Block{
public const INTERNAL_STATE_DATA_BITS = 8; public const INTERNAL_METADATA_BITS = 4;
public const INTERNAL_STATE_DATA_MASK = ~(~0 << self::INTERNAL_STATE_DATA_BITS); public const INTERNAL_METADATA_MASK = ~(~0 << self::INTERNAL_METADATA_BITS);
protected BlockIdentifier $idInfo; protected BlockIdentifier $idInfo;
protected string $fallbackName; protected string $fallbackName;
protected BlockTypeInfo $typeInfo; protected BlockBreakInfo $breakInfo;
protected Position $position; protected Position $position;
/** @var AxisAlignedBB[]|null */ /** @var AxisAlignedBB[]|null */
protected ?array $collisionBoxes = null; protected ?array $collisionBoxes = null;
/**
* @var int[]
* @phpstan-var array<string, int>
*/
private static array $typeDataBits = [];
/**
* @var int[]
* @phpstan-var array<string, int>
*/
private static array $stateDataBits = [];
/** /**
* @param string $name English name of the block type (TODO: implement translations) * @param string $name English name of the block type (TODO: implement translations)
*/ */
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
if(($idInfo->getVariant() & $this->getStateBitmask()) !== 0){
throw new \InvalidArgumentException("Variant 0x" . dechex($idInfo->getVariant()) . " collides with state bitmask 0x" . dechex($this->getStateBitmask()));
}
$this->idInfo = $idInfo; $this->idInfo = $idInfo;
$this->fallbackName = $name; $this->fallbackName = $name;
$this->typeInfo = $typeInfo; $this->breakInfo = $breakInfo;
$this->position = new Position(0, 0, 0, null); $this->position = new Position(0, 0, 0, null);
} }
@ -91,8 +79,8 @@ class Block{
} }
/** /**
* Returns an object containing information about how to identify and store this block type, such as type ID and * Returns an object containing information about how to identify and store this block type, such as its legacy
* tile type (if any). * numeric ID(s), tile type (if any), and legacy variant metadata.
*/ */
public function getIdInfo() : BlockIdentifier{ public function getIdInfo() : BlockIdentifier{
return $this->idInfo; return $this->idInfo;
@ -106,16 +94,12 @@ class Block{
} }
/** /**
* Returns a type ID that identifies this type of block. This allows comparing basic block types, e.g. wool, stone, * @deprecated
* glass, etc.
* *
* This does **NOT** include information like facing, open/closed, powered/unpowered, colour, etc. This means that, * Returns the legacy numeric Minecraft block ID.
* for example, red wool and green wool have the same type ID.
*
* @see BlockTypeIds
*/ */
public function getTypeId() : int{ public function getId() : int{
return $this->idInfo->getBlockTypeId(); return $this->idInfo->getBlockId();
} }
/** /**
@ -124,48 +108,10 @@ class Block{
* Returns the full blockstate ID of this block. This is a compact way of representing a blockstate used to store * Returns the full blockstate ID of this block. This is a compact way of representing a blockstate used to store
* blocks in chunks at runtime. * blocks in chunks at runtime.
* *
* This usually encodes all properties of the block, such as facing, open/closed, powered/unpowered, colour, etc. * This ID can be used to later obtain a copy of this block using {@link BlockFactory::get()}.
* However, some blocks (such as signs and chests) may store additional properties in an associated "tile" if they
* have too many possible values to be encoded into the state ID. These extra properties are **NOT** included in
* this function's result.
*
* This ID can be used to later obtain a copy of this block using {@link RuntimeBlockStateRegistry::fromStateId()}.
*/ */
public function getStateId() : int{ public function getFullId() : int{
return ($this->getTypeId() << self::INTERNAL_STATE_DATA_BITS) | $this->computeTypeAndStateData(); return ($this->getId() << self::INTERNAL_METADATA_BITS) | $this->getMeta();
}
/**
* Returns whether the given block has an equivalent type to this one. This compares the type IDs.
*/
public function isSameType(Block $other) : bool{
return $this->getTypeId() === $other->getTypeId();
}
/**
* Returns whether the given block has the same type and properties as this block.
*/
public function isSameState(Block $other) : bool{
return $this->getStateId() === $other->getStateId();
}
/**
* @return string[]
*/
public function getTypeTags() : array{
return $this->typeInfo->getTypeTags();
}
/**
* Returns whether this block type has the given type tag. Type tags are used as a dynamic way to tag blocks as
* having certain properties, allowing type checks which are more dynamic than hardcoding a bunch of IDs or a bunch
* of instanceof checks.
*
* For example, grass blocks, dirt, farmland, podzol and mycelium are all dirt-like blocks, and support the
* placement of blocks like flowers, so they have a common tag which allows them to be identified as such.
*/
public function hasTypeTag(string $tag) : bool{
return $this->typeInfo->hasTypeTag($tag);
} }
/** /**
@ -174,114 +120,44 @@ class Block{
* Type information such as colour, wood type, etc. is preserved. * Type information such as colour, wood type, etc. is preserved.
*/ */
public function asItem() : Item{ public function asItem() : Item{
return new ItemBlock($this); return ItemFactory::getInstance()->get(
} $this->idInfo->getItemId(),
$this->idInfo->getVariant() | $this->writeStateToItemMeta()
final public function getRequiredTypeDataBits() : int{ );
$class = get_class($this);
if(isset(self::$typeDataBits[$class])){
return self::$typeDataBits[$class];
}
$calculator = new RuntimeDataSizeCalculator();
$this->describeType($calculator);
return self::$typeDataBits[$class] = $calculator->getBitsUsed();
}
final public function getRequiredStateDataBits() : int{
$class = get_class($this);
if(isset(self::$stateDataBits[$class])){
return self::$stateDataBits[$class];
}
$calculator = new RuntimeDataSizeCalculator();
$this->describeState($calculator);
return self::$stateDataBits[$class] = $calculator->getBitsUsed();
} }
/** /**
* @internal * @deprecated
*/
final public function decodeTypeData(int $data) : void{
$typeBits = $this->getRequiredTypeDataBits();
$reader = new RuntimeDataReader($typeBits, $data);
$this->describeType($reader);
$readBits = $reader->getOffset();
if($typeBits !== $readBits){
throw new \LogicException(get_class($this) . ": Exactly $typeBits bits of type data were provided, but $readBits were read");
}
}
/**
* @internal
*/
final public function decodeTypeAndStateData(int $data) : void{
$typeBits = $this->getRequiredTypeDataBits();
$stateBits = $this->getRequiredStateDataBits();
$reader = new RuntimeDataReader($typeBits + $stateBits, $data);
$this->decodeTypeData($reader->readInt($typeBits));
$this->describeState($reader);
$readBits = $reader->getOffset() - $typeBits;
if($stateBits !== $readBits){
throw new \LogicException(get_class($this) . ": Exactly $stateBits bits of state data were provided, but $readBits were read");
}
}
/**
* @internal
*/
final public function computeTypeData() : int{
$typeBits = $this->getRequiredTypeDataBits();
$writer = new RuntimeDataWriter($typeBits);
$this->describeType($writer);
$writtenBits = $writer->getOffset();
if($typeBits !== $writtenBits){
throw new \LogicException(get_class($this) . ": Exactly $typeBits bits of type data were expected, but $writtenBits were written");
}
return $writer->getValue();
}
/**
* @internal
*/
final public function computeTypeAndStateData() : int{
$typeBits = $this->getRequiredTypeDataBits();
$stateBits = $this->getRequiredStateDataBits();
$writer = new RuntimeDataWriter($typeBits + $stateBits);
$writer->writeInt($typeBits, $this->computeTypeData());
$this->describeState($writer);
$writtenBits = $writer->getOffset() - $typeBits;
if($stateBits !== $writtenBits){
throw new \LogicException(get_class($this) . ": Exactly $stateBits bits of state data were expected, but $writtenBits were written");
}
return $writer->getValue();
}
/**
* Describes properties of this block which apply to both the block and item form of the block.
* Examples of suitable properties include colour, skull type, and any other information which **IS** kept when the
* block is mined or block-picked.
* *
* The method implementation must NOT use conditional logic to determine which properties are written. It must * Returns the legacy Minecraft block meta value. This is a mixed-purpose value, which is used to store different
* always write the same properties in the same order, regardless of the current state of the block. * things for different blocks.
*/ */
protected function describeType(RuntimeDataDescriber $w) : void{ public function getMeta() : int{
//NOOP $stateMeta = $this->writeStateToMeta();
assert(($stateMeta & ~$this->getStateBitmask()) === 0);
return $this->idInfo->getVariant() | $stateMeta;
}
protected function writeStateToItemMeta() : int{
return 0;
} }
/** /**
* Describes properties of this block which apply only to the block form of the block. * Returns a bitmask used to extract state bits from block metadata.
* Examples of suitable properties include facing, open/closed, powered/unpowered, on/off, and any other information * This is used to remove unwanted information from the legacy meta value when getting the block as an item.
* which **IS NOT** kept when the block is mined or block-picked.
*
* The method implementation must NOT use conditional logic to determine which properties are written. It must
* always write the same properties in the same order, regardless of the current state of the block.
*/ */
protected function describeState(RuntimeDataDescriber $w) : void{ public function getStateBitmask() : int{
return 0;
}
protected function writeStateToMeta() : int{
return 0;
}
/**
* @throws InvalidBlockStateException
*/
public function readStateFromData(int $id, int $stateMeta) : void{
//NOOP //NOOP
} }
@ -291,14 +167,9 @@ class Block{
* *
* Clears any cached precomputed objects, such as bounding boxes. Remove any outdated precomputed things such as * Clears any cached precomputed objects, such as bounding boxes. Remove any outdated precomputed things such as
* AABBs and force recalculation. * AABBs and force recalculation.
*
* A replacement block may be returned. This is useful if the block type changed due to reading of world data (e.g.
* data from a block entity).
*/ */
public function readStateFromWorld() : Block{ public function readStateFromWorld() : void{
$this->collisionBoxes = null; $this->collisionBoxes = null;
return $this;
} }
/** /**
@ -309,11 +180,7 @@ class Block{
*/ */
public function writeStateToWorld() : void{ public function writeStateToWorld() : void{
$world = $this->position->getWorld(); $world = $this->position->getWorld();
$chunk = $world->getOrLoadChunkAtPosition($this->position); $world->getOrLoadChunkAtPosition($this->position)->setFullBlock($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getFullId());
if($chunk === null){
throw new AssumptionFailedError("World::setBlock() should have loaded the chunk before calling this method");
}
$chunk->setBlockStateId($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getStateId());
$tileType = $this->idInfo->getTileClass(); $tileType = $this->idInfo->getTileClass();
$oldTile = $world->getTile($this->position); $oldTile = $world->getTile($this->position);
@ -335,6 +202,31 @@ class Block{
} }
} }
/**
* Returns a type ID that identifies this type of block. This does not include information like facing, open/closed,
* powered/unpowered, etc.
*/
public function getTypeId() : int{
return ($this->idInfo->getBlockId() << Block::INTERNAL_METADATA_BITS) | $this->idInfo->getVariant();
}
/**
* Returns whether the given block has an equivalent type to this one. This compares the type IDs.
*
* Note: This ignores additional IDs used to represent additional states. This means that, for example, a lit
* furnace and unlit furnace are considered the same type.
*/
public function isSameType(Block $other) : bool{
return $this->getTypeId() === $other->getTypeId();
}
/**
* Returns whether the given block has the same type and properties as this block.
*/
public function isSameState(Block $other) : bool{
return $this->getFullId() === $other->getFullId();
}
/** /**
* AKA: Block->isPlaceable * AKA: Block->isPlaceable
*/ */
@ -388,15 +280,13 @@ class Block{
* Returns an object containing information about the destruction requirements of this block. * Returns an object containing information about the destruction requirements of this block.
*/ */
public function getBreakInfo() : BlockBreakInfo{ public function getBreakInfo() : BlockBreakInfo{
return $this->typeInfo->getBreakInfo(); return $this->breakInfo;
} }
/** /**
* Do the actions needed so the block is broken with the Item * Do the actions needed so the block is broken with the Item
*
* @param Item[] &$returnedItems Items to be added to the target's inventory (or dropped, if full)
*/ */
public function onBreak(Item $item, ?Player $player = null, array &$returnedItems = []) : bool{ public function onBreak(Item $item, ?Player $player = null) : bool{
$world = $this->position->getWorld(); $world = $this->position->getWorld();
if(($t = $world->getTile($this->position)) !== null){ if(($t = $world->getTile($this->position)) !== null){
$t->onBlockDestroyed(); $t->onBlockDestroyed();
@ -436,10 +326,8 @@ class Block{
/** /**
* Do actions when interacted by Item. Returns if it has done anything * Do actions when interacted by Item. Returns if it has done anything
*
* @param Item[] &$returnedItems Items to be added to the target's inventory (or dropped, if the inventory is full)
*/ */
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
return false; return false;
} }
@ -531,7 +419,7 @@ class Block{
* @return Item[] * @return Item[]
*/ */
public function getDrops(Item $item) : array{ public function getDrops(Item $item) : array{
if($this->getBreakInfo()->isToolCompatible($item)){ if($this->breakInfo->isToolCompatible($item)){
if($this->isAffectedBySilkTouch() && $item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){ if($this->isAffectedBySilkTouch() && $item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){
return $this->getSilkTouchDrops($item); return $this->getSilkTouchDrops($item);
} }
@ -573,7 +461,7 @@ class Block{
* Returns how much XP will be dropped by breaking this block with the given item. * Returns how much XP will be dropped by breaking this block with the given item.
*/ */
public function getXpDropForTool(Item $item) : int{ public function getXpDropForTool(Item $item) : int{
if($item->hasEnchantment(VanillaEnchantments::SILK_TOUCH()) || !$this->getBreakInfo()->isToolCompatible($item)){ if($item->hasEnchantment(VanillaEnchantments::SILK_TOUCH()) || !$this->breakInfo->isToolCompatible($item)){
return 0; return 0;
} }
@ -627,10 +515,6 @@ class Block{
return 64; return 64;
} }
public function isFireProofAsItem() : bool{
return false;
}
/** /**
* Returns the chance that the block will catch fire from nearby fire sources. Higher values lead to faster catching * Returns the chance that the block will catch fire from nearby fire sources. Higher values lead to faster catching
* fire. * fire.
@ -720,7 +604,7 @@ class Block{
* @return string * @return string
*/ */
public function __toString(){ public function __toString(){
return "Block[" . $this->getName() . "] (" . $this->getTypeId() . ":" . $this->computeTypeAndStateData() . ")"; return "Block[" . $this->getName() . "] (" . $this->getId() . ":" . $this->getMeta() . ")";
} }
/** /**
@ -779,13 +663,6 @@ class Block{
return null; return null;
} }
/**
* Called when a projectile collides with one of this block's collision boxes.
*/
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
//NOOP
}
/** /**
* Returns an array of collision bounding boxes for this block. * Returns an array of collision bounding boxes for this block.
* These are used for: * These are used for:

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\ToolTier;
use function get_class; use function get_class;
class BlockBreakInfo{ class BlockBreakInfo{
@ -53,22 +52,6 @@ class BlockBreakInfo{
$this->blastResistance = $blastResistance ?? $hardness * 5; $this->blastResistance = $blastResistance ?? $hardness * 5;
} }
public static function tier(float $hardness, int $toolType, ToolTier $toolTier, ?float $blastResistance = null) : self{
return new self($hardness, $toolType, $toolTier->getHarvestLevel(), $blastResistance);
}
public static function pickaxe(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : self{
return new self($hardness, BlockToolType::PICKAXE, $toolTier?->getHarvestLevel() ?? 0, $blastResistance);
}
public static function shovel(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : self{
return new self($hardness, BlockToolType::SHOVEL, $toolTier?->getHarvestLevel() ?? 0, $blastResistance);
}
public static function axe(float $hardness, ?ToolTier $toolTier = null, ?float $blastResistance = null) : self{
return new self($hardness, BlockToolType::AXE, $toolTier?->getHarvestLevel() ?? 0, $blastResistance);
}
public static function instant(int $toolType = BlockToolType::NONE, int $toolHarvestLevel = 0) : self{ public static function instant(int $toolType = BlockToolType::NONE, int $toolHarvestLevel = 0) : self{
return new self(0.0, $toolType, $toolHarvestLevel, 0.0); return new self(0.0, $toolType, $toolHarvestLevel, 0.0);
} }

1090
src/block/BlockFactory.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -31,18 +31,34 @@ class BlockIdentifier{
* @phpstan-param class-string<Tile>|null $tileClass * @phpstan-param class-string<Tile>|null $tileClass
*/ */
public function __construct( public function __construct(
private int $blockTypeId, private int $blockId,
private int $variant,
private ?int $itemId = null,
private ?string $tileClass = null private ?string $tileClass = null
){ ){
if($blockTypeId < 0){
throw new \InvalidArgumentException("Block type ID may not be negative");
}
if($tileClass !== null){ if($tileClass !== null){
Utils::testValidInstance($tileClass, Tile::class); Utils::testValidInstance($tileClass, Tile::class);
} }
} }
public function getBlockTypeId() : int{ return $this->blockTypeId; } public function getBlockId() : int{
return $this->blockId;
}
/**
* @return int[]
*/
public function getAllBlockIds() : array{
return [$this->blockId];
}
public function getVariant() : int{
return $this->variant;
}
public function getItemId() : int{
return $this->itemId ?? ($this->blockId > 255 ? 255 - $this->blockId : $this->blockId);
}
/** /**
* @phpstan-return class-string<Tile>|null * @phpstan-return class-string<Tile>|null

View File

@ -0,0 +1,59 @@
<?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 function count;
class BlockIdentifierFlattened extends BlockIdentifier{
/** @var int[] */
private array $additionalIds;
/**
* @param int[] $additionalIds
*/
public function __construct(int $blockId, array $additionalIds, int $variant, ?int $itemId = null, ?string $tileClass = null){
if(count($additionalIds) === 0){
throw new \InvalidArgumentException("Expected at least 1 additional ID");
}
parent::__construct($blockId, $variant, $itemId, $tileClass);
$this->additionalIds = $additionalIds;
}
public function getAdditionalId(int $index) : int{
if(!isset($this->additionalIds[$index])){
throw new \InvalidArgumentException("No such ID at index $index");
}
return $this->additionalIds[$index];
}
public function getSecondId() : int{
return $this->getAdditionalId(0);
}
public function getAllBlockIds() : array{
return [$this->getBlockId(), ...$this->additionalIds];
}
}

View File

@ -24,270 +24,225 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\BlockIdentifier as BID; use pocketmine\block\BlockIdentifier as BID;
use pocketmine\block\BlockTypeIds as Ids; use pocketmine\block\BlockLegacyIds as Ids;
use pocketmine\block\tile\Sign as TileSign; use pocketmine\block\tile\Sign as TileSign;
use pocketmine\block\utils\LeavesType; use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\TreeType; use pocketmine\block\utils\TreeType;
use pocketmine\block\utils\WoodType; use pocketmine\item\ItemIds;
use pocketmine\item\VanillaItems;
use pocketmine\utils\AssumptionFailedError; use pocketmine\utils\AssumptionFailedError;
final class BlockLegacyIdHelper{ final class BlockLegacyIdHelper{
public static function getWoodenPlanksIdentifier(WoodType $type) : BID{ public static function getWoodenFloorSignIdentifier(TreeType $treeType) : BID{
return new BID(match($type->id()){
WoodType::OAK()->id() => Ids::OAK_PLANKS,
WoodType::SPRUCE()->id() => Ids::SPRUCE_PLANKS,
WoodType::BIRCH()->id() => Ids::BIRCH_PLANKS,
WoodType::JUNGLE()->id() => Ids::JUNGLE_PLANKS,
WoodType::ACACIA()->id() => Ids::ACACIA_PLANKS,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_PLANKS,
WoodType::MANGROVE()->id() => Ids::MANGROVE_PLANKS,
WoodType::CRIMSON()->id() => Ids::CRIMSON_PLANKS,
WoodType::WARPED()->id() => Ids::WARPED_PLANKS,
default => throw new AssumptionFailedError("All tree types should be covered")
});
}
public static function getWoodenFenceIdentifier(WoodType $type) : BID{
return new BID(match($type->id()){
WoodType::OAK()->id() => Ids::OAK_FENCE,
WoodType::SPRUCE()->id() => Ids::SPRUCE_FENCE,
WoodType::BIRCH()->id() => Ids::BIRCH_FENCE,
WoodType::JUNGLE()->id() => Ids::JUNGLE_FENCE,
WoodType::ACACIA()->id() => Ids::ACACIA_FENCE,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_FENCE,
WoodType::MANGROVE()->id() => Ids::MANGROVE_FENCE,
WoodType::CRIMSON()->id() => Ids::CRIMSON_FENCE,
WoodType::WARPED()->id() => Ids::WARPED_FENCE,
default => throw new AssumptionFailedError("All tree types should be covered")
});
}
public static function getWoodenSlabIdentifier(WoodType $type) : BID{
return new BID(match($type->id()){
WoodType::OAK()->id() => Ids::OAK_SLAB,
WoodType::SPRUCE()->id() => Ids::SPRUCE_SLAB,
WoodType::BIRCH()->id() => Ids::BIRCH_SLAB,
WoodType::JUNGLE()->id() => Ids::JUNGLE_SLAB,
WoodType::ACACIA()->id() => Ids::ACACIA_SLAB,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_SLAB,
WoodType::MANGROVE()->id() => Ids::MANGROVE_SLAB,
WoodType::CRIMSON()->id() => Ids::CRIMSON_SLAB,
WoodType::WARPED()->id() => Ids::WARPED_SLAB,
default => throw new AssumptionFailedError("All tree types should be covered")
});
}
public static function getLogIdentifier(WoodType $treeType) : BID{
return new BID(match($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_LOG,
WoodType::SPRUCE()->id() => Ids::SPRUCE_LOG,
WoodType::BIRCH()->id() => Ids::BIRCH_LOG,
WoodType::JUNGLE()->id() => Ids::JUNGLE_LOG,
WoodType::ACACIA()->id() => Ids::ACACIA_LOG,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_LOG,
WoodType::MANGROVE()->id() => Ids::MANGROVE_LOG,
WoodType::CRIMSON()->id() => Ids::CRIMSON_STEM,
WoodType::WARPED()->id() => Ids::WARPED_STEM,
default => throw new AssumptionFailedError("All tree types should be covered")
});
}
public static function getAllSidedLogIdentifier(WoodType $treeType) : BID{
return new BID(match($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_WOOD,
WoodType::SPRUCE()->id() => Ids::SPRUCE_WOOD,
WoodType::BIRCH()->id() => Ids::BIRCH_WOOD,
WoodType::JUNGLE()->id() => Ids::JUNGLE_WOOD,
WoodType::ACACIA()->id() => Ids::ACACIA_WOOD,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_WOOD,
WoodType::MANGROVE()->id() => Ids::MANGROVE_WOOD,
WoodType::CRIMSON()->id() => Ids::CRIMSON_HYPHAE,
WoodType::WARPED()->id() => Ids::WARPED_HYPHAE,
default => throw new AssumptionFailedError("All tree types should be covered")
});
}
public static function getLeavesIdentifier(LeavesType $leavesType) : BID{
return new BID(match($leavesType->id()){
LeavesType::OAK()->id() => Ids::OAK_LEAVES,
LeavesType::SPRUCE()->id() => Ids::SPRUCE_LEAVES,
LeavesType::BIRCH()->id() => Ids::BIRCH_LEAVES,
LeavesType::JUNGLE()->id() => Ids::JUNGLE_LEAVES,
LeavesType::ACACIA()->id() => Ids::ACACIA_LEAVES,
LeavesType::DARK_OAK()->id() => Ids::DARK_OAK_LEAVES,
LeavesType::MANGROVE()->id() => Ids::MANGROVE_LEAVES,
LeavesType::AZALEA()->id() => Ids::AZALEA_LEAVES,
LeavesType::FLOWERING_AZALEA()->id() => Ids::FLOWERING_AZALEA_LEAVES,
default => throw new AssumptionFailedError("All leaves types should be covered")
});
}
public static function getSaplingIdentifier(TreeType $treeType) : BID{
return new BID(match($treeType->id()){
TreeType::OAK()->id() => Ids::OAK_SAPLING,
TreeType::SPRUCE()->id() => Ids::SPRUCE_SAPLING,
TreeType::BIRCH()->id() => Ids::BIRCH_SAPLING,
TreeType::JUNGLE()->id() => Ids::JUNGLE_SAPLING,
TreeType::ACACIA()->id() => Ids::ACACIA_SAPLING,
TreeType::DARK_OAK()->id() => Ids::DARK_OAK_SAPLING,
default => throw new AssumptionFailedError("All tree types should be covered")
});
}
/**
* @return BID[]|\Closure[]
* @phpstan-return array{BID, BID, \Closure() : \pocketmine\item\Item}
*/
public static function getWoodenSignInfo(WoodType $treeType) : array{
switch($treeType->id()){ switch($treeType->id()){
case WoodType::OAK()->id(): case TreeType::OAK()->id():
return [ return new BID(Ids::SIGN_POST, 0, ItemIds::SIGN, TileSign::class);
new BID(Ids::OAK_SIGN, TileSign::class), case TreeType::SPRUCE()->id():
new BID(Ids::OAK_WALL_SIGN, TileSign::class), return new BID(Ids::SPRUCE_STANDING_SIGN, 0, ItemIds::SPRUCE_SIGN, TileSign::class);
fn() => VanillaItems::OAK_SIGN() case TreeType::BIRCH()->id():
]; return new BID(Ids::BIRCH_STANDING_SIGN, 0, ItemIds::BIRCH_SIGN, TileSign::class);
case WoodType::SPRUCE()->id(): case TreeType::JUNGLE()->id():
return [ return new BID(Ids::JUNGLE_STANDING_SIGN, 0, ItemIds::JUNGLE_SIGN, TileSign::class);
new BID(Ids::SPRUCE_SIGN, TileSign::class), case TreeType::ACACIA()->id():
new BID(Ids::SPRUCE_WALL_SIGN, TileSign::class), return new BID(Ids::ACACIA_STANDING_SIGN,0, ItemIds::ACACIA_SIGN, TileSign::class);
fn() => VanillaItems::SPRUCE_SIGN() case TreeType::DARK_OAK()->id():
]; return new BID(Ids::DARKOAK_STANDING_SIGN, 0, ItemIds::DARKOAK_SIGN, TileSign::class);
case WoodType::BIRCH()->id():
return [
new BID(Ids::BIRCH_SIGN, TileSign::class),
new BID(Ids::BIRCH_WALL_SIGN, TileSign::class),
fn() => VanillaItems::BIRCH_SIGN()
];
case WoodType::JUNGLE()->id():
return [
new BID(Ids::JUNGLE_SIGN, TileSign::class),
new BID(Ids::JUNGLE_WALL_SIGN, TileSign::class),
fn() => VanillaItems::JUNGLE_SIGN()
];
case WoodType::ACACIA()->id():
return [
new BID(Ids::ACACIA_SIGN, TileSign::class),
new BID(Ids::ACACIA_WALL_SIGN, TileSign::class),
fn() => VanillaItems::ACACIA_SIGN()
];
case WoodType::DARK_OAK()->id():
return [
new BID(Ids::DARK_OAK_SIGN, TileSign::class),
new BID(Ids::DARK_OAK_WALL_SIGN, TileSign::class),
fn() => VanillaItems::DARK_OAK_SIGN()
];
case WoodType::MANGROVE()->id():
return [
new BID(Ids::MANGROVE_SIGN, TileSign::class),
new BID(Ids::MANGROVE_WALL_SIGN, TileSign::class),
fn() => VanillaItems::MANGROVE_SIGN()
];
case WoodType::CRIMSON()->id():
return [
new BID(Ids::CRIMSON_SIGN, TileSign::class),
new BID(Ids::CRIMSON_WALL_SIGN, TileSign::class),
fn() => VanillaItems::CRIMSON_SIGN()
];
case WoodType::WARPED()->id():
return [
new BID(Ids::WARPED_SIGN, TileSign::class),
new BID(Ids::WARPED_WALL_SIGN, TileSign::class),
fn() => VanillaItems::WARPED_SIGN()
];
} }
throw new AssumptionFailedError("Switch should cover all wood types"); throw new AssumptionFailedError("Switch should cover all wood types");
} }
public static function getWoodenTrapdoorIdentifier(WoodType $treeType) : BlockIdentifier{ public static function getWoodenWallSignIdentifier(TreeType $treeType) : BID{
return new BID(match($treeType->id()){ switch($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_TRAPDOOR, case TreeType::OAK()->id():
WoodType::SPRUCE()->id() => Ids::SPRUCE_TRAPDOOR, return new BID(Ids::WALL_SIGN, 0, ItemIds::SIGN, TileSign::class);
WoodType::BIRCH()->id() => Ids::BIRCH_TRAPDOOR, case TreeType::SPRUCE()->id():
WoodType::JUNGLE()->id() => Ids::JUNGLE_TRAPDOOR, return new BID(Ids::SPRUCE_WALL_SIGN, 0, ItemIds::SPRUCE_SIGN, TileSign::class);
WoodType::ACACIA()->id() => Ids::ACACIA_TRAPDOOR, case TreeType::BIRCH()->id():
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_TRAPDOOR, return new BID(Ids::BIRCH_WALL_SIGN, 0, ItemIds::BIRCH_SIGN, TileSign::class);
WoodType::MANGROVE()->id() => Ids::MANGROVE_TRAPDOOR, case TreeType::JUNGLE()->id():
WoodType::CRIMSON()->id() => Ids::CRIMSON_TRAPDOOR, return new BID(Ids::JUNGLE_WALL_SIGN, 0, ItemIds::JUNGLE_SIGN, TileSign::class);
WoodType::WARPED()->id() => Ids::WARPED_TRAPDOOR, case TreeType::ACACIA()->id():
default => throw new AssumptionFailedError("All wood types should be covered") return new BID(Ids::ACACIA_WALL_SIGN, 0, ItemIds::ACACIA_SIGN, TileSign::class);
}); case TreeType::DARK_OAK()->id():
return new BID(Ids::DARKOAK_WALL_SIGN, 0, ItemIds::DARKOAK_SIGN, TileSign::class);
}
throw new AssumptionFailedError("Switch should cover all wood types");
} }
public static function getWoodenButtonIdentifier(WoodType $treeType) : BlockIdentifier{ public static function getWoodenTrapdoorIdentifier(TreeType $treeType) : BlockIdentifier{
return new BID(match($treeType->id()){ switch($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_BUTTON, case TreeType::OAK()->id():
WoodType::SPRUCE()->id() => Ids::SPRUCE_BUTTON, return new BlockIdentifier(Ids::WOODEN_TRAPDOOR, 0);
WoodType::BIRCH()->id() => Ids::BIRCH_BUTTON, case TreeType::SPRUCE()->id():
WoodType::JUNGLE()->id() => Ids::JUNGLE_BUTTON, return new BlockIdentifier(Ids::SPRUCE_TRAPDOOR, 0);
WoodType::ACACIA()->id() => Ids::ACACIA_BUTTON, case TreeType::BIRCH()->id():
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_BUTTON, return new BlockIdentifier(Ids::BIRCH_TRAPDOOR, 0);
WoodType::MANGROVE()->id() => Ids::MANGROVE_BUTTON, case TreeType::JUNGLE()->id():
WoodType::CRIMSON()->id() => Ids::CRIMSON_BUTTON, return new BlockIdentifier(Ids::JUNGLE_TRAPDOOR, 0);
WoodType::WARPED()->id() => Ids::WARPED_BUTTON, case TreeType::ACACIA()->id():
default => throw new AssumptionFailedError("All wood types should be covered") return new BlockIdentifier(Ids::ACACIA_TRAPDOOR, 0);
}); case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_TRAPDOOR, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
} }
public static function getWoodenPressurePlateIdentifier(WoodType $treeType) : BlockIdentifier{ public static function getWoodenButtonIdentifier(TreeType $treeType) : BlockIdentifier{
return new BID(match($treeType->id()){ switch($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_PRESSURE_PLATE, case TreeType::OAK()->id():
WoodType::SPRUCE()->id() => Ids::SPRUCE_PRESSURE_PLATE, return new BlockIdentifier(Ids::WOODEN_BUTTON, 0);
WoodType::BIRCH()->id() => Ids::BIRCH_PRESSURE_PLATE, case TreeType::SPRUCE()->id():
WoodType::JUNGLE()->id() => Ids::JUNGLE_PRESSURE_PLATE, return new BlockIdentifier(Ids::SPRUCE_BUTTON, 0);
WoodType::ACACIA()->id() => Ids::ACACIA_PRESSURE_PLATE, case TreeType::BIRCH()->id():
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_PRESSURE_PLATE, return new BlockIdentifier(Ids::BIRCH_BUTTON, 0);
WoodType::MANGROVE()->id() => Ids::MANGROVE_PRESSURE_PLATE, case TreeType::JUNGLE()->id():
WoodType::CRIMSON()->id() => Ids::CRIMSON_PRESSURE_PLATE, return new BlockIdentifier(Ids::JUNGLE_BUTTON, 0);
WoodType::WARPED()->id() => Ids::WARPED_PRESSURE_PLATE, case TreeType::ACACIA()->id():
default => throw new AssumptionFailedError("All wood types should be covered") return new BlockIdentifier(Ids::ACACIA_BUTTON, 0);
}); case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_BUTTON, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
} }
public static function getWoodenDoorIdentifier(WoodType $treeType) : BlockIdentifier{ public static function getWoodenPressurePlateIdentifier(TreeType $treeType) : BlockIdentifier{
return new BID(match($treeType->id()){ switch($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_DOOR, case TreeType::OAK()->id():
WoodType::SPRUCE()->id() => Ids::SPRUCE_DOOR, return new BlockIdentifier(Ids::WOODEN_PRESSURE_PLATE, 0);
WoodType::BIRCH()->id() => Ids::BIRCH_DOOR, case TreeType::SPRUCE()->id():
WoodType::JUNGLE()->id() => Ids::JUNGLE_DOOR, return new BlockIdentifier(Ids::SPRUCE_PRESSURE_PLATE, 0);
WoodType::ACACIA()->id() => Ids::ACACIA_DOOR, case TreeType::BIRCH()->id():
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_DOOR, return new BlockIdentifier(Ids::BIRCH_PRESSURE_PLATE, 0);
WoodType::MANGROVE()->id() => Ids::MANGROVE_DOOR, case TreeType::JUNGLE()->id():
WoodType::CRIMSON()->id() => Ids::CRIMSON_DOOR, return new BlockIdentifier(Ids::JUNGLE_PRESSURE_PLATE, 0);
WoodType::WARPED()->id() => Ids::WARPED_DOOR, case TreeType::ACACIA()->id():
default => throw new AssumptionFailedError("All wood types should be covered") return new BlockIdentifier(Ids::ACACIA_PRESSURE_PLATE, 0);
}); case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_PRESSURE_PLATE, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
} }
public static function getWoodenFenceGateIdentifier(WoodType $treeType) : BlockIdentifier{ public static function getWoodenDoorIdentifier(TreeType $treeType) : BlockIdentifier{
return new BID(match($treeType->id()){ switch($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_FENCE_GATE, case TreeType::OAK()->id():
WoodType::SPRUCE()->id() => Ids::SPRUCE_FENCE_GATE, return new BID(Ids::OAK_DOOR_BLOCK, 0, ItemIds::OAK_DOOR);
WoodType::BIRCH()->id() => Ids::BIRCH_FENCE_GATE, case TreeType::SPRUCE()->id():
WoodType::JUNGLE()->id() => Ids::JUNGLE_FENCE_GATE, return new BID(Ids::SPRUCE_DOOR_BLOCK, 0, ItemIds::SPRUCE_DOOR);
WoodType::ACACIA()->id() => Ids::ACACIA_FENCE_GATE, case TreeType::BIRCH()->id():
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_FENCE_GATE, return new BID(Ids::BIRCH_DOOR_BLOCK, 0, ItemIds::BIRCH_DOOR);
WoodType::MANGROVE()->id() => Ids::MANGROVE_FENCE_GATE, case TreeType::JUNGLE()->id():
WoodType::CRIMSON()->id() => Ids::CRIMSON_FENCE_GATE, return new BID(Ids::JUNGLE_DOOR_BLOCK, 0, ItemIds::JUNGLE_DOOR);
WoodType::WARPED()->id() => Ids::WARPED_FENCE_GATE, case TreeType::ACACIA()->id():
default => throw new AssumptionFailedError("All wood types should be covered") return new BID(Ids::ACACIA_DOOR_BLOCK, 0, ItemIds::ACACIA_DOOR);
}); case TreeType::DARK_OAK()->id():
return new BID(Ids::DARK_OAK_DOOR_BLOCK, 0, ItemIds::DARK_OAK_DOOR);
}
throw new AssumptionFailedError("Switch should cover all wood types");
} }
public static function getWoodenStairsIdentifier(WoodType $treeType) : BlockIdentifier{ public static function getWoodenFenceIdentifier(TreeType $treeType) : BlockIdentifier{
return new BID(match($treeType->id()){ switch($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_STAIRS, case TreeType::OAK()->id():
WoodType::SPRUCE()->id() => Ids::SPRUCE_STAIRS, return new BlockIdentifier(Ids::OAK_FENCE_GATE, 0);
WoodType::BIRCH()->id() => Ids::BIRCH_STAIRS, case TreeType::SPRUCE()->id():
WoodType::JUNGLE()->id() => Ids::JUNGLE_STAIRS, return new BlockIdentifier(Ids::SPRUCE_FENCE_GATE, 0);
WoodType::ACACIA()->id() => Ids::ACACIA_STAIRS, case TreeType::BIRCH()->id():
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_STAIRS, return new BlockIdentifier(Ids::BIRCH_FENCE_GATE, 0);
WoodType::MANGROVE()->id() => Ids::MANGROVE_STAIRS, case TreeType::JUNGLE()->id():
WoodType::CRIMSON()->id() => Ids::CRIMSON_STAIRS, return new BlockIdentifier(Ids::JUNGLE_FENCE_GATE, 0);
WoodType::WARPED()->id() => Ids::WARPED_STAIRS, case TreeType::ACACIA()->id():
default => throw new AssumptionFailedError("All wood types should be covered") return new BlockIdentifier(Ids::ACACIA_FENCE_GATE, 0);
}); case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_FENCE_GATE, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getWoodenStairsIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::OAK_STAIRS, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_STAIRS, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_STAIRS, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_STAIRS, 0);
case TreeType::ACACIA()->id():
return new BlockIdentifier(Ids::ACACIA_STAIRS, 0);
case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::DARK_OAK_STAIRS, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getStrippedLogIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::STRIPPED_OAK_LOG, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::STRIPPED_SPRUCE_LOG, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::STRIPPED_BIRCH_LOG, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::STRIPPED_JUNGLE_LOG, 0);
case TreeType::ACACIA()->id():
return new BlockIdentifier(Ids::STRIPPED_ACACIA_LOG, 0);
case TreeType::DARK_OAK()->id():
return new BlockIdentifier(Ids::STRIPPED_DARK_OAK_LOG, 0);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getGlazedTerracottaIdentifier(DyeColor $color) : BlockIdentifier{
switch($color->id()){
case DyeColor::WHITE()->id():
return new BlockIdentifier(Ids::WHITE_GLAZED_TERRACOTTA, 0);
case DyeColor::ORANGE()->id():
return new BlockIdentifier(Ids::ORANGE_GLAZED_TERRACOTTA, 0);
case DyeColor::MAGENTA()->id():
return new BlockIdentifier(Ids::MAGENTA_GLAZED_TERRACOTTA, 0);
case DyeColor::LIGHT_BLUE()->id():
return new BlockIdentifier(Ids::LIGHT_BLUE_GLAZED_TERRACOTTA, 0);
case DyeColor::YELLOW()->id():
return new BlockIdentifier(Ids::YELLOW_GLAZED_TERRACOTTA, 0);
case DyeColor::LIME()->id():
return new BlockIdentifier(Ids::LIME_GLAZED_TERRACOTTA, 0);
case DyeColor::PINK()->id():
return new BlockIdentifier(Ids::PINK_GLAZED_TERRACOTTA, 0);
case DyeColor::GRAY()->id():
return new BlockIdentifier(Ids::GRAY_GLAZED_TERRACOTTA, 0);
case DyeColor::LIGHT_GRAY()->id():
return new BlockIdentifier(Ids::SILVER_GLAZED_TERRACOTTA, 0);
case DyeColor::CYAN()->id():
return new BlockIdentifier(Ids::CYAN_GLAZED_TERRACOTTA, 0);
case DyeColor::PURPLE()->id():
return new BlockIdentifier(Ids::PURPLE_GLAZED_TERRACOTTA, 0);
case DyeColor::BLUE()->id():
return new BlockIdentifier(Ids::BLUE_GLAZED_TERRACOTTA, 0);
case DyeColor::BROWN()->id():
return new BlockIdentifier(Ids::BROWN_GLAZED_TERRACOTTA, 0);
case DyeColor::GREEN()->id():
return new BlockIdentifier(Ids::GREEN_GLAZED_TERRACOTTA, 0);
case DyeColor::RED()->id():
return new BlockIdentifier(Ids::RED_GLAZED_TERRACOTTA, 0);
case DyeColor::BLACK()->id():
return new BlockIdentifier(Ids::BLACK_GLAZED_TERRACOTTA, 0);
}
throw new AssumptionFailedError("Switch should cover all colours");
}
public static function getStoneSlabIdentifier(int $stoneSlabId, int $meta) : BlockIdentifierFlattened{
$id = [
1 => [Ids::STONE_SLAB, Ids::DOUBLE_STONE_SLAB],
2 => [Ids::STONE_SLAB2, Ids::DOUBLE_STONE_SLAB2],
3 => [Ids::STONE_SLAB3, Ids::DOUBLE_STONE_SLAB3],
4 => [Ids::STONE_SLAB4, Ids::DOUBLE_STONE_SLAB4]
][$stoneSlabId] ?? null;
if($id === null){
throw new \InvalidArgumentException("Stone slab type should be 1, 2, 3 or 4");
}
return new BlockIdentifierFlattened($id[0], [$id[1]], $meta);
} }
} }

View File

@ -0,0 +1,501 @@
<?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;
final class BlockLegacyIds{
private function __construct(){
//NOOP
}
public const AIR = 0;
public const STONE = 1;
public const GRASS = 2;
public const DIRT = 3;
public const COBBLESTONE = 4;
public const PLANKS = 5, WOODEN_PLANKS = 5;
public const SAPLING = 6;
public const BEDROCK = 7;
public const FLOWING_WATER = 8;
public const STILL_WATER = 9, WATER = 9;
public const FLOWING_LAVA = 10;
public const LAVA = 11, STILL_LAVA = 11;
public const SAND = 12;
public const GRAVEL = 13;
public const GOLD_ORE = 14;
public const IRON_ORE = 15;
public const COAL_ORE = 16;
public const LOG = 17;
public const LEAVES = 18;
public const SPONGE = 19;
public const GLASS = 20;
public const LAPIS_ORE = 21;
public const LAPIS_BLOCK = 22;
public const DISPENSER = 23;
public const SANDSTONE = 24;
public const NOTEBLOCK = 25, NOTE_BLOCK = 25;
public const BED_BLOCK = 26;
public const GOLDEN_RAIL = 27, POWERED_RAIL = 27;
public const DETECTOR_RAIL = 28;
public const STICKY_PISTON = 29;
public const COBWEB = 30, WEB = 30;
public const TALLGRASS = 31, TALL_GRASS = 31;
public const DEADBUSH = 32, DEAD_BUSH = 32;
public const PISTON = 33;
public const PISTONARMCOLLISION = 34, PISTON_ARM_COLLISION = 34;
public const WOOL = 35;
public const ELEMENT_0 = 36;
public const DANDELION = 37, YELLOW_FLOWER = 37;
public const POPPY = 38, RED_FLOWER = 38;
public const BROWN_MUSHROOM = 39;
public const RED_MUSHROOM = 40;
public const GOLD_BLOCK = 41;
public const IRON_BLOCK = 42;
public const DOUBLE_STONE_SLAB = 43;
public const STONE_SLAB = 44;
public const BRICK_BLOCK = 45;
public const TNT = 46;
public const BOOKSHELF = 47;
public const MOSSY_COBBLESTONE = 48, MOSS_STONE = 48;
public const OBSIDIAN = 49;
public const TORCH = 50;
public const FIRE = 51;
public const MOB_SPAWNER = 52, MONSTER_SPAWNER = 52;
public const OAK_STAIRS = 53, WOODEN_STAIRS = 53;
public const CHEST = 54;
public const REDSTONE_WIRE = 55;
public const DIAMOND_ORE = 56;
public const DIAMOND_BLOCK = 57;
public const CRAFTING_TABLE = 58, WORKBENCH = 58;
public const WHEAT_BLOCK = 59;
public const FARMLAND = 60;
public const FURNACE = 61;
public const BURNING_FURNACE = 62, LIT_FURNACE = 62;
public const SIGN_POST = 63, STANDING_SIGN = 63;
public const OAK_DOOR_BLOCK = 64, WOODEN_DOOR_BLOCK = 64;
public const LADDER = 65;
public const RAIL = 66;
public const COBBLESTONE_STAIRS = 67, STONE_STAIRS = 67;
public const WALL_SIGN = 68;
public const LEVER = 69;
public const STONE_PRESSURE_PLATE = 70;
public const IRON_DOOR_BLOCK = 71;
public const WOODEN_PRESSURE_PLATE = 72;
public const REDSTONE_ORE = 73;
public const GLOWING_REDSTONE_ORE = 74, LIT_REDSTONE_ORE = 74;
public const UNLIT_REDSTONE_TORCH = 75;
public const LIT_REDSTONE_TORCH = 76, REDSTONE_TORCH = 76;
public const STONE_BUTTON = 77;
public const SNOW_LAYER = 78;
public const ICE = 79;
public const SNOW = 80, SNOW_BLOCK = 80;
public const CACTUS = 81;
public const CLAY_BLOCK = 82;
public const REEDS_BLOCK = 83, SUGARCANE_BLOCK = 83;
public const JUKEBOX = 84;
public const FENCE = 85;
public const PUMPKIN = 86;
public const NETHERRACK = 87;
public const SOUL_SAND = 88;
public const GLOWSTONE = 89;
public const PORTAL = 90;
public const JACK_O_LANTERN = 91, LIT_PUMPKIN = 91;
public const CAKE_BLOCK = 92;
public const REPEATER_BLOCK = 93, UNPOWERED_REPEATER = 93;
public const POWERED_REPEATER = 94;
public const INVISIBLEBEDROCK = 95, INVISIBLE_BEDROCK = 95;
public const TRAPDOOR = 96, WOODEN_TRAPDOOR = 96;
public const MONSTER_EGG = 97;
public const STONEBRICK = 98, STONE_BRICK = 98, STONE_BRICKS = 98;
public const BROWN_MUSHROOM_BLOCK = 99;
public const RED_MUSHROOM_BLOCK = 100;
public const IRON_BARS = 101;
public const GLASS_PANE = 102;
public const MELON_BLOCK = 103;
public const PUMPKIN_STEM = 104;
public const MELON_STEM = 105;
public const VINE = 106, VINES = 106;
public const FENCE_GATE = 107, OAK_FENCE_GATE = 107;
public const BRICK_STAIRS = 108;
public const STONE_BRICK_STAIRS = 109;
public const MYCELIUM = 110;
public const LILY_PAD = 111, WATERLILY = 111, WATER_LILY = 111;
public const NETHER_BRICK_BLOCK = 112;
public const NETHER_BRICK_FENCE = 113;
public const NETHER_BRICK_STAIRS = 114;
public const NETHER_WART_PLANT = 115;
public const ENCHANTING_TABLE = 116, ENCHANTMENT_TABLE = 116;
public const BREWING_STAND_BLOCK = 117;
public const CAULDRON_BLOCK = 118;
public const END_PORTAL = 119;
public const END_PORTAL_FRAME = 120;
public const END_STONE = 121;
public const DRAGON_EGG = 122;
public const REDSTONE_LAMP = 123;
public const LIT_REDSTONE_LAMP = 124;
public const DROPPER = 125;
public const ACTIVATOR_RAIL = 126;
public const COCOA = 127, COCOA_BLOCK = 127;
public const SANDSTONE_STAIRS = 128;
public const EMERALD_ORE = 129;
public const ENDER_CHEST = 130;
public const TRIPWIRE_HOOK = 131;
public const TRIPWIRE = 132, TRIP_WIRE = 132;
public const EMERALD_BLOCK = 133;
public const SPRUCE_STAIRS = 134;
public const BIRCH_STAIRS = 135;
public const JUNGLE_STAIRS = 136;
public const COMMAND_BLOCK = 137;
public const BEACON = 138;
public const COBBLESTONE_WALL = 139, STONE_WALL = 139;
public const FLOWER_POT_BLOCK = 140;
public const CARROTS = 141, CARROT_BLOCK = 141;
public const POTATOES = 142, POTATO_BLOCK = 142;
public const WOODEN_BUTTON = 143;
public const MOB_HEAD_BLOCK = 144, SKULL_BLOCK = 144;
public const ANVIL = 145;
public const TRAPPED_CHEST = 146;
public const LIGHT_WEIGHTED_PRESSURE_PLATE = 147;
public const HEAVY_WEIGHTED_PRESSURE_PLATE = 148;
public const COMPARATOR_BLOCK = 149, UNPOWERED_COMPARATOR = 149;
public const POWERED_COMPARATOR = 150;
public const DAYLIGHT_DETECTOR = 151, DAYLIGHT_SENSOR = 151;
public const REDSTONE_BLOCK = 152;
public const NETHER_QUARTZ_ORE = 153, QUARTZ_ORE = 153;
public const HOPPER_BLOCK = 154;
public const QUARTZ_BLOCK = 155;
public const QUARTZ_STAIRS = 156;
public const DOUBLE_WOODEN_SLAB = 157;
public const WOODEN_SLAB = 158;
public const STAINED_CLAY = 159, STAINED_HARDENED_CLAY = 159, TERRACOTTA = 159;
public const STAINED_GLASS_PANE = 160;
public const LEAVES2 = 161;
public const LOG2 = 162;
public const ACACIA_STAIRS = 163;
public const DARK_OAK_STAIRS = 164;
public const SLIME = 165, SLIME_BLOCK = 165;
public const GLOW_STICK = 166;
public const IRON_TRAPDOOR = 167;
public const PRISMARINE = 168;
public const SEALANTERN = 169, SEA_LANTERN = 169;
public const HAY_BALE = 170, HAY_BLOCK = 170;
public const CARPET = 171;
public const HARDENED_CLAY = 172;
public const COAL_BLOCK = 173;
public const PACKED_ICE = 174;
public const DOUBLE_PLANT = 175;
public const STANDING_BANNER = 176;
public const WALL_BANNER = 177;
public const DAYLIGHT_DETECTOR_INVERTED = 178, DAYLIGHT_SENSOR_INVERTED = 178;
public const RED_SANDSTONE = 179;
public const RED_SANDSTONE_STAIRS = 180;
public const DOUBLE_STONE_SLAB2 = 181;
public const STONE_SLAB2 = 182;
public const SPRUCE_FENCE_GATE = 183;
public const BIRCH_FENCE_GATE = 184;
public const JUNGLE_FENCE_GATE = 185;
public const DARK_OAK_FENCE_GATE = 186;
public const ACACIA_FENCE_GATE = 187;
public const REPEATING_COMMAND_BLOCK = 188;
public const CHAIN_COMMAND_BLOCK = 189;
public const HARD_GLASS_PANE = 190;
public const HARD_STAINED_GLASS_PANE = 191;
public const CHEMICAL_HEAT = 192;
public const SPRUCE_DOOR_BLOCK = 193;
public const BIRCH_DOOR_BLOCK = 194;
public const JUNGLE_DOOR_BLOCK = 195;
public const ACACIA_DOOR_BLOCK = 196;
public const DARK_OAK_DOOR_BLOCK = 197;
public const GRASS_PATH = 198;
public const FRAME_BLOCK = 199, ITEM_FRAME_BLOCK = 199;
public const CHORUS_FLOWER = 200;
public const PURPUR_BLOCK = 201;
public const COLORED_TORCH_RG = 202;
public const PURPUR_STAIRS = 203;
public const COLORED_TORCH_BP = 204;
public const UNDYED_SHULKER_BOX = 205;
public const END_BRICKS = 206;
public const FROSTED_ICE = 207;
public const END_ROD = 208;
public const END_GATEWAY = 209;
public const MAGMA = 213;
public const NETHER_WART_BLOCK = 214;
public const RED_NETHER_BRICK = 215;
public const BONE_BLOCK = 216;
public const SHULKER_BOX = 218;
public const PURPLE_GLAZED_TERRACOTTA = 219;
public const WHITE_GLAZED_TERRACOTTA = 220;
public const ORANGE_GLAZED_TERRACOTTA = 221;
public const MAGENTA_GLAZED_TERRACOTTA = 222;
public const LIGHT_BLUE_GLAZED_TERRACOTTA = 223;
public const YELLOW_GLAZED_TERRACOTTA = 224;
public const LIME_GLAZED_TERRACOTTA = 225;
public const PINK_GLAZED_TERRACOTTA = 226;
public const GRAY_GLAZED_TERRACOTTA = 227;
public const SILVER_GLAZED_TERRACOTTA = 228;
public const CYAN_GLAZED_TERRACOTTA = 229;
public const BLUE_GLAZED_TERRACOTTA = 231;
public const BROWN_GLAZED_TERRACOTTA = 232;
public const GREEN_GLAZED_TERRACOTTA = 233;
public const RED_GLAZED_TERRACOTTA = 234;
public const BLACK_GLAZED_TERRACOTTA = 235;
public const CONCRETE = 236;
public const CONCRETEPOWDER = 237, CONCRETE_POWDER = 237;
public const CHEMISTRY_TABLE = 238;
public const UNDERWATER_TORCH = 239;
public const CHORUS_PLANT = 240;
public const STAINED_GLASS = 241;
public const PODZOL = 243;
public const BEETROOT_BLOCK = 244;
public const STONECUTTER = 245;
public const GLOWINGOBSIDIAN = 246, GLOWING_OBSIDIAN = 246;
public const NETHERREACTOR = 247, NETHER_REACTOR = 247;
public const INFO_UPDATE = 248;
public const INFO_UPDATE2 = 249;
public const MOVINGBLOCK = 250, MOVING_BLOCK = 250;
public const OBSERVER = 251;
public const STRUCTURE_BLOCK = 252;
public const HARD_GLASS = 253;
public const HARD_STAINED_GLASS = 254;
public const RESERVED6 = 255;
public const PRISMARINE_STAIRS = 257;
public const DARK_PRISMARINE_STAIRS = 258;
public const PRISMARINE_BRICKS_STAIRS = 259;
public const STRIPPED_SPRUCE_LOG = 260;
public const STRIPPED_BIRCH_LOG = 261;
public const STRIPPED_JUNGLE_LOG = 262;
public const STRIPPED_ACACIA_LOG = 263;
public const STRIPPED_DARK_OAK_LOG = 264;
public const STRIPPED_OAK_LOG = 265;
public const BLUE_ICE = 266;
public const ELEMENT_1 = 267;
public const ELEMENT_2 = 268;
public const ELEMENT_3 = 269;
public const ELEMENT_4 = 270;
public const ELEMENT_5 = 271;
public const ELEMENT_6 = 272;
public const ELEMENT_7 = 273;
public const ELEMENT_8 = 274;
public const ELEMENT_9 = 275;
public const ELEMENT_10 = 276;
public const ELEMENT_11 = 277;
public const ELEMENT_12 = 278;
public const ELEMENT_13 = 279;
public const ELEMENT_14 = 280;
public const ELEMENT_15 = 281;
public const ELEMENT_16 = 282;
public const ELEMENT_17 = 283;
public const ELEMENT_18 = 284;
public const ELEMENT_19 = 285;
public const ELEMENT_20 = 286;
public const ELEMENT_21 = 287;
public const ELEMENT_22 = 288;
public const ELEMENT_23 = 289;
public const ELEMENT_24 = 290;
public const ELEMENT_25 = 291;
public const ELEMENT_26 = 292;
public const ELEMENT_27 = 293;
public const ELEMENT_28 = 294;
public const ELEMENT_29 = 295;
public const ELEMENT_30 = 296;
public const ELEMENT_31 = 297;
public const ELEMENT_32 = 298;
public const ELEMENT_33 = 299;
public const ELEMENT_34 = 300;
public const ELEMENT_35 = 301;
public const ELEMENT_36 = 302;
public const ELEMENT_37 = 303;
public const ELEMENT_38 = 304;
public const ELEMENT_39 = 305;
public const ELEMENT_40 = 306;
public const ELEMENT_41 = 307;
public const ELEMENT_42 = 308;
public const ELEMENT_43 = 309;
public const ELEMENT_44 = 310;
public const ELEMENT_45 = 311;
public const ELEMENT_46 = 312;
public const ELEMENT_47 = 313;
public const ELEMENT_48 = 314;
public const ELEMENT_49 = 315;
public const ELEMENT_50 = 316;
public const ELEMENT_51 = 317;
public const ELEMENT_52 = 318;
public const ELEMENT_53 = 319;
public const ELEMENT_54 = 320;
public const ELEMENT_55 = 321;
public const ELEMENT_56 = 322;
public const ELEMENT_57 = 323;
public const ELEMENT_58 = 324;
public const ELEMENT_59 = 325;
public const ELEMENT_60 = 326;
public const ELEMENT_61 = 327;
public const ELEMENT_62 = 328;
public const ELEMENT_63 = 329;
public const ELEMENT_64 = 330;
public const ELEMENT_65 = 331;
public const ELEMENT_66 = 332;
public const ELEMENT_67 = 333;
public const ELEMENT_68 = 334;
public const ELEMENT_69 = 335;
public const ELEMENT_70 = 336;
public const ELEMENT_71 = 337;
public const ELEMENT_72 = 338;
public const ELEMENT_73 = 339;
public const ELEMENT_74 = 340;
public const ELEMENT_75 = 341;
public const ELEMENT_76 = 342;
public const ELEMENT_77 = 343;
public const ELEMENT_78 = 344;
public const ELEMENT_79 = 345;
public const ELEMENT_80 = 346;
public const ELEMENT_81 = 347;
public const ELEMENT_82 = 348;
public const ELEMENT_83 = 349;
public const ELEMENT_84 = 350;
public const ELEMENT_85 = 351;
public const ELEMENT_86 = 352;
public const ELEMENT_87 = 353;
public const ELEMENT_88 = 354;
public const ELEMENT_89 = 355;
public const ELEMENT_90 = 356;
public const ELEMENT_91 = 357;
public const ELEMENT_92 = 358;
public const ELEMENT_93 = 359;
public const ELEMENT_94 = 360;
public const ELEMENT_95 = 361;
public const ELEMENT_96 = 362;
public const ELEMENT_97 = 363;
public const ELEMENT_98 = 364;
public const ELEMENT_99 = 365;
public const ELEMENT_100 = 366;
public const ELEMENT_101 = 367;
public const ELEMENT_102 = 368;
public const ELEMENT_103 = 369;
public const ELEMENT_104 = 370;
public const ELEMENT_105 = 371;
public const ELEMENT_106 = 372;
public const ELEMENT_107 = 373;
public const ELEMENT_108 = 374;
public const ELEMENT_109 = 375;
public const ELEMENT_110 = 376;
public const ELEMENT_111 = 377;
public const ELEMENT_112 = 378;
public const ELEMENT_113 = 379;
public const ELEMENT_114 = 380;
public const ELEMENT_115 = 381;
public const ELEMENT_116 = 382;
public const ELEMENT_117 = 383;
public const ELEMENT_118 = 384;
public const SEAGRASS = 385;
public const CORAL = 386;
public const CORAL_BLOCK = 387;
public const CORAL_FAN = 388;
public const CORAL_FAN_DEAD = 389;
public const CORAL_FAN_HANG = 390;
public const CORAL_FAN_HANG2 = 391;
public const CORAL_FAN_HANG3 = 392;
public const KELP = 393;
public const DRIED_KELP_BLOCK = 394;
public const ACACIA_BUTTON = 395;
public const BIRCH_BUTTON = 396;
public const DARK_OAK_BUTTON = 397;
public const JUNGLE_BUTTON = 398;
public const SPRUCE_BUTTON = 399;
public const ACACIA_TRAPDOOR = 400;
public const BIRCH_TRAPDOOR = 401;
public const DARK_OAK_TRAPDOOR = 402;
public const JUNGLE_TRAPDOOR = 403;
public const SPRUCE_TRAPDOOR = 404;
public const ACACIA_PRESSURE_PLATE = 405;
public const BIRCH_PRESSURE_PLATE = 406;
public const DARK_OAK_PRESSURE_PLATE = 407;
public const JUNGLE_PRESSURE_PLATE = 408;
public const SPRUCE_PRESSURE_PLATE = 409;
public const CARVED_PUMPKIN = 410;
public const SEA_PICKLE = 411;
public const CONDUIT = 412;
public const TURTLE_EGG = 414;
public const BUBBLE_COLUMN = 415;
public const BARRIER = 416;
public const STONE_SLAB3 = 417;
public const BAMBOO = 418;
public const BAMBOO_SAPLING = 419;
public const SCAFFOLDING = 420;
public const STONE_SLAB4 = 421;
public const DOUBLE_STONE_SLAB3 = 422;
public const DOUBLE_STONE_SLAB4 = 423;
public const GRANITE_STAIRS = 424;
public const DIORITE_STAIRS = 425;
public const ANDESITE_STAIRS = 426;
public const POLISHED_GRANITE_STAIRS = 427;
public const POLISHED_DIORITE_STAIRS = 428;
public const POLISHED_ANDESITE_STAIRS = 429;
public const MOSSY_STONE_BRICK_STAIRS = 430;
public const SMOOTH_RED_SANDSTONE_STAIRS = 431;
public const SMOOTH_SANDSTONE_STAIRS = 432;
public const END_BRICK_STAIRS = 433;
public const MOSSY_COBBLESTONE_STAIRS = 434;
public const NORMAL_STONE_STAIRS = 435;
public const SPRUCE_STANDING_SIGN = 436;
public const SPRUCE_WALL_SIGN = 437;
public const SMOOTH_STONE = 438;
public const RED_NETHER_BRICK_STAIRS = 439;
public const SMOOTH_QUARTZ_STAIRS = 440;
public const BIRCH_STANDING_SIGN = 441;
public const BIRCH_WALL_SIGN = 442;
public const JUNGLE_STANDING_SIGN = 443;
public const JUNGLE_WALL_SIGN = 444;
public const ACACIA_STANDING_SIGN = 445;
public const ACACIA_WALL_SIGN = 446;
public const DARKOAK_STANDING_SIGN = 447;
public const DARKOAK_WALL_SIGN = 448;
public const LECTERN = 449;
public const GRINDSTONE = 450;
public const BLAST_FURNACE = 451;
public const STONECUTTER_BLOCK = 452;
public const SMOKER = 453;
public const LIT_SMOKER = 454;
public const CARTOGRAPHY_TABLE = 455;
public const FLETCHING_TABLE = 456;
public const SMITHING_TABLE = 457;
public const BARREL = 458;
public const LOOM = 459;
public const BELL = 461;
public const SWEET_BERRY_BUSH = 462;
public const LANTERN = 463;
public const CAMPFIRE = 464;
public const LAVA_CAULDRON = 465;
public const JIGSAW = 466;
public const WOOD = 467;
public const COMPOSTER = 468;
public const LIT_BLAST_FURNACE = 469;
}

View File

@ -0,0 +1,303 @@
<?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;
/**
* Constants for legacy metadata for various blocks.
*/
final class BlockLegacyMetadata{
private function __construct(){
//NOOP
}
public const ANVIL_NORMAL = 0;
public const ANVIL_SLIGHTLY_DAMAGED = 4;
public const ANVIL_VERY_DAMAGED = 8;
public const BAMBOO_FLAG_THICK = 0x01;
public const BAMBOO_FLAG_READY = 0x08;
public const BAMBOO_LEAF_SIZE_SHIFT = 1;
public const BAMBOO_LEAF_SIZE_MASK = 0x03;
public const BAMBOO_SAPLING_FLAG_READY = 0x01;
public const BARREL_FLAG_OPEN = 0x08;
public const BED_FLAG_HEAD = 0x08;
public const BED_FLAG_OCCUPIED = 0x04;
public const BEDROCK_FLAG_INFINIBURN = 0x01;
public const BELL_ATTACHMENT_FLOOR = 0;
public const BELL_ATTACHMENT_CEILING = 1;
public const BELL_ATTACHMENT_ONE_WALL = 2;
public const BELL_ATTACHMENT_TWO_WALLS = 3;
public const BREWING_STAND_FLAG_EAST = 0x01;
public const BREWING_STAND_FLAG_SOUTHWEST = 0x02;
public const BREWING_STAND_FLAG_NORTHWEST = 0x04;
public const BUTTON_FLAG_POWERED = 0x08;
public const CHEMISTRY_COMPOUND_CREATOR = 0;
public const CHEMISTRY_MATERIAL_REDUCER = 4;
public const CHEMISTRY_ELEMENT_CONSTRUCTOR = 8;
public const CHEMISTRY_LAB_TABLE = 12;
public const COLORED_TORCH_BP_BLUE = 0;
public const COLORED_TORCH_BP_PURPLE = 8;
public const COLORED_TORCH_RG_RED = 0;
public const COLORED_TORCH_RG_GREEN = 8;
public const CORAL_BLOCK_FLAG_DEAD = 0x8;
public const CORAL_FAN_EAST_WEST = 0;
public const CORAL_FAN_NORTH_SOUTH = 1;
public const CORAL_FAN_TYPE_MASK = 0x7;
public const CORAL_FAN_HANG_FLAG_DEAD = 0x2;
public const CORAL_FAN_HANG_TUBE = 0;
public const CORAL_FAN_HANG_BRAIN = 1;
public const CORAL_FAN_HANG2_BUBBLE = 0;
public const CORAL_FAN_HANG2_FIRE = 1;
public const CORAL_FAN_HANG3_HORN = 0;
public const CORAL_FAN_HANG_TYPE_MASK = 0x1;
public const CORAL_VARIANT_TUBE = 0;
public const CORAL_VARIANT_BRAIN = 1;
public const CORAL_VARIANT_BUBBLE = 2;
public const CORAL_VARIANT_FIRE = 3;
public const CORAL_VARIANT_HORN = 4;
public const DIRT_FLAG_COARSE = 0x1;
public const DOOR_FLAG_TOP = 0x08;
public const DOOR_BOTTOM_FLAG_OPEN = 0x04;
public const DOOR_TOP_FLAG_RIGHT = 0x01;
public const DOOR_TOP_FLAG_POWERED = 0x02;
public const DOUBLE_PLANT_SUNFLOWER = 0;
public const DOUBLE_PLANT_LILAC = 1;
public const DOUBLE_PLANT_TALLGRASS = 2;
public const DOUBLE_PLANT_LARGE_FERN = 3;
public const DOUBLE_PLANT_ROSE_BUSH = 4;
public const DOUBLE_PLANT_PEONY = 5;
public const DOUBLE_PLANT_FLAG_TOP = 0x08;
public const END_PORTAL_FRAME_FLAG_EYE = 0x04;
public const FENCE_GATE_FLAG_OPEN = 0x04;
public const FENCE_GATE_FLAG_IN_WALL = 0x08;
public const FLOWER_POPPY = 0;
public const FLOWER_BLUE_ORCHID = 1;
public const FLOWER_ALLIUM = 2;
public const FLOWER_AZURE_BLUET = 3;
public const FLOWER_RED_TULIP = 4;
public const FLOWER_ORANGE_TULIP = 5;
public const FLOWER_WHITE_TULIP = 6;
public const FLOWER_PINK_TULIP = 7;
public const FLOWER_OXEYE_DAISY = 8;
public const FLOWER_CORNFLOWER = 9;
public const FLOWER_LILY_OF_THE_VALLEY = 10;
public const FLOWER_POT_FLAG_OCCUPIED = 0x01;
public const HOPPER_FLAG_POWERED = 0x08;
public const INFESTED_STONE = 0;
public const INFESTED_COBBLESTONE = 1;
public const INFESTED_STONE_BRICK = 2;
public const INFESTED_STONE_BRICK_MOSSY = 3;
public const INFESTED_STONE_BRICK_CRACKED = 4;
public const INFESTED_STONE_BRICK_CHISELED = 5;
public const ITEM_FRAME_FLAG_HAS_MAP = 0x04;
public const LANTERN_FLAG_HANGING = 0x01;
public const LEAVES_FLAG_NO_DECAY = 0x04;
public const LEAVES_FLAG_CHECK_DECAY = 0x08;
public const LECTERN_FLAG_POWERED = 0x04;
public const LEVER_FLAG_POWERED = 0x08;
public const LIQUID_FLAG_FALLING = 0x08;
public const MUSHROOM_BLOCK_ALL_PORES = 0;
public const MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER = 1;
public const MUSHROOM_BLOCK_CAP_NORTH_SIDE = 2;
public const MUSHROOM_BLOCK_CAP_NORTHEAST_CORNER = 3;
public const MUSHROOM_BLOCK_CAP_WEST_SIDE = 4;
public const MUSHROOM_BLOCK_CAP_TOP_ONLY = 5;
public const MUSHROOM_BLOCK_CAP_EAST_SIDE = 6;
public const MUSHROOM_BLOCK_CAP_SOUTHWEST_CORNER = 7;
public const MUSHROOM_BLOCK_CAP_SOUTH_SIDE = 8;
public const MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER = 9;
public const MUSHROOM_BLOCK_STEM = 10;
//11, 12 and 13 appear the same as 0
public const MUSHROOM_BLOCK_ALL_CAP = 14;
public const MUSHROOM_BLOCK_ALL_STEM = 15;
public const NETHER_PORTAL_AXIS_X = 1;
public const NETHER_PORTAL_AXIS_Z = 2;
public const NETHER_REACTOR_INACTIVE = 0;
public const NETHER_REACTOR_ACTIVE = 1;
public const NETHER_REACTOR_USED = 2;
public const PRESSURE_PLATE_FLAG_POWERED = 0x01;
public const PRISMARINE_NORMAL = 0;
public const PRISMARINE_DARK = 1;
public const PRISMARINE_BRICKS = 2;
public const PURPUR_NORMAL = 0;
public const PURPUR_PILLAR = 2;
public const QUARTZ_NORMAL = 0;
public const QUARTZ_CHISELED = 1;
public const QUARTZ_PILLAR = 2;
public const QUARTZ_SMOOTH = 3;
public const RAIL_STRAIGHT_NORTH_SOUTH = 0;
public const RAIL_STRAIGHT_EAST_WEST = 1;
public const RAIL_ASCENDING_EAST = 2;
public const RAIL_ASCENDING_WEST = 3;
public const RAIL_ASCENDING_NORTH = 4;
public const RAIL_ASCENDING_SOUTH = 5;
public const RAIL_CURVE_SOUTHEAST = 6;
public const RAIL_CURVE_SOUTHWEST = 7;
public const RAIL_CURVE_NORTHWEST = 8;
public const RAIL_CURVE_NORTHEAST = 9;
public const REDSTONE_COMPARATOR_FLAG_SUBTRACT = 0x04;
public const REDSTONE_COMPARATOR_FLAG_POWERED = 0x08;
public const REDSTONE_RAIL_FLAG_POWERED = 0x08;
public const SANDSTONE_NORMAL = 0;
public const SANDSTONE_CHISELED = 1;
public const SANDSTONE_CUT = 2;
public const SANDSTONE_SMOOTH = 3;
public const SAPLING_FLAG_READY = 0x08;
public const SEA_PICKLE_FLAG_NOT_UNDERWATER = 0x04;
public const SKULL_FLAG_NO_DROPS = 0x08;
public const SLAB_FLAG_UPPER = 0x08;
public const SPONGE_FLAG_WET = 0x01;
public const STAIR_FLAG_UPSIDE_DOWN = 0x04;
public const STONE_NORMAL = 0;
public const STONE_GRANITE = 1;
public const STONE_POLISHED_GRANITE = 2;
public const STONE_DIORITE = 3;
public const STONE_POLISHED_DIORITE = 4;
public const STONE_ANDESITE = 5;
public const STONE_POLISHED_ANDESITE = 6;
public const STONE_BRICK_NORMAL = 0;
public const STONE_BRICK_MOSSY = 1;
public const STONE_BRICK_CRACKED = 2;
public const STONE_BRICK_CHISELED = 3;
public const STONE_SLAB_SMOOTH_STONE = 0;
public const STONE_SLAB_SANDSTONE = 1;
public const STONE_SLAB_FAKE_WOODEN = 2;
public const STONE_SLAB_COBBLESTONE = 3;
public const STONE_SLAB_BRICK = 4;
public const STONE_SLAB_STONE_BRICK = 5;
public const STONE_SLAB_QUARTZ = 6;
public const STONE_SLAB_NETHER_BRICK = 7;
public const STONE_SLAB2_RED_SANDSTONE = 0;
public const STONE_SLAB2_PURPUR = 1;
public const STONE_SLAB2_PRISMARINE = 2;
public const STONE_SLAB2_DARK_PRISMARINE = 3;
public const STONE_SLAB2_PRISMARINE_BRICKS = 4;
public const STONE_SLAB2_MOSSY_COBBLESTONE = 5;
public const STONE_SLAB2_SMOOTH_SANDSTONE = 6;
public const STONE_SLAB2_RED_NETHER_BRICK = 7;
public const STONE_SLAB3_END_STONE_BRICK = 0;
public const STONE_SLAB3_SMOOTH_RED_SANDSTONE = 1;
public const STONE_SLAB3_POLISHED_ANDESITE = 2;
public const STONE_SLAB3_ANDESITE = 3;
public const STONE_SLAB3_DIORITE = 4;
public const STONE_SLAB3_POLISHED_DIORITE = 5;
public const STONE_SLAB3_GRANITE = 6;
public const STONE_SLAB3_POLISHED_GRANITE = 7;
public const STONE_SLAB4_MOSSY_STONE_BRICK = 0;
public const STONE_SLAB4_SMOOTH_QUARTZ = 1;
public const STONE_SLAB4_STONE = 2;
public const STONE_SLAB4_CUT_SANDSTONE = 3;
public const STONE_SLAB4_CUT_RED_SANDSTONE = 4;
public const TALLGRASS_NORMAL = 1;
public const TALLGRASS_FERN = 2;
public const TNT_FLAG_UNSTABLE = 0x01;
public const TNT_FLAG_UNDERWATER = 0x02;
public const TRAPDOOR_FLAG_UPPER = 0x04;
public const TRAPDOOR_FLAG_OPEN = 0x08;
public const TRIPWIRE_FLAG_TRIGGERED = 0x01;
public const TRIPWIRE_FLAG_SUSPENDED = 0x02;
public const TRIPWIRE_FLAG_CONNECTED = 0x04;
public const TRIPWIRE_FLAG_DISARMED = 0x08;
public const TRIPWIRE_HOOK_FLAG_CONNECTED = 0x04;
public const TRIPWIRE_HOOK_FLAG_POWERED = 0x08;
public const VINE_FLAG_SOUTH = 0x01;
public const VINE_FLAG_WEST = 0x02;
public const VINE_FLAG_NORTH = 0x04;
public const VINE_FLAG_EAST = 0x08;
public const WALL_COBBLESTONE = 0;
public const WALL_MOSSY_COBBLESTONE = 1;
public const WALL_GRANITE = 2;
public const WALL_DIORITE = 3;
public const WALL_ANDESITE = 4;
public const WALL_SANDSTONE = 5;
public const WALL_BRICK = 6;
public const WALL_STONE_BRICK = 7;
public const WALL_MOSSY_STONE_BRICK = 8;
public const WALL_NETHER_BRICK = 9;
public const WALL_END_STONE_BRICK = 10;
public const WALL_PRISMARINE = 11;
public const WALL_RED_SANDSTONE = 12;
public const WALL_RED_NETHER_BRICK = 13;
public const WOOD_FLAG_STRIPPED = 0x8;
}

View File

@ -1,727 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
/**
* Enum of all the block runtime IDs used by PocketMine-MP. These IDs are specific to PocketMine-MP and have no
* relevance to any Minecraft vanilla things.
*
* WARNING: DO NOT STORE THESE IDS. They can and will change without warning.
* They should ONLY be used to IDENTIFY blocks at runtime.
*/
final class BlockTypeIds{
private function __construct(){
//NOOP
}
public const AIR = 10000;
public const ACACIA_BUTTON = 10001;
public const ACACIA_DOOR = 10002;
public const ACACIA_FENCE = 10003;
public const ACACIA_FENCE_GATE = 10004;
public const ACACIA_LEAVES = 10005;
public const ACACIA_LOG = 10006;
public const ACACIA_PLANKS = 10007;
public const ACACIA_PRESSURE_PLATE = 10008;
public const ACACIA_SAPLING = 10009;
public const ACACIA_SIGN = 10010;
public const ACACIA_SLAB = 10011;
public const ACACIA_STAIRS = 10012;
public const ACACIA_TRAPDOOR = 10013;
public const ACACIA_WALL_SIGN = 10014;
public const ACACIA_WOOD = 10015;
public const ACTIVATOR_RAIL = 10016;
public const ALL_SIDED_MUSHROOM_STEM = 10017;
public const ALLIUM = 10018;
public const ANDESITE = 10019;
public const ANDESITE_SLAB = 10020;
public const ANDESITE_STAIRS = 10021;
public const ANDESITE_WALL = 10022;
public const ANVIL = 10023;
public const AZURE_BLUET = 10024;
public const BAMBOO = 10025;
public const BAMBOO_SAPLING = 10026;
public const BANNER = 10027;
public const BARREL = 10028;
public const BARRIER = 10029;
public const BEACON = 10030;
public const BED = 10031;
public const BEDROCK = 10032;
public const BEETROOTS = 10033;
public const BELL = 10034;
public const BIRCH_BUTTON = 10035;
public const BIRCH_DOOR = 10036;
public const BIRCH_FENCE = 10037;
public const BIRCH_FENCE_GATE = 10038;
public const BIRCH_LEAVES = 10039;
public const BIRCH_LOG = 10040;
public const BIRCH_PLANKS = 10041;
public const BIRCH_PRESSURE_PLATE = 10042;
public const BIRCH_SAPLING = 10043;
public const BIRCH_SIGN = 10044;
public const BIRCH_SLAB = 10045;
public const BIRCH_STAIRS = 10046;
public const BIRCH_TRAPDOOR = 10047;
public const BIRCH_WALL_SIGN = 10048;
public const BIRCH_WOOD = 10049;
public const BLAST_FURNACE = 10051;
public const BLUE_ICE = 10053;
public const BLUE_ORCHID = 10054;
public const BLUE_TORCH = 10055;
public const BONE_BLOCK = 10056;
public const BOOKSHELF = 10057;
public const BREWING_STAND = 10058;
public const BRICK_SLAB = 10059;
public const BRICK_STAIRS = 10060;
public const BRICK_WALL = 10061;
public const BRICKS = 10062;
public const BROWN_MUSHROOM = 10064;
public const BROWN_MUSHROOM_BLOCK = 10065;
public const CACTUS = 10066;
public const CAKE = 10067;
public const CARPET = 10068;
public const CARROTS = 10069;
public const CARVED_PUMPKIN = 10070;
public const CHEMICAL_HEAT = 10071;
public const CHEST = 10072;
public const CHISELED_QUARTZ = 10073;
public const CHISELED_RED_SANDSTONE = 10074;
public const CHISELED_SANDSTONE = 10075;
public const CHISELED_STONE_BRICKS = 10076;
public const CLAY = 10077;
public const COAL = 10078;
public const COAL_ORE = 10079;
public const COBBLESTONE = 10080;
public const COBBLESTONE_SLAB = 10081;
public const COBBLESTONE_STAIRS = 10082;
public const COBBLESTONE_WALL = 10083;
public const COBWEB = 10084;
public const COCOA_POD = 10085;
public const COMPOUND_CREATOR = 10086;
public const CONCRETE = 10087;
public const CONCRETE_POWDER = 10088;
public const CORAL = 10089;
public const CORAL_BLOCK = 10090;
public const CORAL_FAN = 10091;
public const CORNFLOWER = 10092;
public const CRACKED_STONE_BRICKS = 10093;
public const CRAFTING_TABLE = 10094;
public const CUT_RED_SANDSTONE = 10095;
public const CUT_RED_SANDSTONE_SLAB = 10096;
public const CUT_SANDSTONE = 10097;
public const CUT_SANDSTONE_SLAB = 10098;
public const DANDELION = 10100;
public const DARK_OAK_BUTTON = 10101;
public const DARK_OAK_DOOR = 10102;
public const DARK_OAK_FENCE = 10103;
public const DARK_OAK_FENCE_GATE = 10104;
public const DARK_OAK_LEAVES = 10105;
public const DARK_OAK_LOG = 10106;
public const DARK_OAK_PLANKS = 10107;
public const DARK_OAK_PRESSURE_PLATE = 10108;
public const DARK_OAK_SAPLING = 10109;
public const DARK_OAK_SIGN = 10110;
public const DARK_OAK_SLAB = 10111;
public const DARK_OAK_STAIRS = 10112;
public const DARK_OAK_TRAPDOOR = 10113;
public const DARK_OAK_WALL_SIGN = 10114;
public const DARK_OAK_WOOD = 10115;
public const DARK_PRISMARINE = 10116;
public const DARK_PRISMARINE_SLAB = 10117;
public const DARK_PRISMARINE_STAIRS = 10118;
public const DAYLIGHT_SENSOR = 10119;
public const DEAD_BUSH = 10120;
public const DETECTOR_RAIL = 10121;
public const DIAMOND = 10122;
public const DIAMOND_ORE = 10123;
public const DIORITE = 10124;
public const DIORITE_SLAB = 10125;
public const DIORITE_STAIRS = 10126;
public const DIORITE_WALL = 10127;
public const DIRT = 10128;
public const DOUBLE_TALLGRASS = 10129;
public const DRAGON_EGG = 10130;
public const DRIED_KELP = 10131;
public const DYED_SHULKER_BOX = 10132;
public const ELEMENT_ACTINIUM = 10133;
public const ELEMENT_ALUMINUM = 10134;
public const ELEMENT_AMERICIUM = 10135;
public const ELEMENT_ANTIMONY = 10136;
public const ELEMENT_ARGON = 10137;
public const ELEMENT_ARSENIC = 10138;
public const ELEMENT_ASTATINE = 10139;
public const ELEMENT_BARIUM = 10140;
public const ELEMENT_BERKELIUM = 10141;
public const ELEMENT_BERYLLIUM = 10142;
public const ELEMENT_BISMUTH = 10143;
public const ELEMENT_BOHRIUM = 10144;
public const ELEMENT_BORON = 10145;
public const ELEMENT_BROMINE = 10146;
public const ELEMENT_CADMIUM = 10147;
public const ELEMENT_CALCIUM = 10148;
public const ELEMENT_CALIFORNIUM = 10149;
public const ELEMENT_CARBON = 10150;
public const ELEMENT_CERIUM = 10151;
public const ELEMENT_CESIUM = 10152;
public const ELEMENT_CHLORINE = 10153;
public const ELEMENT_CHROMIUM = 10154;
public const ELEMENT_COBALT = 10155;
public const ELEMENT_CONSTRUCTOR = 10156;
public const ELEMENT_COPERNICIUM = 10157;
public const ELEMENT_COPPER = 10158;
public const ELEMENT_CURIUM = 10159;
public const ELEMENT_DARMSTADTIUM = 10160;
public const ELEMENT_DUBNIUM = 10161;
public const ELEMENT_DYSPROSIUM = 10162;
public const ELEMENT_EINSTEINIUM = 10163;
public const ELEMENT_ERBIUM = 10164;
public const ELEMENT_EUROPIUM = 10165;
public const ELEMENT_FERMIUM = 10166;
public const ELEMENT_FLEROVIUM = 10167;
public const ELEMENT_FLUORINE = 10168;
public const ELEMENT_FRANCIUM = 10169;
public const ELEMENT_GADOLINIUM = 10170;
public const ELEMENT_GALLIUM = 10171;
public const ELEMENT_GERMANIUM = 10172;
public const ELEMENT_GOLD = 10173;
public const ELEMENT_HAFNIUM = 10174;
public const ELEMENT_HASSIUM = 10175;
public const ELEMENT_HELIUM = 10176;
public const ELEMENT_HOLMIUM = 10177;
public const ELEMENT_HYDROGEN = 10178;
public const ELEMENT_INDIUM = 10179;
public const ELEMENT_IODINE = 10180;
public const ELEMENT_IRIDIUM = 10181;
public const ELEMENT_IRON = 10182;
public const ELEMENT_KRYPTON = 10183;
public const ELEMENT_LANTHANUM = 10184;
public const ELEMENT_LAWRENCIUM = 10185;
public const ELEMENT_LEAD = 10186;
public const ELEMENT_LITHIUM = 10187;
public const ELEMENT_LIVERMORIUM = 10188;
public const ELEMENT_LUTETIUM = 10189;
public const ELEMENT_MAGNESIUM = 10190;
public const ELEMENT_MANGANESE = 10191;
public const ELEMENT_MEITNERIUM = 10192;
public const ELEMENT_MENDELEVIUM = 10193;
public const ELEMENT_MERCURY = 10194;
public const ELEMENT_MOLYBDENUM = 10195;
public const ELEMENT_MOSCOVIUM = 10196;
public const ELEMENT_NEODYMIUM = 10197;
public const ELEMENT_NEON = 10198;
public const ELEMENT_NEPTUNIUM = 10199;
public const ELEMENT_NICKEL = 10200;
public const ELEMENT_NIHONIUM = 10201;
public const ELEMENT_NIOBIUM = 10202;
public const ELEMENT_NITROGEN = 10203;
public const ELEMENT_NOBELIUM = 10204;
public const ELEMENT_OGANESSON = 10205;
public const ELEMENT_OSMIUM = 10206;
public const ELEMENT_OXYGEN = 10207;
public const ELEMENT_PALLADIUM = 10208;
public const ELEMENT_PHOSPHORUS = 10209;
public const ELEMENT_PLATINUM = 10210;
public const ELEMENT_PLUTONIUM = 10211;
public const ELEMENT_POLONIUM = 10212;
public const ELEMENT_POTASSIUM = 10213;
public const ELEMENT_PRASEODYMIUM = 10214;
public const ELEMENT_PROMETHIUM = 10215;
public const ELEMENT_PROTACTINIUM = 10216;
public const ELEMENT_RADIUM = 10217;
public const ELEMENT_RADON = 10218;
public const ELEMENT_RHENIUM = 10219;
public const ELEMENT_RHODIUM = 10220;
public const ELEMENT_ROENTGENIUM = 10221;
public const ELEMENT_RUBIDIUM = 10222;
public const ELEMENT_RUTHENIUM = 10223;
public const ELEMENT_RUTHERFORDIUM = 10224;
public const ELEMENT_SAMARIUM = 10225;
public const ELEMENT_SCANDIUM = 10226;
public const ELEMENT_SEABORGIUM = 10227;
public const ELEMENT_SELENIUM = 10228;
public const ELEMENT_SILICON = 10229;
public const ELEMENT_SILVER = 10230;
public const ELEMENT_SODIUM = 10231;
public const ELEMENT_STRONTIUM = 10232;
public const ELEMENT_SULFUR = 10233;
public const ELEMENT_TANTALUM = 10234;
public const ELEMENT_TECHNETIUM = 10235;
public const ELEMENT_TELLURIUM = 10236;
public const ELEMENT_TENNESSINE = 10237;
public const ELEMENT_TERBIUM = 10238;
public const ELEMENT_THALLIUM = 10239;
public const ELEMENT_THORIUM = 10240;
public const ELEMENT_THULIUM = 10241;
public const ELEMENT_TIN = 10242;
public const ELEMENT_TITANIUM = 10243;
public const ELEMENT_TUNGSTEN = 10244;
public const ELEMENT_URANIUM = 10245;
public const ELEMENT_VANADIUM = 10246;
public const ELEMENT_XENON = 10247;
public const ELEMENT_YTTERBIUM = 10248;
public const ELEMENT_YTTRIUM = 10249;
public const ELEMENT_ZERO = 10250;
public const ELEMENT_ZINC = 10251;
public const ELEMENT_ZIRCONIUM = 10252;
public const EMERALD = 10253;
public const EMERALD_ORE = 10254;
public const ENCHANTING_TABLE = 10255;
public const END_PORTAL_FRAME = 10256;
public const END_ROD = 10257;
public const END_STONE = 10258;
public const END_STONE_BRICK_SLAB = 10259;
public const END_STONE_BRICK_STAIRS = 10260;
public const END_STONE_BRICK_WALL = 10261;
public const END_STONE_BRICKS = 10262;
public const ENDER_CHEST = 10263;
public const FAKE_WOODEN_SLAB = 10264;
public const FARMLAND = 10265;
public const FERN = 10266;
public const FIRE = 10267;
public const FLETCHING_TABLE = 10268;
public const FLOWER_POT = 10269;
public const FROSTED_ICE = 10270;
public const FURNACE = 10271;
public const GLASS = 10272;
public const GLASS_PANE = 10273;
public const GLOWING_OBSIDIAN = 10274;
public const GLOWSTONE = 10275;
public const GOLD = 10276;
public const GOLD_ORE = 10277;
public const GRANITE = 10278;
public const GRANITE_SLAB = 10279;
public const GRANITE_STAIRS = 10280;
public const GRANITE_WALL = 10281;
public const GRASS = 10282;
public const GRASS_PATH = 10283;
public const GRAVEL = 10284;
public const GREEN_TORCH = 10287;
public const HARDENED_CLAY = 10288;
public const HARDENED_GLASS = 10289;
public const HARDENED_GLASS_PANE = 10290;
public const HAY_BALE = 10291;
public const HOPPER = 10292;
public const ICE = 10293;
public const INFESTED_CHISELED_STONE_BRICK = 10294;
public const INFESTED_COBBLESTONE = 10295;
public const INFESTED_CRACKED_STONE_BRICK = 10296;
public const INFESTED_MOSSY_STONE_BRICK = 10297;
public const INFESTED_STONE = 10298;
public const INFESTED_STONE_BRICK = 10299;
public const INFO_UPDATE = 10300;
public const INFO_UPDATE2 = 10301;
public const INVISIBLE_BEDROCK = 10302;
public const IRON = 10303;
public const IRON_BARS = 10304;
public const IRON_DOOR = 10305;
public const IRON_ORE = 10306;
public const IRON_TRAPDOOR = 10307;
public const ITEM_FRAME = 10308;
public const JUKEBOX = 10309;
public const JUNGLE_BUTTON = 10310;
public const JUNGLE_DOOR = 10311;
public const JUNGLE_FENCE = 10312;
public const JUNGLE_FENCE_GATE = 10313;
public const JUNGLE_LEAVES = 10314;
public const JUNGLE_LOG = 10315;
public const JUNGLE_PLANKS = 10316;
public const JUNGLE_PRESSURE_PLATE = 10317;
public const JUNGLE_SAPLING = 10318;
public const JUNGLE_SIGN = 10319;
public const JUNGLE_SLAB = 10320;
public const JUNGLE_STAIRS = 10321;
public const JUNGLE_TRAPDOOR = 10322;
public const JUNGLE_WALL_SIGN = 10323;
public const JUNGLE_WOOD = 10324;
public const LAB_TABLE = 10325;
public const LADDER = 10326;
public const LANTERN = 10327;
public const LAPIS_LAZULI = 10328;
public const LAPIS_LAZULI_ORE = 10329;
public const LARGE_FERN = 10330;
public const LAVA = 10331;
public const LECTERN = 10332;
public const LEGACY_STONECUTTER = 10333;
public const LEVER = 10334;
public const LILAC = 10337;
public const LILY_OF_THE_VALLEY = 10338;
public const LILY_PAD = 10339;
public const LIT_PUMPKIN = 10341;
public const LOOM = 10342;
public const MAGMA = 10344;
public const MATERIAL_REDUCER = 10345;
public const MELON = 10346;
public const MELON_STEM = 10347;
public const MOB_HEAD = 10348;
public const MONSTER_SPAWNER = 10349;
public const MOSSY_COBBLESTONE = 10350;
public const MOSSY_COBBLESTONE_SLAB = 10351;
public const MOSSY_COBBLESTONE_STAIRS = 10352;
public const MOSSY_COBBLESTONE_WALL = 10353;
public const MOSSY_STONE_BRICK_SLAB = 10354;
public const MOSSY_STONE_BRICK_STAIRS = 10355;
public const MOSSY_STONE_BRICK_WALL = 10356;
public const MOSSY_STONE_BRICKS = 10357;
public const MUSHROOM_STEM = 10358;
public const MYCELIUM = 10359;
public const NETHER_BRICK_FENCE = 10360;
public const NETHER_BRICK_SLAB = 10361;
public const NETHER_BRICK_STAIRS = 10362;
public const NETHER_BRICK_WALL = 10363;
public const NETHER_BRICKS = 10364;
public const NETHER_PORTAL = 10365;
public const NETHER_QUARTZ_ORE = 10366;
public const NETHER_REACTOR_CORE = 10367;
public const NETHER_WART = 10368;
public const NETHER_WART_BLOCK = 10369;
public const NETHERRACK = 10370;
public const NOTE_BLOCK = 10371;
public const OAK_BUTTON = 10372;
public const OAK_DOOR = 10373;
public const OAK_FENCE = 10374;
public const OAK_FENCE_GATE = 10375;
public const OAK_LEAVES = 10376;
public const OAK_LOG = 10377;
public const OAK_PLANKS = 10378;
public const OAK_PRESSURE_PLATE = 10379;
public const OAK_SAPLING = 10380;
public const OAK_SIGN = 10381;
public const OAK_SLAB = 10382;
public const OAK_STAIRS = 10383;
public const OAK_TRAPDOOR = 10384;
public const OAK_WALL_SIGN = 10385;
public const OAK_WOOD = 10386;
public const OBSIDIAN = 10387;
public const ORANGE_TULIP = 10389;
public const OXEYE_DAISY = 10390;
public const PACKED_ICE = 10391;
public const PEONY = 10392;
public const PINK_TULIP = 10394;
public const PODZOL = 10395;
public const POLISHED_ANDESITE = 10396;
public const POLISHED_ANDESITE_SLAB = 10397;
public const POLISHED_ANDESITE_STAIRS = 10398;
public const POLISHED_DIORITE = 10399;
public const POLISHED_DIORITE_SLAB = 10400;
public const POLISHED_DIORITE_STAIRS = 10401;
public const POLISHED_GRANITE = 10402;
public const POLISHED_GRANITE_SLAB = 10403;
public const POLISHED_GRANITE_STAIRS = 10404;
public const POPPY = 10405;
public const POTATOES = 10406;
public const POWERED_RAIL = 10407;
public const PRISMARINE = 10408;
public const PRISMARINE_BRICKS = 10409;
public const PRISMARINE_BRICKS_SLAB = 10410;
public const PRISMARINE_BRICKS_STAIRS = 10411;
public const PRISMARINE_SLAB = 10412;
public const PRISMARINE_STAIRS = 10413;
public const PRISMARINE_WALL = 10414;
public const PUMPKIN = 10415;
public const PUMPKIN_STEM = 10416;
public const PURPLE_TORCH = 10418;
public const PURPUR = 10419;
public const PURPUR_PILLAR = 10420;
public const PURPUR_SLAB = 10421;
public const PURPUR_STAIRS = 10422;
public const QUARTZ = 10423;
public const QUARTZ_PILLAR = 10424;
public const QUARTZ_SLAB = 10425;
public const QUARTZ_STAIRS = 10426;
public const RAIL = 10427;
public const RED_MUSHROOM = 10429;
public const RED_MUSHROOM_BLOCK = 10430;
public const RED_NETHER_BRICK_SLAB = 10431;
public const RED_NETHER_BRICK_STAIRS = 10432;
public const RED_NETHER_BRICK_WALL = 10433;
public const RED_NETHER_BRICKS = 10434;
public const RED_SAND = 10435;
public const RED_SANDSTONE = 10436;
public const RED_SANDSTONE_SLAB = 10437;
public const RED_SANDSTONE_STAIRS = 10438;
public const RED_SANDSTONE_WALL = 10439;
public const RED_TORCH = 10440;
public const RED_TULIP = 10441;
public const REDSTONE = 10442;
public const REDSTONE_COMPARATOR = 10443;
public const REDSTONE_LAMP = 10444;
public const REDSTONE_ORE = 10445;
public const REDSTONE_REPEATER = 10446;
public const REDSTONE_TORCH = 10447;
public const REDSTONE_WIRE = 10448;
public const RESERVED6 = 10449;
public const ROSE_BUSH = 10450;
public const SAND = 10451;
public const SANDSTONE = 10452;
public const SANDSTONE_SLAB = 10453;
public const SANDSTONE_STAIRS = 10454;
public const SANDSTONE_WALL = 10455;
public const SEA_LANTERN = 10456;
public const SEA_PICKLE = 10457;
public const SHULKER_BOX = 10458;
public const SLIME = 10459;
public const SMOKER = 10460;
public const SMOOTH_QUARTZ = 10461;
public const SMOOTH_QUARTZ_SLAB = 10462;
public const SMOOTH_QUARTZ_STAIRS = 10463;
public const SMOOTH_RED_SANDSTONE = 10464;
public const SMOOTH_RED_SANDSTONE_SLAB = 10465;
public const SMOOTH_RED_SANDSTONE_STAIRS = 10466;
public const SMOOTH_SANDSTONE = 10467;
public const SMOOTH_SANDSTONE_SLAB = 10468;
public const SMOOTH_SANDSTONE_STAIRS = 10469;
public const SMOOTH_STONE = 10470;
public const SMOOTH_STONE_SLAB = 10471;
public const SNOW = 10472;
public const SNOW_LAYER = 10473;
public const SOUL_SAND = 10474;
public const SPONGE = 10475;
public const SPRUCE_BUTTON = 10476;
public const SPRUCE_DOOR = 10477;
public const SPRUCE_FENCE = 10478;
public const SPRUCE_FENCE_GATE = 10479;
public const SPRUCE_LEAVES = 10480;
public const SPRUCE_LOG = 10481;
public const SPRUCE_PLANKS = 10482;
public const SPRUCE_PRESSURE_PLATE = 10483;
public const SPRUCE_SAPLING = 10484;
public const SPRUCE_SIGN = 10485;
public const SPRUCE_SLAB = 10486;
public const SPRUCE_STAIRS = 10487;
public const SPRUCE_TRAPDOOR = 10488;
public const SPRUCE_WALL_SIGN = 10489;
public const SPRUCE_WOOD = 10490;
public const STAINED_CLAY = 10491;
public const STAINED_GLASS = 10492;
public const STAINED_GLASS_PANE = 10493;
public const STAINED_HARDENED_GLASS = 10494;
public const STAINED_HARDENED_GLASS_PANE = 10495;
public const STONE = 10496;
public const STONE_BRICK_SLAB = 10497;
public const STONE_BRICK_STAIRS = 10498;
public const STONE_BRICK_WALL = 10499;
public const STONE_BRICKS = 10500;
public const STONE_BUTTON = 10501;
public const STONE_PRESSURE_PLATE = 10502;
public const STONE_SLAB = 10503;
public const STONE_STAIRS = 10504;
public const STONECUTTER = 10505;
public const SUGARCANE = 10518;
public const SUNFLOWER = 10519;
public const SWEET_BERRY_BUSH = 10520;
public const TALL_GRASS = 10521;
public const TNT = 10522;
public const TORCH = 10523;
public const TRAPPED_CHEST = 10524;
public const TRIPWIRE = 10525;
public const TRIPWIRE_HOOK = 10526;
public const UNDERWATER_TORCH = 10527;
public const VINES = 10528;
public const WALL_BANNER = 10529;
public const WALL_CORAL_FAN = 10530;
public const WATER = 10531;
public const WEIGHTED_PRESSURE_PLATE_HEAVY = 10532;
public const WEIGHTED_PRESSURE_PLATE_LIGHT = 10533;
public const WHEAT = 10534;
public const WHITE_TULIP = 10536;
public const WOOL = 10537;
public const GLAZED_TERRACOTTA = 10539;
public const AMETHYST = 10540;
public const ANCIENT_DEBRIS = 10541;
public const BASALT = 10542;
public const POLISHED_BASALT = 10543;
public const SMOOTH_BASALT = 10544;
public const BLACKSTONE = 10545;
public const BLACKSTONE_SLAB = 10546;
public const BLACKSTONE_STAIRS = 10547;
public const BLACKSTONE_WALL = 10548;
public const POLISHED_BLACKSTONE = 10549;
public const POLISHED_BLACKSTONE_BUTTON = 10550;
public const POLISHED_BLACKSTONE_PRESSURE_PLATE = 10551;
public const POLISHED_BLACKSTONE_SLAB = 10552;
public const POLISHED_BLACKSTONE_STAIRS = 10553;
public const POLISHED_BLACKSTONE_WALL = 10554;
public const CHISELED_POLISHED_BLACKSTONE = 10555;
public const POLISHED_BLACKSTONE_BRICKS = 10556;
public const POLISHED_BLACKSTONE_BRICK_SLAB = 10557;
public const POLISHED_BLACKSTONE_BRICK_STAIRS = 10558;
public const POLISHED_BLACKSTONE_BRICK_WALL = 10559;
public const CRACKED_POLISHED_BLACKSTONE_BRICKS = 10560;
public const LIGHT = 10561;
public const RAW_COPPER = 10562;
public const RAW_GOLD = 10563;
public const RAW_IRON = 10564;
public const CALCITE = 10565;
public const DEEPSLATE = 10566;
public const DEEPSLATE_BRICKS = 10567;
public const DEEPSLATE_BRICK_SLAB = 10568;
public const DEEPSLATE_BRICK_STAIRS = 10569;
public const DEEPSLATE_BRICK_WALL = 10570;
public const CRACKED_DEEPSLATE_BRICKS = 10571;
public const DEEPSLATE_TILES = 10572;
public const DEEPSLATE_TILE_SLAB = 10573;
public const DEEPSLATE_TILE_STAIRS = 10574;
public const DEEPSLATE_TILE_WALL = 10575;
public const CRACKED_DEEPSLATE_TILES = 10576;
public const COBBLED_DEEPSLATE = 10577;
public const COBBLED_DEEPSLATE_SLAB = 10578;
public const COBBLED_DEEPSLATE_STAIRS = 10579;
public const COBBLED_DEEPSLATE_WALL = 10580;
public const POLISHED_DEEPSLATE = 10581;
public const POLISHED_DEEPSLATE_SLAB = 10582;
public const POLISHED_DEEPSLATE_STAIRS = 10583;
public const POLISHED_DEEPSLATE_WALL = 10584;
public const QUARTZ_BRICKS = 10585;
public const CHISELED_DEEPSLATE = 10586;
public const CHISELED_NETHER_BRICKS = 10587;
public const CRACKED_NETHER_BRICKS = 10588;
public const TUFF = 10589;
public const SOUL_TORCH = 10590;
public const SOUL_LANTERN = 10591;
public const SOUL_SOIL = 10592;
public const SOUL_FIRE = 10593;
public const SHROOMLIGHT = 10594;
public const MANGROVE_PLANKS = 10595;
public const CRIMSON_PLANKS = 10596;
public const WARPED_PLANKS = 10597;
public const MANGROVE_FENCE = 10598;
public const CRIMSON_FENCE = 10599;
public const WARPED_FENCE = 10600;
public const MANGROVE_SLAB = 10601;
public const CRIMSON_SLAB = 10602;
public const WARPED_SLAB = 10603;
public const MANGROVE_LOG = 10604;
public const CRIMSON_STEM = 10605;
public const WARPED_STEM = 10606;
public const MANGROVE_WOOD = 10607;
public const CRIMSON_HYPHAE = 10608;
public const WARPED_HYPHAE = 10609;
public const MANGROVE_TRAPDOOR = 10610;
public const CRIMSON_TRAPDOOR = 10611;
public const WARPED_TRAPDOOR = 10612;
public const MANGROVE_BUTTON = 10613;
public const CRIMSON_BUTTON = 10614;
public const WARPED_BUTTON = 10615;
public const MANGROVE_PRESSURE_PLATE = 10616;
public const CRIMSON_PRESSURE_PLATE = 10617;
public const WARPED_PRESSURE_PLATE = 10618;
public const MANGROVE_DOOR = 10619;
public const CRIMSON_DOOR = 10620;
public const WARPED_DOOR = 10621;
public const MANGROVE_FENCE_GATE = 10622;
public const CRIMSON_FENCE_GATE = 10623;
public const WARPED_FENCE_GATE = 10624;
public const MANGROVE_STAIRS = 10625;
public const CRIMSON_STAIRS = 10626;
public const WARPED_STAIRS = 10627;
public const MANGROVE_SIGN = 10628;
public const CRIMSON_SIGN = 10629;
public const WARPED_SIGN = 10630;
public const MANGROVE_WALL_SIGN = 10631;
public const CRIMSON_WALL_SIGN = 10632;
public const WARPED_WALL_SIGN = 10633;
public const TINTED_GLASS = 10634;
public const HONEYCOMB = 10635;
public const DEEPSLATE_COAL_ORE = 10636;
public const DEEPSLATE_DIAMOND_ORE = 10637;
public const DEEPSLATE_EMERALD_ORE = 10638;
public const DEEPSLATE_LAPIS_LAZULI_ORE = 10639;
public const DEEPSLATE_REDSTONE_ORE = 10640;
public const DEEPSLATE_IRON_ORE = 10641;
public const DEEPSLATE_GOLD_ORE = 10642;
public const DEEPSLATE_COPPER_ORE = 10643;
public const COPPER_ORE = 10644;
public const NETHER_GOLD_ORE = 10645;
public const MUD = 10646;
public const MUD_BRICKS = 10647;
public const MUD_BRICK_SLAB = 10648;
public const MUD_BRICK_STAIRS = 10649;
public const MUD_BRICK_WALL = 10650;
public const PACKED_MUD = 10651;
public const WARPED_WART_BLOCK = 10652;
public const CRYING_OBSIDIAN = 10653;
public const GILDED_BLACKSTONE = 10654;
public const LIGHTNING_ROD = 10655;
public const COPPER = 10656;
public const CUT_COPPER = 10657;
public const CUT_COPPER_SLAB = 10658;
public const CUT_COPPER_STAIRS = 10659;
public const CANDLE = 10660;
public const DYED_CANDLE = 10661;
public const CAKE_WITH_CANDLE = 10662;
public const CAKE_WITH_DYED_CANDLE = 10663;
public const WITHER_ROSE = 10664;
public const HANGING_ROOTS = 10665;
public const CARTOGRAPHY_TABLE = 10666;
public const SMITHING_TABLE = 10667;
public const NETHERITE = 10668;
public const SPORE_BLOSSOM = 10669;
public const CAULDRON = 10670;
public const WATER_CAULDRON = 10671;
public const LAVA_CAULDRON = 10672;
public const POTION_CAULDRON = 10673;
public const POWDER_SNOW_CAULDRON = 10674;
public const CHORUS_FLOWER = 10675;
public const CHORUS_PLANT = 10676;
public const MANGROVE_ROOTS = 10677;
public const MUDDY_MANGROVE_ROOTS = 10678;
public const FROGLIGHT = 10679;
public const TWISTING_VINES = 10680;
public const WEEPING_VINES = 10681;
public const CHAIN = 10682;
public const SCULK = 10683;
public const GLOWING_ITEM_FRAME = 10684;
public const MANGROVE_LEAVES = 10685;
public const AZALEA_LEAVES = 10686;
public const FLOWERING_AZALEA_LEAVES = 10687;
public const REINFORCED_DEEPSLATE = 10688;
public const FIRST_UNUSED_BLOCK_ID = 10689;
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;
/**
* Returns a new runtime block type ID, e.g. for use by a custom block.
*/
public static function newId() : int{
return self::$nextDynamicId++;
}
}

View File

@ -1,52 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use function array_fill_keys;
use function array_keys;
final class BlockTypeInfo{
/**
* @var true[]
* @phpstan-var array<string, true>
*/
private array $typeTags;
/**
* @param string[] $typeTags
*/
public function __construct(
private BlockBreakInfo $breakInfo,
array $typeTags = []
){
$this->typeTags = array_fill_keys($typeTags, true);
}
public function getBreakInfo() : BlockBreakInfo{ return $this->breakInfo; }
/** @return string[] */
public function getTypeTags() : array{ return array_keys($this->typeTags); }
public function hasTypeTag(string $tag) : bool{ return isset($this->typeTags[$tag]); }
}

View File

@ -1,34 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
final class BlockTypeTags{
private const PREFIX = "pocketmine:";
public const DIRT = self::PREFIX . "dirt";
public const MUD = self::PREFIX . "mud";
public const SAND = self::PREFIX . "sand";
public const POTTABLE_PLANTS = self::PREFIX . "pottable";
public const FIRE = self::PREFIX . "fire";
}

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\PillarRotationTrait; use pocketmine\block\utils\PillarRotationInMetadataTrait;
class BoneBlock extends Opaque{ class BoneBlock extends Opaque{
use PillarRotationTrait; use PillarRotationInMetadataTrait;
} }

View File

@ -26,7 +26,6 @@ namespace pocketmine\block;
use pocketmine\block\tile\BrewingStand as TileBrewingStand; use pocketmine\block\tile\BrewingStand as TileBrewingStand;
use pocketmine\block\utils\BrewingStandSlot; use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Axis; use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
@ -43,8 +42,33 @@ class BrewingStand extends Transparent{
*/ */
protected array $slots = []; protected array $slots = [];
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->brewingStandSlots($this->slots); $flags = 0;
foreach([
BlockLegacyMetadata::BREWING_STAND_FLAG_EAST => BrewingStandSlot::EAST(),
BlockLegacyMetadata::BREWING_STAND_FLAG_NORTHWEST => BrewingStandSlot::NORTHWEST(),
BlockLegacyMetadata::BREWING_STAND_FLAG_SOUTHWEST => BrewingStandSlot::SOUTHWEST(),
] as $flag => $slot){
$flags |= (array_key_exists($slot->id(), $this->slots) ? $flag : 0);
}
return $flags;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->slots = [];
foreach([
BlockLegacyMetadata::BREWING_STAND_FLAG_EAST => BrewingStandSlot::EAST(),
BlockLegacyMetadata::BREWING_STAND_FLAG_NORTHWEST => BrewingStandSlot::NORTHWEST(),
BlockLegacyMetadata::BREWING_STAND_FLAG_SOUTHWEST => BrewingStandSlot::SOUTHWEST(),
] as $flag => $slot){
if(($stateMeta & $flag) !== 0){
$this->slots[$slot->id()] = $slot;
}
}
}
public function getStateBitmask() : int{
return 0b111;
} }
protected function recalculateCollisionBoxes() : array{ protected function recalculateCollisionBoxes() : array{
@ -94,7 +118,7 @@ class BrewingStand extends Transparent{
return $this; return $this;
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){ if($player instanceof Player){
$stand = $this->position->getWorld()->getTile($this->position); $stand = $this->position->getWorld()->getTile($this->position);
if($stand instanceof TileBrewingStand && $stand->canOpenWith($item->getCustomName())){ if($stand instanceof TileBrewingStand && $stand->canOpenWith($item->getCustomName())){

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\AnyFacingTrait; use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
@ -38,9 +38,18 @@ abstract class Button extends Flowable{
protected bool $pressed = false; protected bool $pressed = false;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->facing($this->facing); return BlockDataSerializer::writeFacing($this->facing) | ($this->pressed ? BlockLegacyMetadata::BUTTON_FLAG_POWERED : 0);
$w->bool($this->pressed); }
public function readStateFromData(int $id, int $stateMeta) : void{
//TODO: in PC it's (6 - facing) for every meta except 0 (down)
$this->facing = BlockDataSerializer::readFacing($stateMeta & 0x07);
$this->pressed = ($stateMeta & BlockLegacyMetadata::BUTTON_FLAG_POWERED) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
} }
public function isPressed() : bool{ return $this->pressed; } public function isPressed() : bool{ return $this->pressed; }
@ -61,7 +70,7 @@ abstract class Button extends Flowable{
abstract protected function getActivationTime() : int; abstract protected function getActivationTime() : int;
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->pressed){ if(!$this->pressed){
$this->pressed = true; $this->pressed = true;
$world = $this->position->getWorld(); $world = $this->position->getWorld();

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\event\block\BlockGrowEvent; use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent; use pocketmine\event\entity\EntityDamageByBlockEvent;
@ -41,8 +41,16 @@ class Cactus extends Transparent{
protected int $age = 0; protected int $age = 0;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->boundedInt(4, 0, self::MAX_AGE, $this->age); return $this->age;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta, 0, self::MAX_AGE);
}
public function getStateBitmask() : int{
return 0b1111;
} }
public function getAge() : int{ return $this->age; } public function getAge() : int{ return $this->age; }
@ -78,13 +86,10 @@ class Cactus extends Transparent{
return true; return true;
} }
private function canBeSupportedBy(Block $block) : bool{
return $block->isSameType($this) || $block->hasTypeTag(BlockTypeTags::SAND);
}
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$down = $this->getSide(Facing::DOWN);
$world = $this->position->getWorld(); $world = $this->position->getWorld();
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ if($down->getId() !== BlockLegacyIds::SAND && !$down->isSameType($this)){
$world->useBreakOn($this->position); $world->useBreakOn($this->position);
}else{ }else{
foreach(Facing::HORIZONTAL as $side){ foreach(Facing::HORIZONTAL as $side){
@ -110,7 +115,7 @@ class Cactus extends Transparent{
break; break;
} }
$b = $world->getBlockAt($this->position->x, $this->position->y + $y, $this->position->z); $b = $world->getBlockAt($this->position->x, $this->position->y + $y, $this->position->z);
if($b->getTypeId() === BlockTypeIds::AIR){ if($b->getId() === BlockLegacyIds::AIR){
$ev = new BlockGrowEvent($b, VanillaBlocks::CACTUS()); $ev = new BlockGrowEvent($b, VanillaBlocks::CACTUS());
$ev->call(); $ev->call();
if($ev->isCancelled()){ if($ev->isCancelled()){
@ -131,7 +136,8 @@ class Cactus extends Transparent{
} }
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedBy($this->getSide(Facing::DOWN))){ $down = $this->getSide(Facing::DOWN);
if($down->getId() === BlockLegacyIds::SAND || $down->isSameType($this)){
foreach(Facing::HORIZONTAL as $side){ foreach(Facing::HORIZONTAL as $side){
if($this->getSide($side)->isSolid()){ if($this->getSide($side)->isSolid()){
return false; return false;

View File

@ -23,21 +23,33 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType;
use pocketmine\entity\effect\EffectInstance;
use pocketmine\entity\FoodSource;
use pocketmine\entity\Living;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\ItemBlock;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class Cake extends BaseCake{ class Cake extends Transparent implements FoodSource{
public const MAX_BITES = 6; public const MAX_BITES = 6;
protected int $bites = 0; protected int $bites = 0;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->boundedInt(3, 0, self::MAX_BITES, $this->bites); return $this->bites;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->bites = BlockDataSerializer::readBoundedInt("bites", $stateMeta, 0, self::MAX_BITES);
}
public function getStateBitmask() : int{
return 0b111;
} }
/** /**
@ -52,6 +64,10 @@ class Cake extends BaseCake{
]; ];
} }
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
public function getBites() : int{ return $this->bites; } public function getBites() : int{ return $this->bites; }
/** @return $this */ /** @return $this */
@ -63,27 +79,49 @@ class Cake extends BaseCake{
return $this; return $this;
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof ItemBlock){ $down = $this->getSide(Facing::DOWN);
$block = $item->getBlock(); if($down->getId() !== BlockLegacyIds::AIR){
$resultBlock = null; return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
if($block->getTypeId() === BlockTypeIds::CANDLE){
$resultBlock = VanillaBlocks::CAKE_WITH_CANDLE();
}elseif($block instanceof DyedCandle){
$resultBlock = VanillaBlocks::CAKE_WITH_DYED_CANDLE()->setColor($block->getColor());
}
if($resultBlock !== null){
$this->position->getWorld()->setBlock($this->position, $resultBlock);
$item->pop();
return true;
}
} }
return parent::onInteract($item, $face, $clickVector, $player, $returnedItems); return false;
} }
public function getResidue() : Block{ public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getId() === BlockLegacyIds::AIR){ //Replace with common break method
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::AIR());
}
}
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
return $player->consumeObject($this);
}
return false;
}
public function getFoodRestore() : int{
return 2;
}
public function getSaturationRestore() : float{
return 0.4;
}
public function requiresHunger() : bool{
return true;
}
/**
* @return Block
*/
public function getResidue(){
$clone = clone $this; $clone = clone $this;
$clone->bites++; $clone->bites++;
if($clone->bites > self::MAX_BITES){ if($clone->bites > self::MAX_BITES){
@ -91,4 +129,15 @@ class Cake extends BaseCake{
} }
return $clone; return $clone;
} }
/**
* @return EffectInstance[]
*/
public function getAdditionalEffects() : array{
return [];
}
public function onConsume(Living $consumer) : void{
$this->position->getWorld()->setBlock($this->position, $this->getResidue());
}
} }

View File

@ -1,78 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CandleTrait;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
class CakeWithCandle extends BaseCake{
use CandleTrait {
onInteract as onInteractCandle;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()
->contract(1 / 16, 0, 1 / 16)
->trim(Facing::UP, 0.5) //TODO: not sure if the candle affects height
];
}
public function getCandle() : Candle{
return VanillaBlocks::CANDLE();
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($this->onInteractCandle($item, $face, $clickVector, $player, $returnedItems)){
return true;
}
return parent::onInteract($item, $face, $clickVector, $player, $returnedItems);
}
public function getDropsForCompatibleTool(Item $item) : array{
return [$this->getCandle()->asItem()];
}
public function getPickedItem(bool $addUserData = false) : Item{
return VanillaBlocks::CAKE()->getPickedItem($addUserData);
}
public function getResidue() : Block{
return VanillaBlocks::CAKE()->setBites(1);
}
public function onConsume(Living $consumer) : void{
parent::onConsume($consumer);
$this->position->getWorld()->dropItem($this->position->add(0.5, 0.5, 0.5), $this->getCandle()->asItem());
}
}

View File

@ -1,40 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
class CakeWithDyedCandle extends CakeWithCandle{
use ColoredTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
$this->color = DyeColor::WHITE();
parent::__construct($idInfo, $name, $typeInfo);
}
public function getCandle() : Candle{
return VanillaBlocks::DYED_CANDLE()->setColor($this->color);
}
}

View File

@ -1,126 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CandleTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
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\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
class Candle extends Transparent{
use CandleTrait {
describeState as encodeLitState;
getLightLevel as getBaseLightLevel;
}
public const MIN_COUNT = 1;
public const MAX_COUNT = 4;
private int $count = self::MIN_COUNT;
protected function describeState(RuntimeDataDescriber $w) : void{
$this->encodeLitState($w);
$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;
}
public function getLightLevel() : int{
return $this->getBaseLightLevel() * $this->count;
}
protected function recalculateCollisionBoxes() : array{
return [
(match($this->count){
1 => AxisAlignedBB::one()
->squash(Axis::X, 7 / 16)
->squash(Axis::Z, 7 / 16),
2 => AxisAlignedBB::one()
->squash(Axis::X, 5 / 16)
->trim(Facing::NORTH, 7 / 16) //0.3 thick on the Z axis
->trim(Facing::SOUTH, 6 / 16),
3 => AxisAlignedBB::one()
->trim(Facing::WEST, 5 / 16)
->trim(Facing::EAST, 6 / 16)
->trim(Facing::NORTH, 6 / 16)
->trim(Facing::SOUTH, 5 / 16),
4 => AxisAlignedBB::one()
->squash(Axis::X, 5 / 16)
->trim(Facing::NORTH, 5 / 16)
->trim(Facing::SOUTH, 6 / 16),
default => throw new AssumptionFailedError("Unreachable")
})->trim(Facing::UP, 10 / 16)
];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE();
}
protected function getCandleIfCompatibleType(Block $block) : ?Candle{
return $block instanceof Candle && $block->isSameType($this) ? $block : null;
}
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
$candle = $this->getCandleIfCompatibleType($blockReplace);
return $candle !== null ? $candle->count < 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{
$down = $blockReplace->getSide(Facing::DOWN);
if(!$down->getSupportType(Facing::UP)->hasCenterSupport()){
return false;
}
$existing = $this->getCandleIfCompatibleType($blockReplace);
if($existing !== null){
if($existing->count >= self::MAX_COUNT){
return false;
}
$this->count = $existing->count + 1;
$this->lit = $existing->lit;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function getDropsForCompatibleTool(Item $item) : array{
return [$this->asItem()->setCount($this->count)];
}
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\ColoredTrait; use pocketmine\block\utils\ColorInMetadataTrait;
use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\DyeColor;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
@ -33,11 +33,11 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction; use pocketmine\world\BlockTransaction;
class Carpet extends Flowable{ class Carpet extends Flowable{
use ColoredTrait; use ColorInMetadataTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::WHITE(); $this->color = DyeColor::WHITE();
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
} }
public function isSolid() : bool{ public function isSolid() : bool{
@ -53,7 +53,7 @@ class Carpet extends Flowable{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $this->getSide(Facing::DOWN); $down = $this->getSide(Facing::DOWN);
if($down->getTypeId() !== BlockTypeIds::AIR){ if($down->getId() !== BlockLegacyIds::AIR){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
@ -61,7 +61,7 @@ class Carpet extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::AIR){ if($this->getSide(Facing::DOWN)->getId() === BlockLegacyIds::AIR){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }

View File

@ -35,7 +35,7 @@ class Carrot extends Crops{
]; ];
} }
public function asItem() : Item{ public function getPickedItem(bool $addUserData = false) : Item{
return VanillaItems::CARROT(); return VanillaItems::CARROT();
} }
} }

View File

@ -23,10 +23,23 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\HorizontalFacingTrait;
class CarvedPumpkin extends Opaque{ class CarvedPumpkin extends Opaque{
use FacesOppositePlacingPlayerTrait; use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait; use HorizontalFacingTrait;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
}
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing);
}
public function getStateBitmask() : int{
return 0b11;
}
} }

View File

@ -1,104 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Cauldron as TileCauldron;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\item\Potion;
use pocketmine\item\PotionType;
use pocketmine\item\SplashPotion;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function assert;
final class Cauldron extends Transparent{
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileCauldron);
//empty cauldrons don't use this information
$tile->setCustomWaterColor(null);
$tile->setPotionItem(null);
}
protected function recalculateCollisionBoxes() : array{
$result = [
AxisAlignedBB::one()->trim(Facing::UP, 11 / 16) //bottom of the cauldron
];
foreach(Facing::HORIZONTAL as $f){ //add the frame parts around the bowl
$result[] = AxisAlignedBB::one()->trim($f, 14 / 16);
}
return $result;
}
public function getSupportType(int $facing) : SupportType{
return $facing === Facing::UP ? SupportType::EDGE() : SupportType::NONE();
}
/**
* @param Item[] &$returnedItems
*/
private function fill(int $amount, FillableCauldron $result, Item $usedItem, Item $returnedItem, array &$returnedItems) : void{
$this->position->getWorld()->setBlock($this->position, $result->setFillLevel($amount));
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), $result->getFillSound());
$usedItem->pop();
$returnedItems[] = $returnedItem;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item->getTypeId() === ItemTypeIds::WATER_BUCKET){
$this->fill(FillableCauldron::MAX_FILL_LEVEL, VanillaBlocks::WATER_CAULDRON(), $item, VanillaItems::BUCKET(), $returnedItems);
}elseif($item->getTypeId() === ItemTypeIds::LAVA_BUCKET){
$this->fill(FillableCauldron::MAX_FILL_LEVEL, VanillaBlocks::LAVA_CAULDRON(), $item, VanillaItems::BUCKET(), $returnedItems);
}elseif($item->getTypeId() === ItemTypeIds::POWDER_SNOW_BUCKET){
//TODO: powder snow cauldron
}elseif($item instanceof Potion || $item instanceof SplashPotion){ //TODO: lingering potion
if($item->getType()->equals(PotionType::WATER())){
$this->fill(WaterCauldron::WATER_BOTTLE_FILL_AMOUNT, VanillaBlocks::WATER_CAULDRON(), $item, VanillaItems::GLASS_BOTTLE(), $returnedItems);
}else{
$this->fill(PotionCauldron::POTION_FILL_AMOUNT, VanillaBlocks::POTION_CAULDRON()->setPotionItem($item), $item, VanillaItems::GLASS_BOTTLE(), $returnedItems);
}
}
return true;
}
public function onNearbyBlockChange() : void{
$world = $this->position->getWorld();
if($world->getBlock($this->position->up())->getTypeId() === BlockTypeIds::WATER){
$cauldron = VanillaBlocks::WATER_CAULDRON()->setFillLevel(FillableCauldron::MAX_FILL_LEVEL);
$world->setBlock($this->position, $cauldron);
$world->addSound($this->position->add(0.5, 0.5, 0.5), $cauldron->getFillSound());
}
}
}

View File

@ -1,48 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\PillarRotationTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
final class Chain extends Transparent{
use PillarRotationTrait;
public function getSupportType(int $facing) : SupportType{
return $this->axis === Axis::Y && Facing::axis($facing) === Axis::Y ? SupportType::CENTER() : SupportType::NONE();
}
protected function recalculateCollisionBoxes() : array{
$bb = AxisAlignedBB::one();
foreach([Axis::Y, Axis::Z, Axis::X] as $axis){
if($axis !== $this->axis){
$bb->squash($axis, 13 / 32);
}
}
return [$bb];
}
}

View File

@ -23,9 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
@ -33,7 +35,19 @@ final class ChemistryTable extends Opaque{
use FacesOppositePlacingPlayerTrait; use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait; use HorizontalFacingTrait;
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = Facing::opposite(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x3));
}
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing(Facing::opposite($this->facing));
}
public function getStateBitmask() : int{
return 0b0011;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
//TODO //TODO
return false; return false;
} }

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Chest as TileChest; use pocketmine\block\tile\Chest as TileChest;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\event\block\ChestPairEvent; use pocketmine\event\block\ChestPairEvent;
use pocketmine\item\Item; use pocketmine\item\Item;
@ -36,7 +36,7 @@ use pocketmine\player\Player;
class Chest extends Transparent{ class Chest extends Transparent{
use FacesOppositePlacingPlayerTrait; use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait; use NormalHorizontalFacingInMetadataTrait;
/** /**
* @return AxisAlignedBB[] * @return AxisAlignedBB[]
@ -74,7 +74,7 @@ class Chest extends Transparent{
} }
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){ if($player instanceof Player){
$chest = $this->position->getWorld()->getTile($this->position); $chest = $this->position->getWorld()->getTile($this->position);

View File

@ -1,233 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\projectile\Projectile;
use pocketmine\event\block\StructureGrowEvent;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\Position;
use pocketmine\world\sound\ChorusFlowerDieSound;
use pocketmine\world\sound\ChorusFlowerGrowSound;
use pocketmine\world\World;
use function array_rand;
use function mt_rand;
final class ChorusFlower extends Flowable{
public const MIN_AGE = 0;
public const MAX_AGE = 5;
private const MAX_STEM_HEIGHT = 5;
private int $age = self::MIN_AGE;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->boundedInt(3, self::MIN_AGE, self::MAX_AGE, $this->age);
}
public function getAge() : int{ return $this->age; }
/** @return $this */
public function setAge(int $age) : self{
if($age < self::MIN_AGE || $age > self::MAX_AGE){
throw new \InvalidArgumentException("Age must be in the range " . self::MIN_AGE . " ... " . self::MAX_AGE);
}
$this->age = $age;
return $this;
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()];
}
private function canBeSupportedAt(Position $position) : bool{
$world = $position->getWorld();
$down = $world->getBlock($position->down());
if($down->getTypeId() === BlockTypeIds::END_STONE || $down->getTypeId() === BlockTypeIds::CHORUS_PLANT){
return true;
}
$plantAdjacent = false;
foreach($position->sidesAroundAxis(Axis::Y) as $sidePosition){
$block = $world->getBlock($sidePosition);
if($block->getTypeId() === BlockTypeIds::CHORUS_PLANT){
if($plantAdjacent){ //at most one plant may be horizontally adjacent
return false;
}
$plantAdjacent = true;
}elseif($block->getTypeId() !== BlockTypeIds::AIR){
return false;
}
}
return $plantAdjacent;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedAt($blockReplace->getPosition())){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedAt($this->position)){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
$this->position->getWorld()->useBreakOn($this->position);
}
public function ticksRandomly() : bool{ return $this->age < self::MAX_AGE; }
/**
* @phpstan-return array{int, bool}
*/
private function scanStem() : array{
$world = $this->position->getWorld();
$stemHeight = 0;
$endStoneBelow = false;
for($yOffset = 0; $yOffset < self::MAX_STEM_HEIGHT; $yOffset++, $stemHeight++){
$down = $world->getBlock($this->position->down($yOffset + 1));
if($down->getTypeId() !== BlockTypeIds::CHORUS_PLANT){
if($down->getTypeId() === BlockTypeIds::END_STONE){
$endStoneBelow = true;
}
break;
}
}
return [$stemHeight, $endStoneBelow];
}
private function allHorizontalBlocksEmpty(World $world, Vector3 $position, ?int $except) : bool{
foreach($position->sidesAroundAxis(Axis::Y) as $facing => $sidePosition){
if($facing === $except){
continue;
}
if($world->getBlock($sidePosition)->getTypeId() !== BlockTypeIds::AIR){
return false;
}
}
return true;
}
private function canGrowUpwards(int $stemHeight, bool $endStoneBelow) : bool{
$world = $this->position->getWorld();
$up = $this->position->up();
if(
//the space above must be empty and writable
!$world->isInWorld($up->x, $up->y, $up->z) ||
$world->getBlock($up)->getTypeId() !== BlockTypeIds::AIR ||
(
//the space above that must be empty, but doesn't need to be writable
$world->isInWorld($up->x, $up->y + 1, $up->z) &&
$world->getBlock($up->up())->getTypeId() !== BlockTypeIds::AIR
)
){
return false;
}
if($this->getSide(Facing::DOWN)->getTypeId() !== BlockTypeIds::AIR){
if($stemHeight >= self::MAX_STEM_HEIGHT){
return false;
}
if($stemHeight > 1 && $stemHeight > mt_rand(0, $endStoneBelow ? 4 : 3)){ //chance decreases for each added block of chorus plant
return false;
}
}
return $this->allHorizontalBlocksEmpty($world, $up, null);
}
private function grow(int $facing, int $ageChange, ?BlockTransaction $tx) : BlockTransaction{
if($tx === null){
$tx = new BlockTransaction($this->position->getWorld());
}
$tx->addBlock($this->position->getSide($facing), (clone $this)->setAge($this->getAge() + $ageChange));
return $tx;
}
public function onRandomTick() : void{
$world = $this->position->getWorld();
if($this->age >= self::MAX_AGE){
return;
}
$tx = null;
[$stemHeight, $endStoneBelow] = $this->scanStem();
if($this->canGrowUpwards($stemHeight, $endStoneBelow)){
$tx = $this->grow(Facing::UP, 0, $tx);
}else{
$facingVisited = [];
for($attempts = 0, $maxAttempts = mt_rand(0, $endStoneBelow ? 4 : 3); $attempts < $maxAttempts; $attempts++){
$facing = Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)];
if(isset($facingVisited[$facing])){
continue;
}
$facingVisited[$facing] = true;
$sidePosition = $this->position->getSide($facing);
if(
$world->getBlock($sidePosition)->getTypeId() === BlockTypeIds::AIR &&
$world->getBlock($sidePosition->down())->getTypeId() === BlockTypeIds::AIR &&
$this->allHorizontalBlocksEmpty($world, $sidePosition, Facing::opposite($facing))
){
$tx = $this->grow($facing, 1, $tx);
}
}
}
if($tx !== null){
$tx->addBlock($this->position, VanillaBlocks::CHORUS_PLANT());
$ev = new StructureGrowEvent($this, $tx, null);
$ev->call();
if(!$ev->isCancelled() && $tx->apply()){
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ChorusFlowerGrowSound());
}
}else{
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ChorusFlowerDieSound());
$this->position->getWorld()->setBlock($this->position, $this->setAge(self::MAX_AGE));
}
}
}

View File

@ -1,102 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
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\Position;
use function mt_rand;
final class ChorusPlant extends Flowable{
protected function recalculateCollisionBoxes() : array{
$bb = AxisAlignedBB::one();
foreach($this->getAllSides() as $facing => $block){
$id = $block->getTypeId();
if($id !== BlockTypeIds::END_STONE && $id !== BlockTypeIds::CHORUS_FLOWER && !$block->isSameType($this)){
$bb->trim($facing, 2 / 16);
}
}
return [$bb];
}
private function canBeSupportedBy(Block $block) : bool{
return $block->isSameType($this) || $block->getTypeId() === BlockTypeIds::END_STONE;
}
private function canStay(Position $position) : bool{
$world = $position->getWorld();
$down = $world->getBlock($position->down());
$verticalAir = $down->getTypeId() === BlockTypeIds::AIR || $world->getBlock($position->up())->getTypeId() === BlockTypeIds::AIR;
foreach($position->sidesAroundAxis(Axis::Y) as $sidePosition){
$block = $world->getBlock($sidePosition);
if($block->getTypeId() === BlockTypeIds::CHORUS_PLANT){
if(!$verticalAir){
return false;
}
if($this->canBeSupportedBy($block->getSide(Facing::DOWN))){
return true;
}
}
}
if($this->canBeSupportedBy($down)){
return true;
}
return false;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canStay($blockReplace->getPosition())){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if(!$this->canStay($this->position)){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function getDropsForCompatibleTool(Item $item) : array{
if(mt_rand(0, 1) === 1){
return [VanillaItems::CHORUS_FRUIT()];
}
return [];
}
}

View File

@ -23,10 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\WoodType; use pocketmine\block\utils\TreeType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockGrowEvent; use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer; use pocketmine\item\Fertilizer;
use pocketmine\item\Item; use pocketmine\item\Item;
@ -46,9 +46,17 @@ class CocoaBlock extends Transparent{
protected int $age = 0; protected int $age = 0;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->horizontalFacing($this->facing); return BlockDataSerializer::writeLegacyHorizontalFacing(Facing::opposite($this->facing)) | ($this->age << 2);
$w->boundedInt(2, 0, self::MAX_AGE, $this->age); }
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = Facing::opposite(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03));
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta >> 2, 0, self::MAX_AGE);
}
public function getStateBitmask() : int{
return 0b1111;
} }
public function getAge() : int{ return $this->age; } public function getAge() : int{ return $this->age; }
@ -81,7 +89,7 @@ class CocoaBlock extends Transparent{
} }
private function canAttachTo(Block $block) : bool{ private function canAttachTo(Block $block) : bool{
return $block instanceof Wood && $block->getWoodType()->equals(WoodType::JUNGLE()); return $block instanceof Wood && $block->getTreeType()->equals(TreeType::JUNGLE());
} }
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
@ -93,7 +101,7 @@ class CocoaBlock extends Transparent{
return false; return false;
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($item instanceof Fertilizer && $this->grow()){ if($item instanceof Fertilizer && $this->grow()){
$item->pop(); $item->pop();
@ -139,7 +147,7 @@ class CocoaBlock extends Transparent{
]; ];
} }
public function asItem() : Item{ public function getPickedItem(bool $addUserData = false) : Item{
return VanillaItems::COCOA_BEANS(); return VanillaItems::COCOA_BEANS();
} }
} }

View File

@ -23,14 +23,14 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\ColoredTrait; use pocketmine\block\utils\ColorInMetadataTrait;
use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\DyeColor;
class Concrete extends Opaque{ class Concrete extends Opaque{
use ColoredTrait; use ColorInMetadataTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::WHITE(); $this->color = DyeColor::WHITE();
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
} }
} }

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\ColoredTrait; use pocketmine\block\utils\ColorInMetadataTrait;
use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\Fallable; use pocketmine\block\utils\Fallable;
use pocketmine\block\utils\FallableTrait; use pocketmine\block\utils\FallableTrait;
@ -31,19 +31,19 @@ use pocketmine\event\block\BlockFormEvent;
use pocketmine\math\Facing; use pocketmine\math\Facing;
class ConcretePowder extends Opaque implements Fallable{ class ConcretePowder extends Opaque implements Fallable{
use ColoredTrait; use ColorInMetadataTrait;
use FallableTrait { use FallableTrait {
onNearbyBlockChange as protected startFalling; onNearbyBlockChange as protected startFalling;
} }
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::WHITE(); $this->color = DyeColor::WHITE();
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if(($water = $this->getAdjacentWater()) !== null){ if(($block = $this->checkAdjacentWater()) !== null){
$ev = new BlockFormEvent($this, VanillaBlocks::CONCRETE()->setColor($this->color), $water); $ev = new BlockFormEvent($this, $block);
$ev->call(); $ev->call();
if(!$ev->isCancelled()){ if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState()); $this->position->getWorld()->setBlock($this->position, $ev->getNewState());
@ -54,20 +54,16 @@ class ConcretePowder extends Opaque implements Fallable{
} }
public function tickFalling() : ?Block{ public function tickFalling() : ?Block{
if($this->getAdjacentWater() === null){ return $this->checkAdjacentWater();
return null;
}
return VanillaBlocks::CONCRETE()->setColor($this->color);
} }
private function getAdjacentWater() : ?Water{ private function checkAdjacentWater() : ?Block{
foreach(Facing::ALL as $i){ foreach(Facing::ALL as $i){
if($i === Facing::DOWN){ if($i === Facing::DOWN){
continue; continue;
} }
$block = $this->getSide($i); if($this->getSide($i) instanceof Water){
if($block instanceof Water){ return VanillaBlocks::CONCRETE()->setColor($this->color);
return $block;
} }
} }

View File

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

View File

@ -1,36 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
final class CopperOre extends Opaque{
public function getDropsForCompatibleTool(Item $item) : array{
return [VanillaItems::RAW_COPPER()];
}
public function isAffectedBySilkTouch() : bool{ return true; }
}

View File

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

View File

@ -1,36 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CopperOxidation;
use pocketmine\block\utils\CopperTrait;
class CopperStairs extends Stair{
use CopperTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
$this->oxidation = CopperOxidation::NONE();
parent::__construct($idInfo, $name, $typeInfo);
}
}

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\data\bedrock\CoralTypeIdMap;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
@ -31,6 +33,38 @@ use pocketmine\world\BlockTransaction;
final class Coral extends BaseCoral{ final class Coral extends BaseCoral{
public function readStateFromData(int $id, int $stateMeta) : void{
$coralType = CoralTypeIdMap::getInstance()->fromId($stateMeta);
if($coralType === null){
throw new InvalidBlockStateException("No such coral type");
}
$this->coralType = $coralType;
}
public function writeStateToMeta() : int{
return CoralTypeIdMap::getInstance()->toId($this->coralType);
}
protected function writeStateToItemMeta() : int{
return $this->writeStateToMeta();
}
public function getStateBitmask() : int{
return 0b0111;
}
public function readStateFromWorld() : void{
//TODO: this hack ensures correct state of coral plants, because they don't retain their dead flag in metadata
$world = $this->position->getWorld();
$this->dead = true;
foreach($this->position->sides() as $vector3){
if($world->getBlock($vector3) instanceof Water){
$this->dead = false;
break;
}
}
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($tx->fetchBlock($blockReplace->getPosition()->down()))){ if(!$this->canBeSupportedBy($tx->fetchBlock($blockReplace->getPosition()->down()))){
return false; return false;

View File

@ -25,6 +25,8 @@ namespace pocketmine\block;
use pocketmine\block\utils\CoralType; use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\CoralTypeTrait; use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\data\bedrock\CoralTypeIdMap;
use pocketmine\event\block\BlockDeathEvent; use pocketmine\event\block\BlockDeathEvent;
use pocketmine\item\Item; use pocketmine\item\Item;
use function mt_rand; use function mt_rand;
@ -32,9 +34,30 @@ use function mt_rand;
final class CoralBlock extends Opaque{ final class CoralBlock extends Opaque{
use CoralTypeTrait; use CoralTypeTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->coralType = CoralType::TUBE(); $this->coralType = CoralType::TUBE();
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$coralType = CoralTypeIdMap::getInstance()->fromId($stateMeta & 0x7);
if($coralType === null){
throw new InvalidBlockStateException("No such coral type");
}
$this->coralType = $coralType;
$this->dead = ($stateMeta & BlockLegacyMetadata::CORAL_BLOCK_FLAG_DEAD) !== 0;
}
protected function writeStateToMeta() : int{
return ($this->dead ? BlockLegacyMetadata::CORAL_BLOCK_FLAG_DEAD : 0) | CoralTypeIdMap::getInstance()->toId($this->coralType);
}
protected function writeStateToItemMeta() : int{
return $this->writeStateToMeta();
}
public function getStateBitmask() : int{
return 0b1111;
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{

View File

@ -30,7 +30,7 @@ use pocketmine\player\Player;
class CraftingTable extends Opaque{ class CraftingTable extends Opaque{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){ if($player instanceof Player){
$player->setCurrentWindow(new CraftingTableInventory($this->position)); $player->setCurrentWindow(new CraftingTableInventory($this->position));
} }

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\event\block\BlockGrowEvent; use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer; use pocketmine\item\Fertilizer;
use pocketmine\item\Item; use pocketmine\item\Item;
@ -38,8 +38,16 @@ abstract class Crops extends Flowable{
protected int $age = 0; protected int $age = 0;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->boundedInt(3, 0, self::MAX_AGE, $this->age); return $this->age;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->age = BlockDataSerializer::readBoundedInt("age", $stateMeta, 0, self::MAX_AGE);
}
public function getStateBitmask() : int{
return 0b111;
} }
public function getAge() : int{ return $this->age; } public function getAge() : int{ return $this->age; }
@ -54,14 +62,14 @@ abstract class Crops extends Flowable{
} }
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($blockReplace->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::FARMLAND){ if($blockReplace->getSide(Facing::DOWN)->getId() === BlockLegacyIds::FARMLAND){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
} }
return false; return false;
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->age < self::MAX_AGE && $item instanceof Fertilizer){ if($this->age < self::MAX_AGE && $item instanceof Fertilizer){
$block = clone $this; $block = clone $this;
$block->age += mt_rand(2, 5); $block->age += mt_rand(2, 5);
@ -83,7 +91,7 @@ abstract class Crops extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
if($this->getSide(Facing::DOWN)->getTypeId() !== BlockTypeIds::FARMLAND){ if($this->getSide(Facing::DOWN)->getId() !== BlockLegacyIds::FARMLAND){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }

View File

@ -24,8 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait; use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
@ -39,11 +39,30 @@ use const M_PI;
class DaylightSensor extends Transparent{ class DaylightSensor extends Transparent{
use AnalogRedstoneSignalEmitterTrait; use AnalogRedstoneSignalEmitterTrait;
protected BlockIdentifierFlattened $idInfoFlattened;
protected bool $inverted = false; protected bool $inverted = false;
protected function describeState(RuntimeDataDescriber $w) : void{ public function __construct(BlockIdentifierFlattened $idInfo, string $name, BlockBreakInfo $breakInfo){
$w->boundedInt(4, 0, 15, $this->signalStrength); $this->idInfoFlattened = $idInfo;
$w->bool($this->inverted); parent::__construct($idInfo, $name, $breakInfo);
}
public function getId() : int{
return $this->inverted ? $this->idInfoFlattened->getSecondId() : parent::getId();
}
protected function writeStateToMeta() : int{
return $this->signalStrength;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->signalStrength = BlockDataSerializer::readBoundedInt("signalStrength", $stateMeta, 0, 15);
$this->inverted = $id === $this->idInfoFlattened->getSecondId();
}
public function getStateBitmask() : int{
return 0b1111;
} }
public function isInverted() : bool{ public function isInverted() : bool{
@ -73,7 +92,7 @@ class DaylightSensor extends Transparent{
return SupportType::NONE(); return SupportType::NONE();
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->inverted = !$this->inverted; $this->inverted = !$this->inverted;
$this->signalStrength = $this->recalculateSignalStrength(); $this->signalStrength = $this->recalculateSignalStrength();
$this->position->getWorld()->setBlock($this->position, $this); $this->position->getWorld()->setBlock($this->position, $this);

View File

@ -66,13 +66,12 @@ class DeadBush extends Flowable{
} }
private function canBeSupportedBy(Block $block) : bool{ private function canBeSupportedBy(Block $block) : bool{
$blockId = $block->getTypeId(); $blockId = $block->getId();
return $blockId === BlockTypeIds::SAND return $blockId === BlockLegacyIds::SAND
|| $blockId === BlockTypeIds::RED_SAND || $blockId === BlockLegacyIds::PODZOL
|| $blockId === BlockTypeIds::PODZOL || $blockId === BlockLegacyIds::MYCELIUM
|| $blockId === BlockTypeIds::MYCELIUM || $blockId === BlockLegacyIds::DIRT
|| $blockId === BlockTypeIds::DIRT || $blockId === BlockLegacyIds::HARDENED_CLAY
|| $blockId === BlockTypeIds::HARDENED_CLAY || $blockId === BlockLegacyIds::STAINED_HARDENED_CLAY;
|| $blockId === BlockTypeIds::STAINED_CLAY;
} }
} }

View File

@ -23,16 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
class DetectorRail extends StraightOnlyRail{ class DetectorRail extends StraightOnlyRail{
protected bool $activated = false; protected bool $activated = false;
protected function describeState(RuntimeDataDescriber $w) : void{
parent::describeState($w);
$w->bool($this->activated);
}
public function isActivated() : bool{ return $this->activated; } public function isActivated() : bool{ return $this->activated; }
/** @return $this */ /** @return $this */
@ -40,5 +33,19 @@ class DetectorRail extends StraightOnlyRail{
$this->activated = $activated; $this->activated = $activated;
return $this; return $this;
} }
public function readStateFromData(int $id, int $stateMeta) : void{
parent::readStateFromData($id, $stateMeta & ~BlockLegacyMetadata::REDSTONE_RAIL_FLAG_POWERED);
$this->activated = ($stateMeta & BlockLegacyMetadata::REDSTONE_RAIL_FLAG_POWERED) !== 0;
}
protected function writeStateToMeta() : int{
return parent::writeStateToMeta() | ($this->activated ? BlockLegacyMetadata::REDSTONE_RAIL_FLAG_POWERED : 0);
}
public function getStateBitmask() : int{
return 0b1111;
}
//TODO //TODO
} }

View File

@ -23,67 +23,50 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\DirtType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Fertilizer;
use pocketmine\item\Hoe; use pocketmine\item\Hoe;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\Potion;
use pocketmine\item\PotionType;
use pocketmine\item\SplashPotion;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\player\Player; use pocketmine\player\Player;
use pocketmine\world\sound\ItemUseOnBlockSound; use pocketmine\world\sound\ItemUseOnBlockSound;
use pocketmine\world\sound\WaterSplashSound;
class Dirt extends Opaque{ class Dirt extends Opaque{
protected DirtType $dirtType;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ protected bool $coarse = false;
$this->dirtType = DirtType::NORMAL();
parent::__construct($idInfo, $name, $typeInfo); public function readStateFromData(int $id, int $stateMeta) : void{
$this->coarse = ($stateMeta & BlockLegacyMetadata::DIRT_FLAG_COARSE) !== 0;
} }
protected function describeType(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->dirtType($this->dirtType); return $this->coarse ? BlockLegacyMetadata::DIRT_FLAG_COARSE : 0;
} }
public function getDirtType() : DirtType{ return $this->dirtType; } protected function writeStateToItemMeta() : int{
return $this->writeStateToMeta();
}
public function getStateBitmask() : int{
return 0b1;
}
public function isCoarse() : bool{ return $this->coarse; }
/** @return $this */ /** @return $this */
public function setDirtType(DirtType $dirtType) : self{ public function setCoarse(bool $coarse) : self{
$this->dirtType = $dirtType; $this->coarse = $coarse;
return $this; return $this;
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$world = $this->position->getWorld();
if($face === Facing::UP && $item instanceof Hoe){ if($face === Facing::UP && $item instanceof Hoe){
$item->applyDamage(1); $item->applyDamage(1);
$newBlock = $this->dirtType->equals(DirtType::NORMAL()) ? VanillaBlocks::FARMLAND() : VanillaBlocks::DIRT(); $newBlock = $this->coarse ? VanillaBlocks::DIRT() : VanillaBlocks::FARMLAND();
$center = $this->position->add(0.5, 0.5, 0.5); $world = $this->position->getWorld();
$world->addSound($center, new ItemUseOnBlockSound($newBlock)); $world->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($newBlock));
$world->setBlock($this->position, $newBlock); $world->setBlock($this->position, $newBlock);
if($this->dirtType->equals(DirtType::ROOTED())){
$world->dropItem($center, VanillaBlocks::HANGING_ROOTS()->asItem());
}
return true;
}elseif($this->dirtType->equals(DirtType::ROOTED()) && $item instanceof Fertilizer){
$down = $this->getSide(Facing::DOWN);
if($down->getTypeId() !== BlockTypeIds::AIR){
return true;
}
$item->pop();
$world->setBlock($down->position, VanillaBlocks::HANGING_ROOTS());
//TODO: bonemeal particles, growth sounds
}elseif(($item instanceof Potion || $item instanceof SplashPotion) && $item->getType()->equals(PotionType::WATER())){
$item->pop();
$world->setBlock($this->position, VanillaBlocks::MUD());
$world->addSound($this->position, new WaterSplashSound(0.5));
return true; return true;
} }

View File

@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
@ -36,19 +37,38 @@ use pocketmine\world\sound\DoorSound;
class Door extends Transparent{ class Door extends Transparent{
use HorizontalFacingTrait; use HorizontalFacingTrait;
use PoweredByRedstoneTrait;
protected bool $top = false; protected bool $top = false;
protected bool $hingeRight = false; protected bool $hingeRight = false;
protected bool $open = false; protected bool $open = false;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->horizontalFacing($this->facing); if($this->top){
$w->bool($this->top); return BlockLegacyMetadata::DOOR_FLAG_TOP |
$w->bool($this->hingeRight); ($this->hingeRight ? BlockLegacyMetadata::DOOR_TOP_FLAG_RIGHT : 0) |
$w->bool($this->open); ($this->powered ? BlockLegacyMetadata::DOOR_TOP_FLAG_POWERED : 0);
}
return BlockDataSerializer::writeLegacyHorizontalFacing(Facing::rotateY($this->facing, true)) | ($this->open ? BlockLegacyMetadata::DOOR_BOTTOM_FLAG_OPEN : 0);
} }
public function readStateFromWorld() : Block{ public function readStateFromData(int $id, int $stateMeta) : void{
$this->top = ($stateMeta & BlockLegacyMetadata::DOOR_FLAG_TOP) !== 0;
if($this->top){
$this->hingeRight = ($stateMeta & BlockLegacyMetadata::DOOR_TOP_FLAG_RIGHT) !== 0;
$this->powered = ($stateMeta & BlockLegacyMetadata::DOOR_TOP_FLAG_POWERED) !== 0;
}else{
$this->facing = Facing::rotateY(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03), false);
$this->open = ($stateMeta & BlockLegacyMetadata::DOOR_BOTTOM_FLAG_OPEN) !== 0;
}
}
public function getStateBitmask() : int{
return 0b1111;
}
public function readStateFromWorld() : void{
parent::readStateFromWorld(); parent::readStateFromWorld();
//copy door properties from other half //copy door properties from other half
@ -59,10 +79,9 @@ class Door extends Transparent{
$this->open = $other->open; $this->open = $other->open;
}else{ }else{
$this->hingeRight = $other->hingeRight; $this->hingeRight = $other->hingeRight;
$this->powered = $other->powered;
} }
} }
return $this;
} }
public function isTop() : bool{ return $this->top; } public function isTop() : bool{ return $this->top; }
@ -140,7 +159,7 @@ class Door extends Transparent{
return false; return false;
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->open = !$this->open; $this->open = !$this->open;
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP); $other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Facing; use pocketmine\math\Facing;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
@ -31,10 +30,19 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction; use pocketmine\world\BlockTransaction;
class DoublePlant extends Flowable{ class DoublePlant extends Flowable{
protected bool $top = false; protected bool $top = false;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->bool($this->top); return ($this->top ? BlockLegacyMetadata::DOUBLE_PLANT_FLAG_TOP : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->top = ($stateMeta & BlockLegacyMetadata::DOUBLE_PLANT_FLAG_TOP) !== 0;
}
public function getStateBitmask() : int{
return 0b1000;
} }
public function isTop() : bool{ return $this->top; } public function isTop() : bool{ return $this->top; }
@ -46,8 +54,8 @@ class DoublePlant extends Flowable{
} }
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$down = $blockReplace->getSide(Facing::DOWN); $id = $blockReplace->getSide(Facing::DOWN)->getId();
if($down->hasTypeTag(BlockTypeTags::DIRT) && $blockReplace->getSide(Facing::UP)->canBeReplaced()){ if(($id === BlockLegacyIds::GRASS || $id === BlockLegacyIds::DIRT) && $blockReplace->getSide(Facing::UP)->canBeReplaced()){
$top = clone $this; $top = clone $this;
$top->top = true; $top->top = true;
$tx->addBlock($blockReplace->position, $this)->addBlock($blockReplace->position->getSide(Facing::UP), $top); $tx->addBlock($blockReplace->position, $this)->addBlock($blockReplace->position->getSide(Facing::UP), $top);
@ -71,8 +79,7 @@ class DoublePlant extends Flowable{
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{
$down = $this->getSide(Facing::DOWN); if(!$this->isValidHalfPlant() || (!$this->top && $this->getSide(Facing::DOWN)->isTransparent())){
if(!$this->isValidHalfPlant() || (!$this->top && !$down->hasTypeTag(BlockTypeTags::DIRT) && !$down->hasTypeTag(BlockTypeTags::MUD))){
$this->position->getWorld()->useBreakOn($this->position); $this->position->getWorld()->useBreakOn($this->position);
} }
} }

View File

@ -44,7 +44,11 @@ class DragonEgg extends Transparent implements Fallable{
return 1; return 1;
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function tickFalling() : ?Block{
return null;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->teleport(); $this->teleport();
return true; return true;
} }

View File

@ -1,42 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
class DyedCandle extends Candle{
use ColoredTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
$this->color = DyeColor::WHITE();
parent::__construct($idInfo, $name, $typeInfo);
}
protected function getCandleIfCompatibleType(Block $block) : ?Candle{
$result = parent::getCandleIfCompatibleType($block);
//different coloured candles can't be combined in the same block
return $result instanceof DyedCandle && $result->color->equals($this->color) ? $result : null;
}
}

View File

@ -23,14 +23,14 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\ColoredTrait; use pocketmine\block\utils\ColorInMetadataTrait;
use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\DyeColor;
final class DyedShulkerBox extends ShulkerBox{ final class DyedShulkerBox extends ShulkerBox{
use ColoredTrait; use ColorInMetadataTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){ public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->color = DyeColor::WHITE(); $this->color = DyeColor::WHITE();
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
} }
} }

View File

@ -27,12 +27,12 @@ class Element extends Opaque{
public function __construct( public function __construct(
BlockIdentifier $idInfo, BlockIdentifier $idInfo,
string $name, string $name,
BlockTypeInfo $typeInfo, BlockBreakInfo $breakInfo,
private string $symbol, private string $symbol,
private int $atomicWeight, private int $atomicWeight,
private int $group private int $group
){ ){
parent::__construct($idInfo, $name, $typeInfo); parent::__construct($idInfo, $name, $breakInfo);
} }
public function getAtomicWeight() : int{ public function getAtomicWeight() : int{

View File

@ -44,7 +44,7 @@ class EnchantingTable extends Transparent{
return SupportType::NONE(); return SupportType::NONE();
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){ if($player instanceof Player){
//TODO lock //TODO lock

View File

@ -23,9 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
@ -35,9 +35,17 @@ class EndPortalFrame extends Opaque{
protected bool $eye = false; protected bool $eye = false;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->horizontalFacing($this->facing); return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) | ($this->eye ? BlockLegacyMetadata::END_PORTAL_FRAME_FLAG_EYE : 0);
$w->bool($this->eye); }
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
$this->eye = ($stateMeta & BlockLegacyMetadata::END_PORTAL_FRAME_FLAG_EYE) !== 0;
}
public function getStateBitmask() : int{
return 0b111;
} }
public function hasEye() : bool{ return $this->eye; } public function hasEye() : bool{ return $this->eye; }

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\AnyFacingTrait; use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\Axis; use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
@ -35,6 +36,27 @@ use pocketmine\world\BlockTransaction;
class EndRod extends Flowable{ class EndRod extends Flowable{
use AnyFacingTrait; use AnyFacingTrait;
protected function writeStateToMeta() : int{
$result = BlockDataSerializer::writeFacing($this->facing);
if(Facing::axis($this->facing) !== Axis::Y){
$result ^= 1; //TODO: in PC this is always the same as facing, just PE is stupid
}
return $result;
}
public function readStateFromData(int $id, int $stateMeta) : void{
if($stateMeta !== 0 && $stateMeta !== 1){
$stateMeta ^= 1;
}
$this->facing = BlockDataSerializer::readFacing($stateMeta);
}
public function getStateBitmask() : int{
return 0b111;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->facing = $face; $this->facing = $face;
if($blockClicked instanceof EndRod && $blockClicked->facing === $this->facing){ if($blockClicked instanceof EndRod && $blockClicked->facing === $this->facing){

View File

@ -26,7 +26,7 @@ namespace pocketmine\block;
use pocketmine\block\inventory\EnderChestInventory; use pocketmine\block\inventory\EnderChestInventory;
use pocketmine\block\tile\EnderChest as TileEnderChest; use pocketmine\block\tile\EnderChest as TileEnderChest;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
@ -36,7 +36,7 @@ use pocketmine\player\Player;
class EnderChest extends Transparent{ class EnderChest extends Transparent{
use FacesOppositePlacingPlayerTrait; use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait; use NormalHorizontalFacingInMetadataTrait;
public function getLightLevel() : int{ public function getLightLevel() : int{
return 7; return 7;
@ -54,7 +54,7 @@ class EnderChest extends Transparent{
return SupportType::NONE(); return SupportType::NONE();
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player instanceof Player){ if($player instanceof Player){
$enderChest = $this->position->getWorld()->getTile($this->position); $enderChest = $this->position->getWorld()->getTile($this->position);
if($enderChest instanceof TileEnderChest && $this->getSide(Facing::UP)->isTransparent()){ if($enderChest instanceof TileEnderChest && $this->getSide(Facing::UP)->isTransparent()){

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\Living; use pocketmine\entity\Living;
use pocketmine\event\entity\EntityTrampleFarmlandEvent; use pocketmine\event\entity\EntityTrampleFarmlandEvent;
@ -37,8 +37,16 @@ class Farmland extends Transparent{
protected int $wetness = 0; //"moisture" blockstate property in PC protected int $wetness = 0; //"moisture" blockstate property in PC
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->boundedInt(3, 0, self::MAX_WETNESS, $this->wetness); return $this->wetness;
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->wetness = BlockDataSerializer::readBoundedInt("wetness", $stateMeta, 0, self::MAX_WETNESS);
}
public function getStateBitmask() : int{
return 0b111;
} }
public function getWetness() : int{ return $this->wetness; } public function getWetness() : int{ return $this->wetness; }
@ -56,7 +64,7 @@ class Farmland extends Transparent{
* @return AxisAlignedBB[] * @return AxisAlignedBB[]
*/ */
protected function recalculateCollisionBoxes() : array{ protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()]; //TODO: this should be trimmed at the top by 1/16, but MCPE currently treats them as a full block (https://bugs.mojang.com/browse/MCPE-12109) return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
} }
public function onNearbyBlockChange() : void{ public function onNearbyBlockChange() : void{

View File

@ -37,7 +37,7 @@ class Fence extends Transparent{
return 0.25; return 0.25;
} }
public function readStateFromWorld() : Block{ public function readStateFromWorld() : void{
parent::readStateFromWorld(); parent::readStateFromWorld();
foreach(Facing::HORIZONTAL as $facing){ foreach(Facing::HORIZONTAL as $facing){
@ -48,8 +48,6 @@ class Fence extends Transparent{
unset($this->connections[$facing]); unset($this->connections[$facing]);
} }
} }
return $this;
} }
/** /**

View File

@ -23,10 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block; namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType; use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\WoodTypeTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB; use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing; use pocketmine\math\Facing;
@ -36,16 +35,25 @@ use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\DoorSound; use pocketmine\world\sound\DoorSound;
class FenceGate extends Transparent{ class FenceGate extends Transparent{
use WoodTypeTrait;
use HorizontalFacingTrait; use HorizontalFacingTrait;
protected bool $open = false; protected bool $open = false;
protected bool $inWall = false; protected bool $inWall = false;
protected function describeState(RuntimeDataDescriber $w) : void{ protected function writeStateToMeta() : int{
$w->horizontalFacing($this->facing); return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) |
$w->bool($this->open); ($this->open ? BlockLegacyMetadata::FENCE_GATE_FLAG_OPEN : 0) |
$w->bool($this->inWall); ($this->inWall ? BlockLegacyMetadata::FENCE_GATE_FLAG_IN_WALL : 0);
}
public function readStateFromData(int $id, int $stateMeta) : void{
$this->facing = BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03);
$this->open = ($stateMeta & BlockLegacyMetadata::FENCE_GATE_FLAG_OPEN) !== 0;
$this->inWall = ($stateMeta & BlockLegacyMetadata::FENCE_GATE_FLAG_IN_WALL) !== 0;
}
public function getStateBitmask() : int{
return 0b1111;
} }
public function isOpen() : bool{ return $this->open; } public function isOpen() : bool{ return $this->open; }
@ -100,7 +108,7 @@ class FenceGate extends Transparent{
} }
} }
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->open = !$this->open; $this->open = !$this->open;
if($this->open && $player !== null){ if($this->open && $player !== null){
$playerFacing = $player->getHorizontalFacing(); $playerFacing = $player->getHorizontalFacing();
@ -116,14 +124,14 @@ class FenceGate extends Transparent{
} }
public function getFuelTime() : int{ public function getFuelTime() : int{
return $this->woodType->isFlammable() ? 300 : 0; return 300;
} }
public function getFlameEncouragement() : int{ public function getFlameEncouragement() : int{
return $this->woodType->isFlammable() ? 5 : 0; return 5;
} }
public function getFlammability() : int{ public function getFlammability() : int{
return $this->woodType->isFlammable() ? 20 : 0; return 20;
} }
} }

View File

@ -1,127 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\world\sound\Sound;
use function min;
abstract class FillableCauldron extends Transparent{
public const MIN_FILL_LEVEL = 1;
public const MAX_FILL_LEVEL = 6;
private int $fillLevel = self::MIN_FILL_LEVEL;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->boundedInt(3, self::MIN_FILL_LEVEL, self::MAX_FILL_LEVEL, $this->fillLevel);
}
public function getFillLevel() : int{ return $this->fillLevel; }
/** @return $this */
public function setFillLevel(int $fillLevel) : self{
if($fillLevel < self::MIN_FILL_LEVEL || $fillLevel > self::MAX_FILL_LEVEL){
throw new \InvalidArgumentException("Fill level must be in range " . self::MIN_FILL_LEVEL . " ... " . self::MAX_FILL_LEVEL);
}
$this->fillLevel = $fillLevel;
return $this;
}
protected function recalculateCollisionBoxes() : array{
$result = [
AxisAlignedBB::one()->trim(Facing::UP, 11 / 16) //bottom of the cauldron
];
foreach(Facing::HORIZONTAL as $f){ //add the frame parts around the bowl
$result[] = AxisAlignedBB::one()->trim($f, 14 / 16);
}
return $result;
}
public function getSupportType(int $facing) : SupportType{
return $facing === Facing::UP ? SupportType::EDGE() : SupportType::NONE();
}
protected function withFillLevel(int $fillLevel) : Block{
return $fillLevel === 0 ? VanillaBlocks::CAULDRON() : $this->setFillLevel(min(self::MAX_FILL_LEVEL, $fillLevel));
}
/**
* @param Item[] &$returnedItems
*/
protected function addFillLevels(int $amount, Item $usedItem, Item $returnedItem, array &$returnedItems) : void{
if($this->fillLevel >= self::MAX_FILL_LEVEL){
return;
}
$this->position->getWorld()->setBlock($this->position, $this->withFillLevel($this->fillLevel + $amount));
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), $this->getFillSound());
$usedItem->pop();
$returnedItems[] = $returnedItem;
}
/**
* @param Item[] &$returnedItems
*/
protected function removeFillLevels(int $amount, Item $usedItem, Item $returnedItem, array &$returnedItems) : void{
if($this->fillLevel < $amount){
return;
}
$this->position->getWorld()->setBlock($this->position, $this->withFillLevel($this->fillLevel - $amount));
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), $this->getEmptySound());
$usedItem->pop();
$returnedItems[] = $returnedItem;
}
/**
* Returns the sound played when adding levels to the cauldron liquid.
*/
abstract public function getFillSound() : Sound;
/**
* Returns the sound played when removing levels from the cauldron liquid.
*/
abstract public function getEmptySound() : Sound;
/**
* @param Item[] &$returnedItems
*/
protected function mix(Item $usedItem, Item $returnedItem, array &$returnedItems) : void{
$this->position->getWorld()->setBlock($this->position, VanillaBlocks::CAULDRON());
//TODO: sounds and particles
$usedItem->pop();
$returnedItems[] = $returnedItem;
}
public function asItem() : Item{
return VanillaBlocks::CAULDRON()->asItem();
}
}

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