Compare commits

..

373 Commits

Author SHA1 Message Date
9d4c37fc3a Release 4.23.6 2023-08-21 18:26:47 +01:00
7f78ec0a32 Include PHP binary URLs in GitHub releases and build info 2023-08-21 16:05:59 +01:00
9f09acc079 Workaround for slot IDs not changing client side when old item == new item
this is a really dumb bug and seems similar to the armor bug I fixed a while ago.

fixes #5987

it's unlikely that #5727 will be solved by this, but one can hope...
2023-08-18 12:27:27 +01:00
aa3f4f2545 4.23.6 is next 2023-08-09 13:56:19 +01:00
f7279b6672 Release 4.23.5 2023-08-09 13:56:19 +01:00
2711ab4f00 Update composer dependencies 2023-08-09 13:49:19 +01:00
b4c5f5d58d PluginBase: fixed resource leak
all this time we've been harping at plugin devs to fix their own leaks, and here's one right under our noses that no one spotted for 10 years ...

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

This bug was introduced in 2014 by commit 6328834681.
2023-08-09 13:28:05 +01:00
d88c3d8ced Fixed coral block killing itself when calling getDropsForCompatibleTool()
this might be called by plugins without actually breaking the block, in which case the block will glitch.
2023-08-02 13:43:36 +01:00
bb0e648276 Fixed BlockDeathEvent usages showing an oldState which is already dead 2023-08-02 13:36:54 +01:00
e9e5923639 4.23.5 is next 2023-08-01 11:12:52 +01:00
49a9da147b Release 4.23.4 2023-08-01 11:12:41 +01:00
eb53b795d5 ItemEntity: fixed O(n^2) performance issue when many of the same unstackable item are in the same place
this produced a 40% performance improvement in a simulation with 800 item entities.

If the items were all different, then this would still be a problem. However, many of the same unstackable items occupying the same space is a problem for SkyBlock farms, so this should improve performance for SkyBlock quite a bit.
2023-07-31 11:29:12 +01:00
1c611a03e6 4.23.4 is next 2023-07-24 16:59:48 +01:00
948875b025 Release 4.23.3 2023-07-24 16:59:45 +01:00
2a4909d328 Fixed missing handling for some ContainerUIIds
SMITHING_TABLE_TEMPLATE is new in 1.20
HORSE_EQUIP was always present, but somehow got overlooked when building up that big ugly switch table
2023-07-24 16:44:01 +01:00
70dd8732e2 Update build/php to pmmp/PHP-Binaries@46604f2f6a 2023-07-24 11:59:11 +01:00
cdf72563f4 Update composer dependencies 2023-07-24 11:58:50 +01:00
d65d8c3356 Fix typo in documentation of ChunkSelector:selectChunks() (#5924) 2023-07-21 10:34:34 +01:00
9b43ddecbd Drop usages of Process:kill() with subprocesses parameter
we don't need this any more with console reader improvements, and this was not working correctly anyway.

closes #5234
2023-07-20 17:10:39 +01:00
4bdd6410db Fire: fixed support requirements
closes #5599
2023-07-20 17:00:32 +01:00
6ea7fd7d6b ShulkerBox: do not offer support for other blocks 2023-07-20 16:36:25 +01:00
5e7f18cbcf StandardEntityEventBroadcaster: suppress client-side emote messages
if users want these, they can broadcast them themselves using Server::broadcastMessage(), which will also record the message in the server log like chat

closes #5669
2023-07-20 16:20:34 +01:00
cff4a8d2bc 4.23.3 is next 2023-07-18 22:14:24 +01:00
20b7e8d702 Release 4.23.2 2023-07-18 22:14:23 +01:00
c6110be051 Update BedrockProtocol dependency 2023-07-18 22:12:33 +01:00
86bd6777a3 4.23.2 is next 2023-07-14 13:06:26 +01:00
935df62006 Release 4.23.1 2023-07-14 13:06:26 +01:00
2709dd359c ProcessLoginTask: fixed backport errors 2023-07-14 12:37:50 +01:00
4e646d19a4 Harden login EC key validation 2023-07-14 11:55:47 +01:00
2a11762e61 Update JsonMapper dependency 2023-07-14 11:54:05 +01:00
7e0b5cf73d 4.23.1 is next 2023-07-12 13:44:16 +01:00
e903da8998 Release 4.23.0 2023-07-12 13:44:16 +01:00
f2193d1ba7 1.20.10 2023-07-12 13:23:47 +01:00
f7977c9668 Update build/php submodule to pmmp/PHP-Binaries@16378ffcc3 2023-07-12 12:10:09 +01:00
cfd9950b02 4.22.4 is next 2023-07-11 16:01:42 +01:00
8ebcdb452d Release 4.22.3 2023-07-11 16:01:38 +01:00
aacc00a911 update-updater-api: do not allow multiple jobs to run simultaneously
this would result in git conflicts if multiple releases are made at the same time

closes #5814
2023-07-11 15:10:35 +01:00
0c250a2ef0 InGamePacketHandler: fixed inconsistent handling of invalid data in BlockActorDataPacket 2023-07-11 12:53:29 +01:00
70dd9c7371 AsyncTask: fixed reentrancy bug tested by f8e6f036af 2023-07-01 13:27:32 +01:00
f8e6f036af AsyncPoolTest: added failing test case for AsyncTask::__destruct() reentrancy bug 2023-07-01 13:24:50 +01:00
bbabccfc89 4.22.3 is next 2023-07-01 12:04:59 +01:00
1698eac6dc Release 4.22.2 2023-07-01 12:04:59 +01:00
321972b87b Composer: do not allow automatic minor dependency updates
manual intervention should always be used here, since we need to present a consistent API to plugins.
2023-07-01 11:57:13 +01:00
c86c9b3ead Update Composer dependencies 2023-07-01 11:43:36 +01:00
249ef9c534 ProcessLoginTask: remove old key expiry
since we don't have a hard date for this, and I've already made one wrong educated guess, I'd rather not have another massive outage.
A security update will have to be made to remove the old key as soon as the new one is rolled. This is not ideal, but it's the least disruptive option.
2023-07-01 11:41:04 +01:00
f4dab17a1b Added deprecation notices 2023-07-01 10:29:14 +01:00
e85605af7f changelog: fixed typo
[ci skip]
2023-06-09 01:44:45 +01:00
dfd70615ad 4.22.2 is next 2023-06-09 01:33:35 +01:00
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
87d8c1ea11 4.19.1 is next 2023-04-11 22:48:05 +01:00
89deb0fe18 Release 4.19.0 2023-04-11 22:48:02 +01:00
ad88490e84 Mark TickingChunkEntry as internal 2023-04-11 22:34:11 +01:00
3490e2b06a Mark RegisteredListenerCache as internal 2023-04-11 22:33:44 +01:00
946c2fbacc Ticking chunks rewrite (#5689)
This API is much more flexible than the old, allowing any arbitrary set of chunks to be ticked.

These changes also improve the performance of random chunk ticking by almost entirely eliminating the cost of chunk selection. Ticking chunks are now reevaluated when a player moves, instead of every tick.

The system also does not attempt to check the same chunks twice, leading to further improvements.

Overall, the overhead of random chunk selection is reduced anywhere from 80-96%. In practice, this can offer a 5-10% performance gain for servers with sparsely distributed players.
2023-04-11 20:01:19 +01:00
1c0eed56f1 Added runtime test for event handler inheritance, to ensure I don't accidentally break it with optimisations 2023-04-11 13:52:37 +01:00
9e9b4db00f Merge branch 'stable' into minor-next 2023-04-10 14:32:33 +01:00
e667b5c7db 4.18.5 is next 2023-04-10 14:17:56 +01:00
f61f72180f Release 4.18.4 2023-04-10 14:17:53 +01:00
3f82150837 Update Composer dependencies 2023-04-10 14:06:50 +01:00
017fcde6aa always the CS... 2023-04-10 13:56:53 +01:00
24374297e7 NetworkSession: extract rate limiting functionality into its own unit, and apply a separate rate limit to game packets 2023-04-10 13:53:22 +01:00
76ebedff6a HandlerList: remove unnecessary variable 2023-04-07 22:58:30 +01:00
3ea8d27a3b HandlerList: improve listener list development to make way for #5678 2023-04-07 22:55:27 +01:00
d6c923b525 ExperienceOrb: add get/setDespawnDelay
closes #5645

the code for this is borrowed from ItemEntity. I didn't feel like a base class was appropriate, and we can't (yet) declare constants in traits.
2023-04-07 22:33:30 +01:00
7b55c984bf InGamePacketHandler: reduce debug noise on outdated movements 2023-04-07 21:40:46 +01:00
f5b4d64668 Player: increase max distance between movements to allow high levels of speed to work correctly
speed 255 may allow the player to move as much as 14.8 blocks per tick when sprinting.
2023-04-07 21:35:58 +01:00
1683aa681d TimingsHandler: added format version 2023-04-06 15:08:49 +01:00
bf84caa02c Timings: record peak tick time and active ticks
this information is useful for determining the sizes of lag spikes, and giving more accurate average times.
2023-04-06 15:05:40 +01:00
734adec90d TimingsCommand: log the response body on failed paste 2023-04-06 14:46:02 +01:00
4724195791 Improved performance of event calls
This change significantly reduces the amount of work done by event handlers. Instead of traversing all of the priorities and event parent chain multiple times, we reduce event handlers down to a simple list, which doesn't require any logic to iterate over.
Previously, calling an event with lots of parents costed more than an event which directly descended from Event.
In addition, we had to do a lot of usually useless work to check all priorities, when in practice, only NORMAL will be used in almost all cases.

This change makes it more cost effective to implement the feature suggested by #5678; however, it will still require additional changes.
2023-04-05 23:02:44 +01:00
f32a853bd4 HandlerList: remove useless isset 2023-04-05 21:37:08 +01:00
61b0ad3e7f PreSpawnPacketHandler: added dedicated timer for the humongous amount of crap that has to be sent pre-spawn 2023-04-05 20:58:49 +01:00
b2f755720d Use a proper Breakdown timing group instead of the unwieldy INCLUDED_BY_OTHER_TIMINGS_PREFIX 2023-04-05 20:47:47 +01:00
8ef2780dcd Use group format for tasks 2023-04-05 20:35:54 +01:00
b19c7212ab Merge branch 'stable' into minor-next 2023-04-05 20:12:31 +01:00
14c1a9550d Update composer dependencies 2023-04-05 20:12:21 +01:00
9037d5f16b 4.18.4 is next 2023-04-05 20:07:38 +01:00
8b64ea9e65 Release 4.18.3 2023-04-05 20:07:23 +01:00
2936726bf8 Fixed packets sent by EntityEventBroadcaster not firing DataPacketSendEvent
closes #5670

I'm not super happy with this fix, since it can still be broken if StandardPacketBroadcaster is replaced by something else. However, fixing that problem is probably going to require internal BC breaks, which are not suitable for a patch release.
2023-04-03 22:46:14 +01:00
9cd07f6721 NetworkBroadcastUtils: remove dead code
we don't allow changing the target list anymore, since it increases internal complexity, so this code is redundant.
2023-04-03 22:37:22 +01:00
4bb8daa1a5 ItemStackRequestExecutor: allow any action to take from the created output slot
fixes #5679
2023-04-03 22:24:40 +01:00
6e8eda4ac1 Fixed creative inventory items getting modified by ItemStackRequests 2023-04-03 22:22:21 +01:00
73522d06ef ... 2023-03-31 21:51:07 +01:00
a6a360d179 Revert "Be more concise in event handler timing names"
This reverts commit 9db7e5f0ca.
2023-03-31 21:51:00 +01:00
199ef7401f Revert "Timings: do not shorten event handler timing names"
This reverts commit a2ff9649d5.
2023-03-31 21:49:25 +01:00
f63d349be4 Merge remote-tracking branch 'origin/stable' into minor-next 2023-03-31 21:28:14 +01:00
02e11b5a60 Timings tree (#5587)
Split timings into tree reports
this will allow the timings site to display timings as a tree, instead of as a list as is done now, which will enable more precise identification of performance issues.

An example of this can be seen here: https://timings.pmmp.io/?id=302629

The format changes are fully backwards compatible, as the timings site
aggregates timings from timers with the same names, and doesn't limit
how much extra data can appear at the end of a line.
2023-03-31 21:26:58 +01:00
4a770e5801 CS 2023-03-31 20:32:42 +01:00
a2ff9649d5 Timings: do not shorten event handler timing names
this doesn't work very well in tree view timings
2023-03-31 19:44:06 +01:00
a862cf5144 Workaround ItemStackRequest offhand incorrect slot bug
closes #5667

this appears to be a client bug specific to ItemStackRequest.
2023-03-31 17:27:11 +01:00
5ac0d7ae11 TimingsRecord: fixed incorrect violations calculation
closes #5665
2023-03-31 17:08:59 +01:00
0c47455b24 Timings: ensure that Average Players count is shown properly when custom player classes are used 2023-03-30 18:12:06 +01:00
821dd8885b Merge branch 'stable' into minor-next 2023-03-29 23:56:08 +01:00
a78ae73119 4.18.3 is next 2023-03-29 23:52:31 +01:00
17a1266056 Release 4.18.2 2023-03-29 23:52:31 +01:00
217d7ab4cf Merge tag '4.17.2' into stable 2023-03-29 23:50:58 +01:00
9e8c0a6bea Release 4.17.2 2023-03-29 23:47:49 +01:00
dc1b5a9285 it might help if we actually included the fix 2023-03-29 23:46:53 +01:00
c3a16d9b1f ItemStackResponseBuilder: fixed durability appearing to reset when moving durables around the inventory
closes #5656
2023-03-29 23:31:46 +01:00
bed218d1dd Fixed the first letter of event timing names getting trimmed off when src-namespace-prefix is not used 2023-03-29 23:11:30 +01:00
5e1f837a73 ... 2023-03-28 22:46:18 +01:00
b49a9ae81d Added timings for calling events
this gives a somewhat better overview of events, particularly if many plugins are subscribed to the same costly event (e.g. PlayerMoveEvent).

In addition, it allows us to see the frequency that events are occurring.
2023-03-28 17:26:20 +01:00
4c60e82110 Merge remote-tracking branch 'origin/stable' into minor-next 2023-03-27 19:08:18 +01:00
beb0713a40 4.18.2 is next 2023-03-27 18:03:17 +01:00
cd603e8266 Release 4.18.1 2023-03-27 18:03:16 +01:00
af385668c2 InventoryManager: give more detailed information on failure to get info for held item 2023-03-27 17:55:39 +01:00
3ee62d8440 InGamePacketHandler: increase max ItemStackRequest actions to 60
due to implementation quirks + some unforeseen ways these actions can behave, there can be as many as 53 actions in a single crafting request. This is an edge case, but it has to be catered for.
2023-03-27 15:44:42 +01:00
811639f2cd InGamePacketHandler: relax errors on normal transactions to fix book editing
for some reason book edits generate a transaction in addition to BookEditPacket. PM has never used the transaction, and it doesn't pass anyway because CreateItemAction can't be used in survival mode.
However, since the strict validation introduced since ItemStackRequest, this dud transaction now causes the player to get kicked without these changes.
2023-03-27 13:26:26 +01:00
58974765a6 InGamePacketHandler: fixed crash when attempting to drop more of an item than is available 2023-03-27 13:26:26 +01:00
eca9fe50b6 Bump build/php from a464454 to 9d8807b (#5654)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `a464454` to `9d8807b`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](a464454d1e...9d8807be82)

---
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-03-27 13:03:30 +01:00
1959d6dc9b Fix CS 2023-03-27 12:59:26 +01:00
9db7e5f0ca Be more concise in event handler timing names 2023-03-27 01:19:17 +01:00
c1cef19f84 stringifyKeys 2023-03-27 01:17:15 +01:00
cebdb95265 Optimise plugin timings report entries
this format is already supported by the timings host, so no changes are required to support this.
2023-03-27 01:15:42 +01:00
006cdaf6ea RakLibInterface: log the name of the session which triggered an unhandled exception
this makes it easier to identify what sequence of events led up to the crash.
2023-03-26 18:56:24 +01:00
acc8ae87fb 4.18.1 is next 2023-03-25 20:51:38 +00:00
0e8b28716a Release 4.18.0 2023-03-25 20:51:34 +00:00
7c77233d12 Merge branch 'stable' into minor-next 2023-03-25 20:26:54 +00:00
6f02b83a26 Update composer dependencies 2023-03-25 20:26:50 +00:00
fbfdf749f2 Merge branch 'stable' into minor-next 2023-03-25 20:25:48 +00:00
289c0b08f4 Explicitly state that pocketmine\network\mcpe is an internal package 2023-03-24 14:06:25 +00:00
dd37b531ad CONTRIBUTING.md: document network API policy 2023-03-24 14:02:23 +00:00
58d5126ada InventoryManager: fixed crashes when setting contents or slots of inventories during InventoryCloseEvent (and other similar logic) 2023-03-24 13:31:30 +00:00
f978c1e9a0 Merge remote-tracking branch 'origin/stable' into minor-next 2023-03-22 22:45:41 +00:00
0b8193aeb3 4.17.2 is next 2023-03-22 22:35:25 +00:00
00286e761c Release 4.17.1 2023-03-22 22:35:24 +00:00
db59f71130 attempt to fix ghcr.io docker image push 2023-03-22 22:29:00 +00:00
b11457d605 Fixed uncaught exception when retrieving a packet from the pool 2023-03-22 22:24:25 +00:00
ea386c42d3 InGamePacketHandler: fixed dropping items from unselected hotbar slots 2023-03-21 14:45:18 +00:00
043e81e737 4.18.0-ALPHA3 is next 2023-03-21 00:26:19 +00:00
66a4c4c88b Release 4.18.0-ALPHA2 2023-03-21 00:26:19 +00:00
1a9322c00a ItemStackRequestExecutor: added some missing @throws 2023-03-21 00:23:31 +00:00
c8d9477da1 ItemStackRequestExecutor: make non-final, and make some stuff protected
this allows for plugin extension, for example to implement anvils.
2023-03-21 00:22:21 +00:00
08e8ef275f remove comment 2023-03-21 00:17:24 +00:00
e57fbff28c ItemStackRequestExecutor: added a sanity check for recipe repetitions 2023-03-21 00:16:03 +00:00
f90315c4a2 ItemStackRequestExecutor: harden against invalid item counts
these cases should all be impossible, but that's assuming that the core code doesn't start using them for a different purpose in the future.
2023-03-21 00:13:21 +00:00
955f7944bb ItemStackRequestExecutor: fixed another possible crash condition 2023-03-21 00:06:33 +00:00
ccd288d7fa Avoid repeated calls to getItemInHand() in drop item handler 2023-03-21 00:04:29 +00:00
097632902a InGamePacketHandler: fixed crash condition in drop item handler 2023-03-21 00:02:32 +00:00
e7771d76f2 Cover buffered inventory sync in timings 2023-03-20 23:29:02 +00:00
ecc830a689 InventoryManager: avoid calling TypeConverter::getInstance() in a loop 2023-03-20 23:24:52 +00:00
ee72e80fbb ItemStackResponseBuilder: removed incorrect code
the client expects that all itemstacks must be acked by ItemStackResponse, regardless of whether the server changed them to some other item.
We'll overwrite the item to the correct thing at the end of the tick anyway.
2023-03-20 23:21:24 +00:00
63310cf764 Do not cache ItemStacks for every item
this is very memory inefficient, and only provides a performance advantage in cold code anyway.
2023-03-20 23:18:43 +00:00
1992d3b6db InventoryManager: avoid useless work in trackItemStack()
this attempts to accommodate slots being set to themselves, which is a rare enough occurrence (only plugins will cause it) that it doesn't make sense to penalize every inventory update this way.
attempting to avoid changing the itemstackID in this way is detrimental to performance, and it doesn't actually matter if we set a new itemstackID anyway.
2023-03-20 23:08:17 +00:00
035a0a4e9d InventoryManager: specialize trackItemStack() to avoid useless lookups 2023-03-20 22:57:58 +00:00
23ea721164 Reduce packets-per-batch limit to 100
this should be well in excess of requirements with the ItemStackRequest system in use.
2023-03-20 22:15:02 +00:00
8408da8534 Merge branch 'item-stack-request' into minor-next 2023-03-20 22:05:50 +00:00
c9601ae67d Fixed crash when opening crafting table and other 'UI' inventories 2023-03-20 22:00:38 +00:00
758b5ee500 InventoryManager: fixed armor slots hack
the correct condition for this should be an unsynced armor slot changed during a transaction, but conveying this information to syncSlot() is a bit of a hassle, so this will do for now.
2023-03-20 21:27:56 +00:00
ca6d51498f Buffer slot and content syncing until the end of the tick
we may receive multiple requests in one tick (e.g. crafting in a batch)
2023-03-20 19:16:00 +00:00
e8085e22a0 Fixed crash when opening main inventory
the InventoryManagerEntry was getting overwritten, since we don't expect to open the same inventory with two different window IDs.
2023-03-20 18:40:18 +00:00
a83fc85f1e InventoryManagerEntry: fixed missing default 2023-03-20 17:32:44 +00:00
3d70a169e1 Reduce chaos in InventoryManager
the information in these arrays is usually needed all at the same time, so it doesn't make sense to force multiple array lookups for it.

in addition, this (obviously) cleans up the code quite a lot.
2023-03-20 17:31:54 +00:00
6ccb8f7373 git 2023-03-20 16:57:38 +00:00
59bae9b077 Give InventoryManager internals clearer names
and stop mixing 'window' and 'inventory' terminology...
2023-03-20 16:53:57 +00:00
2751e1ec02 replacing new Vector3(0, 0, 0) with Vector3::zero() (#5640) 2023-03-20 12:54:28 +00:00
c91168db66 ... 2023-03-20 01:35:15 +00:00
4e55433ed8 Fixed request rejecting 2023-03-20 01:35:03 +00:00
eece6c4433 InGamePacketHandler: remove dead code 2023-03-20 01:28:18 +00:00
67b7b60d18 .............. 2023-03-20 01:19:07 +00:00
804feedb67 Added some dumb limits 2023-03-20 00:54:33 +00:00
d57aca1367 CS 2023-03-20 00:53:00 +00:00
7b0816e42f Properly handle transaction building errors instead of kicking the player 2023-03-20 00:52:26 +00:00
4864444440 Added CraftingManager::getCraftingRecipeFromIndex() 2023-03-19 22:14:23 +00:00
52ea4feac0 Updated pocketmine/locale-data 2023-03-19 16:53:02 +00:00
01d557062a Remove dead baseline 2023-03-19 16:41:01 +00:00
a619fd2be6 Scrub PHPStan baselines 2023-03-19 16:37:38 +00:00
05d9298958 PHPStan 1.10.7 2023-03-19 16:33:59 +00:00
f696a5881b Merge remote-tracking branch 'origin/stable' into minor-next 2023-03-19 16:23:09 +00:00
419962d3a2 Added timer for player-specific movement code
players use an entirely different pathway for movement processing, which could be costly.
2023-03-19 16:12:47 +00:00
054c06fab9 Add specialized entityBaseTick timer for item entities
since item merging is a potential hotspot, we want to know if this code section is a performance problem.
Current timers only tell us whether overall ticking of a particular entity is slow, but that includes movement and therefore isn't particularly helpful.
2023-03-19 15:59:06 +00:00
7bc5d8c824 Rename more timers 2023-03-19 15:57:36 +00:00
607bdfa42f Timings: added new timers for entity move collision checks and projectile move ray tracing
projectiles get their own distinct sub-timer, since the logic is completely different from regular entities.
2023-03-19 15:49:35 +00:00
eec53f9ae0 Timings: clean up timer names 2023-03-19 15:39:44 +00:00
3d56bd267c Timings: fixup network timer inheritance 2023-03-18 23:13:25 +00:00
9a969e21c7 ÂNetworkSession: ensure onResolve handler for CompressBatchPromise is covered by network send timings 2023-03-18 22:49:52 +00:00
195bc3b623 NetworkSession: prevent dev client asserts from missing ability flags 2023-03-18 21:53:17 +00:00
2177d8d352 Push Docker image tags to ghcr.io 2023-03-17 16:32:28 +00:00
471625e697 readme: remove docker hub shield
sadly there isn't any ghcr replacement right now.

[ci skip]
2023-03-17 16:24:13 +00:00
2135776c19 readme: goodbye docker hub, won't miss you
[ci skip]
2023-03-17 16:21:57 +00:00
765aef0810 4.18.0-ALPHA2 is next 2023-03-16 21:45:21 +00:00
bd21feffc4 Release 4.18.0-ALPHA1 2023-03-16 21:45:18 +00:00
5b324f695c Merge branch 'stable' into minor-next 2023-03-16 15:04:19 +00:00
9caed10488 update-updater-api: use github.repository_owner to make fork testing of this workflow less obnoxious 2023-03-16 15:03:14 +00:00
83945ff0a0 Do not update release channels if the new build has a lower version ID
this prevents stuff like 5.0.0 beta versions getting overwritten by 4.x beta versions.
2023-03-16 15:02:42 +00:00
ef45180b80 Rename DataPacketPreReceiveEvent -> DataPacketDecodeEvent
thank you @IvanCraft623 for the suggestion
2023-03-16 13:40:37 +00:00
941fd03998 Remove useless code 2023-03-15 22:58:10 +00:00
1af8da3c1f Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into minor-next 2023-03-15 22:54:05 +00:00
a5985dcf7d Merge branch 'stable' into minor-next 2023-03-15 22:53:44 +00:00
183d1f4038 Implement DataPacketPreReceiveEvent (#5559)
closes #5554

This is called just before the packet is decoded, allowing the event to be used to drop packets from clients without wasting CPU time decoding them. This can be particularly useful for mitigating denial-of-service attacks.
2023-03-15 22:47:19 +00:00
08ee825d91 StandardPacketBroadcaster: Include varint length prefix in length calculation
varints encode 7 bits per byte, so a log with base 128 will tell us how many bytes are required to encode the length of the packet.
2023-03-15 22:41:19 +00:00
337a254768 Use NetworkBroadcastUtils for broadcasting packets
this eradicates all but 4 usages of Server in Entity, which is extremely cool.
2023-03-15 22:28:51 +00:00
a31e3331fd Move Server::broadcastPackets() to NetworkBroadcastUtils::broadcastPackets()
this has no business being in Server, and it also doesn't need to be an instance method, since it never uses $this.
2023-03-15 22:25:23 +00:00
acebbeed16 Added version channels for update.pmmp.io 2023-03-15 20:59:36 +00:00
e0fdbe6eb1 make-release: don't automatically push
this is rather obnoxious when attempting to push test releases to a
fork.
2023-03-15 20:47:01 +00:00
cc8660629b First look at shared EntityEventBroadcaster,
this improves performance in PvP servers and other areas where lots of players or entities exist in one space.

fixes #5622
2023-03-15 18:22:56 +00:00
e7e19abe85 IPv4 and IPv6 RakLibInterface instances now both use the same broadcaster and context
fixes #5625
2023-03-15 17:17:56 +00:00
5f9e0081fd Fixed mushroom block silk-touch drops and block picking behaviour
fixes #5284
2023-03-15 16:36:35 +00:00
b266f45152 Bump build/php from 71b9f9d to a464454 (#5637)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `71b9f9d` to `a464454`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](71b9f9d2d7...a464454d1e)

---
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-03-15 13:44:20 +00:00
34ced382db Eliminate final remaining usage of TypeConverter::netItemStackToCore()
instead, we can verify that the held items match by comparing the received ItemStack with the one cached in InventoryManager, which is more cost effective and closes off internal item deserializers to external attacks.
2023-03-14 22:56:11 +00:00
a573a279fa Merge branch 'minor-next' into item-stack-request 2023-03-14 22:25:49 +00:00
14f141fab2 NetworkSession: Stop counting DataPacketReceiveEvent in handler timings
we want it to be included in receive timings, but not handler timings. Handler timings should reflect the time spent in the actual session PacketHandler, not in the event.
2023-03-14 19:00:15 +00:00
daff955bc4 Merge remote-tracking branch 'origin/stable' into minor-next 2023-03-14 18:42:14 +00:00
0022d82779 Merge commit 'd376399b7f332384532a82eaf69b9b02dad5bd0c' into minor-next 2023-03-14 18:39:03 +00:00
7cad9be0d2 Bump build/php from b2207cf to 71b9f9d (#5634)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `b2207cf` to `71b9f9d`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](b2207cf70d...71b9f9d2d7)

---
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-03-14 18:32:10 +00:00
2f862a552a actions: Replace deprecated ::set-output commands 2023-03-14 18:31:25 +00:00
590f6dad08 4.17.1 is next 2023-03-14 18:14:40 +00:00
9564c81582 Release 4.17.0 2023-03-14 18:14:40 +00:00
3de7a8c27f Updated for 1.19.70 2023-03-14 18:08:10 +00:00
d376399b7f Update composer dependencies
bedrock-item-upgrade-schema and bedrock-block-upgrade-schema are now minor-version-locked, to prevent introducing new upgrade schemas not intended for the currently in-use version
previously I'd intended to do this using max schema IDs, but this has proven to be error-prone, so it makes more sense to lock them in using package version constraints instead.
2023-03-14 17:29:25 +00:00
e2071e59c8 actions: update PHP versions 2023-03-13 17:44:10 +00:00
8e280ebb8b RuntimeBlockMapping: avoid unnecessary PacketSerializer usage 2023-03-11 22:16:24 +00:00
fa7c38276c Fixing gigantic clusterfuck with protocol contexts and broadcasting
fixes #5623
2023-03-11 21:54:14 +00:00
b13e97de3d Timings: fixed receivePacket timer showing 2x the actual number of received packets 2023-03-11 19:13:10 +00:00
328b87fc18 Bump phpstan/phpstan from 1.10.4 to 1.10.6 (#5617)
Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan) from 1.10.4 to 1.10.6.
- [Release notes](https://github.com/phpstan/phpstan/releases)
- [Changelog](https://github.com/phpstan/phpstan/blob/1.10.x/CHANGELOG.md)
- [Commits](https://github.com/phpstan/phpstan/compare/1.10.4...1.10.6)

---
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-03-10 11:49:34 +00:00
acaa1a9ce1 contributing: update table to reflect branch name changes
these branches were renamed to make them more auto-complete-friendly.
2023-03-07 17:28:31 +00:00
faaec12aaf Update BedrockProtocol 2023-01-06 22:16:29 +00:00
1123a5aa23 InventoryManager: Track predictions using ItemStack directly, instead of internal Item
this removes the need for deserializing network itemstacks to core items, thereby eliminating a whole bunch of potential security issues.
2023-01-06 20:45:08 +00:00
8633804f15 InventoryManager: disentangle slot tracking from slot syncing 2023-01-06 20:26:19 +00:00
d3cea2ca7c CS 2023-01-06 02:07:31 +00:00
5d6dba96af Merge branch 'stable' into item-stack-request 2023-01-06 01:47:27 +00:00
b24eb153f9 Constrain inventory transaction predictions
these are now only used for actions done with a closed inventory window. This means that they can only predict the slots of inventory, offhand and armor (total 41 slots) and perhaps include some DropItem actions.
2023-01-05 21:18:30 +00:00
36525d9055 Fixed multi-output recipe handling 2023-01-05 20:41:44 +00:00
3d6baa8a55 Working creative inventory, with a few more hacks than I'd like 2023-01-05 18:09:57 +00:00
30d3869eea Remove dead code 2023-01-05 17:26:58 +00:00
81697111b9 Merge branch 'item-stack-request' of github.com:pmmp/PocketMine-MP into item-stack-request 2023-01-05 17:24:15 +00:00
eedc943766 Confine legacy transaction handling to dropping items only 2023-01-05 17:23:50 +00:00
c6e11a8453 Remove unnecessary ternary operator (#5493) 2023-01-04 23:22:31 +00:00
2e9a3f9160 Working crafting :woohoo: 2023-01-04 22:29:29 +00:00
3d4ed5308e Merge branch 'stable' into item-stack-request 2023-01-04 01:28:42 +00:00
58dd4a44e3 Merge branch 'stable' into item-stack-request 2023-01-04 00:41:58 +00:00
5fdbb19852 Fixed a whole bunch of issues with legacy transactions 2023-01-04 00:13:51 +00:00
6b2156151f Merge branch 'stable' into item-stack-request 2023-01-03 23:51:37 +00:00
d8d236842f Fixed merge error 2023-01-03 19:54:41 +00:00
f51717323b Merge branch 'stable' into item-stack-request 2023-01-03 19:53:25 +00:00
0039af984d Merge branch 'next-minor' into item-stack-request 2022-10-16 16:56:26 +01:00
3235d128e5 Fixed handling of fake requests during block placement and other actions 2022-08-18 18:25:49 +01:00
2b7510945a First look at ItemStackRequest usage (very unstable) 2022-08-18 17:38:57 +01:00
736 changed files with 72386 additions and 30968 deletions

View File

@ -20,6 +20,13 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Clone pmmp/PocketMine-Docker repository
uses: actions/checkout@v3
with:
@ -30,20 +37,20 @@ jobs:
id: tag-name
run: |
VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
echo ::set-output name=TAG_NAME::$VERSION
echo ::set-output name=MAJOR::$(echo $VERSION | cut -d. -f1)
echo ::set-output name=MINOR::$(echo $VERSION | cut -d. -f1-2)
echo TAG_NAME=$VERSION >> $GITHUB_OUTPUT
echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT
echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT
- name: Download new release information
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
- name: Detect channel
id: channel
run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json)
run: echo CHANNEL=$(jq -r '.channel' new_build_info.json) >> $GITHUB_OUTPUT
- name: Get name of Docker repository name
id: docker-repo-name
run: echo ::set-output name=NAME::$(echo "${GITHUB_REPOSITORY,,}")
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
- name: Build image for tag
uses: docker/build-push-action@v4.0.0
@ -52,7 +59,7 @@ jobs:
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }}
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }}
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.TAG_NAME }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
@ -65,7 +72,7 @@ jobs:
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
@ -78,7 +85,7 @@ jobs:
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
@ -91,7 +98,7 @@ jobs:
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:latest
# ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:latest
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:latest
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}

View File

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

View File

@ -13,9 +13,9 @@ jobs:
- uses: actions/checkout@v3
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.24.0
uses: shivammathur/setup-php@2.25.2
with:
php-version: 8.0
php-version: 8.1
- name: Restore Composer package cache
uses: actions/cache@v3
@ -32,7 +32,7 @@ jobs:
- name: Get actual tag name
id: tag-name
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
- name: Run webhook post script
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }} ${{ secrets.DISCORD_NEWS_PING_ROLE_ID }}

View File

@ -11,6 +11,8 @@ jobs:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
php-version: [8.1]
steps:
- uses: actions/checkout@v3
@ -18,9 +20,9 @@ jobs:
submodules: true
- name: Setup PHP
uses: shivammathur/setup-php@2.24.0
uses: shivammathur/setup-php@2.25.2
with:
php-version: 8.0
php-version: ${{ matrix.php-version }}
- name: Restore Composer package cache
uses: actions/cache@v3
@ -40,7 +42,7 @@ jobs:
run: |
BUILD_NUMBER=$((2000+$GITHUB_RUN_NUMBER)) #to stay above jenkins
echo "Build number: $BUILD_NUMBER"
echo ::set-output name=BUILD_NUMBER::$BUILD_NUMBER
echo BUILD_NUMBER=$BUILD_NUMBER >> $GITHUB_OUTPUT
- name: Minify BedrockData JSON files
run: php vendor/pocketmine/bedrock-data/.minify_json.php
@ -51,15 +53,28 @@ jobs:
- name: Get PocketMine-MP release version
id: get-pm-version
run: |
echo ::set-output name=PM_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BASE_VERSION;')
echo ::set-output name=MCPE_VERSION::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;')
echo ::set-output name=PM_VERSION_SHORT::$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);')
echo ::set-output name=PM_VERSION_MD::$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);')
echo ::set-output name=CHANGELOG_SUFFIX::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;')
echo ::set-output name=PRERELEASE::$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "false" : "true";')
echo PM_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BASE_VERSION;') >> $GITHUB_OUTPUT
echo MCPE_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;') >> $GITHUB_OUTPUT
echo PM_VERSION_SHORT=$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);') >> $GITHUB_OUTPUT
echo PM_VERSION_MD=$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);') >> $GITHUB_OUTPUT
echo CHANGELOG_SUFFIX=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;') >> $GITHUB_OUTPUT
echo PRERELEASE=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "false" : "true";') >> $GITHUB_OUTPUT
- name: Generate PHP binary download URL
id: php-binary-url
run: |
echo PHP_BINARY_URL="${{ github.server_url }}/${{ github.repository_owner }}/PHP-Binaries/releases/tag/php-${{ matrix.php-version }}-latest" >> $GITHUB_OUTPUT
- name: Generate build info
run: php build/generate-build-info-json.php ${{ github.sha }} ${{ steps.get-pm-version.outputs.PM_VERSION }} ${{ github.repository }} ${{ steps.build-number.outputs.BUILD_NUMBER }} ${{ github.run_id }} > build_info.json
run: |
php build/generate-build-info-json.php \
${{ github.sha }} \
${{ steps.get-pm-version.outputs.PM_VERSION }} \
${{ github.repository }} \
${{ steps.build-number.outputs.BUILD_NUMBER }} \
${{ github.run_id }} \
${{ steps.php-binary-url.outputs.PHP_BINARY_URL }} \
> build_info.json
- name: Upload release artifacts
uses: actions/upload-artifact@v3
@ -84,3 +99,7 @@ jobs:
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}${{ steps.get-pm-version.outputs.CHANGELOG_SUFFIX }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
:information_source: Download the recommended PHP binary [here](${{ steps.php-binary-url.outputs.PHP_BINARY_URL }}).
:warning: **4.x is now deprecated. Please read https://github.com/pmmp/PocketMine-MP/issues/5784 for details, and prepare to upgrade to 5.x.**

View File

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

@ -8,6 +8,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
concurrency: update-updater-api # only one job can run at a time, to avoid git conflicts when updating the repository
steps:
- name: Install jq
@ -15,23 +16,68 @@ jobs:
- uses: actions/checkout@v3
with:
repository: pmmp/update.pmmp.io
repository: ${{ github.repository_owner }}/update.pmmp.io
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
- name: Get actual tag name
id: tag-name
run: echo ::set-output name=TAG_NAME::$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
- name: Download new release information
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
- name: Detect channel
- name: Detect channels
id: channel
run: echo ::set-output name=CHANNEL::$(jq -r '.channel' new_build_info.json)
- name: Copy release information
run: |
cp new_build_info.json channels/${{ steps.channel.outputs.CHANNEL }}.json
CHANNEL=$(jq -r '.channel' new_build_info.json)
VERSION=${{ steps.tag-name.outputs.TAG_NAME }}
echo CHANNEL=$CHANNEL >> $GITHUB_OUTPUT
if [ "$CHANNEL" == "stable" ]; then
echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT
echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT
else
echo MAJOR=$(echo $VERSION | cut -d. -f1)-$CHANNEL >> $GITHUB_OUTPUT
echo MINOR=$(echo $VERSION | cut -d. -f1-2)-$CHANNEL >> $GITHUB_OUTPUT
fi
- name: Update channel info
run: |
function version_id() {
major=$(echo $1 | cut -d. -f1)
minor=$(echo $1 | cut -d. -f2)
patch=$(echo $1 | cut -d. -f3)
echo $(((major * 1000000) + (minor * 1000) + patch))
}
function update_channel() {
local target_file_name="$1"
local new_file_name="$2"
local old_version_id
local new_version_id
if [ ! -f "$target_file_name" ]; then
echo "Creating channel file: $target_file_name"
cp "$new_file_name" "$target_file_name"
else
old_version_id=$(version_id "$(jq -r '.base_version' "$target_file_name")")
new_version_id=$(version_id "$(jq -r '.base_version' "$new_file_name")")
echo "Old version ID: $old_version_id"
echo "New version ID: $new_version_id"
if [ $new_version_id -ge $old_version_id ]; then #suffixed versions will have the same version ID - assume they'll always be newer
echo "Updating channel file: $target_file_name ($old_version_id -> $new_version_id)"
cp "$new_file_name" "$target_file_name"
else
echo "Version $new_version_id is less than $old_version_id, not updating channel file: $target_file_name"
fi
fi
}
update_channel "channels/${{ steps.channel.outputs.CHANNEL }}.json" "new_build_info.json"
update_channel "channels/${{ steps.channel.outputs.MAJOR }}.json" "new_build_info.json"
update_channel "channels/${{ steps.channel.outputs.MINOR }}.json" "new_build_info.json"
rm new_build_info.json
- name: Commit changes

View File

@ -30,6 +30,13 @@
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</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">
<option name="CLASS_BRACE_STYLE" value="1" />
<option name="METHOD_BRACE_STYLE" value="1" />

View File

@ -2,13 +2,13 @@
## Pre-requisites
- A bash shell (git bash is sufficient for Windows)
- [`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
## 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.
- [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`
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.
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
Run `src/PocketMine.php` using your preferred PHP binary.

View File

@ -18,24 +18,49 @@ Larger contributions like feature additions should be preceded by a [Change Prop
## Other things you'll need
- [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
PocketMine-MP has three primary branches of development.
| Type of change | `stable` | `next-minor` | `next-major` |
|:---------------|:--------:|:------------:|:------------:|
| Bug fixes | ✔️ | ✔️ | ✔️ |
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
| Cleaning up code | ❌ | ✔️ | ✔️ |
| Changing code formatting or style | ❌ | ✔️ | ✔️ |
| Addition of new core features | ❌ | 🟡 Only if non-disruptive | ✔️ |
| Changing core behaviour (e.g. making something use threads) | ❌ | ✔️ | ✔️ |
| Addition of new configuration options | ❌ | 🟡 Only if optional | ✔️ |
| Addition of new API classes, methods or constants | ❌ | ✔️ | ✔️ |
| Deprecating API classes, methods or constants | ❌ | ✔️ | ✔️ |
| Adding optional parameters to an API method | ❌ | ✔️ | ✔️ |
| Changing API behaviour | ❌ | 🟡 Only if backwards-compatible | ✔️ |
| Removal of API | ❌ | ❌ | ✔️ |
| Backwards-incompatible API change (e.g. renaming a method) | ❌ | ❌ | ✔️ |
| Type of change | `stable` | `minor-next` | `major-next` |
|:--------------------------------------------------------------------------------------------|:--------:|:-------------------------------:|:------------:|
| Bug fixes | ✔️ | ✔️ | ✔️ |
| Improvements to API docs | ✔️ | ✔️ | ✔️ |
| Cleaning up code | ❌ | ✔️ | ✔️ |
| Changing code formatting or style | ❌ | ✔️ | ✔️ |
| Addition of new core features | ❌ | 🟡 Only if non-disruptive | ✔️ |
| Changing core behaviour (e.g. making something use threads) | ❌ | ✔️ | ✔️ |
| Addition of new configuration options | ❌ | 🟡 Only if optional | ✔️ |
| Addition of new API classes, methods or constants | ❌ | ✔️ | ✔️ |
| Deprecating API classes, methods or constants | ❌ | ✔️ | ✔️ |
| Adding optional parameters to an API method | ❌ | ✔️ | ✔️ |
| Changing API behaviour | ❌ | 🟡 Only if backwards-compatible | ✔️ |
| Removal of API | ❌ | ❌ | ✔️ |
| Backwards-incompatible API change (e.g. renaming a method) | ❌ | ❌ | ✔️ |
| Backwards-incompatible internals change (e.g. changing things in `pocketmine\network\mcpe`) | ❌ | ✔️ | ✔️ |
### Notes
- **Non-disruptive** means that usage should not be significantly altered by the change.
@ -43,6 +68,10 @@ PocketMine-MP has three primary branches of development.
- Examples of **disruptive** changes include changing the way the server is run, world format changes (since those require downtime for the user to convert their world).
- **API** includes all public and protected classes, functions and constants (unless marked as `@internal`).
- Private members are not part of the API, **unless in a trait**.
- The `pocketmine\network\mcpe` package is considered implicitly `@internal` in its entirety (see its [README](src/network/mcpe/README.md) for more details).
- Minecraft's protocol changes are considered necessary internal changes, and are **not** subject to the same rules.
- Protocol changes must always be released in a new minor version, since they disrupt user experience by requiring a client update.
- BC-breaking changes to the internal network API are allowed, but only in new minor versions. This ensures that plugins which use the internal network API will not break (though they shouldn't use such API anyway).
## Making a pull request
The basic procedure to create a pull request is:

View File

@ -14,7 +14,6 @@
<p align="center">
<a href="https://github.com/pmmp/PocketMine-MP/actions/workflows/main.yml"><img src="https://github.com/pmmp/PocketMine-MP/workflows/CI/badge.svg" alt="CI" /></a>
<a href="https://github.com/pmmp/PocketMine-MP/releases/latest"><img alt="GitHub release (latest SemVer)" src="https://img.shields.io/github/v/release/pmmp/PocketMine-MP?label=release&sort=semver"></a>
<a href="https://hub.docker.com/r/pmmp/pocketmine-mp"><img src="https://img.shields.io/docker/v/pmmp/pocketmine-mp?logo=docker&label=image" alt="Docker image version (latest semver)" /></a>
<a href="https://discord.gg/bmSAZBG"><img src="https://img.shields.io/discord/373199722573201408?label=discord&color=7289DA&logo=discord" alt="Discord" /></a>
<br>
<a href="https://github.com/pmmp/PocketMine-MP/releases"><img alt="GitHub all releases" src="https://img.shields.io/github/downloads/pmmp/PocketMine-MP/total?label=downloads%40total"></a>
@ -24,7 +23,7 @@
## Getting started
- [Documentation](http://pmmp.readthedocs.org/)
- [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html)
- [Docker image](https://hub.docker.com/r/pmmp/pocketmine-mp)
- [Docker image](https://github.com/pmmp/PocketMine-MP/pkgs/container/pocketmine-mp)
- [Plugin repository](https://poggit.pmmp.io/plugins)
## Discussion/Help
@ -36,7 +35,7 @@
* [Building and running from source](BUILDING.md)
* [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 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
* [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features
* [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

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

View File

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

@ -38,7 +38,6 @@ use function is_string;
use function max;
use function preg_match;
use function preg_replace;
use function sleep;
use function sprintf;
use function str_pad;
use function strlen;
@ -160,9 +159,6 @@ function main() : void{
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel);
systemWrapper('git add "' . $versionInfoPath . '"', "failed to stage changes for post-release commit");
systemWrapper('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"', "failed to create post-release commit");
echo "pushing changes in 5 seconds\n";
sleep(5);
systemWrapper('git push origin HEAD ' . $currentVer->getBaseVersion(), "failed to push changes to remote");
}
main();

39
changelogs/4.17.md Normal file
View File

@ -0,0 +1,39 @@
**For Minecraft: Bedrock Edition 1.19.70**
### Note about API versions
Plugins which don't touch the protocol and 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 protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 4.17.0
Released 14th March 2023.
## General
- Added support for Minecraft: Bedrock Edition 1.19.70.
- Removed support for older versions.
# 4.17.1
Released 22nd March 2023.
## General
- Docker images for PocketMine-MP are now published on [GitHub Container Registry](https://github.com/pmmp/PocketMine-MP/pkgs/container/pocketmine-mp). The Docker Hub images will stop being maintained in the future.
- Updated translations.
## Fixes
- Fixed server crash on empty packets in certain cases.
- Fixed mushroom blocks dropping the wrong items when broken with a silk-touch tool.
- Fixed mushroom blocks giving the wrong items when block-picked.
- Fixed missing ability flag `PRIVILEGED_BUILDER`.
## Internals
- `update-updater-api.yml` workflow now uses `github.repository_owner` to make it easier to test the workflow on forks.
- Added version-specific channels to `update.pmmp.io`, such as `4`, `4.18-beta`, `4.17`, etc.
- Replaced deprecated `::set-output` commands in GitHub Actions workflows.
- `build/make-release.php` no longer automatically pushes changes, to avoid accidents when testing release workflows on forks.
# 4.17.2
Released 29th March 2023.
## Fixes
- Fixed players being unable to join due to the appearance of a new `x5t` field in the JWT header of Xbox Live authentication tokens.

91
changelogs/4.18-alpha.md Normal file
View File

@ -0,0 +1,91 @@
**For Minecraft: Bedrock Edition 1.19.70**
### 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.
### Alpha release warning
Alpha releases are **experimental**. Features introduced in these releases are subject to change or removal.
APIs which existed **prior** to this version will continue to work as normal, so plugins which use them will continue to work.
### Highlights
This version makes changes to the internal network system to improve server performance and reduce memory usage.
While these changes don't affect non-internal API, they are still significant enough to warrant a new minor version, as they may break plugins which use the internal network API (not recommended).
# 4.18.0-ALPHA1
Released 16th March 2023.
## General
- Improved server performance in congested areas of the world (lots of players and/or entities in the same area).
## API
### `pocketmine\event\server`
- The following new classes have been added:
- `DataPacketDecodeEvent` - called before a packet is decoded by a `NetworkSession`; useful to mitigate DoS attacks if PocketMine-MP hasn't been patched against new bugs yet
## Internals
- Introduced new system for broadcasting entity events to network sessions.
- This change improves performance when lots of players and/or entities are in the same area.
- New interface `EntityEventBroadcaster` and class `StandardEntityEventBroadcaster` have been added to implement this.
- All entity-specific `on*()` and `sync*()` methods have been removed from `NetworkSession` (BC break).
- `NetworkSession` now accepts an `EntityEventBroadcaster` instance in its constructor.
- `NetworkBroadcastUtils::broadcastEntityEvent()` can be used to efficiently broadcast events to unique broadcasters shared by several network sessions.
- All network sessions now share the same `PacketSerializerContext` and `PacketBroadcaster` by default.
- Previously, every session had its own context, meaning that broadcast optimisations were not used, causing significant performance losses compared to 3.x.
- This change improves performance in congested areas by allowing reuse of previously encoded packet buffers for all sessions sharing the same context.
- Packet broadcasts are automatically encoded separately per unique `PacketSerializerContext` instance. This allows, for example, a multi-version fork to have a separate context for each protocol version, to ensure maximum broadcast efficiency while encoding different packets for different versions.
- `PacketSerializerContext` is now passed in `NetworkSession::__construct()`, instead of being created by the session.
- `StandardPacketBroadcaster` is now locked to a single `PacketSerializer` context, reducing complexity.
- Introduced `NetworkBroadcastUtils::broadcastPackets()`, replacing `Server->broadcastPackets()`.
- `Server->broadcastPackets()` has been deprecated. It will be removed in a future version.
# 4.18.0-ALPHA2
Released 21st March 2023.
## General
- Included more sections of the network system in Player Network Send timings.
- Changed the names of some timings to make them more user-friendly.
- Removed packet IDs from `receivePacket` and `sendPacket` timings, as they were not very useful.
- Added new specialized timers for the following:
- Item entity base ticking (merging)
- Player movement processing
- Entity movement processing (collision checking section)
- Projectile movement (all)
- Projectile movement processing (ray tracing section)
## API
### `pocketmine\crafting`
- The following new API methods have been added:
- `CraftingManager->getCraftingRecipeIndex() : array<int, CraftingRecipe>` - returns a list of all crafting recipes
- `CraftingManager->getCraftingRecipeFromIndex(int $index) : ?CraftingRecipe` - returns the crafting recipe at the given index, or null if it doesn't exist
### `pocketmine\inventory\transaction`
- The following API methods have changed signatures:
- `CraftingTransaction->__construct()` now accepts additional arguments `?CraftingRecipe $recipe = null, ?int $repetitions = null`
- The following new API methods have been added:
- `TransactionBuilderInventory->getActualInventory() : Inventory` - returns the actual inventory that this inventory is a proxy for
## Internals
### Network
- Introduced support for the `ItemStackRequest` Minecraft: Bedrock network protocol.
- This fixes a large number of inventory- and crafting-related bugs.
- This also improves server security by closing off many code pathways that might have been used for exploits. `TypeConverter->netItemStackToCore()` is no longer used in server code, and remains for tool usage only.
- This system is also significantly more bandwidth-efficient and has lower overhead than the legacy system.
- This now opens the gateway to easily implement lots of gameplay features which have been missing for a long time, such as enchanting, anvils, looms, and more.
- Significant changes have been made to `pocketmine\network\mcpe\InventoryManager` internals. These shouldn't affect plugins, but may affect plugins which use internal network API.
- **No changes have been made to the plugin `InventoryTransaction` API**.
- This system has been implemented as a shim for the existing PocketMine-MP transaction system to preserve plugin compatibility. Plugins using `InventoryTransactionEvent` should continue to work seamlessly.
- The `InventoryTransaction` API will be redesigned in a future major version to make use of the new information provided by the `ItemStackRequest` system.
- `InventoryTransactionPacket` is no longer sent by the client for "regular" inventory actions. However, it is still sent when dropping items, interacting with blocks, and using items.
- Inventory slot and content syncing is now buffered until the end of the tick. This reduces outbound network usage when the client performs multiple transactions in a single tick (e.g. crafting a stack of items).
- Renamed some `InventoryManager` internal properties to make them easier to understand.
- `TypeConverter->createInventoryAction()` has been removed.
- Packet batch limit has been lowered to `100` packets. With the introduction of `ItemStackRequest`, this is more than sufficient for normal gameplay.
### Other
- Use `Vector3::zero()` instead of `new Vector3()` in some places.

123
changelogs/4.18.md Normal file
View File

@ -0,0 +1,123 @@
**For Minecraft: Bedrock Edition 1.19.70**
### 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.
### Highlights
This version significantly improves server performance with many players and/or entities by making changes to the internal network system.
It also introduces support for the newer `ItemStackRequest` protocol, which fixes many bugs and improves server security.
While these changes don't affect non-internal API, they are still significant enough to warrant a new minor version, as they may break plugins which use the internal network API (not recommended).
# 4.18.0
Released 25th March 2023.
## General
- Significantly improved server performance in congested areas of the world (lots of players and/or entities in the same area).
- Included more sections of the network system in `Player Network Send` performance timings.
- Changed the names of some performance timings to make them more user-friendly.
- Removed packet IDs from `receivePacket` and `sendPacket` performance timings, as they were not very useful.
- Added new specialized performance timings for the following:
- Item entity base ticking (merging)
- Player movement processing
- Entity movement processing (collision checking section)
- Projectile movement (all)
- Projectile movement processing (ray tracing section)
## API
### `pocketmine\crafting`
- The following new API methods have been added:
- `CraftingManager->getCraftingRecipeIndex() : array<int, CraftingRecipe>` - returns a list of all crafting recipes
- `CraftingManager->getCraftingRecipeFromIndex(int $index) : ?CraftingRecipe` - returns the crafting recipe at the given index, or null if it doesn't exist
### `pocketmine\event\server`
- The following new classes have been added:
- `DataPacketDecodeEvent` - called before a packet is decoded by a `NetworkSession`; useful to mitigate DoS attacks if PocketMine-MP hasn't been patched against new bugs yet
### `pocketmine\inventory\transaction`
- The following API methods have changed signatures:
- `CraftingTransaction->__construct()` now accepts additional arguments `?CraftingRecipe $recipe = null, ?int $repetitions = null`
- The following new API methods have been added:
- `TransactionBuilderInventory->getActualInventory() : Inventory` - returns the actual inventory that this inventory is a proxy for
## Internals
### Network
- Introduced new system for broadcasting entity events to network sessions.
- This change improves performance when lots of players and/or entities are in the same area.
- New interface `EntityEventBroadcaster` and class `StandardEntityEventBroadcaster` have been added to implement this.
- All entity-specific `on*()` and `sync*()` methods have been removed from `NetworkSession` (internals backwards compatibility break, not covered by API version guarantee).
- `NetworkSession` now accepts an `EntityEventBroadcaster` instance in its constructor.
- `NetworkBroadcastUtils::broadcastEntityEvent()` can be used to efficiently broadcast events to unique broadcasters shared by several network sessions.
- All network sessions now share the same `PacketSerializerContext` and `PacketBroadcaster` by default.
- Previously, every session had its own context, meaning that broadcast optimisations were not used, causing significant performance losses compared to 3.x.
- This change improves performance in congested areas by allowing reuse of previously encoded packet buffers for all sessions sharing the same context.
- Packet broadcasts are automatically encoded separately per unique `PacketSerializerContext` instance. This allows, for example, a multi-version fork to have a separate context for each protocol version, to ensure maximum broadcast efficiency while encoding different packets for different versions.
- `PacketSerializerContext` is now passed in `NetworkSession::__construct()`, instead of being created by the session.
- `StandardPacketBroadcaster` is now locked to a single `PacketSerializer` context, reducing complexity.
- Introduced `NetworkBroadcastUtils::broadcastPackets()`, replacing `Server->broadcastPackets()`.
- `Server->broadcastPackets()` has been deprecated. It will be removed in a future version.
- Introduced support for the `ItemStackRequest` Minecraft: Bedrock network protocol.
- This fixes a large number of inventory- and crafting-related bugs.
- This also improves server security by closing off many code pathways that might have been used for exploits. `TypeConverter->netItemStackToCore()` is no longer used in server code, and remains for tool usage only.
- This system is also significantly more bandwidth-efficient and has lower overhead than the legacy system.
- This now opens the gateway to easily implement lots of gameplay features which have been missing for a long time, such as enchanting, anvils, looms, and more.
- Significant changes have been made to `pocketmine\network\mcpe\InventoryManager` internals. These shouldn't affect plugins, but may affect plugins which use internal network API.
- **No changes have been made to the plugin `InventoryTransaction` API**.
- This system has been implemented as a shim for the existing PocketMine-MP transaction system to preserve plugin compatibility. Plugins using `InventoryTransactionEvent` should continue to work seamlessly.
- The `InventoryTransaction` API will be redesigned in a future major version to make use of the new information provided by the `ItemStackRequest` system.
- `InventoryTransactionPacket` is no longer sent by the client for "regular" inventory actions. However, it is still sent when dropping items, interacting with blocks, and using items.
- Inventory slot and content syncing is now buffered until the end of the tick. This reduces outbound network usage when the client performs multiple transactions in a single tick (e.g. crafting a stack of items).
- Renamed some `InventoryManager` internal properties to make them easier to understand.
- `TypeConverter->createInventoryAction()` has been removed.
- Packet batch limit has been lowered to `100` packets. With the introduction of `ItemStackRequest`, this is more than sufficient for normal gameplay.
### Other
- Use `Vector3::zero()` instead of `new Vector3()` in some places.
# 4.18.1
Released 27th March 2023.
## General
- `RakLibInterface` now logs the name of the currently active session if a crash occurs when processing a packet. This makes it easier to reproduce bugs, which is important to be able to fix them.
- Added more detailed debugging information to `InventoryManager->syncSelectedHotbarSlot()`.
## Fixes
- Fixed server crash when attempting to drop more of an item from a stack than available in the inventory.
- Fixed packet processing errors when editing writable books.
- Fixed packet processing errors when shift-clicking on the recipe book to craft recipes which draw from a large number of inventory slots.
# 4.18.2
Released 29th March 2023.
## Fixes
- Fixed players being unable to join due to the appearance of a new `x5t` field in the JWT header of Xbox Live authentication tokens.
- Fixed items' durability appearing to reset when moving them around in the inventory.
# 4.18.3
Released 5th April 2023.
## Fixes
- Fixed Average Players not being shown on timings reports when custom player classes are used.
- Fixed incorrect tick violation calculation in timings reports.
- Fixed not being able to add or remove items from the offhand slot.
- Fixed creative inventory item count corruption when taking items (some players would see 64x items in the creative inventory after rejoining or changing gamemode).
- Fixed not being able to drop items directly from the creative inventory on mobile.
- Fixed `DataPacketReceiveEvent` not being called for packets sent by `EntityEventBroadcaster`.
- `CreativeInventory::getItem()` and `CreativeInventory::getAll()` now return cloned itemstacks, to prevent accidental modification of the creative inventory.
# 4.18.4
Released 10th April 2023.
## Fixes
- Fixed movement becoming broken when the player moves at high speed (e.g. due to high levels of the Speed effect).
- Updated dependencies to get fixes in `pocketmine/nbt` and `pocketmine/bedrock-protocol`.
## Internals
### Network
- Game packets are now rate-limited in a similar manner to packet batches. This helps to more effectively mitigate certain types of DoS attacks.
- Added a new class `PacketRateLimiter`, implementing functionality previously baked directly into `NetworkSession` in a more generic way to allow reuse.

111
changelogs/4.19.md Normal file
View File

@ -0,0 +1,111 @@
**For Minecraft: Bedrock Edition 1.19.70**
### 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.
### Highlights
This version introduces support for a new, more advanced version of Timings.
This improved system provides more detail than the old system, and supports being displayed in a tree view, making it much easier to see which timers contribute to which other timers.
In addition, some minor performance improvements have been made, along with a couple of minor API additions.
# 4.19.0
Released 11th April 2023.
## General
- Updated the Timings system.
- Timings records now include parent information, allowing them to be displayed in a tree view (e.g. https://timings.pmmp.io/?id=303556).
- Timings records now include additional information, such as Peak (max time spent on any single tick), and Ticks (number of ticks the timer was active on).
- New timings have been added for every event.
- A new timer `Player Network Send - Pre-Spawn Game Data` has been added, and covers most of the time spent handling `ResourcePackClientResponsePacket`, giving a clearer picture of what's happening.
- Improved performance of the plugin event system.
- By introducing some caching, the event system now has 90% less overhead than in previous versions.
- Improved performance of the random chunk ticking system.
- The selection of ticked random chunks, and their validation for ticking, is now cached. This significantly reduces the overhead of chunk selection.
- Factions servers and other game modes with big maps and sparsely populated areas will see the most benefit from this change.
- Real-world performance benefit of this change is anywhere from 0-20%, depending on server type and configuration.
- The `timings paste` command now logs a debug message with the server response on failure to paste a timings report.
## API
### `pocketmine\entity\object`
- The following API constants have been added:
- `ExperienceOrb::DEFAULT_DESPAWN_DELAY` - the default delay in ticks before an experience orb despawns
- `ExperienceOrb::NEVER_DESPAWN` - magic value for `setDespawnDelay()` to make an experience orb never despawn
- `ExperienceOrb::MAX_DESPAWN_DELAY` - the maximum delay in ticks before an experience orb despawns
- The following API methods have been added:
- `public ExperienceOrb->getDespawnDelay() : int` - returns the delay in ticks before this experience orb despawns
- `public ExperienceOrb->setDespawnDelay(int $despawnDelay) : void` - sets the delay in ticks before this experience orb despawns
- The following properties have been deprecated
- `ExperienceOrb->age` - superseded by despawn delay methods
### `pocketmine\event`
- The following API methods have been added:
- `public HandlerList->getListenerList() : list<RegisteredListener>` - returns an ordered list of handlers to be called for the event
### `pocketmine\player`
- The following API methods have behavioural changes:
- `ChunkSelector->selectChunks()` now yields the distance in chunks from the center as the key, instead of an incrementing integer.
- The following classes have been deprecated:
- `PlayerChunkLoader` (this was technically internal, but never marked as such)
### `pocketmine\timings`
- The following API constants have been deprecated:
- `Timings::INCLUDED_BY_OTHER_TIMINGS_PREFIX` - this is superseded by timings group support (see `Timings::GROUP_BREAKDOWN`)
- 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
- 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
- The following API methods have changed signatures:
- `TimingsHandler->__construct()` now accepts an additional, optional `string $group` parameter, which defaults to `Minecraft`.
### `pocketmine\world`
#### Highlights
Ticking chunks is now done using the `ChunkTicker` system, which has a much more fine-grained API than the old `TickingChunkLoader` system, as well as better performance.
It works similarly to the `ChunkLoader` system, in that chunks will be ticked as long as at least one `ChunkTicker` is registered for them.
#### API changes
- The following classes have been deprecated:
- `TickingChunkLoader` - this has been superseded by the more powerful and performant `ChunkTicker` APIs
- The following classes have been added:
- `ChunkTicker` - an opaque object used for `registerTickingChunk()` to instruct the `World` that we want a chunk to be ticked
- 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->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).

58
changelogs/4.22.md Normal file
View File

@ -0,0 +1,58 @@
# 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
- Replaced 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.
# 4.22.2
Released 1st July 2023.
## Changes
- Added obsoletion warnings to the server log at the end of the startup sequence.
## Fixes
- Fixed players being disconnected en masse with "Not authenticated" messages.
- This occurred due to a check intended to disable the old authentication key after July 1st.
- We expected that the new key would have been deployed by Mojang by now, but it seems like that has not yet happened.
- Due to the lack of a hard date for the key changeover, we guessed that July 1st would be a safe bet, but this appears to have backfired.
- This version will accept both old and new keys indefinitely.
- A security release will be published to remove the old key after the transition occurs.
# 4.22.3
Released 11th July 2023.
## Fixes
- Fixed mishandling of NBT leading to a server crash when editing signs.
- Fixed an edge case crash that could occur in `AsyncTask->__destruct()` when thread-local storage referenced other `AsyncTask` objects.
## Internals
- Added a concurrency lock to prevent the `update-updater-api` GitHub Action from running for multiple releases at the same time (which would have caused one of them to fail due to git conflicts).

68
changelogs/4.23.md Normal file
View File

@ -0,0 +1,68 @@
# 4.23.0
Released 12th July 2023.
**For Minecraft: Bedrock Edition 1.20.10**
This is a support release for Minecraft: Bedrock Edition 1.20.10.
**Plugin compatibility:** Plugins for previous 4.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.20.10.
- Removed support for older versions.
## Fixes
- Fixed Docker image build failure due to outdated `build/php` submodule.
# 4.23.1
Released 14th July 2023.
## Fixes
- Hardened validation of JWT signing keys in `LoginPacket`.
- Fixed server crash due to a bug in upstream dependency [`netresearch/jsonmapper`](https://github.com/cweiske/JsonMapper).
# 4.23.2
Released 18th July 2023.
## Fixes
- Fixed login errors due to a new `sandboxId` field appearing in the Xbox Live authentication data in `LoginPacket`. All clients, regardless of version, are affected by this change.
# 4.23.3
Released 24th July 2023.
## Documentation
- Fixed typo in `ChunkSelector::selectChunks()` documentation.
## Fixes
- Fixed the server not stopping properly during crash conditions on *nix platforms.
- Fixed `HORSE_EQUIP` and `SMITHING_TABLE_TEMPLATE` container UI types not being handled by `ItemStackContainerIdTranslator`. This bug prevented plugins from implementing missing inventory types.
- Player emotes no longer broadcast messages to other players. This was unintended behaviour caused by a client-side behavioural change.
- Shulker boxes no longer support the placement of torches or other similar blocks.
- Fire can now be placed on upper slabs and the top of upside-down stairs.
# 4.23.4
Released 1st August 2023.
## Fixes
- Fixed exponentially increasing lag when many hundreds of non-mergeable dropped items occupied the same space. This disproportionately affected SkyBlock servers due to large cactus farms using water to collect items together.
# 4.23.5
Released 9th August 2023.
## General
- Updated translation data to [pmmp/Language 2.19.6](https://github.com/pmmp/Language/releases/tag/2.19.6).
## Fixes
- Fixed `PluginBase->saveResource()` leaking file resources when the data file already exists in the plugin's data folder. This bug existed since 2014 and was only discovered recently.
- Fixed coral blocks becoming dead after calling `getDropsForCompatibleTool()` on them.
- Fixed `BlockDeathEvent->getOldState()` returning a block which is already dead.
# 4.23.6
Released 21st August 2023.
## Fixes
- Added a workaround for armor and other inventories not working correctly after inventory sync. This is caused by a client bug.

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +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.

View File

@ -5,7 +5,7 @@
"homepage": "https://pmmp.io",
"license": "LGPL-3.0",
"require": {
"php": "^8.0",
"php": "^8.1",
"php-64bit": "*",
"ext-chunkutils2": "^0.3.1",
"ext-crypto": "^0.3.1",
@ -22,7 +22,7 @@
"ext-openssl": "*",
"ext-pcre": "*",
"ext-phar": "*",
"ext-pthreads": "^5.1",
"ext-pthreads": "^4.0",
"ext-reflection": "*",
"ext-simplexml": "*",
"ext-sockets": "*",
@ -31,34 +31,35 @@
"ext-zip": "*",
"ext-zlib": ">=1.2.11",
"composer-runtime-api": "^2.0",
"adhocore/json-comment": "^1.1",
"fgrosse/phpasn1": "^2.3",
"netresearch/jsonmapper": "^4.0",
"pocketmine/bedrock-block-upgrade-schema": "^1.0.0",
"pocketmine/bedrock-data": "~2.0.0+bedrock-1.19.60",
"pocketmine/bedrock-item-upgrade-schema": "^1.0.0",
"pocketmine/bedrock-protocol": "~19.3.0+bedrock-1.19.62",
"adhocore/json-comment": "~1.2.0",
"fgrosse/phpasn1": "~2.5.0",
"pocketmine/netresearch-jsonmapper": "~v4.2.1000",
"pocketmine/bedrock-block-upgrade-schema": "~3.1.0+bedrock-1.20.10",
"pocketmine/bedrock-data": "~2.4.0+bedrock-1.20.10",
"pocketmine/bedrock-item-upgrade-schema": "~1.4.0+bedrock-1.20.10",
"pocketmine/bedrock-protocol": "~23.0.2+bedrock-1.20.10",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/classloader": "^0.3.0",
"pocketmine/classloader": "^0.2.0",
"pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.6.0",
"pocketmine/locale-data": "~2.19.0",
"pocketmine/log": "^0.4.0",
"pocketmine/log-pthreads": "^0.5.0",
"pocketmine/log-pthreads": "^0.4.0",
"pocketmine/math": "^0.4.0",
"pocketmine/nbt": "^0.3.2",
"pocketmine/raklib": "^0.15.0",
"pocketmine/raklib-ipc": "^0.2.0",
"pocketmine/snooze": "^0.4.0",
"ramsey/uuid": "^4.1",
"symfony/filesystem": "^5.4"
"pocketmine/raklib": "^0.14.2",
"pocketmine/raklib-ipc": "^0.1.0",
"pocketmine/snooze": "^0.3.0",
"ramsey/uuid": "~4.7.0",
"symfony/filesystem": "~5.4.0",
"webmozart/path-util": "~2.3.0"
},
"require-dev": {
"phpstan/phpstan": "1.10.4",
"phpstan/phpstan": "1.10.15",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "^9.2"
"phpunit/phpunit": "^10.1"
},
"autoload": {
"psr-4": {
@ -76,7 +77,7 @@
},
"config": {
"platform": {
"php": "8.0.0"
"php": "8.1.0"
},
"sort-packages": true
},

1126
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
includes:
- tests/phpstan/analyse-for-current-php-version.neon.php
- tests/phpstan/configs/actual-problems.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/impossible-generics.neon
- tests/phpstan/configs/php-bugs.neon
- tests/phpstan/configs/phpstan-bugs.neon
- tests/phpstan/configs/runtime-type-checks.neon
- tests/phpstan/configs/spl-fixed-array-sucks.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.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
#Compression level used when sending batched packets. Higher = more CPU, less bandwidth usage
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
#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
upnp-forwarding: false
#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.
*
* @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");
ini_set('memory_limit', '-1');
gc_disable();
@ -314,9 +316,6 @@ class MemoryManager{
continue;
}
if(!$property->isPublic()){
$property->setAccessible(true);
}
if(!$property->isInitialized()){
continue;
}
@ -440,9 +439,6 @@ class MemoryManager{
continue;
}
}
if(!$property->isPublic()){
$property->setAccessible(true);
}
if(!$property->isInitialized($object)){
continue;
}
@ -474,6 +470,7 @@ class MemoryManager{
}
/**
* @param mixed $from
* @param object[] $objects reference parameter
* @param int[] $refCounts reference parameter
*
@ -481,8 +478,10 @@ class MemoryManager{
* @phpstan-param array<string, int> $refCounts
* @phpstan-param-out array<string, object> $objects
* @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){
return "(error) NESTING LIMIT REACHED";
}

View File

@ -50,7 +50,7 @@ namespace pocketmine {
require_once __DIR__ . '/VersionInfo.php';
const MIN_PHP_VERSION = "8.0.0";
const MIN_PHP_VERSION = "8.1.0";
/**
* @param string $message
@ -122,8 +122,8 @@ namespace pocketmine {
if(substr_count($pthreads_version, ".") < 2){
$pthreads_version = "0.$pthreads_version";
}
if(version_compare($pthreads_version, "5.1.0") < 0 || version_compare($pthreads_version, "6.0.0") >= 0){
$messages[] = "pthreads ^5.0.0 is required, while you have $pthreads_version.";
if(version_compare($pthreads_version, "4.0.0") < 0 || version_compare($pthreads_version, "5.0.0") >= 0){
$messages[] = "pthreads ^4.0.0 is required, while you have $pthreads_version.";
}
}
@ -265,9 +265,6 @@ JIT_WARNING
exit(1);
}
}
if(extension_loaded('parallel')){
\parallel\bootstrap(\pocketmine\COMPOSER_AUTOLOADER_PATH);
}
ErrorToExceptionHandler::set();
@ -346,7 +343,7 @@ JIT_WARNING
if(ThreadManager::getInstance()->stopAll() > 0){
$logger->debug("Some threads could not be stopped, performing a force-kill");
Process::kill(Process::pid(), true);
Process::kill(Process::pid());
}
}while(false);

View File

@ -43,7 +43,6 @@ use pocketmine\event\player\PlayerCreationEvent;
use pocketmine\event\player\PlayerDataSaveEvent;
use pocketmine\event\player\PlayerLoginEvent;
use pocketmine\event\server\CommandEvent;
use pocketmine\event\server\DataPacketSendEvent;
use pocketmine\event\server\QueryRegenerateEvent;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\lang\Language;
@ -54,13 +53,19 @@ use pocketmine\network\mcpe\compression\CompressBatchPromise;
use pocketmine\network\mcpe\compression\CompressBatchTask;
use pocketmine\network\mcpe\compression\Compressor;
use pocketmine\network\mcpe\compression\ZlibCompressor;
use pocketmine\network\mcpe\convert\GlobalItemTypeDictionary;
use pocketmine\network\mcpe\encryption\EncryptionContext;
use pocketmine\network\mcpe\EntityEventBroadcaster;
use pocketmine\network\mcpe\NetworkBroadcastUtils;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\PacketBroadcaster;
use pocketmine\network\mcpe\protocol\ClientboundPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\serializer\PacketBatch;
use pocketmine\network\mcpe\protocol\serializer\PacketSerializerContext;
use pocketmine\network\mcpe\raklib\RakLibInterface;
use pocketmine\network\mcpe\StandardEntityEventBroadcaster;
use pocketmine\network\mcpe\StandardPacketBroadcaster;
use pocketmine\network\Network;
use pocketmine\network\NetworkInterfaceStartException;
use pocketmine\network\query\DedicatedQueryNetworkInterface;
@ -203,6 +208,8 @@ class Server{
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 DEFAULT_ASYNC_COMPRESSION_THRESHOLD = 10_000;
private static ?Server $instance = null;
private TimeTrackingSleeperHandler $tickSleeper;
@ -261,6 +268,7 @@ class Server{
private Network $network;
private bool $networkCompressionAsync = true;
private int $networkCompressionAsyncThreshold = self::DEFAULT_ASYNC_COMPRESSION_THRESHOLD;
private Language $language;
private bool $forceLanguage = false;
@ -491,7 +499,10 @@ class Server{
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);
$result = $this->getPlayerExact($name);
@ -580,7 +591,8 @@ class Server{
},
function() use ($playerPromiseResolver, $session) : void{
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();
}
@ -899,6 +911,10 @@ class Server{
ZlibCompressor::setInstance(new ZlibCompressor($netCompressionLevel, $netCompressionThreshold, ZlibCompressor::DEFAULT_MAX_DECOMPRESSION_SIZE));
$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);
@ -958,7 +974,7 @@ class Server{
$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);
@ -1038,6 +1054,11 @@ class Server{
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_defaultGameMode($this->getGamemode()->getTranslatableName())));
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
$this->logger->alert($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_obsolete_warning1("4.x", "5.0")));
$this->logger->alert($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_obsolete_warning2("4.x", "2023-09-01")));
$this->logger->alert($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_obsolete_warning3("https://github.com/pmmp/PocketMine-MP/issues/5784")));
$this->logger->info($this->getLanguage()->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));
$forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language);
@ -1165,10 +1186,18 @@ class Server{
return !$anyWorldFailedToLoad;
}
private function startupPrepareConnectableNetworkInterfaces(string $ip, int $port, bool $ipV6, bool $useQuery) : bool{
private function startupPrepareConnectableNetworkInterfaces(
string $ip,
int $port,
bool $ipV6,
bool $useQuery,
PacketBroadcaster $packetBroadcaster,
EntityEventBroadcaster $entityEventBroadcaster,
PacketSerializerContext $packetSerializerContext
) : bool{
$prettyIp = $ipV6 ? "[$ip]" : $ip;
try{
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6));
$rakLibRegistered = $this->network->registerInterface(new RakLibInterface($this, $ip, $port, $ipV6, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext));
}catch(NetworkInterfaceStartException $e){
$this->logger->emergency($this->language->translate(KnownTranslationFactory::pocketmine_server_networkStartFailed(
$ip,
@ -1194,11 +1223,15 @@ class Server{
private function startupPrepareNetworkInterfaces() : bool{
$useQuery = $this->configGroup->getConfigBool("enable-query", true);
$packetSerializerContext = new PacketSerializerContext(GlobalItemTypeDictionary::getInstance()->getDictionary());
$packetBroadcaster = new StandardPacketBroadcaster($this, $packetSerializerContext);
$entityEventBroadcaster = new StandardEntityEventBroadcaster($packetBroadcaster);
if(
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery) ||
!$this->startupPrepareConnectableNetworkInterfaces($this->getIp(), $this->getPort(), false, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext) ||
(
$this->configGroup->getConfigBool("enable-ipv6", true) &&
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery)
!$this->startupPrepareConnectableNetworkInterfaces($this->getIpV6(), $this->getPortV6(), true, $useQuery, $packetBroadcaster, $entityEventBroadcaster, $packetSerializerContext)
)
){
return false;
@ -1330,47 +1363,10 @@ class Server{
/**
* @param Player[] $players
* @param ClientboundPacket[] $packets
* @deprecated
*/
public function broadcastPackets(array $players, array $packets) : bool{
if(count($packets) === 0){
throw new \InvalidArgumentException("Cannot broadcast empty list of packets");
}
return Timings::$broadcastPackets->time(function() use ($players, $packets) : bool{
/** @var NetworkSession[] $recipients */
$recipients = [];
foreach($players as $player){
if($player->isConnected()){
$recipients[] = $player->getNetworkSession();
}
}
if(count($recipients) === 0){
return false;
}
$ev = new DataPacketSendEvent($recipients, $packets);
$ev->call();
if($ev->isCancelled()){
return false;
}
$recipients = $ev->getTargets();
$packets = $ev->getPackets();
/** @var PacketBroadcaster[] $broadcasters */
$broadcasters = [];
/** @var NetworkSession[][] $broadcasterTargets */
$broadcasterTargets = [];
foreach($recipients as $recipient){
$broadcaster = $recipient->getBroadcaster();
$broadcasters[spl_object_id($broadcaster)] = $broadcaster;
$broadcasterTargets[spl_object_id($broadcaster)][] = $recipient;
}
foreach($broadcasters as $broadcaster){
$broadcaster->broadcastPackets($broadcasterTargets[spl_object_id($broadcaster)], $packets);
}
return true;
});
return NetworkBroadcastUtils::broadcastPackets($players, $packets);
}
/**
@ -1391,7 +1387,7 @@ class Server{
}
$promise = new CompressBatchPromise();
if(!$sync){
if(!$sync && strlen($buffer) >= $this->networkCompressionAsyncThreshold){
$task = new CompressBatchTask($buffer, $promise, $compressor);
$this->asyncPool->submitTask($task);
}else{
@ -1450,7 +1446,7 @@ class Server{
private function forceShutdownExit() : void{
$this->forceShutdown();
Process::kill(Process::pid(), true);
Process::kill(Process::pid());
}
public function forceShutdown() : void{
@ -1518,7 +1514,7 @@ class Server{
}catch(\Throwable $e){
$this->logger->logException($e);
$this->logger->emergency("Crashed while crashing, killing process");
@Process::kill(Process::pid(), true);
@Process::kill(Process::pid());
}
}
@ -1531,7 +1527,7 @@ class Server{
* @param 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()){}
global $lastError;
@ -1672,7 +1668,7 @@ class Server{
echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL;
sleep($spacing);
}
@Process::kill(Process::pid(), true);
@Process::kill(Process::pid());
exit(1);
}

View File

@ -43,7 +43,12 @@ final class ServerConfigGroup{
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)){
$v = getopt("", ["$variable::"]);
if(isset($v[$variable])){

View File

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

View File

@ -24,22 +24,17 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\AnvilInventory;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\Fallable;
use pocketmine\block\utils\FallableTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\object\FallingBlock;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
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{
use FallableTrait;
@ -51,12 +46,21 @@ class Anvil extends Transparent implements Fallable{
private int $damage = self::UNDAMAGED;
protected function describeType(RuntimeDataDescriber $w) : void{
$w->boundedInt(2, self::UNDAMAGED, self::VERY_DAMAGED, $this->damage);
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing($this->facing) | ($this->damage << 2);
}
protected function describeState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
public function readStateFromData(int $id, int $stateMeta) : void{
$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; }
@ -81,7 +85,7 @@ class Anvil extends Transparent implements Fallable{
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){
$player->setCurrentWindow(new AnvilInventory($this->position));
}
@ -96,18 +100,7 @@ class Anvil extends Transparent implements Fallable{
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onHitGround(FallingBlock $blockEntity) : bool{
if(lcg_value() < 0.05 + (round($blockEntity->getFallDistance()) - 1) * 0.05){
if($this->damage !== self::VERY_DAMAGED){
$this->damage = $this->damage + 1;
}else{
return false;
}
}
return true;
}
public function getLandSound() : ?Sound{
return new AnvilFallSound();
public function tickFalling() : ?Block{
return null;
}
}

View File

@ -23,13 +23,12 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\StructureGrowEvent;
use pocketmine\item\Bamboo as ItemBamboo;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
@ -55,10 +54,18 @@ class Bamboo extends Transparent{
protected bool $ready = false;
protected int $leafSize = self::NO_LEAVES;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->boundedInt(2, self::NO_LEAVES, self::LARGE_LEAVES, $this->leafSize);
$w->bool($this->thick);
$w->bool($this->ready);
public function readStateFromData(int $id, int $stateMeta) : void{
$this->thick = ($stateMeta & BlockLegacyMetadata::BAMBOO_FLAG_THICK) !== 0;
$this->leafSize = BlockDataSerializer::readBoundedInt("leafSize", ($stateMeta >> BlockLegacyMetadata::BAMBOO_LEAF_SIZE_SHIFT) & BlockLegacyMetadata::BAMBOO_LEAF_SIZE_MASK, self::NO_LEAVES, self::LARGE_LEAVES);
$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; }
@ -121,11 +128,14 @@ class Bamboo extends Transparent{
}
private function canBeSupportedBy(Block $block) : bool{
//TODO: tags would be better for this
return
$block->getTypeId() === BlockTypeIds::GRAVEL ||
$block->hasTypeTag(BlockTypeTags::DIRT) ||
$block->hasTypeTag(BlockTypeTags::MUD) ||
$block->hasTypeTag(BlockTypeTags::SAND);
$block instanceof Dirt ||
$block instanceof Grass ||
$block instanceof Gravel ||
$block instanceof Sand ||
$block instanceof Mycelium ||
$block instanceof Podzol;
}
private function seekToTop() : Bamboo{
@ -137,7 +147,7 @@ class Bamboo extends Transparent{
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){
$top = $this->seekToTop();
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);
}
}
public function asItem() : Item{
return VanillaItems::BAMBOO();
}
}

View File

@ -23,23 +23,28 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\StructureGrowEvent;
use pocketmine\item\Bamboo as ItemBamboo;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class BambooSapling extends Flowable{
private bool $ready = false;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->bool($this->ready);
public function readStateFromData(int $id, int $stateMeta) : void{
$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; }
/** @return $this */
@ -49,11 +54,14 @@ final class BambooSapling extends Flowable{
}
private function canBeSupportedBy(Block $block) : bool{
//TODO: tags would be better for this
return
$block->getTypeId() === BlockTypeIds::GRAVEL ||
$block->hasTypeTag(BlockTypeTags::DIRT) ||
$block->hasTypeTag(BlockTypeTags::MUD) ||
$block->hasTypeTag(BlockTypeTags::SAND);
$block instanceof Dirt ||
$block instanceof Grass ||
$block instanceof Gravel ||
$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{
@ -63,7 +71,7 @@ final class BambooSapling extends Flowable{
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($this->grow($player)){
$item->pop();
@ -118,6 +126,6 @@ final class BambooSapling extends Flowable{
}
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\utils\AnyFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
@ -38,9 +38,17 @@ class Barrel extends Opaque{
protected bool $open = false;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->facing($this->facing);
$w->bool($this->open);
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeFacing($this->facing) | ($this->open ? BlockLegacyMetadata::BARREL_FLAG_OPEN : 0);
}
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{
@ -73,7 +81,7 @@ class Barrel extends Opaque{
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){
$barrel = $this->position->getWorld()->getTile($this->position);
if($barrel instanceof TileBarrel){

View File

@ -28,9 +28,9 @@ use pocketmine\block\utils\BannerPatternLayer;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SupportType;
use pocketmine\data\bedrock\DyeColorIdMap;
use pocketmine\item\Banner as ItemBanner;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
@ -48,20 +48,18 @@ abstract class BaseBanner extends Transparent{
*/
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();
parent::__construct($idInfo, $name, $typeInfo);
parent::__construct($idInfo, $name, $breakInfo);
}
public function readStateFromWorld() : Block{
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBanner){
$this->color = $tile->getBaseColor();
$this->setPatterns($tile->getPatterns());
}
return $this;
}
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{
$drop = $this->asItem();
if($drop instanceof ItemBanner && count($this->patterns) > 0){
@ -154,8 +156,4 @@ abstract class BaseBanner extends Transparent{
}
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\event\block\BlockDeathEvent;
use pocketmine\item\Item;
use function mt_rand;
abstract class BaseCoral extends Transparent{
use CoralTypeTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
parent::__construct($idInfo, $name, $typeInfo);
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
parent::__construct($idInfo, $name, $breakInfo);
$this->coralType = CoralType::TUBE();
}
public function onNearbyBlockChange() : void{
if(!$this->dead){
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, mt_rand(40, 200));
}
}
$world = $this->position->getWorld();
public function onScheduledUpdate() : void{
if(!$this->dead && !$this->isCoveredWithWater()){
$ev = new BlockDeathEvent($this, $this->setDead(true));
$ev->call();
if(!$ev->isCancelled()){
$this->position->getWorld()->setBlock($this->position, $ev->getNewState());
$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)
if(!$hasWater){
$ev = new BlockDeathEvent($this, (clone $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; }
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 []; }
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;
use pocketmine\block\tile\Sign as TileSign;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SignText;
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\item\Dye;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\TextFormat;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\DyeUseSound;
use pocketmine\world\sound\InkSacUseSound;
use function array_map;
use function assert;
use function strlen;
abstract class BaseSign extends Transparent{
use WoodTypeTrait;
protected SignText $text;
protected ?int $editorEntityRuntimeId = null;
/** @var \Closure() : Item */
private \Closure $asItemCallback;
/**
* @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);
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
parent::__construct($idInfo, $name, $breakInfo);
$this->text = new SignText();
$this->asItemCallback = $asItemCallback;
}
public function readStateFromWorld() : Block{
public function readStateFromWorld() : void{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileSign){
$this->text = $tile->getText();
$this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId();
}
return $this;
}
public function writeStateToWorld() : void{
@ -105,7 +85,7 @@ abstract class BaseSign extends Transparent{
abstract protected function getSupportingFace() : int;
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);
}
}
@ -117,53 +97,13 @@ abstract class BaseSign extends Transparent{
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
private function doSignChange(SignText $newText, Player $player, Item $item) : bool{
$ev = new SignChangeEvent($this, $player, $newText);
$ev->call();
if(!$ev->isCancelled()){
$this->text = $ev->getNewText();
$this->position->getWorld()->setBlock($this->position, $this);
$item->pop();
return true;
public function onPostPlace() : void{
$player = $this->editorEntityRuntimeId !== null ?
$this->position->getWorld()->getEntity($this->editorEntityRuntimeId) :
null;
if($player instanceof Player){
$player->openSignEditor($this->position);
}
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;
}
/**
* 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.
*
@ -202,14 +155,11 @@ abstract class BaseSign extends Transparent{
$ev->call();
if(!$ev->isCancelled()){
$this->setText($ev->getNewText());
$this->setEditorEntityRuntimeId(null);
$this->position->getWorld()->setBlock($this->position, $this);
return true;
}
return false;
}
public function asItem() : Item{
return ($this->asItemCallback)();
}
}

View File

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

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();
}
}

View File

@ -25,16 +25,16 @@ namespace pocketmine\block;
use pocketmine\block\tile\Bell as TileBell;
use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\projectile\Projectile;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\BellRingSound;
@ -43,14 +43,41 @@ final class Bell extends Transparent{
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();
parent::__construct($idInfo, $name, $typeInfo);
parent::__construct($idInfo, $name, $breakInfo);
}
protected function describeState(RuntimeDataDescriber $w) : void{
$w->bellAttachmentType($this->attachmentType);
$w->horizontalFacing($this->facing);
public function readStateFromData(int $id, int $stateMeta) : void{
$this->setFacing(BlockDataSerializer::readLegacyHorizontalFacing($stateMeta & 0x03));
$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{
@ -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){
$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);
return true;
}
@ -142,13 +176,6 @@ final class Bell extends Transparent{
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{
$world = $this->position->getWorld();
$world->addSound($this->position, new BellRingSound());
@ -157,15 +184,4 @@ final class Bell extends Transparent{
$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\Tile;
use pocketmine\block\utils\InvalidBlockStateException;
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\projectile\Projectile;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\item\Item;
use pocketmine\item\ItemBlock;
use pocketmine\item\ItemFactory;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
use pocketmine\world\format\Chunk;
use pocketmine\world\Position;
use pocketmine\world\World;
use function assert;
use function count;
use function get_class;
use function dechex;
use const PHP_INT_MAX;
class Block{
public const INTERNAL_STATE_DATA_BITS = 8;
public const INTERNAL_STATE_DATA_MASK = ~(~0 << self::INTERNAL_STATE_DATA_BITS);
public const INTERNAL_METADATA_BITS = 4;
public const INTERNAL_METADATA_MASK = ~(~0 << self::INTERNAL_METADATA_BITS);
protected BlockIdentifier $idInfo;
protected string $fallbackName;
protected BlockTypeInfo $typeInfo;
protected BlockBreakInfo $breakInfo;
protected Position $position;
/** @var AxisAlignedBB[]|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)
*/
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->fallbackName = $name;
$this->typeInfo = $typeInfo;
$this->breakInfo = $breakInfo;
$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
* tile type (if any).
* Returns an object containing information about how to identify and store this block type, such as its legacy
* numeric ID(s), tile type (if any), and legacy variant metadata.
*/
public function getIdInfo() : BlockIdentifier{
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,
* glass, etc.
* @deprecated
*
* This does **NOT** include information like facing, open/closed, powered/unpowered, colour, etc. This means that,
* for example, red wool and green wool have the same type ID.
*
* @see BlockTypeIds
* Returns the legacy numeric Minecraft block ID.
*/
public function getTypeId() : int{
return $this->idInfo->getBlockTypeId();
public function getId() : int{
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
* blocks in chunks at runtime.
*
* This usually encodes all properties of the block, such as facing, open/closed, powered/unpowered, colour, etc.
* 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()}.
* This ID can be used to later obtain a copy of this block using {@link BlockFactory::get()}.
*/
public function getStateId() : int{
return ($this->getTypeId() << self::INTERNAL_STATE_DATA_BITS) | $this->computeTypeAndStateData();
}
/**
* 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);
public function getFullId() : int{
return ($this->getId() << self::INTERNAL_METADATA_BITS) | $this->getMeta();
}
/**
@ -174,114 +120,44 @@ class Block{
* Type information such as colour, wood type, etc. is preserved.
*/
public function asItem() : Item{
return new ItemBlock($this);
}
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();
return ItemFactory::getInstance()->get(
$this->idInfo->getItemId(),
$this->idInfo->getVariant() | $this->writeStateToItemMeta()
);
}
/**
* @internal
*/
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.
* @deprecated
*
* 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.
* Returns the legacy Minecraft block meta value. This is a mixed-purpose value, which is used to store different
* things for different blocks.
*/
protected function describeType(RuntimeDataDescriber $w) : void{
//NOOP
public function getMeta() : int{
$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.
* Examples of suitable properties include facing, open/closed, powered/unpowered, on/off, and any other information
* 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.
* Returns a bitmask used to extract state bits from block metadata.
* This is used to remove unwanted information from the legacy meta value when getting the block as an item.
*/
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
}
@ -291,14 +167,9 @@ class Block{
*
* Clears any cached precomputed objects, such as bounding boxes. Remove any outdated precomputed things such as
* 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;
return $this;
}
/**
@ -309,11 +180,7 @@ class Block{
*/
public function writeStateToWorld() : void{
$world = $this->position->getWorld();
$chunk = $world->getOrLoadChunkAtPosition($this->position);
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());
$world->getOrLoadChunkAtPosition($this->position)->setFullBlock($this->position->x & Chunk::COORD_MASK, $this->position->y, $this->position->z & Chunk::COORD_MASK, $this->getFullId());
$tileType = $this->idInfo->getTileClass();
$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
*/
@ -388,15 +280,13 @@ class Block{
* Returns an object containing information about the destruction requirements of this block.
*/
public function getBreakInfo() : BlockBreakInfo{
return $this->typeInfo->getBreakInfo();
return $this->breakInfo;
}
/**
* 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();
if(($t = $world->getTile($this->position)) !== null){
$t->onBlockDestroyed();
@ -436,10 +326,8 @@ class Block{
/**
* 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;
}
@ -531,7 +419,7 @@ class Block{
* @return Item[]
*/
public function getDrops(Item $item) : array{
if($this->getBreakInfo()->isToolCompatible($item)){
if($this->breakInfo->isToolCompatible($item)){
if($this->isAffectedBySilkTouch() && $item->hasEnchantment(VanillaEnchantments::SILK_TOUCH())){
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.
*/
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;
}
@ -627,10 +515,6 @@ class Block{
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
* fire.
@ -720,7 +604,7 @@ class Block{
* @return string
*/
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;
}
/**
* 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.
* These are used for:

View File

@ -24,7 +24,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\item\ToolTier;
use function get_class;
class BlockBreakInfo{
@ -53,22 +52,6 @@ class BlockBreakInfo{
$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{
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
*/
public function __construct(
private int $blockTypeId,
private int $blockId,
private int $variant,
private ?int $itemId = null,
private ?string $tileClass = null
){
if($blockTypeId < 0){
throw new \InvalidArgumentException("Block type ID may not be negative");
}
if($tileClass !== null){
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

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;
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\utils\LeavesType;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\TreeType;
use pocketmine\block\utils\WoodType;
use pocketmine\item\VanillaItems;
use pocketmine\item\ItemIds;
use pocketmine\utils\AssumptionFailedError;
final class BlockLegacyIdHelper{
public static function getWoodenPlanksIdentifier(WoodType $type) : 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{
public static function getWoodenFloorSignIdentifier(TreeType $treeType) : BID{
switch($treeType->id()){
case WoodType::OAK()->id():
return [
new BID(Ids::OAK_SIGN, TileSign::class),
new BID(Ids::OAK_WALL_SIGN, TileSign::class),
fn() => VanillaItems::OAK_SIGN()
];
case WoodType::SPRUCE()->id():
return [
new BID(Ids::SPRUCE_SIGN, TileSign::class),
new BID(Ids::SPRUCE_WALL_SIGN, TileSign::class),
fn() => VanillaItems::SPRUCE_SIGN()
];
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()
];
case TreeType::OAK()->id():
return new BID(Ids::SIGN_POST, 0, ItemIds::SIGN, TileSign::class);
case TreeType::SPRUCE()->id():
return new BID(Ids::SPRUCE_STANDING_SIGN, 0, ItemIds::SPRUCE_SIGN, TileSign::class);
case TreeType::BIRCH()->id():
return new BID(Ids::BIRCH_STANDING_SIGN, 0, ItemIds::BIRCH_SIGN, TileSign::class);
case TreeType::JUNGLE()->id():
return new BID(Ids::JUNGLE_STANDING_SIGN, 0, ItemIds::JUNGLE_SIGN, TileSign::class);
case TreeType::ACACIA()->id():
return new BID(Ids::ACACIA_STANDING_SIGN,0, ItemIds::ACACIA_SIGN, TileSign::class);
case TreeType::DARK_OAK()->id():
return new BID(Ids::DARKOAK_STANDING_SIGN, 0, ItemIds::DARKOAK_SIGN, TileSign::class);
}
throw new AssumptionFailedError("Switch should cover all wood types");
}
public static function getWoodenTrapdoorIdentifier(WoodType $treeType) : BlockIdentifier{
return new BID(match($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_TRAPDOOR,
WoodType::SPRUCE()->id() => Ids::SPRUCE_TRAPDOOR,
WoodType::BIRCH()->id() => Ids::BIRCH_TRAPDOOR,
WoodType::JUNGLE()->id() => Ids::JUNGLE_TRAPDOOR,
WoodType::ACACIA()->id() => Ids::ACACIA_TRAPDOOR,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_TRAPDOOR,
WoodType::MANGROVE()->id() => Ids::MANGROVE_TRAPDOOR,
WoodType::CRIMSON()->id() => Ids::CRIMSON_TRAPDOOR,
WoodType::WARPED()->id() => Ids::WARPED_TRAPDOOR,
default => throw new AssumptionFailedError("All wood types should be covered")
});
public static function getWoodenWallSignIdentifier(TreeType $treeType) : BID{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BID(Ids::WALL_SIGN, 0, ItemIds::SIGN, TileSign::class);
case TreeType::SPRUCE()->id():
return new BID(Ids::SPRUCE_WALL_SIGN, 0, ItemIds::SPRUCE_SIGN, TileSign::class);
case TreeType::BIRCH()->id():
return new BID(Ids::BIRCH_WALL_SIGN, 0, ItemIds::BIRCH_SIGN, TileSign::class);
case TreeType::JUNGLE()->id():
return new BID(Ids::JUNGLE_WALL_SIGN, 0, ItemIds::JUNGLE_SIGN, TileSign::class);
case TreeType::ACACIA()->id():
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{
return new BID(match($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_BUTTON,
WoodType::SPRUCE()->id() => Ids::SPRUCE_BUTTON,
WoodType::BIRCH()->id() => Ids::BIRCH_BUTTON,
WoodType::JUNGLE()->id() => Ids::JUNGLE_BUTTON,
WoodType::ACACIA()->id() => Ids::ACACIA_BUTTON,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_BUTTON,
WoodType::MANGROVE()->id() => Ids::MANGROVE_BUTTON,
WoodType::CRIMSON()->id() => Ids::CRIMSON_BUTTON,
WoodType::WARPED()->id() => Ids::WARPED_BUTTON,
default => throw new AssumptionFailedError("All wood types should be covered")
});
public static function getWoodenTrapdoorIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::WOODEN_TRAPDOOR, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_TRAPDOOR, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_TRAPDOOR, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_TRAPDOOR, 0);
case TreeType::ACACIA()->id():
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{
return new BID(match($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_PRESSURE_PLATE,
WoodType::SPRUCE()->id() => Ids::SPRUCE_PRESSURE_PLATE,
WoodType::BIRCH()->id() => Ids::BIRCH_PRESSURE_PLATE,
WoodType::JUNGLE()->id() => Ids::JUNGLE_PRESSURE_PLATE,
WoodType::ACACIA()->id() => Ids::ACACIA_PRESSURE_PLATE,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_PRESSURE_PLATE,
WoodType::MANGROVE()->id() => Ids::MANGROVE_PRESSURE_PLATE,
WoodType::CRIMSON()->id() => Ids::CRIMSON_PRESSURE_PLATE,
WoodType::WARPED()->id() => Ids::WARPED_PRESSURE_PLATE,
default => throw new AssumptionFailedError("All wood types should be covered")
});
public static function getWoodenButtonIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::WOODEN_BUTTON, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_BUTTON, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_BUTTON, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_BUTTON, 0);
case TreeType::ACACIA()->id():
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{
return new BID(match($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_DOOR,
WoodType::SPRUCE()->id() => Ids::SPRUCE_DOOR,
WoodType::BIRCH()->id() => Ids::BIRCH_DOOR,
WoodType::JUNGLE()->id() => Ids::JUNGLE_DOOR,
WoodType::ACACIA()->id() => Ids::ACACIA_DOOR,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_DOOR,
WoodType::MANGROVE()->id() => Ids::MANGROVE_DOOR,
WoodType::CRIMSON()->id() => Ids::CRIMSON_DOOR,
WoodType::WARPED()->id() => Ids::WARPED_DOOR,
default => throw new AssumptionFailedError("All wood types should be covered")
});
public static function getWoodenPressurePlateIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::WOODEN_PRESSURE_PLATE, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_PRESSURE_PLATE, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_PRESSURE_PLATE, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_PRESSURE_PLATE, 0);
case TreeType::ACACIA()->id():
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{
return new BID(match($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_FENCE_GATE,
WoodType::SPRUCE()->id() => Ids::SPRUCE_FENCE_GATE,
WoodType::BIRCH()->id() => Ids::BIRCH_FENCE_GATE,
WoodType::JUNGLE()->id() => Ids::JUNGLE_FENCE_GATE,
WoodType::ACACIA()->id() => Ids::ACACIA_FENCE_GATE,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_FENCE_GATE,
WoodType::MANGROVE()->id() => Ids::MANGROVE_FENCE_GATE,
WoodType::CRIMSON()->id() => Ids::CRIMSON_FENCE_GATE,
WoodType::WARPED()->id() => Ids::WARPED_FENCE_GATE,
default => throw new AssumptionFailedError("All wood types should be covered")
});
public static function getWoodenDoorIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BID(Ids::OAK_DOOR_BLOCK, 0, ItemIds::OAK_DOOR);
case TreeType::SPRUCE()->id():
return new BID(Ids::SPRUCE_DOOR_BLOCK, 0, ItemIds::SPRUCE_DOOR);
case TreeType::BIRCH()->id():
return new BID(Ids::BIRCH_DOOR_BLOCK, 0, ItemIds::BIRCH_DOOR);
case TreeType::JUNGLE()->id():
return new BID(Ids::JUNGLE_DOOR_BLOCK, 0, ItemIds::JUNGLE_DOOR);
case TreeType::ACACIA()->id():
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{
return new BID(match($treeType->id()){
WoodType::OAK()->id() => Ids::OAK_STAIRS,
WoodType::SPRUCE()->id() => Ids::SPRUCE_STAIRS,
WoodType::BIRCH()->id() => Ids::BIRCH_STAIRS,
WoodType::JUNGLE()->id() => Ids::JUNGLE_STAIRS,
WoodType::ACACIA()->id() => Ids::ACACIA_STAIRS,
WoodType::DARK_OAK()->id() => Ids::DARK_OAK_STAIRS,
WoodType::MANGROVE()->id() => Ids::MANGROVE_STAIRS,
WoodType::CRIMSON()->id() => Ids::CRIMSON_STAIRS,
WoodType::WARPED()->id() => Ids::WARPED_STAIRS,
default => throw new AssumptionFailedError("All wood types should be covered")
});
public static function getWoodenFenceIdentifier(TreeType $treeType) : BlockIdentifier{
switch($treeType->id()){
case TreeType::OAK()->id():
return new BlockIdentifier(Ids::OAK_FENCE_GATE, 0);
case TreeType::SPRUCE()->id():
return new BlockIdentifier(Ids::SPRUCE_FENCE_GATE, 0);
case TreeType::BIRCH()->id():
return new BlockIdentifier(Ids::BIRCH_FENCE_GATE, 0);
case TreeType::JUNGLE()->id():
return new BlockIdentifier(Ids::JUNGLE_FENCE_GATE, 0);
case TreeType::ACACIA()->id():
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;
use pocketmine\block\utils\PillarRotationTrait;
use pocketmine\block\utils\PillarRotationInMetadataTrait;
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\utils\BrewingStandSlot;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
@ -43,8 +42,33 @@ class BrewingStand extends Transparent{
*/
protected array $slots = [];
protected function describeState(RuntimeDataDescriber $w) : void{
$w->brewingStandSlots($this->slots);
protected function writeStateToMeta() : int{
$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{
@ -94,7 +118,7 @@ class BrewingStand extends Transparent{
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){
$stand = $this->position->getWorld()->getTile($this->position);
if($stand instanceof TileBrewingStand && $stand->canOpenWith($item->getCustomName())){

View File

@ -24,7 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
@ -38,9 +38,18 @@ abstract class Button extends Flowable{
protected bool $pressed = false;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->facing($this->facing);
$w->bool($this->pressed);
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeFacing($this->facing) | ($this->pressed ? BlockLegacyMetadata::BUTTON_FLAG_POWERED : 0);
}
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; }
@ -61,7 +70,7 @@ abstract class Button extends Flowable{
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){
$this->pressed = true;
$world = $this->position->getWorld();

View File

@ -23,8 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
@ -41,8 +41,16 @@ class Cactus extends Transparent{
protected int $age = 0;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->boundedInt(4, 0, self::MAX_AGE, $this->age);
protected function writeStateToMeta() : int{
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; }
@ -78,13 +86,10 @@ class Cactus extends Transparent{
return true;
}
private function canBeSupportedBy(Block $block) : bool{
return $block->isSameType($this) || $block->hasTypeTag(BlockTypeTags::SAND);
}
public function onNearbyBlockChange() : void{
$down = $this->getSide(Facing::DOWN);
$world = $this->position->getWorld();
if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){
if($down->getId() !== BlockLegacyIds::SAND && !$down->isSameType($this)){
$world->useBreakOn($this->position);
}else{
foreach(Facing::HORIZONTAL as $side){
@ -110,7 +115,7 @@ class Cactus extends Transparent{
break;
}
$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->call();
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{
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){
if($this->getSide($side)->isSolid()){
return false;

View File

@ -23,21 +23,33 @@ declare(strict_types=1);
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\ItemBlock;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class Cake extends BaseCake{
class Cake extends Transparent implements FoodSource{
public const MAX_BITES = 6;
protected int $bites = 0;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->boundedInt(3, 0, self::MAX_BITES, $this->bites);
protected function writeStateToMeta() : int{
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; }
/** @return $this */
@ -63,27 +79,49 @@ class Cake extends BaseCake{
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof ItemBlock){
$block = $item->getBlock();
$resultBlock = null;
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;
}
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->getId() !== BlockLegacyIds::AIR){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
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->bites++;
if($clone->bites > self::MAX_BITES){
@ -91,4 +129,15 @@ class Cake extends BaseCake{
}
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;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\ColorInMetadataTrait;
use pocketmine\block\utils\DyeColor;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
@ -33,11 +33,11 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
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();
parent::__construct($idInfo, $name, $typeInfo);
parent::__construct($idInfo, $name, $breakInfo);
}
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{
$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);
}
@ -61,7 +61,7 @@ class Carpet extends Flowable{
}
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);
}
}

View File

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

View File

@ -1,44 +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\inventory\CartographyTableInventory;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
final class CartographyTable extends Opaque{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player !== null){
$player->setCurrentWindow(new CartographyTableInventory($this->position));
}
return true;
}
public function getFuelTime() : int{
return 300;
}
}

View File

@ -23,10 +23,23 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
class CarvedPumpkin extends Opaque{
use FacesOppositePlacingPlayerTrait;
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;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
@ -33,7 +35,19 @@ final class ChemistryTable extends Opaque{
use FacesOppositePlacingPlayerTrait;
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
return false;
}

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\tile\Chest as TileChest;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\ChestPairEvent;
use pocketmine\item\Item;
@ -36,7 +36,7 @@ use pocketmine\player\Player;
class Chest extends Transparent{
use FacesOppositePlacingPlayerTrait;
use HorizontalFacingTrait;
use NormalHorizontalFacingInMetadataTrait;
/**
* @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){
$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;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\block\utils\WoodType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\block\utils\TreeType;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
@ -46,9 +46,17 @@ class CocoaBlock extends Transparent{
protected int $age = 0;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->boundedInt(2, 0, self::MAX_AGE, $this->age);
protected function writeStateToMeta() : int{
return BlockDataSerializer::writeLegacyHorizontalFacing(Facing::opposite($this->facing)) | ($this->age << 2);
}
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; }
@ -81,7 +89,7 @@ class CocoaBlock extends Transparent{
}
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{
@ -93,7 +101,7 @@ class CocoaBlock extends Transparent{
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()){
$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();
}
}

View File

@ -23,14 +23,14 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\ColorInMetadataTrait;
use pocketmine\block\utils\DyeColor;
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();
parent::__construct($idInfo, $name, $typeInfo);
parent::__construct($idInfo, $name, $breakInfo);
}
}

View File

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

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,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;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\data\bedrock\CoralTypeIdMap;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
@ -31,6 +33,38 @@ use pocketmine\world\BlockTransaction;
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{
if(!$this->canBeSupportedBy($tx->fetchBlock($blockReplace->getPosition()->down()))){
return false;

View File

@ -25,6 +25,8 @@ namespace pocketmine\block;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\block\utils\InvalidBlockStateException;
use pocketmine\data\bedrock\CoralTypeIdMap;
use pocketmine\event\block\BlockDeathEvent;
use pocketmine\item\Item;
use function mt_rand;
@ -32,9 +34,30 @@ use function mt_rand;
final class CoralBlock extends Opaque{
use CoralTypeTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
public function __construct(BlockIdentifier $idInfo, string $name, BlockBreakInfo $breakInfo){
$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{
@ -55,7 +78,7 @@ final class CoralBlock extends Opaque{
}
}
if(!$hasWater){
$ev = new BlockDeathEvent($this, $this->setDead(true));
$ev = new BlockDeathEvent($this, (clone $this)->setDead(true));
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $ev->getNewState());
@ -65,7 +88,7 @@ final class CoralBlock extends Opaque{
}
public function getDropsForCompatibleTool(Item $item) : array{
return [$this->setDead(true)->asItem()];
return [(clone $this)->setDead(true)->asItem()];
}
public function isAffectedBySilkTouch() : bool{

View File

@ -30,7 +30,7 @@ use pocketmine\player\Player;
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){
$player->setCurrentWindow(new CraftingTableInventory($this->position));
}

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
@ -38,8 +38,16 @@ abstract class Crops extends Flowable{
protected int $age = 0;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->boundedInt(3, 0, self::MAX_AGE, $this->age);
protected function writeStateToMeta() : int{
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; }
@ -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{
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 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){
$block = clone $this;
$block->age += mt_rand(2, 5);
@ -83,7 +91,7 @@ abstract class Crops extends Flowable{
}
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);
}
}

View File

@ -24,8 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
@ -39,11 +39,30 @@ use const M_PI;
class DaylightSensor extends Transparent{
use AnalogRedstoneSignalEmitterTrait;
protected BlockIdentifierFlattened $idInfoFlattened;
protected bool $inverted = false;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->boundedInt(4, 0, 15, $this->signalStrength);
$w->bool($this->inverted);
public function __construct(BlockIdentifierFlattened $idInfo, string $name, BlockBreakInfo $breakInfo){
$this->idInfoFlattened = $idInfo;
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{
@ -73,7 +92,7 @@ class DaylightSensor extends Transparent{
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->signalStrength = $this->recalculateSignalStrength();
$this->position->getWorld()->setBlock($this->position, $this);

View File

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

View File

@ -23,16 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
class DetectorRail extends StraightOnlyRail{
protected bool $activated = false;
protected function describeState(RuntimeDataDescriber $w) : void{
parent::describeState($w);
$w->bool($this->activated);
}
public function isActivated() : bool{ return $this->activated; }
/** @return $this */
@ -40,5 +33,19 @@ class DetectorRail extends StraightOnlyRail{
$this->activated = $activated;
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
}

View File

@ -23,67 +23,50 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\DirtType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Fertilizer;
use pocketmine\item\Hoe;
use pocketmine\item\Item;
use pocketmine\item\Potion;
use pocketmine\item\PotionType;
use pocketmine\item\SplashPotion;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\ItemUseOnBlockSound;
use pocketmine\world\sound\WaterSplashSound;
class Dirt extends Opaque{
protected DirtType $dirtType;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){
$this->dirtType = DirtType::NORMAL();
parent::__construct($idInfo, $name, $typeInfo);
protected bool $coarse = false;
public function readStateFromData(int $id, int $stateMeta) : void{
$this->coarse = ($stateMeta & BlockLegacyMetadata::DIRT_FLAG_COARSE) !== 0;
}
protected function describeType(RuntimeDataDescriber $w) : void{
$w->dirtType($this->dirtType);
protected function writeStateToMeta() : int{
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 */
public function setDirtType(DirtType $dirtType) : self{
$this->dirtType = $dirtType;
public function setCoarse(bool $coarse) : self{
$this->coarse = $coarse;
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
$world = $this->position->getWorld();
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face === Facing::UP && $item instanceof Hoe){
$item->applyDamage(1);
$newBlock = $this->dirtType->equals(DirtType::NORMAL()) ? VanillaBlocks::FARMLAND() : VanillaBlocks::DIRT();
$center = $this->position->add(0.5, 0.5, 0.5);
$world->addSound($center, new ItemUseOnBlockSound($newBlock));
$newBlock = $this->coarse ? VanillaBlocks::DIRT() : VanillaBlocks::FARMLAND();
$world = $this->position->getWorld();
$world->addSound($this->position->add(0.5, 0.5, 0.5), new ItemUseOnBlockSound($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;
}

View File

@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockDataSerializer;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
@ -36,19 +37,38 @@ use pocketmine\world\sound\DoorSound;
class Door extends Transparent{
use HorizontalFacingTrait;
use PoweredByRedstoneTrait;
protected bool $top = false;
protected bool $hingeRight = false;
protected bool $open = false;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->bool($this->top);
$w->bool($this->hingeRight);
$w->bool($this->open);
protected function writeStateToMeta() : int{
if($this->top){
return BlockLegacyMetadata::DOOR_FLAG_TOP |
($this->hingeRight ? BlockLegacyMetadata::DOOR_TOP_FLAG_RIGHT : 0) |
($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();
//copy door properties from other half
@ -59,10 +79,9 @@ class Door extends Transparent{
$this->open = $other->open;
}else{
$this->hingeRight = $other->hingeRight;
$this->powered = $other->powered;
}
}
return $this;
}
public function isTop() : bool{ return $this->top; }
@ -140,7 +159,7 @@ class Door extends Transparent{
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;
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
@ -31,10 +30,19 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
class DoublePlant extends Flowable{
protected bool $top = false;
protected function describeState(RuntimeDataDescriber $w) : void{
$w->bool($this->top);
protected function writeStateToMeta() : int{
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; }
@ -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{
$down = $blockReplace->getSide(Facing::DOWN);
if($down->hasTypeTag(BlockTypeTags::DIRT) && $blockReplace->getSide(Facing::UP)->canBeReplaced()){
$id = $blockReplace->getSide(Facing::DOWN)->getId();
if(($id === BlockLegacyIds::GRASS || $id === BlockLegacyIds::DIRT) && $blockReplace->getSide(Facing::UP)->canBeReplaced()){
$top = clone $this;
$top->top = true;
$tx->addBlock($blockReplace->position, $this)->addBlock($blockReplace->position->getSide(Facing::UP), $top);
@ -71,8 +79,7 @@ class DoublePlant extends Flowable{
}
public function onNearbyBlockChange() : void{
$down = $this->getSide(Facing::DOWN);
if(!$this->isValidHalfPlant() || (!$this->top && !$down->hasTypeTag(BlockTypeTags::DIRT) && !$down->hasTypeTag(BlockTypeTags::MUD))){
if(!$this->isValidHalfPlant() || (!$this->top && $this->getSide(Facing::DOWN)->isTransparent())){
$this->position->getWorld()->useBreakOn($this->position);
}
}

View File

@ -44,7 +44,11 @@ class DragonEgg extends Transparent implements Fallable{
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();
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;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\ColorInMetadataTrait;
use pocketmine\block\utils\DyeColor;
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();
parent::__construct($idInfo, $name, $typeInfo);
parent::__construct($idInfo, $name, $breakInfo);
}
}

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