Compare commits

...

790 Commits

Author SHA1 Message Date
47dac7244f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17567495443
2025-09-09 00:02:55 +00:00
9fcb16b6c1 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17567495443
2025-09-09 00:02:53 +00:00
ce90835c7b Bump build/php from b839e52 to 1d9cda6 (#6796) 2025-09-08 10:21:54 +00:00
1133d49c92 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17507094833
2025-09-06 00:02:55 +00:00
2f2c53067b Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17507094833
2025-09-06 00:02:53 +00:00
dc04992ba9 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into stable 2025-09-05 19:25:31 +01:00
bddab47ee8 Bump build/php from ce1b095 to b839e52 (#6795) 2025-09-05 10:32:17 +00:00
66b8f2f160 Scrub PHPStan baselines 2025-09-04 23:35:57 +01:00
1bc7cf340d Merge branch 'stable' into minor-next 2025-09-04 23:30:09 +01:00
3411103e11 Remove dead PHPStan ignores 2025-09-04 23:29:55 +01:00
25e937715e Merge branch 'minor-next' into major-next 2025-09-04 22:11:36 +01:00
26cd5c471c Merge branch 'stable' into minor-next 2025-09-04 22:03:22 +01:00
1868536916 Add PHP 8.4 to test matrix 2025-09-04 21:58:12 +01:00
e276fed3c8 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17449184125
2025-09-04 00:02:51 +00:00
82323cc7ca Make CombinedInventoryProxy listener a bit less nasty 2025-09-03 18:18:03 +01:00
6610a19640 CombinedInventoryProxy for double chests is now ephemeral
previously we had to make sure that the two chests shared the same instance, so that the viewer
lists would be properly updated. Now, instead, we can just combine the viewer lists of the individual
chests, which is a lot cleaner.
2025-09-03 17:34:37 +01:00
f91f5bff9b Fix merge error 2025-09-03 17:11:37 +01:00
c61829ee19 Rework double chest handling, move logic to the Block 2025-09-03 16:42:44 +01:00
3999a1f9f4 Fix sneaking hitbox height (#6771) 2025-09-03 08:53:32 +02:00
344d0af01b Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17418990148
2025-09-03 00:02:54 +00:00
925b34e5c6 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17418990148
2025-09-03 00:02:53 +00:00
86c9adca7f Fix minor-next merge error 2025-09-02 19:29:14 +01:00
644f73aa84 Separate inventory holder info from container & player inventories (#6533)
This PR breaks the cyclic dependency between `Inventory` and its holder, which unblocks a lot of new developments.

### Related issues & PRs
- Fixes #5033
- Removes a blocker for #6147 (which in turn means that async tasks will eventually be able to work with tiles)
- Removes a blocker for #2684

## Changes
### API changes
- `Player->getCurrentWindow()` now returns `?InventoryWindow` instead of `?Inventory`
- `Player->setCurrentWindow()` now accepts `?InventoryWindow` instead of `?Inventory`
- `InventoryWindow` introduced, which is created for each player viewing the inventory, provides decorative information like holder info for `InventoryTransactionEvent`, and is destroyed when the window is closed, eliminating cyclic references
- Added:
  - `player\InventoryWindow`
  - `player\PlayerInventoryWindow` - wraps all permanent inventories of Player with type info for transactions
  - `inventory\Hotbar` - replaces all hotbar usages in `PlayerInventory`
  - `Human->getHotbar()`
  - `Human->getMainHandItem()`, `Human->setMainHandItem()`, `Human->getOffHandItem()`, `Human->setOffHandItem()`
  - `block\utils\AnimatedContainerLike` & `block\utils\AnimatedContainerLikeTrait` (for chests, shulkerboxes, etc)
  - `block\utils\Container` & `block\utils\ContainerTrait` for blocks containing items (chests, etc)
  - `block\utils\MenuAccessor` implemented by all blocks that can open inventory menus
  - `block\utils\MenuAccessorTrait` used by blocks with menus but without inventories (anvils, crafting tables etc)
- Removed:
  - `inventory\DelegateInventory` (only used for ender chests)
  - `inventory\PlayerInventory`,
  - `inventory\PlayerOffHandInventory`,
  - `inventory\PlayerCraftingInventory`,
  - `inventory\PlayerCursorInventory` - these have all been internally replaced by `SimpleInventory` & they will appear as `PlayerInventoryWindow` in transactions (check `getType()` against the `PlayerInventoryWindow::TYPE_*` constants to identify them)
  - `block\inventory\AnimatedBlockInventoryTrait`, (blocks now handle this logic directly using `AnimatedContainer` and `AnimatedContainerTrait`)
  - `block\inventory\BlockInventoryTrait`,
  - `block\inventory\BlockInventory`
- Most `BlockInventory` classes have been transitioned to `InventoryWindow` wrappers
- Tiles now all use `SimpleInventory` internally (no cyclic references) except for `Chest` (which uses `CombinedInventory`, without holder info)
- `InventoryOpenEvent` and `InventoryCloseEvent` now provide `InventoryWindow` instead of `Inventory` (to provide type information)
- `InventoryTransaction` and `SlotChangeAction` now provide `InventoryWindow` instead of `Inventory`
- Renamed `TransactionBuilderInventory` to `SlotChangeActionBuilder`
- `TransactionBuilderInventory->getBuilder()` now accepts `InventoryWindow` instead of `Inventory`
- `DoubleChestInventory` superseded by `CombinedInventory` - this new class allows combining any number of inventories behind a single object; mainly used for double chests but plugins could use it to do lots of fun things

### Impacts to plugins
Plugins can now do the following:
```php
$block = $world->getBlockAt($x, $y, $z);
if($block instanceof MenuAccessor){
    $block->openToUnchecked($player);
}
```
As compared to the old way:
```php
$tile = $world->getTileAt($x, $y, $z);
if($tile instanceof Container){
    $player->setCurrentWindow($tile->getInventory());
}
```

#### Advantages
- No tile access needed
- Works for menu blocks without inventories as well as container blocks
- Less code

### Behavioural changes
Inventories no longer keep permanent cyclic references to their holders.

## Backwards compatibility
This makes significant BC breaks. However, all changes are able to be adapted to and the same amount of information is present on all APIs and events.

## Follow-up
- Implement #6147 
- Support inventory inheritance when copying blocks from one position to another
2025-09-02 19:23:16 +01:00
fa5cc3301c Strip unnecessary NBT from network items (#6790)
TypeConverter: Strip unnecessary NBT from clientbound items
Item containers like shulker boxes, or chests with block entity data obtained with ctrl+middle click, will often have extremely large NBT payloads.
This problem gets exponentially worse in cases where it's possible to nest inventories, as in #4665.

We can't easily address this at the core level, because tiles are not able to exist within items (due to position requirement)
so we don't have a good way to avoid this useless NBT in the first place. However, we can strip it before the item is sent to
the client, which dramatically reduces the network costs of such items, as well as removing any reason the client could have
to send such enormous items to the server.

A fully loaded shulker box with written books now takes only 5-6 KB on the wire instead of ~1 MB, which is a substantial improvement.

Dealing with this in a less hacky way is currently blocked on #6147.
2025-09-02 18:36:00 +01:00
9a0a8a55b1 Bump shivammathur/setup-php in the github-actions group (#6787) 2025-09-02 13:17:41 +00:00
702733bdde Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17389426542
2025-09-02 00:02:59 +00:00
b2d0be5b75 Support editing the back side of signs (#6774)
* Deprecate BaseSign get/set/updateText(), add get/set/updateFaceText() which accepts true/false for front/back
* add isFrontFace() to SignChangeEvent
* add optional frontFace to Player::openSignEditor()
* add BaseSign::getFacingDegrees() and getHitboxCenter() which need to be implemented by subclasses
2025-09-01 17:15:29 +01:00
77ce07d065 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17364003235
2025-09-01 00:03:51 +00:00
d3c36e6287 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17364003235
2025-09-01 00:03:50 +00:00
e569cc3275 stfu 2025-08-31 21:47:49 +01:00
c931437a30 InventoryTransaction: Remove action shuffling
we used to have this to prevent dependence on client ordering, and make ordering consistently not work.
However, since the introduction of the ItemStackRequest protocol, we don't expect to see client actions
in the wrong order anymore, so this shouldn't be needed anymore.

closes #6701
2025-08-31 21:45:55 +01:00
09cc76ae2b 5.33.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/17351431906
2025-08-31 02:28:17 +00:00
a540de1e3c Prepare 5.33.1 patch release (#6784) 2025-08-31 03:27:21 +01:00
9eee1a9a6e Banner: don't bail on missing type tags
we didn't set these prior to 5.33.0, so these won't be present on older worlds.
2025-08-31 03:22:58 +01:00
9a9506b793 Upgrade CallbackValidator
closes #6343
2025-08-30 19:23:38 +01:00
06b48d97e9 Fix merge error 2025-08-30 19:01:14 +01:00
851ac29f71 CS 2025-08-30 18:56:56 +01:00
de7dcf114f Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into major-next 2025-08-30 18:51:15 +01:00
dca9d3a010 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17346805858
2025-08-30 17:49:04 +00:00
f673159471 5.33.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/17346780638
2025-08-30 17:46:07 +00:00
831c5a0464 Merge pull request #6783 from pmmp/r5.33.0
Release 5.33.0
2025-08-30 18:45:11 +01:00
5c363965f0 Fix build date
we really need a better way to deal with this
2025-08-30 18:43:18 +01:00
95679b5a29 Update BedrockData and some transient deps 2025-08-30 18:36:42 +01:00
4e82482a80 Use generic enumSet() for blocks with facing flags 2025-08-30 18:11:24 +01:00
e87e6cf19f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17336647491
2025-08-30 00:02:48 +00:00
9310c46ea1 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17336647491
2025-08-30 00:02:47 +00:00
8dc4371385 Enums for rail shapes, sort of
this makes the API more sane, although the internals will need to be rewritten at some point in the future.
2025-08-29 23:33:52 +01:00
7449ad5637 tidy 2025-08-29 23:12:58 +01:00
6aaf6b336a Make an enum for horizontal facing blocks
awkward that the interface is also called HorizontalFacing, so I had to improvise for the naming
2025-08-29 23:11:17 +01:00
6f6b23d4e4 Integrate dev-major-next version of pocketmine/math
this is a reduced version compared to the original, due to the difficulty of getting rid of Facing values internally.
2025-08-29 21:47:20 +01:00
97027db70a Merge branch 'minor-next' into major-next 2025-08-29 20:56:59 +01:00
f1b1e1977e Harden validation for server auth block breaking 2025-08-29 20:37:29 +01:00
23d612f1af Suggested additions 2025-08-29 18:49:08 +01:00
8f7e16a9ad Prepare 5.33.0 release 2025-08-29 14:11:50 +01:00
beaedc3627 Tidy up in block properties aisle 2025-08-29 13:07:09 +01:00
48ba334218 CS again :< 2025-08-29 12:33:50 +01:00
0be15a7403 Rename MultiFacing -> MultiAnyFacing
to match the trait name
2025-08-29 12:33:04 +01:00
2404d63b1f Ageable: added getMaxAge()
we'll probably need this...
2025-08-29 12:24:24 +01:00
aae88c5c26 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17310812886
2025-08-29 00:02:52 +00:00
dd9030f1f5 tools/generate-bedrock-data-from-packets: generate less noise for items
if we have only a name (the majority case), we can just return the name directly instead of an object.
this massively reduces the amount of noise in the files as seen in pmmp/BedrockData@f814036229
2025-08-28 21:15:09 +01:00
24795eef0e Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17223908234
2025-08-26 00:03:10 +00:00
de234d1f38 Improved placement logic 2025-08-26 00:10:50 +01:00
db54c481aa Fixed hanging signs placement criteria (#6775) 2025-08-25 23:27:17 +01:00
ac2c07c3fe Added a space after hanging sign wood type (#6776) 2025-08-25 17:00:41 +01:00
ec56d65bcc Fix BC break in BaseBanner 2025-08-25 02:17:45 +01:00
c548923116 ... 2025-08-25 02:16:38 +01:00
4a2c7dc684 Apparently hanging signs are self supporting 2025-08-25 02:15:24 +01:00
f04c458e54 Merge branch 'stable' into minor-next 2025-08-25 01:49:19 +01:00
5c0a109f18 Sign: Strip trailing newlines from text blobs
fixes sign editor always putting the cursor on the last line when right-clicking to edit
2025-08-25 01:48:29 +01:00
1ebd7d3960 Remove unused deprecated stuff 2025-08-24 23:29:55 +01:00
36211a96c1 Strip deprecated leftovers from #6769 2025-08-24 23:24:38 +01:00
e8eda19ae5 Merge remote-tracking branch 'origin/minor-next' into major-next 2025-08-24 23:18:21 +01:00
31f6f5d252 CS again 2025-08-24 20:13:15 +01:00
0e498720bd Regenerate phpstan-bugs baseline 2025-08-24 20:10:34 +01:00
00d6171463 Implement hanging signs 2025-08-24 20:07:59 +01:00
be90c6c399 World: trigger readStateFromWorld on tile blocks immediately on load
this ensures that the state IDs reflect the actual PM block type, which would probably
be important for a bunch of different async things.
2025-08-24 17:01:59 +01:00
17ecf11a1b Remove stupid thing PhpStorm keeps doing 2025-08-24 16:49:49 +01:00
93e33dad8e tidy CS 2025-08-24 16:42:05 +01:00
4cdf064344 VanillaBlockMappings: Use some model mappings
this way there are some minor symmetry benefits, and the only asymmetric parts are the code that selects which model to use.

it also has the added benefit of removing some duplicated code paths (e.g. now it's possible to get rid of readUnitEnum() and such).
2025-08-24 16:37:42 +01:00
5bf0cbec87 ... 2025-08-24 15:39:23 +01:00
ef53676a59 Fix unit tests 2025-08-24 15:38:07 +01:00
8f9478e82f Illager banners finally working
closes #2951
2025-08-24 15:31:10 +01:00
7c521b456e Unify block serializers (#6769)
This has several advantages:

    Easier to implement new blocks (one less file to modify)
    Easier to adjust serialization of existing blocks
    Guaranteed consistency between serializers and deserializers
    Potentially, exposes more metadata for programmatic analysis, instead of having everything baked inside opaque Closures

There are some exceptions which still use the old approach: big dripleaf, cauldrons, mushroom stems, and pitcher crops. These all have multiple PM block types for a single ID, with relatively complex logic to select which to use. These weren't worth the effort to unify due to their small number. I may revisit this in the future, but I already spent a lot of brainpower on it.
2025-08-24 14:12:18 +01:00
6d5c46b091 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17168505072
2025-08-23 00:03:09 +00:00
47140cb8d7 RedstoneLamp: implement Lightable, shimmed to powered 2025-08-22 18:27:32 +01:00
e824266457 ChiseledBookshelf: add setSlots() 2025-08-22 18:27:06 +01:00
4e7077d169 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17084719293
2025-08-20 00:03:16 +00:00
2bb78f2a94 Fixed Furnace not implementing HorizontalFacing
looks like this was missed in #6639
I checked all other uses of HorizontalFacingTrait and FacesOppositePlacingPlayerTrait and this seems to be the only one.
2025-08-20 00:58:57 +01:00
237b304ef9 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17027521569
2025-08-18 00:03:20 +00:00
547544b5b4 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2025-08-17 15:25:57 +01:00
eea4f40138 BlockStateToObjectDeserializer: Remove duplicated CHISELED_COPPER registration
allowing overriding of serializers by the same method as first registration was a mistake...
2025-08-17 15:24:40 +01:00
fc3f3d62f1 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17001748601
2025-08-16 00:03:11 +00:00
237ac0f802 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17001748601
2025-08-16 00:03:09 +00:00
431790a319 Additional specialisation for colored blocks
this reduces boilerplate even further
2025-08-15 22:24:27 +01:00
c0fad353a2 missed one
sadly glazed_terracotta had to be special
2025-08-15 22:09:54 +01:00
e89523ce66 First look at flattened ID specialisation for block serializers
in the future we should be able to unify these, similarly to simple mappings.
unifying blocks with states will, however, be considerably more work.

only color benefits from this so far
2025-08-15 22:02:12 +01:00
1e8612cfc8 BlockObjectToStateSerializer: Avoid unnecessary Writer and Closure (#6759)
---------

Co-authored-by: Dylan K. Taylor <dktapps@pmmp.io>
2025-08-15 20:39:13 +01:00
cb7a562c8b Bump the github-actions group across 1 directory with 2 updates (#6767) 2025-08-15 00:17:24 +00:00
5ee081fbb1 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16979483636
2025-08-15 00:03:09 +00:00
edb8dcbe90 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16979483636
2025-08-15 00:03:08 +00:00
f633416f05 5.32.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/16962847004
2025-08-14 10:38:22 +00:00
442049d564 Prepare 5.32.1 release (#6766) 2025-08-14 11:37:24 +01:00
b03804d1eb Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16923820104
2025-08-13 00:03:17 +00:00
cce55e8939 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16923820104
2025-08-13 00:03:15 +00:00
e375437439 ResourcePacksPacketHandler: harden checks for client responses 2025-08-12 20:11:35 +01:00
c417ecd30d NetworkSession: Abort packet processing if handling triggered a disconnection
this shows up when requesting invalid data during resource pack handling, for example
2025-08-12 18:38:24 +01:00
cd6199ad62 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16867858213
2025-08-11 00:03:30 +00:00
1f87c67e37 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16867858213
2025-08-11 00:03:28 +00:00
11612ed0e2 Fixed content log warning about recipe with missing ID 2025-08-11 00:49:37 +01:00
12f404b20d Merge branch 'minor-next' into major-next 2025-08-08 01:09:17 +01:00
959fd7e5e6 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16791576698
2025-08-07 00:03:34 +00:00
0b9e680753 Fix GitHub release trigger actions borked
https://github.com/actions/runner/issues/2788
2025-08-06 17:15:21 +01:00
275fdc4280 5.32.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/16781699267
2025-08-06 15:42:50 +00:00
173b685b02 Bedrock 1.21.100 (#6760)
---------

Co-authored-by: Dylan T. <dktapps@pmmp.io>
2025-08-06 16:41:44 +01:00
89d18f929f RakLibServer: fixed deadlock on thread crash
synchronized block -> getCrashInfo -> join -> synchronized on the same
context on the child thread -> deadlock

instead we check for isTerminated and then get the crash info outside
of the synchronized block.
2025-08-06 15:49:52 +01:00
c65f740ce5 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16710901339
2025-08-04 00:03:46 +00:00
5139800e13 BlockStateUpgrader: All but removed dependency on BlockStateData 2025-08-03 15:47:12 +01:00
e630fc2dd6 Merge remote-tracking branch 'origin/minor-next' into major-next 2025-07-31 13:00:12 +01:00
cc17e68072 Add blocks interfaces for commons properties (#6639) 2025-07-31 08:48:47 +02:00
5bfa02716d Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16636416829
2025-07-31 00:03:30 +00:00
a83c62a4a2 readme: Stop showing random PR statuses on CI badge 2025-07-30 19:08:29 +01:00
4a3a78f11a Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16610111309
2025-07-30 00:03:37 +00:00
40ea6dd30d Bump phpstan/phpstan-strict-rules in the development-patch-updates group (#6758) 2025-07-29 09:26:25 +00:00
866df55edf Bump ramsey/uuid from 4.8.1 to 4.9.0 (#6748) 2025-07-29 09:25:19 +00:00
79e3f2b281 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16533775916
2025-07-26 00:03:00 +00:00
d41f1b2889 World: avoid hammering the disk looking for known ungenerated chunks
closes #6679

judging by the debug logs, this actually happens a lot during initial world generation,
which I suppose isn't that surprising.
2025-07-25 18:01:02 +01:00
7fbd868bc1 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16484425188
2025-07-24 00:03:17 +00:00
051671df50 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16484425188
2025-07-24 00:03:16 +00:00
4047cbaafe Bump phpstan/phpstan-strict-rules in the development-patch-updates group (#6756) 2025-07-23 12:07:07 +00:00
c02feba056 Merge remote-tracking branch 'origin/minor-next' into major-next 2025-07-10 01:58:34 +01:00
0977f0db7d Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16144129050
2025-07-08 13:08:27 +00:00
a1d74b5710 5.31.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/16143550499
2025-07-08 12:43:11 +00:00
50e15db9ac Prepare 5.31.0 release (#6752) 2025-07-08 13:41:59 +01:00
a3efaad328 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16012796137
2025-07-02 16:00:27 +00:00
55777d20c3 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16012796137
2025-07-02 00:02:55 +00:00
f1f6e796a4 Bump the github-actions group with 2 updates (#6749) 2025-07-01 10:28:28 +00:00
98f0417611 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15889715513
2025-06-26 00:03:07 +00:00
6e861afd9e Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15889715513
2025-06-26 00:03:06 +00:00
7ea0f2ff43 copilot-setup-steps: also add extension stubs 2025-06-26 00:14:34 +01:00
6dbd4282cb fix cache key 2025-06-26 00:12:12 +01:00
3176e7549e woops 2025-06-26 00:11:26 +01:00
92c3ce7f02 Create copilot-setup-steps.yml 2025-06-26 00:10:46 +01:00
3a5432b316 Bump build/php from 1549433 to ce1b095 (#6741) 2025-06-25 00:16:12 +00:00
afcd6b4e12 Merge remote-tracking branch 'origin/minor-next' into major-next 2025-06-25 01:07:16 +01:00
45e350ddf7 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15864040154
2025-06-25 00:02:58 +00:00
40a3ee68dd fix typo in changelog (#6745) 2025-06-24 13:35:32 +01:00
7082522509 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15837783229
2025-06-24 00:03:00 +00:00
e415518435 5.30.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15834488047
2025-06-23 20:31:58 +00:00
cb508f4382 Release 5.30.1 (#6744) 2025-06-23 23:30:48 +03:00
177fa76434 Disable client-side locator bar (#6743)
Without a propper server-side implementation, it just a mess of white dots of nearby players
2025-06-23 14:57:33 -05:00
2a97b4294d Fixed held block placement after respawn anchor explosion (#6742) 2025-06-23 16:59:40 +01:00
68126b308a Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15800888918
2025-06-22 00:03:38 +00:00
258923cc78 World: verify blockstate IDs in setChunk()
I think I've finally traced the source of these problems back to BuilderTools setting bad values in async tasks :)
2025-06-21 23:05:51 +01:00
e4b6f96535 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15789835501
2025-06-21 00:02:58 +00:00
04494e845c EntityExplodeEvent: Fixed accidental BC break introduced by #6646
thanks @Yexeed
2025-06-20 15:26:42 +01:00
f8ed7efb3f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15746137301
2025-06-19 00:03:12 +00:00
0e511ff783 smh 2025-06-18 21:55:53 +01:00
6826420876 5.30.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15743323722
2025-06-18 20:49:31 +00:00
f0161c84b9 Merge pull request #6737 from pmmp/r5.30.0
5.30.0
2025-06-18 21:48:30 +01:00
3643d3aeb8 Ready 5.30.0 release 2025-06-18 20:42:10 +01:00
6340d12881 Merge branch 'minor-next' into major-next 2025-06-18 19:56:54 +01:00
a662510cca Merge remote-tracking branch 'origin/stable' into minor-next 2025-06-18 19:56:02 +01:00
670d3fb997 Mention developer team in draft release notification 2025-06-18 19:29:28 +01:00
8843b1b568 5.29.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15720776704
2025-06-18 00:16:13 +00:00
9c71f4fc1c Assemble 1.21.90 (#6736) 2025-06-18 01:15:00 +01:00
6d32ea5850 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15598290427
2025-06-12 00:02:57 +00:00
bd39caccb0 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15598290427
2025-06-12 00:02:56 +00:00
95b4db5169 Fix slow SubChunk garbage collection check, closes #6574 (#6731) 2025-06-11 21:29:03 +01:00
8229ee1812 ChunkLoader is now a final class (#6730) 2025-06-11 21:02:31 +01:00
950fb48bcb Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15523860509
2025-06-09 00:03:27 +00:00
9e773ed439 PHPUnit migrated to attributes :( 2025-06-08 19:19:17 +01:00
6b5ff5016e Fixed double loading of PluginDescription
closes #4593
closes #6723
2025-06-08 19:09:12 +01:00
48b80ecf78 Change crashdump file name format
this has bothered me for ages since it sorts into some absurd order by default due to the name starting with the day of the week.

this way it'll ensure that the files are always alphanumerically ordered, which means the most recent crashdump should always be
at the bottom.
2025-06-08 19:01:11 +01:00
215da7e3f4 PHP 8.3 package bumps 2025-06-08 18:58:42 +01:00
c3ea6edc22 Bump minimum PHP version to 8.3 2025-06-08 18:49:27 +01:00
0330b25768 Merge branch 'minor-next' into major-next 2025-06-08 18:44:54 +01:00
4c3a2ef46e Update dependencies (minor-next) 2025-06-08 18:44:37 +01:00
d053e9e168 Merge branch 'stable' into minor-next 2025-06-08 18:43:31 +01:00
5ebbcd5d33 Move to newer systems for movement and block break handling (#6718)
MS is due to remove the non-server-auth versions of all of this stuff.

Fortunately v3 server auth movement works just fine without any changes,
although we will need to start sending player tick in some packets if
someone wants to actually use the rewind stuff.
2025-06-02 15:24:25 +01:00
a4ac28592c Updated dependencies 2025-06-02 15:17:00 +01:00
e99665fb12 Bump docker/build-push-action in the github-actions group (#6719) 2025-06-02 14:08:14 +00:00
b4b6bbe29f BaseInventory: fixed internalAddItem() setting air slots to air
this bug was introduced in #4237, but it was unnoticed due to having no adverse
effects other than noisy debugs and network traffic.
2025-05-29 17:18:45 +01:00
0910a219d4 Fixed improper pre-checking of PlayerAuthInputPacket flags 2025-05-28 23:29:37 +01:00
56da492e48 World: make less noise about deleted tile entities
no need to repeat the same message 100 times
2025-05-28 22:10:20 +01:00
035d2dec23 LevelDB: make unknown block errors way less annoying
these would previously generate a new line for every error.
since errors are often repeated for different offsets (e.g. different states of the same block),
we can save a lot of spam by deduplicating them and telling which offsets the errors occurred in.
2025-05-28 22:03:29 +01:00
b40b99fe72 Player: fixed crash on action item return
this can happen if the old item had a lower max damage than the new one, and the new
one has a damage higher than the old one's max damage.

it can also happen if the damage was overridden to some illegal value by a custom item
as seen in https://crash.pmmp.io/view/12754811
2025-05-28 21:32:48 +01:00
baafaed362 Stem drops seeds according to binomial distribution
fixes #6709

we really need a better way to reverse-engineer the chance parameter for these
as the wiki just gives a probability table, which is quite tiresome to extract
patterns from.
2025-05-28 21:00:40 +01:00
d5a1007c80 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15288247521
2025-05-28 00:03:15 +00:00
bf33a625c9 Implemented Respawn Anchor (#6646)
PlayerRespawnAnchorUseEvent is also added with options SET_SPAWN and EXPLODE, which allows plugins to customise the outcome of using the anchor in PM, which currently doesn't support dimensions. The event is also cancellable.
2025-05-27 21:57:28 +01:00
059f4ee7bf Extract GeneratorExecutor system from World, v2 (#6682)
- `AsyncGeneratorExecutor` class added that encapsulates the logic of generating chunks using async tasks as previously
- `GeneratorExecutor` interface added that can be implemented to provide chunks in other ways
- `SyncGeneratorExecutor` which invokes the generator directly on the main thread, useful for simple generators like `Flat` where async tasks are not needed
- Some redundant APIs were removed from `World` (these will probably come back as deprecated stubs for the remainder of 5.x, but I was having too much fun deleting code)
- Removed internal `World->registerGeneratorToWorker()` (no longer useful)
- `World` now invokes generator executor instead of posting AsyncTasks directly
- Some internal classes moved to `pocketmine\world\generator\executor` (PopulationTask excluded because plugins use it in lieu of being able to regenerate chunks
- Generators can opt into main-thread execution by setting the `$fast` parameter to `true` in `GeneratorManager::register()`
2025-05-27 21:51:10 +01:00
dca2665e17 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15243296100
2025-05-26 00:02:56 +00:00
dd17adeaaf Reintroduce step height additions for minor-next
Revert "Revert change that can't go on stable"

This reverts commit a554d2acf5.
2025-05-25 11:33:47 +01:00
98f28f8b6d Merge branch 'stable' into minor-next 2025-05-25 11:33:32 +01:00
a554d2acf5 Revert change that can't go on stable
API additions need to wait for the next minor release

Revert "Entity: make stepHeight accessable (#6702)"

This reverts commit 5527a0c6bf.
2025-05-25 11:32:40 +01:00
05eda887b1 Item: make setter methods fluent (#6678)
- `Item::clearCustomBlockData` previously, the instance was returned, but the return type has been changed
- `Item::setCanPlaceOn`, `Item::setCanDestroy` and `Item::setKeepOnDeath` now return `$this`
2025-05-25 10:35:26 +02:00
5527a0c6bf Entity: make stepHeight accessable (#6702) 2025-05-25 10:07:41 +02:00
18b6b1742c Rename PlayerExhaustEvent to EntityExhaustEvent (#6674)
Removed the `getPlayer` function
2025-05-25 10:04:33 +02:00
eee2e62d81 Add EntityFrostWalkerEvent (#6673) 2025-05-25 10:01:46 +02:00
b20d1b84b5 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15232190072
2025-05-25 00:03:31 +00:00
4d5c27a734 Unit test block hardness & blast resistance values (#6629) 2025-05-24 21:01:36 +01:00
e1af2a4af1 Update language dependency 2025-05-24 16:19:48 +01:00
a8e898b13b Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15221216334
2025-05-24 00:02:50 +00:00
f656d7d3d7 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15221216334
2025-05-24 00:02:49 +00:00
3636173d75 ... 2025-05-23 23:28:15 +01:00
9606c0e0bb Remove stale labels as well as Waiting on Author labels
actions/stale is far too slow to do this itself since it processes lots of irrelevant crap on every run
2025-05-23 22:16:57 +01:00
d907d72e9b Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15090310700
2025-05-18 00:03:34 +00:00
55123b36e1 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15090310700
2025-05-18 00:03:33 +00:00
94fb5d95b9 CommonThreadPartsTrait: fixed thread crashes sometimes missing cause info
closes #6669

this happens because isTerminated returns true before the thread's shutdown handler runs,
so we join with the thread to make sure that shutdown handlers are done before returning.

... hopefully we don't get servers randomly deadlocking in shutdown handlers ???
2025-05-17 19:09:54 +01:00
b5f236c019 Apparently we're supposed to use replace for this, not provide 2025-05-17 18:09:14 +01:00
9d532b6e95 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15087062558
2025-05-17 16:31:33 +00:00
7169f8e553 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/15087062558
2025-05-17 16:31:32 +00:00
657e6c8130 Added trigger cron workflow for RestrictedActions branch sync
we're having problems with the restricted action getting disabled due to repo inactivity,
so it's best we trigger it from here, since this repo's activity is what it's
interested in anyway.
2025-05-17 17:29:35 +01:00
647c2587a8 5.28.3 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15086729525
2025-05-17 15:45:22 +00:00
81d3017ad5 Murphy's Law (#6698) 2025-05-17 16:44:19 +01:00
a37353c060 composer: fixed borked version constraints
bruhhhhhhhhhhhh
2025-05-17 16:37:22 +01:00
280911ec59 5.28.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/15085916916
2025-05-17 14:01:49 +00:00
abb004fbc5 Ready 5.28.1 (#6696) 2025-05-17 15:00:53 +01:00
e0864e7ee8 composer: also axe unnecessary ctype polyfill 2025-05-17 14:54:26 +01:00
dca37d5842 Hack: forcibly remove symfony/polyfill-mbstring
we don't need this dependency anyway because mbstring is already provided.
2025-05-17 14:11:57 +01:00
67f3bb9c52 Update composer dependencies
and fix an error found by new PHPStan update
2025-05-17 13:46:33 +01:00
acf4341d71 always the CS... 2025-05-17 13:35:55 +01:00
84bb9d2ab4 Consolidate Bedrock data version info
this ensures we don't have to go into a bunch of randomly scattered files to update version numbers.
2025-05-17 13:33:42 +01:00
bb7bfee0cd Remove ServerEvent class (#6695) 2025-05-14 08:06:22 +02:00
88cdc2eb67 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14951134662
2025-05-11 01:49:35 +00:00
50f3fe2578 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14951134662
2025-05-11 01:49:34 +00:00
04de72e85e Fix changelog typo (#6690) 2025-05-10 14:34:37 +01:00
112bcf7af9 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14940598161
2025-05-10 01:40:10 +00:00
4bcef443f7 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14940598161
2025-05-10 01:40:09 +00:00
d90fc3415c fixed wrong version info (#6689) 2025-05-09 16:33:55 +01:00
1c70cee72e Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14931383427
2025-05-09 14:38:29 +00:00
e2e16a4ec5 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14931383427
2025-05-09 14:38:28 +00:00
134c7309c5 5.28.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/14931216524
2025-05-09 14:30:04 +00:00
5e830c7320 Protocol changes for 1.21.80 (#6687)
* Bedrock 1.21.80 support

* Update bedrock-data

* Add required tags to models

* Fixed biome data loading

* Support newest world format
apparently I messed up the blockstate data version last time around... it hasn't changed since 1.21.60

* always CS has to complain...

* Sync with release versions

* Ready 5.28.0 release

* this might help...

---------

Co-authored-by: Dylan T. <dktapps@pmmp.io>
2025-05-09 15:29:05 +01:00
7847524df6 Merge branch 'minor-next' into major-next 2025-05-08 02:28:09 +01:00
c1cee1fc24 Merge branch 'stable' into minor-next 2025-05-08 02:27:51 +01:00
d789c75c00 Improve PHPStan error reporting for unsafe foreaches
these are actually two separate concerns: one for dodgy PHPStan type suppression on implicit keys, and the other for arrays being casted to strings by PHP.
2025-05-08 02:26:09 +01:00
1d26b21fe0 Merge branch 'minor-next' into major-next 2025-05-04 17:21:24 +01:00
6196b9c995 Merge branch 'stable' into minor-next 2025-05-04 17:20:27 +01:00
f2e7473629 Update PHP-CS-Fixer 2025-05-04 17:19:15 +01:00
eb3922fc7e shut 2025-05-04 17:10:01 +01:00
912a5d6ad0 Remove TODO 2025-05-04 16:45:25 +01:00
2a42e2c75d Drop PluginLoader from Plugin, expose path instead
we already had this anyway, and it's already being reflected into.
Instead of DevTools checking for FolderPluginLoader instances, it
could just check if the file is a directory instead.
2025-05-04 16:44:28 +01:00
3de604ef95 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14816570368
2025-05-04 01:51:27 +00:00
6bf9a305de Rename confusing PHPStan rule name
it never occurred to me that this was misleading until I read some Devin documentation,
noticed that Devin misunderstood was the class was for, and then realized actually
Devin understood correctly, and it was the name of the class that was wrong. Funny
how that happens...
2025-05-03 19:24:21 +01:00
cb4364f8fd Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14786989960
2025-05-02 01:42:53 +00:00
f8abcd5102 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14786989960
2025-05-02 01:42:51 +00:00
6f3506360e Bump the github-actions group with 3 updates (#6683) 2025-05-01 08:30:26 +00:00
5bfa40618d Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14768020274
2025-05-01 01:50:54 +00:00
efaf9311b3 Extract population business logic from PopulationTask 2025-04-30 17:38:16 +01:00
8e1426e25e Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14687149888
2025-04-27 01:46:41 +00:00
fe70b31881 Fix crash when a player is added to the world 2025-04-26 22:11:03 +01:00
d86943fa8c Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14565559872
2025-04-21 01:45:18 +00:00
cfafb584a8 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14565559872
2025-04-21 01:45:17 +00:00
ad6f7dfedb World: verify saveability of blocks, entities and tiles at entry points
I want to do the same for items, but items are going to be a pain in the ass.
For items there are multiple possible entry points and all of them will need to be checked:
- dropped items
- inventory contents
- lecterns
- item frames

I don't see a good way to deal with all these. We can't check for registration in the constructor
because we need to fully construct the item in order to register it.

Blocks are also a potential issue in other areas, but setBlock() is definitely the biggest offender.
2025-04-20 19:48:28 +01:00
1ea5c060fd bruh 2025-04-20 18:16:54 +01:00
4a5c1e7540 Entity: truncate fire ticks instead of throwing exceptions
as written in the comments, it's not reasonable to propagate this limitation, since it
ultimately comes from a shortfall in the Mojang save format, not a limitation of PM's
capability. It's also not obvious how this would be propagated to the likes of setOnFire(),
as this would translate into a max time of 1638 seconds, a value no one is going to
remember.

There's a case to be made for truncating this on save rather than on initial set, but
this is at least better than having Fire Aspect level 1000 cause crashes and whatever
other gameplay logic that would have to work around this stupid limitation.
2025-04-20 16:57:44 +01:00
2548422973 AvailableEnchantmentRegistry: reject non-string tags
fixes https://crash.pmmp.io/view/12627328
2025-04-20 16:44:23 +01:00
baee0110c7 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14544397106
2025-04-19 01:36:21 +00:00
028815490e Add EntityExtinguishEvent (#6671) 2025-04-18 11:19:46 +02:00
5617347949 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14482870321
2025-04-16 01:41:53 +00:00
a74168953c Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14482870321
2025-04-16 01:41:52 +00:00
f661443ec7 Update Ubuntu base image for GitHub Actions 2025-04-15 16:48:13 +01:00
0bbe56beb4 Merge branch 'minor-next' into major-next 2025-04-06 20:01:23 +01:00
1073f372f8 Merge branch 'stable' into minor-next 2025-04-06 20:00:45 +01:00
835c383d4e Update Composer dependencies 2025-04-06 20:00:21 +01:00
d3f6c22996 5.27.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/14288755593
2025-04-06 03:53:08 +00:00
6f3851be80 5.27.1 (#6670) 2025-04-06 04:52:15 +01:00
94caea97e0 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14287788168
2025-04-06 01:43:19 +00:00
071c15d7de NetworkSession: immediate-send now causes a buffer flush when the packet is ready
instead of skipping queues and forcing sync compression as previously seen.

this maintains proper packet order and allows immediate-flush to be used to reduce latency in-game.

Small servers won't notice any difference, but for larger ones it may make a difference, since the buffer time effectively depends on the amount of load RakLib is under.
closes #3325
2025-04-05 17:40:48 +01:00
ad95f392c1 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14233077278
2025-04-03 01:38:27 +00:00
673b39e2a1 Internet: remove curl_close() call (#6667)
curl_close() has no effect as of php8: https://www.php.net/manual/en/function.curl-close.php
2025-04-02 22:24:50 +01:00
9af3cde03f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14120132647
2025-03-28 01:37:50 +00:00
17faa19743 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14120132647
2025-03-28 01:37:48 +00:00
e88b81a4cb 5.27.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/14110940403
2025-03-27 15:49:33 +00:00
687112f4cd 5.27.0, Bedrock 1.21.70 support (#6665)
Co-authored-by: Dylan K. Taylor <dktapps@pmmp.io>
2025-03-27 15:48:19 +00:00
72f1391bd9 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14049692123
2025-03-25 01:38:30 +00:00
644c04bee4 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14049692123
2025-03-25 01:38:29 +00:00
c9e85603b0 Bump phpstan/phpstan-strict-rules in the development-patch-updates group (#6664) 2025-03-24 14:43:29 +00:00
a90e5a6aa2 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14014323991
2025-03-23 01:42:16 +00:00
d954772a20 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/14014323991
2025-03-23 01:42:15 +00:00
c80a4d5b55 5.26.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/14011298411
2025-03-22 18:33:19 +00:00
f416cb8902 Merge pull request #6658 from pmmp/minor-next-release 2025-03-22 18:32:15 +00:00
f123df5e0d changelog: use more accurate terminology 2025-03-22 18:16:33 +00:00
de26ebd124 Prepare 5.26.0 release 2025-03-22 17:59:20 +00:00
df5f87e309 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13913481960
2025-03-18 01:37:04 +00:00
6b04bb504f Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13913481960
2025-03-18 01:37:03 +00:00
1c6a4bde86 Bump pocketmine/locale-data in the production-patch-updates group (#6656) 2025-03-17 13:20:59 +00:00
510ef94698 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13878654456
2025-03-16 01:41:31 +00:00
c2f8e9365b BlockStateToObjectDeserializer: check that the returned state is actually registered
if not, this will cause random crashes in core code, which assumes that state IDs found on runtime chunk memory are valid and registered.

this problem exists in other places too, and probably requires a rethink of how we're dealing with this, but for now, this will do as a band-aid.
2025-03-15 20:53:49 +00:00
d3f40b7b0c Merge branch 'minor-next' into major-next 2025-03-15 20:37:37 +00:00
4ef21fabab Merge branch 'stable' into minor-next 2025-03-15 20:37:28 +00:00
4407e585e4 Update composer dependencies (minor-next) 2025-03-15 20:36:39 +00:00
463be36b72 Update composer dependencies 2025-03-15 20:33:47 +00:00
8b57e9007a 👺 2025-03-15 01:33:29 +00:00
e03c586c86 GarbageCollectorManager: promote debug message to info
this has such a big impact on performance that I think this is warranted. Should also make it more obvious what the GC is doing without needing to enable ALL debug info.
2025-03-15 01:29:49 +00:00
dae3e2b336 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13868087288
2025-03-15 01:26:48 +00:00
802e373bf3 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13868087288
2025-03-15 01:26:47 +00:00
09acbfab4c dependabot: ignore phpstan/phpstan updates
these are noisy and cause conflicts. Since they also usually cause new errors to be reported, we often can't directly update it anyway. Better to test & update this locally.
2025-03-15 00:03:09 +00:00
7cfaf04b87 stfu 2025-03-14 16:10:56 +00:00
d9e0e51e14 Reduce code duplication in copper block serialization handling 2025-03-14 16:08:06 +00:00
069ecf007f Merge branch 'stable' into minor-next 2025-03-14 15:41:46 +00:00
341c7a03a9 CopperMaterial: fixed missing @return $this docs 2025-03-14 15:40:27 +00:00
f2fa5933ea Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13825107599
2025-03-13 01:36:48 +00:00
7ae90dda5d Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13825107599
2025-03-13 01:36:47 +00:00
73a4b076d6 actions: tidy support response message 2025-03-12 16:19:11 +00:00
00df508727 Update bug-report.yml 2025-03-12 13:06:57 +00:00
95a324755b Merge branch 'minor-next' into major-next 2025-03-10 01:31:34 +00:00
a6553097f4 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13754675430
2025-03-10 01:14:10 +00:00
afc4a3c7f1 Fixed entity position offset not being included in AddActorPacket (#6643)
this was causing TNT and falling blocks to briefly appear half a block lower than their true position, because their positions are measured from the center and not the base.
2025-03-09 02:09:53 +00:00
1d13054608 Merge branch 'minor-next' into major-next 2025-03-09 01:18:55 +00:00
ac7b5b3b13 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13743358576
2025-03-09 01:16:28 +00:00
7af5eb3da2 crafting: validate array inputs
this makes sure wrong parameters don't show up as core errors, as seen in crash report 12373907
closes #6642
2025-03-09 01:10:12 +00:00
95284bc9de change error identifier 2025-03-09 00:54:39 +00:00
2291546610 phpstan: added rule to ban new $class
see #6635 for rationale on why we want to get rid of this

for now, this rule will prevent this anti-feature from being used in new code
2025-03-09 00:51:12 +00:00
aad2bce9e4 readme: call out Easy tasks issues 2025-03-09 00:23:59 +00:00
ec140f7861 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13666455727
2025-03-05 01:27:21 +00:00
09f0ce458c Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13666455727
2025-03-05 01:27:20 +00:00
50a1e59aa4 5.25.3 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/13662905668
2025-03-04 21:05:10 +00:00
e8824a36b9 Merge pull request #6645 from pmmp/explode-limit
5.25.2
2025-03-04 21:03:52 +00:00
b1e63e544f Merge branch 'stable' into explode-limit 2025-03-04 21:00:40 +00:00
9e9f8a4870 Prepare 5.25.2 release 2025-03-04 20:57:47 +00:00
d0d84d4c51 New rule: explode() limit parameter must be set 2025-03-04 20:44:01 +00:00
66f5bdcb94 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13610829991
2025-03-02 01:38:08 +00:00
9382e6e5b3 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13610829991
2025-03-02 01:38:07 +00:00
e3e0c14275 Bump the github-actions group with 2 updates (#6644) 2025-03-01 10:04:01 +00:00
5d24d8de0b Merge branch 'minor-next' into major-next 2025-02-26 17:32:14 +00:00
afac178cf4 Merge branch 'stable' into minor-next 2025-02-26 17:31:55 +00:00
e2f5e3e73c Update composer dependencies 2025-02-26 17:31:26 +00:00
3a2d0d77d1 Update composer dependencies 2025-02-26 17:30:20 +00:00
32b98dcbde draft-release: add a warning about bug reporting
too many people just spam on discord and expect that to somehow do something ...
2025-02-26 17:23:27 +00:00
092ea07d51 5.25.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/13549549222
2025-02-26 17:14:49 +00:00
706f391068 Release 5.25.1 (#6641) 2025-02-26 17:13:44 +00:00
7c654271a8 Bump phpstan/phpstan in the development-patch-updates group (#6640) 2025-02-25 13:40:11 +00:00
1ad08e2432 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13488997706
2025-02-24 01:26:36 +00:00
19425e35ea Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13488997706
2025-02-24 01:26:36 +00:00
3df2bdb879 Fixed door facing
this was broken in 1.21.60 update.

should've known better to expect a blockstate upgrade to mean a
blockstate fix...
2025-02-24 01:04:52 +00:00
1fed9f6cb5 BlockBreakInfo: fixed confusing error message 2025-02-23 20:02:27 +00:00
3050af0bc0 ResourcePackManager: validate pack UUIDs
fixes CrashArchive ##12248760
2025-02-23 19:45:38 +00:00
a43ebcf217 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13403469065
2025-02-19 01:24:13 +00:00
a08b06d322 also sort table by ID 2025-02-18 15:34:20 +00:00
c876253f76 tools/blockstate-upgrade-schema-utils: added dump-table command
this command dumps a human-readable version of pmmp/mapping palette mapping files to a .txt file.
may be useful for debugging issues with the schema generator or the upgrade process.
2025-02-18 15:30:39 +00:00
c637d852e2 Merge branch 'minor-next' into major-next 2025-02-18 01:26:08 +00:00
67272f8f2b Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2025-02-18 01:25:46 +00:00
77be5f8e25 Update PHPStan 2025-02-17 17:51:39 +00:00
9744bd7073 CraftingManager: make a less dumb hash function
fixes #4415
2025-02-17 15:35:18 +00:00
c58c64de85 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13360931724
2025-02-17 01:26:25 +00:00
51cf6817b1 World: fixed overflow checks for getCollisionBlocks(), closes #6630 2025-02-16 23:24:39 +00:00
694aa17cc9 Merge branch 'minor-next' into major-next 2025-02-16 23:18:56 +00:00
fd04894a7b Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2025-02-16 23:18:34 +00:00
d2d6a59c72 ItemDeserializer: fix doc comment typo 2025-02-16 22:52:11 +00:00
788ee9a008 Allow overriding deserializers for block and item IDs
there's no technical reason not to support this, since it doesn't violate any assumptions and the type returned is a base anyway.

this enables implementing stuff like snow cauldrons in a plugin, which previously would require reflection due to the minecraft:cauldron deserializer being registered already.
it also enables overriding IDs to map to custom blocks, which might be useful for overriding some functionality (although this is inadvisable - and won't alter the usage of stuff like VanillaBlocks::WHATEVER()).

we do *not* allow overriding serializers, since type IDs are expected to be paired to block implementations, and allowing them to be reassigned could lead to crashes if the new class was incorrect. So the correct approach for overriding nether portals would be to create a custom type ID as if you were adding a fully custom item. This will also allow other plugins to distinguish between your implementation and the built-in one.
2025-02-16 22:49:40 +00:00
34f801ee3c 5.25.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/13359320328
2025-02-16 22:18:20 +00:00
d96ef21c4d Prepare 5.25.0 release (#6631) 2025-02-16 22:16:47 +00:00
246c1776df InventoryAction: avoid throwaway Item clones 2025-02-16 21:47:35 +00:00
03e4b53ac4 BedrockDataFiles: added constants for folders as well as files
we probably should have it recurse too, but this is an easy win.
2025-02-16 20:57:16 +00:00
91ac64783f Bedrock 1.21.60 (#6627)
Co-authored-by: Dylan K. Taylor <dktapps@pmmp.io>
2025-02-16 20:51:53 +00:00
9402a20ee3 Update Utils::getOS() doc comment
closes #6628
2025-02-16 16:12:29 +00:00
c9441e1078 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13276594014
2025-02-12 02:16:01 +00:00
2670e81668 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2025-02-12 02:14:51 +00:00
e29aa2f337 Added resin material color (#6622) 2025-02-11 16:15:42 +00:00
5ef89200c6 Bump phpstan/phpstan in the development-patch-updates group (#6620) 2025-02-10 22:14:30 +00:00
b0ac8863c4 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13191240897
2025-02-07 01:23:45 +00:00
9b3b45258a Optimise collision box checks by caching some basic info (#6606)
This PR significantly improves performance of entity movement calculation.

Previous attempts to optimise this were ineffective, as they used a cache to mitigate the cost of recomputing AABBs. Entities tend to move around randomly, so the non-cached pathway really needed to be optimized.

This change improves performance on multiple fronts:
1) avoiding Block allocations for blocks with 1x1x1 AABBs and with no AABBs (the most common)
2) avoiding Block allocations and overlapping intersection checks unless a stateID is specifically known to potentially exceed its cell boundaries (like fences)
3) avoiding overlapping AABB checks when overlaps can't make any difference anyway (cubes)

Together, these changes improve the performance of World->getBlockCollisionBoxes() by a factor of 5. In real-world terms, this shows up as a major performance improvement in situations with lots of entities moving in random directions. Testing with item entities showed an increase from 400 to 1200 moving items with the same CPU usage.

This change is built on the assumption that `Block->recalculateCollisionBoxes()` and its overrides don't interact with any world. This is technically possible due to the crappy design of the `Block` architecture, but should be avoided. As a world is not available during `RuntimeBlockStateRegistry` initialization, attempting to interact with a world during `recalculateCollisionBoxes()` will now cause a crash.

This turned out to be a problem for `ChorusPlant`, which was fixed by 70fb9bbdfd. The correct solution in this case was to use dynamic states similar to how we currently deal with fence connections.
2025-02-06 15:42:10 +00:00
e9df0baffb Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into major-next 2025-02-05 01:37:00 +00:00
ca4debbf08 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13126338048
2025-02-04 01:22:15 +00:00
39e69276a1 Bump tests/plugins/DevTools from c6dca35 to a030d39 (#6617) 2025-02-03 11:43:03 +00:00
94797e3afa Bump build/php from ae94694 to 1549433 (#6616) 2025-02-03 11:42:37 +00:00
b3723b5b3e Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13104521333
2025-02-03 01:23:13 +00:00
03f98ee0a9 New version of NBT for performance improvements 2025-02-02 19:47:47 +00:00
70368ea653 Merge branch 'stable' into minor-next 2025-02-02 19:47:03 +00:00
9d6a0cc738 Update composer dependencies 2025-02-02 19:46:54 +00:00
21ccd90147 ChunkCache: parameterize dimension ID
(cc @Muqsit)
2025-02-02 19:43:04 +00:00
0a9a45a126 Improve block break progress
closes #6500

This fixes break time animations for mining fatigue and haste, and
improves the underwater and on-ground behaviour.

on-ground is still not quite right for reasons not related to this PR
(see #6547).
I'm also not quite sure the underwater logic is correct (in water vs
underwater?) but it's definitely better than what we have currently.
2025-02-02 19:34:14 +00:00
b370b5458f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13094301661
2025-02-02 01:26:09 +00:00
88937f1785 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13094301661
2025-02-02 01:26:08 +00:00
07987890a0 Bump the github-actions group with 2 updates (#6613) 2025-02-01 13:38:25 +00:00
8af2d05ec0 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13001707314
2025-01-28 01:21:44 +00:00
e5a783cb9e Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/13001707314
2025-01-28 01:21:43 +00:00
70fb9bbdfd ChorusPlant: fixed recalculateCollisionBoxes() depending on the world 2025-01-27 21:28:26 +00:00
f60120a75e Bump the development-patch-updates group with 3 updates (#6603) 2025-01-27 10:43:28 +00:00
4d186b52da Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12920308572
2025-01-23 01:22:04 +00:00
fc86d3a44e 5.24.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/12916833718
2025-01-22 20:50:42 +00:00
393d7f72a9 5.24.0
5.24.0 minor release
2025-01-22 20:49:38 +00:00
b625fee94b Prepare 5.24.0 release 2025-01-22 18:00:41 +00:00
6b606dca95 UPnP: better fix for postURL error that doesn't require behavioural breaks 2025-01-22 17:46:43 +00:00
406ddf3e53 Revert "Internet: make postURL() error reporting behaviour more predictable"
This reverts commit 97c5902ae2.
2025-01-22 17:44:23 +00:00
ec6077776a Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into minor-next 2025-01-22 16:45:49 +00:00
e6ff55823f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12899221905
2025-01-22 01:23:50 +00:00
f7b5cd7ff3 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12899221905
2025-01-22 01:23:49 +00:00
3453ff03fd 5.23.4 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/12898306655
2025-01-22 00:10:10 +00:00
04e63172c3 5.23.3 (#6597) 2025-01-22 00:08:49 +00:00
d556389b11 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12839491049
2025-01-18 01:19:33 +00:00
51cb1875bb Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12839491049
2025-01-18 01:19:32 +00:00
0b60a47cde Noteblock instrument changes from 1.21.50 (#6596)
Good thing this isn't saved on disk :|
2025-01-17 19:56:19 +00:00
d1066d0199 Bump build/php from 56cec11 to ae94694 (#6595) 2025-01-17 19:54:48 +00:00
976fc63567 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12701510185
2025-01-10 01:26:17 +00:00
f349ce75e4 Player: add ability to get & set flight speed multiplier (#6076)
Since this doesn't directly correspond to flight speed (it's multiplied by different values depending on whether sprinting or not, and possibly other states), "multiplier" was preferred instead of directly calling it flight speed.

Default value is 0.05.
2025-01-09 20:13:46 +00:00
02ac512b4e Merge branch 'minor-next' into major-next 2025-01-08 15:25:12 +00:00
b3f15435cc Projectile: clean up dodgy code 2025-01-08 02:31:50 +00:00
847ae26cad PHPStan: don't remember possibly-impure function return values
I don't think we get much benefit from this, and the assumption that functions with a return value are pure is sketchy.
In any case, it's better to avoid these repeated calls anyway.
2025-01-08 02:04:06 +00:00
d42ec06647 ZippedResourcePack: don't pass exception code to new exception
this is a BUT (int|string) under PHPStan, and we don't need the errors. We don't care about this code anyway.
2025-01-08 01:48:55 +00:00
5e0f03dff0 Stub PalettedBlockArray functions that work with arrays
and workaround PHPStan stupidity
2025-01-08 01:48:15 +00:00
4a83920db9 PlayerPreLoginEvent: improve array type info 2025-01-08 01:47:04 +00:00
0a16daa619 Avoid dodgy array_flip hash building
the conventional way is using array_keys and array_fill_keys. Behaviour is more predictable & also avoids benevolent union fuckery from PHPStan.
2025-01-08 01:45:28 +00:00
e34f34f9f4 Update BedrockProtocol dependency 2025-01-07 23:09:28 +00:00
e8c4b743b5 LevelDB: stop overriding types from NBT
NBT has better quality type info already
2025-01-07 22:54:10 +00:00
689a7996b9 Update NBT dependency 2025-01-07 22:51:38 +00:00
794641c0f8 Utils: split some horrifying code across multiple lines 2025-01-07 22:35:19 +00:00
9633b7d8a7 Update to PHPStan 2.x 2025-01-07 22:34:43 +00:00
d25ec58a6f AsyncPoolTest: phpdoc 2025-01-07 22:25:37 +00:00
d69a887b0d Utils: fix parameter doc for printableExceptionInfo() 2025-01-07 22:24:26 +00:00
38441a6ba3 build: avoid weak comparison 2025-01-07 22:23:16 +00:00
47cb04f6a6 tools: fix PHPStan 2.0 issues 2025-01-07 22:15:50 +00:00
b1c7fc017a CS 2025-01-07 22:13:20 +00:00
cd59e272bc PHPStan 2.0 fixes 2025-01-07 22:10:42 +00:00
7b1b35ab1f generator: fixup issues reported by PHPStan 2.0 2025-01-07 22:07:38 +00:00
28d31c97f8 Server: fixup PHPStan 2.x reported issues 2025-01-07 22:05:01 +00:00
708784b0a2 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12643390650
2025-01-07 01:24:48 +00:00
a17512de93 Command: don't trust plugins not to pass junk 2025-01-06 23:26:13 +00:00
601be3fb33 stfu 2025-01-06 23:09:26 +00:00
2e32c50670 NetworkSession: apparently aliases are already a list at this point??? 2025-01-06 23:08:48 +00:00
d1fa6edc50 InGamePacketHandler: fix weak comparisons 2025-01-06 23:08:18 +00:00
a1ba8bc3da NetworkSession: improve PHPDoc types 2025-01-06 23:07:54 +00:00
73edb8799d SignalHandler: fixed dodgy setup logic 2025-01-06 23:06:19 +00:00
9592f066f3 PHPDoc: Restrict ReversePriorityQueue to numeric priorities 2025-01-06 23:05:49 +00:00
db9ba83001 Make some assumptions about proc_open() 2025-01-06 23:05:06 +00:00
1b2d2a3fe1 plugin: improve PHPDocs and type compliance 2025-01-06 23:04:00 +00:00
84ec8b7abe Removed dead error patterns
I do think these are PHPStan bugs, since the trait should inherit the parent class's doc comment
But for the sake of catching more bugs, these doc comments have been manually added anyway.
2025-01-06 23:02:18 +00:00
357dfb5c7e Fixed build 2025-01-06 23:01:14 +00:00
0358b7dce4 utils: avoid weak comparisons 2025-01-06 22:53:35 +00:00
97c5902ae2 Internet: make postURL() error reporting behaviour more predictable
err is now always set to null when doing a new operation.

previously, if the same var was used multiple times and a previous one failed,
code might think that a previous error belonged to the current operation.
2025-01-06 22:52:05 +00:00
9a130bce32 Config: remove bad assumptions about string root keys
these could just as easily be integers and the code should still work.
2025-01-06 22:50:25 +00:00
20849d6268 Fixed potential crashes in type ID tests
if the constants had any non-stringable values, these would blow up.
this would still be fine in the sense that the tests would fail, but better that they fail gracefully if possible.
2025-01-06 22:48:22 +00:00
b6bd3ef30c Improve PHPDocs in world package 2025-01-06 22:46:16 +00:00
c5a1c15389 TimingsCommand: beware crash on invalid timings server response 2025-01-06 22:44:17 +00:00
e30ae487dc SimpleCommandMap: ensure we always pass a list to Command::setAliases()
some offsets may have been removed if the alias failed to be registered.
2025-01-06 22:44:17 +00:00
59f6c85105 Command: mark execute $args as being list<string> 2025-01-06 22:44:17 +00:00
90f0b85d2e Eliminate weak comparisons in entity package
Weak comparisons were used in cases when we were worried about comparing int and float.

In some cases (particularly involving Vector3) we do need to be wary of this, so floatval() is used to avoid incorrect type comparisons.
In other cases, we were already exclusively comparing float-float, so weak compare wasn't needed anyway.
2025-01-06 22:44:17 +00:00
8ee70b209e MemoryDump: fix PHPDoc types 2025-01-06 22:44:16 +00:00
5c905d9a95 BlockBreakInfo: use strict comparison
weak compare isn't needed here since this can be float/float
2025-01-06 22:44:16 +00:00
8b23231537 Fixup PHPDoc for blocks 2025-01-06 22:44:16 +00:00
3f7f11b812 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12615442245
2025-01-05 01:37:23 +00:00
8e039f2711 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12615442245
2025-01-05 01:37:22 +00:00
4a4572131f Bump shivammathur/setup-php in the github-actions group (#6591) 2025-01-04 22:26:14 +00:00
984e995659 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12606221104
2025-01-04 01:22:34 +00:00
3da0b82b86 Merge branch 'stable' into minor-next 2025-01-03 19:26:45 +00:00
da62eb9f33 ... 2025-01-03 19:26:24 +00:00
46604b26f2 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12510342531
2024-12-27 01:23:48 +00:00
09c434983b Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12510342531
2024-12-27 01:23:47 +00:00
fbaa125d0c Bump build/php from 9728fa5 to 56cec11 (#6588)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `9728fa5` to `56cec11`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](9728fa57f7...56cec11745)

---
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>
2024-12-26 12:36:17 +00:00
6b2fb9c4f8 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12498201064
2024-12-26 01:23:26 +00:00
6ad9dde43d Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12498201064
2024-12-26 01:23:25 +00:00
d634a5fa3d Bump build/php from b1eaaa4 to 9728fa5 (#6587)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `b1eaaa4` to `9728fa5`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](b1eaaa48ec...9728fa57f7)

---
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>
2024-12-25 13:06:46 +00:00
80b761627a Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12487960388
2024-12-25 01:23:10 +00:00
8cea4c13c4 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12487960388
2024-12-25 01:23:09 +00:00
dc2e82df7f crash.yml: add field ID for crash archive "report github issue" button 2024-12-24 16:37:18 +00:00
debf8d18fc Upgrade issue templates 2024-12-24 16:27:40 +00:00
81e3730b99 Fixed crashes containing PHP internal stack frames being flagged as plugin-caused 2024-12-24 14:20:16 +00:00
882d8c4ab9 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12475368381
2024-12-24 01:24:08 +00:00
8a5eb71432 ChunkCache: track strings in cache directly instead of CompressBatchPromise
this reduces memory footprint slightly, but more importantly reduces GC workload.
Since it also reduces the work done on cache hit, it might *slightly* improve performance,
but any improvement is likely to be minimal.
2024-12-23 21:04:33 +00:00
1c35987ead Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12450134566
2024-12-22 01:37:17 +00:00
306623e890 FormatConverter: do periodic GC
this reduces the risk of OOM during conversion of large worlds
we probably ought to limit the size of region caches for regionized worlds, but that's a problem for another time.
2024-12-21 17:49:03 +00:00
ada3acdba4 FormatConverter: ensure we don't get stalled due to stdout buffer flood
this can happen due to very noisy outputs during conversion, e.g. if there were many unknown blocks.
2024-12-21 17:49:03 +00:00
6a1d80e021 tools/convert-world: fixed some UI issues 2024-12-21 17:49:02 +00:00
88ae00fc4d Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12440895736
2024-12-21 01:22:55 +00:00
1ff0988e75 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12440895736
2024-12-21 01:22:54 +00:00
506cfe0362 Bump build/php from 5016e0a to b1eaaa4 (#6579)
Bumps [build/php](https://github.com/pmmp/php-build-scripts) from `5016e0a` to `b1eaaa4`.
- [Release notes](https://github.com/pmmp/php-build-scripts/releases)
- [Commits](5016e0a3d5...b1eaaa48ec)

---
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>
2024-12-20 10:39:39 +00:00
47a1aa6470 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12423751811
2024-12-20 01:24:32 +00:00
fea17fa4a9 RakLibServer: disable GC
GC is not required for RakLib as it doesn't generate any unmanaged cycles.
Cycles in general do exist (e.g. Server <-> ServerSession), but these are
explicitly cleaned up, so GC wouldn't have any useful work to do.
2024-12-19 20:33:40 +00:00
3e69ee87e4 Remove deprecated stuff
except Permission subscriptions; turns out we still need those
perhaps they should be marked @internal
2024-12-19 00:14:18 +00:00
a2a2ec9d8b Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12364667325
2024-12-17 01:39:12 +00:00
aee358d329 This timings handler management is a crap design
This has bitten me on the ass so many times now
2024-12-16 03:11:07 +00:00
3a0f15ef0d Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12344337356
2024-12-16 01:42:31 +00:00
80899ea72c Make sure timings are counted under the proper parents 2024-12-15 21:34:16 +00:00
42f90e94ff AsyncWorker now manually triggers GC at the end of each task run, similar to the main thread
this avoids costly GC runs during hot code.
2024-12-15 21:25:32 +00:00
8f536e6f21 always the CS 2024-12-15 20:46:10 +00:00
45482e868d Fixed AsyncWorker GC not getting re-enabled after memory dump
async workers still use automatic GC for now. We should probably switch to manual GC at some point, but it's not a priority right now.
2024-12-15 20:45:51 +00:00
742aa46b88 Separate memory dumping utilities from MemoryManager 2024-12-15 20:44:00 +00:00
cf1b360a62 World: Prevent block cache from getting too big
This has been a long-standing issue since at least 2016, and probably longer.
Heavy use of getBlock(At) could cause the cache to blow up and use all available memory.

Recently, it's become clear that unmanaged cache size is also a problem for GC, because
the large number of objects blows up the GC root buffer. At first, this causes more frequent
GC runs; later, the frequency of GC runs drops, but the performance cost of them goes up
substantially because of the sheer number of objects. We can avoid this by trimming the
cache when we detect that it's exceeded limits.

I've implemented this in such a way that failing to update blockCacheSize in new code
won't have lasting impacts, since the cache count will be recalculated during scheduled
cache cleaning anyway.

Closes #152.
2024-12-15 18:40:32 +00:00
0aa6cde259 Remove stupid MemoryManager settings
No one in their right mind is going to change the defaults for these anyway.

All this crap does is overwhelm users with stuff they don't understand.
Most of this stuff has no business being modified by non-developers anyway.
2024-12-15 16:41:54 +00:00
8f8fe948c1 MemoryManager: Control when cycle garbage collection is run (#6554)
This PR replicates the mechanism by which PHP's own GC is triggered: using a dynamically adjusted threshold based on the number of roots and the number of destroyed cycles. This approach was chosen to minimize behavioural changes.

This currently only applies to the main thread. Doing this for other threads is a bit more complicated (and in the case of RakLib, possibly not necessary anyway).

By doing this, we can get more accurate performance profiling. Instead of GC happening in random pathways and throwing off GC numbers, we trigger it in a predictable place, where timings can record it.

This change may also produce minor performance improvements in code touching lots of objects (such as `CraftingDataPacket` encoding`), which previously might've triggered multiple GC runs within a single tick. Now that GC runs wait for `MemoryManager`, it can touch as many objects as it wants during a tick without paying a performance penalty.

While working on this change I came across a number of issues that should probably be addressed in the future:

1) Objects like Server, World and Player that can't possibly be GC'd repeatedly end up in the GC root buffer because the refcounts fluctuate frequently. Because of the dependency chains in these objects, they all drag each other into GC, causing an almost guaranteed parasitic performance cost to GC. This is discussed in php/php-src#17131, as the proper solution to this is probably generational GC, or perhaps some way to explicitly mark objects to be ignored by GC.
2) World's `blockCache` blows up the GC root threshold due to poor size management. This leads to infrequent, but extremely expensive GC runs due to the sheer number of objects being scanned. We could avoid a lot of this cost by managing caches like this more effectively.
3) StringToItemParser and many of the pocketmine\data classes which make heavy use of closures are afflicted by thousands of reference cycles. This doesn't present a major performance issue in most cases because the cycles are simple, but this could easily be fixed with some simple refactors.
2024-12-15 16:26:39 +00:00
7a2427ace2 Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into major-next 2024-12-14 02:40:03 +00:00
b10caf7437 Remove tool tier of some blocks to match vanilla (#6573) 2024-12-13 21:54:48 +00:00
de66d84d29 Implement new 1.20 and 1.21 records (#6572) 2024-12-13 21:10:34 +03:00
f82c8dd3d3 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12307996607
2024-12-13 01:40:43 +00:00
636f562bcf Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12307996607
2024-12-13 01:40:42 +00:00
42094e6768 Implement resin blocks & items (#6571) 2024-12-12 23:21:41 +03:00
b341078765 Implement new pale oak blocks (#6570) 2024-12-12 17:53:52 +03:00
f7687af337 Fixed draft release being created on release publish 2024-12-12 13:44:15 +00:00
851bbd7384 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12268005529
2024-12-11 01:40:03 +00:00
ba93665fe7 TextFormat: reduce hella duplicated code in toHTML() 2024-12-10 14:11:11 +00:00
6817215683 TextFormat: Added new material colours for armor trims (#5838)
Unfortunately, these new formatting codes conflict with the Java strikethrough and underline, so we can't support these anymore.

A TextFormat::javaToBedrock() is provided to strip these codes, or (if these formats become supported via different codes) to convert them to Bedrock variants.

Co-authored-by: Dylan T. <dktapps@pmmp.io>
2024-12-10 13:40:03 +00:00
1ee52b69b0 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12247725255
2024-12-10 01:41:10 +00:00
67b9d6222d 5.23.3 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/12240364052
2024-12-09 16:52:50 +00:00
6f197bc1bb 5.23.2 (#6569) 2024-12-09 16:51:41 +00:00
bba525da02 Remove dead PHPStan ignored errors 2024-12-09 16:44:25 +00:00
ad6d34f1a6 Remove legacy make-release script
we no longer use this release workflow, all releases should now be done via pull request
2024-12-09 16:44:07 +00:00
a8eaa43bc8 Recombine release workflows
having two different workflows able to trigger releases is a pain for build number continuity.
perhaps longer term we should source the build number a different way, but these workflows needed restructuring anyway.
2024-12-09 16:36:26 +00:00
fe7c282052 Bump pocketmine/locale-data in the production-patch-updates group (#6568) 2024-12-09 12:03:09 +00:00
851f7a9d80 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12227347339
2024-12-09 01:42:26 +00:00
45917d495c Fixed CrashDump incorrectly detecting phar core crashes as plugin crashes (#6564)
fixes #6563

Since #6217 was merged, \pocketmine\PATH no longer includes the path of the original phar.
This means that the frame originating from the phar stub would not get its path cleaned up,
leading to it being incorrectly detected as a plugin frame.

We should probably explore better methods of detecting plugin crashes in the future; however
this fix should solve the immediate issue.
2024-12-08 16:52:33 +00:00
6d2329128a Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12191303914
2024-12-06 01:38:37 +00:00
1481977f35 Create pr-stale.yml 2024-12-05 20:47:46 +00:00
8efdf501ad 5.23.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/12187209543
2024-12-05 20:05:36 +00:00
2b0daebc2a 5.23.1 (#6562) 2024-12-05 20:04:43 +00:00
6b2da15b80 Fixed signs 2024-12-05 19:58:52 +00:00
2ef02a2c5e Upgraded block consistency check to detect tile changes 2024-12-05 19:57:13 +00:00
07045dd424 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12184052098
2024-12-05 16:35:59 +00:00
c5b0df4578 Merge remote-tracking branch 'origin/minor-next' into major-next 2024-12-05 16:07:28 +00:00
15e8895e54 5.23.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/12183301507
2024-12-05 15:52:16 +00:00
ea8f971287 Release 5.23.0 (#6561) 2024-12-05 15:51:13 +00:00
62e1d87f5e Mention internal timings deprecations
plugins shouldn't be using these, but since it's not marked as internal, we can't be sure.
2024-12-05 15:47:34 +00:00
ea068d4907 Update 5.23.md 2024-12-05 15:01:49 +00:00
fa7bc78e7c Prepare 5.23.0 release 2024-12-05 14:29:17 +00:00
0aaf4238a8 more deprecations in line with major-next 2024-12-05 13:02:09 +00:00
35a90d24ec AsyncTask: deprecate progress update related stuff 2024-12-05 12:57:26 +00:00
5e9dbace90 Merge branch 'minor-next' into major-next 2024-12-05 10:13:24 +00:00
9a6e258b6c Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2024-12-05 10:13:06 +00:00
205aabe11f Fixed merge error 2024-12-04 15:27:09 +00:00
a1448bfb88 5.22.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/12160926590
2024-12-04 13:38:41 +00:00
ba6828c6bd Release 5.22.0 (Bedrock 1.21.50 support) (#6559)
Co-authored-by: Dylan K. Taylor <dktapps@pmmp.io>
2024-12-04 13:36:52 +00:00
3091e1325f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12151373979
2024-12-04 01:39:59 +00:00
5fc96c393d Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12151373979
2024-12-04 01:39:58 +00:00
2d0321ff02 Switch back to official JsonMapper
the issues that led to the need for a fork have been addressed in the 5.0.0 release.
2024-12-03 15:19:38 +00:00
c56d4d3e3c dependabot: update github actions deps together, monthly 2024-12-03 14:56:22 +00:00
06028aac97 issues: don't recommend forums to get help 2024-12-03 02:07:58 +00:00
779e80a961 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12131296321
2024-12-03 01:39:33 +00:00
950f7ad7a4 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12131296321
2024-12-03 01:39:32 +00:00
49da50659f Bump docker/build-push-action from 6.9.0 to 6.10.0 (#6553) 2024-12-02 16:36:12 +00:00
007673cb96 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12111121061
2024-12-02 01:41:02 +00:00
ae9b4dbb05 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12111121061
2024-12-02 01:41:01 +00:00
fcef015f32 L link 2024-12-02 00:40:55 +00:00
0dae786a21 feat(Server): add a setter for maxPlayers (#6261) 2024-12-01 20:24:50 +00:00
f1a3b42620 Implement frost walker enchantment (#5497)
Co-authored-by: Dylan T. <dktapps@pmmp.io>
2024-12-01 19:46:38 +00:00
f3763ae691 Implement Recovery compass (#5502)
Co-authored-by: Dylan K. Taylor <dktapps@pmmp.io>
2024-12-01 18:25:45 +00:00
12214792b3 Allow eating in creative & peaceful
closes #5923
closes #6056
2024-12-01 17:42:26 +00:00
93a9007f3c Added ClosureCommand (#6063)
this is intended to replace PluginCommand and CommandExecutor, both of which are overengineered and unfit for purpose.
Allowing a closure allows much greater flexibility.

We can't use this within the core yet, as plugins will expect PluginBase->getCommand() to return PluginCommand (with its associated setExecutor() and similar APIs).
However, I think this is useful enough to add by itself.
2024-12-01 15:10:07 +00:00
02d181d0c8 Merge branch 'minor-next' into major-next 2024-12-01 15:02:36 +00:00
a593180ef9 Deprecate some stuff 2024-12-01 15:01:41 +00:00
61560ec375 Support for collecting timings from threads, and implement async task timings (#6333)
The following callbacks can now be registered in timings, to allow threads to be notified of these events:
- Turning on/off (`TimingsHandler::getToggleCallbacks()->add(...)`)
- Reset (`TimingsHandler::getReloadCallbacks()->add(...)`)
- Collect (`TimingsHandler::getCollectCallbacks()->add(...)`)

Collect callbacks must return `list<Promise>`. The promises must be `resolve()`d with `list<string>` of printed timings records, as returned by `TimingsHandler::printCurrentThreadRecords()`. It's recommended to use 1 promise per thread.

A timings report will be produced once all promises have been resolved.

This system is used internally to collect timings for async tasks (closes #6166).

For timings viewer developers:
Timings format version has been bumped to 3 to accommodate this change. Timings groups should now include a `ThreadId`  at the end of timings group names to ensure that their record IDs are segregated correctly, as they could otherwise conflict between threads. The main thread is not required to specify a thread ID. See pmmp/timings@13cefa6279 for implementation examples.

New PHPStan error is caused by phpstan/phpstan#10924
2024-12-01 14:49:27 +00:00
44771c892d Use PlayerAuthInputPacket::SNEAKING flag to test for sneaking (#6544)
This binds internal sneaking to whether or not the player is currently pressing the shift key, which fixes #5792 and fixes #5903.

However, it does introduce visual issues with sneaking, as explained in #6548. This needs to be worked on separately. For now, it's better we trade 2 functional bugs for 1 visual bug.
2024-12-01 13:14:30 +00:00
2fc6bbe84e Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12092463227
2024-11-30 01:35:08 +00:00
89f88a9333 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12092463227
2024-11-30 01:35:06 +00:00
9cab72ed59 5.21.3 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/12090411351
2024-11-29 20:43:17 +00:00
2bd9f4108b 5.21.2 (#6545) 2024-11-29 20:42:14 +00:00
cd2a1fdc1d Bump build/php from 8a396c6 to 5016e0a (#6541) 2024-11-29 11:03:27 +00:00
002383be89 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12077579940
2024-11-29 01:37:53 +00:00
a396233e57 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12077579940
2024-11-29 01:37:52 +00:00
d666f17ec6 Bump build/php from a51259d to 8a396c6 (#6540) 2024-11-28 15:46:30 +00:00
00bdb6be73 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12060967026
2024-11-28 01:37:50 +00:00
a84326cb2d Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12060967026
2024-11-28 01:37:49 +00:00
0543bf301e draft-release: updated php_download_url 2024-11-27 19:19:51 +00:00
c3c917bb05 Merge branch 'minor-next' into major-next 2024-11-27 17:56:45 +00:00
603ab081bc Merge branch 'stable' into minor-next 2024-11-27 17:56:34 +00:00
daacc8eddb Updated setup-php-action to 3.2.0 2024-11-27 17:56:00 +00:00
a078f653f4 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12042121495
2024-11-27 01:39:13 +00:00
269effcecf Introduce Utils::getRandomFloat() (#6532)
Drop-in replacement for lcg_value() for PHP 8.4
2024-11-26 11:33:29 +00:00
ed33983792 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12022106146
2024-11-26 01:36:42 +00:00
ae750b60d0 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/12022106146
2024-11-26 01:36:41 +00:00
905a10e980 Deprecate InventoryAction->onAddToTransaction()
this never made any sense
2024-11-25 21:39:35 +00:00
52fe2cb97f PermissionManager: deprecate permission subscription system
this is no longer used by the core, and as far as I can tell no plugin uses it either.
it was used in the past for chat broadcast channels, but not anymore.
2024-11-25 21:29:26 +00:00
8cdc7d7ee1 auto-approve: drop pull_request_review trigger
this doesn't work for PRs from forks, since fork PRs don't have access to repo secrets.

we'll need some more advanced mechanism to avoid redundant reviews, but that's a job for another time.
2024-11-25 20:43:59 +00:00
15eaf67a0c Merge branch 'minor-next' into major-next 2024-11-25 14:36:25 +00:00
12ae8dc03b Merge branch 'stable' into minor-next 2024-11-25 14:32:30 +00:00
a9787f0d99 Fix PHPStan error 2024-11-25 14:32:17 +00:00
5325ecee37 Deal with a whole lot of PHPStan suppressed key casting errors
closes #6534
2024-11-25 14:30:58 +00:00
d72941c36c Update IceBomb.php 2024-11-24 23:56:44 +00:00
e51903d7ea Merge branch 'minor-next' into major-next 2024-11-24 23:51:07 +00:00
30ee0aa63d Merge branch 'stable' into minor-next 2024-11-24 23:50:56 +00:00
aef4fa7174 Remove unused variable 2024-11-24 23:50:30 +00:00
53aa380ca3 Candle: fix extinguish logic
closes #5983
2024-11-24 23:49:32 +00:00
a5f607138c Implement Ice Bomb (#5452)
Co-authored-by: Dylan K. Taylor <dktapps@pmmp.io>
2024-11-24 15:01:26 +00:00
8338ebaffd Add generic types for TaskHandler (#6030) 2024-11-24 14:14:34 +00:00
3e9a96b43a Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11990667732
2024-11-23 21:49:02 +00:00
082119cfd2 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11990667732
2024-11-23 21:49:01 +00:00
7460e12b6a pr-remove-waiting-label: suppress failure on 404 errors
this usually means the label wasn't on the PR in the first place
2024-11-23 21:48:30 +00:00
9fce27eaa8 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11990103798
2024-11-23 20:14:24 +00:00
a53b0116a0 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11990103798
2024-11-23 20:14:23 +00:00
5b72f202bf actions: automatically remove waiting label from PRs on synchronize
there are probably other conditions where we'd want to remove this, but this will do for now.
2024-11-23 20:13:46 +00:00
7208733d62 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11989715327
2024-11-23 19:10:14 +00:00
8b6adf86d6 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11989715327
2024-11-23 19:10:12 +00:00
0070426e97 auto-approve: only re-review if previous review was dismissed
this avoids unnecessary spam when someone clicks "Update branch" on the PR.
2024-11-23 19:07:24 +00:00
c61434d87b Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11964819241
2024-11-22 01:36:17 +00:00
a523ed6e40 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11964819241
2024-11-22 01:36:16 +00:00
7c2ed7d884 Fix insta break check (#6528) 2024-11-21 02:22:10 +00:00
dcc258706f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11944832380
2024-11-21 01:27:14 +00:00
1e3a858de6 Add setUp and tearDown for event unit tests 2024-11-20 16:42:50 +00:00
844ba0ff9f Move event test fixtures to a subdirectory 2024-11-20 15:40:34 +00:00
49bdaee930 Move event handler inheritance test to PHPUnit using mock objects
this is dodgy and we shouldn't rely on it long term.

relates to #6524
2024-11-20 15:38:51 +00:00
9195c88670 ConsoleReader: Use proc_open()'s socket support to send commands back to the main server process (#5273)
Support for this was introduced in PHP 8.0, though not mentioned in any changelog: php/php-src#5777

This simplifies the subprocess handling considerably. However, there is a potential for problems if PHP generates any E_* errors, since these get written to STDOUT as well.
To avoid error messages being treated as a command, a hash is attached to each IPC message, seeded with an incrementing counter. This prevents error messages causing command replays or unintended commands.

Unfortunately, PHP doesn't support binding pipes other than stdin/stdout/stderr on Windows for the child process, so we have to use stdout for this. In the future, if it becomes possible, a dedicated pipe for the purpose should be introduced. We'd need something like php://fd/<number> to work on Windows.
2024-11-20 14:56:52 +00:00
820e2d4a2f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11924942897
2024-11-20 01:27:32 +00:00
ae19d05fd5 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11924942897
2024-11-20 01:27:30 +00:00
bf7a53b00f Update api-change-request.md
[ci skip]
2024-11-19 17:47:46 +00:00
e710b3750f Adjust pretty name of closures on PHP 8.4 (#6351)
related to https://github.com/php/php-src/pull/13550

see analog symfony change: https://github.com/symfony/symfony/pull/54614
2024-11-19 17:05:21 +00:00
0fb1415f7f Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11904511045
2024-11-19 01:36:12 +00:00
8ccd1edb17 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11904511045
2024-11-19 01:36:11 +00:00
faf1e26bac Fix: implicitly nullable parameter declarations deprecated (#6522) 2024-11-18 23:54:22 +00:00
a6534ecbbb Fixed merge error 2024-11-17 01:55:46 +00:00
330bcd2423 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11874902000
2024-11-17 01:39:53 +00:00
b4259ef988 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11874902000
2024-11-17 01:39:52 +00:00
b2aa6396c3 auto-approve: don't request approvals for draft PRs 2024-11-16 23:15:07 +00:00
1555fa17e7 Added ability to pick end crystal item (#6509) 2024-11-16 19:06:03 +00:00
e77f2c5198 Implemented End Crystal (#4715)
Co-authored-by: Dylan T. <dktapps@pmmp.io>
2024-11-16 17:57:57 +00:00
e71b9e8dc6 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11866065217
2024-11-16 01:37:29 +00:00
e8e441f739 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11866065217
2024-11-16 01:37:27 +00:00
48a908ee8c maybe making this specific to gameplay wasn't a good idea 2024-11-16 01:36:51 +00:00
9e2d91bae6 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11865975725
2024-11-16 01:26:32 +00:00
dc87a2b10e Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11865975725
2024-11-16 01:26:31 +00:00
d3add78d3e Add support for basic entity picking via middle-click (#5397)
Support for more advanced stuff like NBT copying wasn't added in this PR, as the NBT used by PM is currently an inconsistent mess and doesn't play nice with vanilla. In the interests of avoiding this mess propagating, it's been left for another time.

Adds PlayerEntityPickEvent a la PlayerBlockPickEvent
and Entity->getPickedItem().
2024-11-15 21:27:10 +00:00
ff695a5f97 PlayerInteractEvent: added APIs to independently control reaction of item and block (#4683)
This allows, for example, banning the usage of spawn eggs, without preventing opening of doors, without the need for item ID whitelists.

It also allows customizing the behaviour of item and block interactions when sneaking - it's now possible to force spawn eggs to work when sneaking, or force containers to open.

Finally, this also allows preventing any interaction at all without preventing block placement (by setting both to false). Since cancelling the event will typically prevent placement too (which might not be desired).

Side note: Blocks are now always synced when right-clicking on a block.
This differs from the previous behaviour, where the blocks were only synced when the action "failed".
However, since this change introduces a situation where the action may succeed but have different results than the client expects, it's best to just always sync blocks in this situation.

Fixes #3267
2024-11-15 21:19:54 +00:00
4b630cb726 start.sh: print warnings on unusual exit codes from the server process (#6497) 2024-11-15 21:14:21 +00:00
4331f69b9c Update team-pr-auto-approve.yml 2024-11-15 20:44:51 +00:00
b6f55b78a9 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11862895039
2024-11-15 20:21:33 +00:00
fb1213e964 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11862895039
2024-11-15 20:21:32 +00:00
8a693f2a4c team-pr-auto-approve: Use RestrictedActions auto approver 2024-11-15 20:08:54 +00:00
8474eaf5f1 Adjust Sugar Cane to break when there is no water (#6486) 2024-11-15 16:27:27 +00:00
a75d4687ce Implemented vanilla /xp command (#6429) 2024-11-15 16:09:55 +00:00
0b0c425805 Extract glow lichen multi face logic into traits (#6396)
This will be useful for future block additions
2024-11-15 15:47:26 +00:00
b5469dede2 Flowable blocks now can't be placed inside liquid (#5392) 2024-11-15 00:10:43 +00:00
ab5176baf9 Merge branch 'minor-next' into major-next 2024-11-14 23:16:44 +00:00
e0d270a870 Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into minor-next 2024-11-14 23:14:33 +00:00
2d9cee3d62 Update Language dependency 2024-11-14 23:14:23 +00:00
ed64231c57 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2024-11-14 23:12:26 +00:00
33a7b46329 Use reflection to locate BlockTypeIds and ItemTypeIds for VanillaBlocks/VanillaItems (#6498)
Use reflection to locate BlockTypeIds and ItemTypeIds for VanillaBlocks/VanillaItems

Since BlockTypeIds and ItemTypeIds are derived from VanillaBlocks and VanillaItems respectively anyway (they only exist to allow identifying blocks/items without having to create instances of them), this hack is probably OK, and reduces the chances of mistakes.
Previously it was explored to have these IDs generated by auto-incrementing in VanillaBlocks/Items and have the constants generated that way, but this proved to be too problematic because of unstable diffs no matter how we chose to sort the elements. See #6313 for previous research on the subject.

This is obviously not a desirable hack to keep long-term. In the future it will probably make sense to redesign VanillaBlocks like so:

enum VanillaBlocks { ... }
VanillaBlocks::STONE (the type ID)
VanillaBlocks::STONE->new() (to create a block)

However, more research is needed on this, as I'd prefer not to make block creation any more verbose.
2024-11-14 17:32:22 +00:00
9b58d35516 Implement Goat horns (#5232)
Co-authored-by: ipad54 <63200545+ipad54@users.noreply.github.com>
Co-authored-by: Dylan T. <dktapps@pmmp.io>
2024-11-14 13:57:07 +00:00
ef6fce4091 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11824307499
2024-11-13 19:21:19 +00:00
3629ee7e7b Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11824307499
2024-11-13 19:21:16 +00:00
fbeb017670 Promise: allow zero promises
not supporting this has caused problems every time this function has been used in reality so far (#6092 and #6333).
2024-11-13 14:55:14 +00:00
09bf203267 Update RuntimeDataDescriber.php 2024-11-12 22:57:14 +00:00
f3cc4a28e1 Easy wins for PHPStan 2.0 support 2024-11-12 22:12:54 +00:00
fe70150db2 Update composer dependencies 2024-11-12 21:47:52 +00:00
054538e6b7 Update PULL_REQUEST_TEMPLATE.md 2024-11-12 17:54:31 +00:00
cc335889f3 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11802296296
2024-11-12 17:14:26 +00:00
3586bc42a9 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11802296296
2024-11-12 17:14:24 +00:00
1f86949836 Create CODEOWNERS 2024-11-12 14:37:02 +00:00
053a71c59d Bump build/php from 084822a to a51259d (#6495) 2024-11-12 14:28:32 +00:00
07d5046b83 5.21.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/11796630402
2024-11-12 11:48:59 +00:00
4a702b97fd Prepare 5.21.1 release (#6493) 2024-11-12 11:48:01 +00:00
d2c3b8dacb Fix GC cycle count increases on player disconnect (#6487) 2024-11-11 16:10:19 +01:00
80b7f6aba4 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11769186885
2024-11-10 22:56:09 +00:00
fa3529966f Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11769186885
2024-11-10 22:56:08 +00:00
2ff6470792 Fixed server crash when applying item cooldown (#6491)
This commit fixes server crash when applying a cooldown to any item which count is equals to 1.

closes #6490 
closes #6488
2024-11-10 19:15:30 +00:00
05a9e9c76e Implemented sound when drinking a potion (#6444) 2024-11-10 15:07:18 +00:00
231eec911f Enchanted Golden Apple: Regeneration 5 => 2 matching Java (#6445) 2024-11-09 19:43:30 +00:00
8c04d47b1b Make weakness effect only applicable for melee damage (#6489) 2024-11-09 19:18:30 +00:00
b3b8aaddff Bump docker/build-push-action from 6.8.0 to 6.9.0 (#6465) 2024-11-04 16:29:01 +00:00
2173aab967 Bump thollander/actions-comment-pull-request from 2 to 3 (#6482) 2024-11-04 16:05:38 +00:00
82c5a3160c Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11652590245
2024-11-03 15:33:37 +00:00
e598364f06 5.21.1 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/11652565588
2024-11-03 15:30:16 +00:00
734ca1cc6b Merge pull request #6480 from pmmp/minor-next
5.21.0
2024-11-03 15:29:06 +00:00
96b12bddc1 Prepare 5.21.0 release 2024-11-03 15:24:43 +00:00
84464cde4f Update BedrockBlockUpgradeSchema 2024-11-03 14:44:50 +00:00
72fc138631 Regenerate PHPStan baselines 2024-11-03 14:43:34 +00:00
c63d0ef1b6 Fix dodgy ignored PHPStan error 2024-11-03 14:43:34 +00:00
82c416624d Merge pull request #6416 from pmmp/blockstate-schema-generator-improvements
Blockstate schema generator improvements
2024-11-03 14:10:38 +00:00
9e19391f20 Merge branch 'minor-next' into blockstate-schema-generator-improvements 2024-11-03 14:06:57 +00:00
c0b74b0341 Update BlockStateUpgrader.php 2024-11-03 14:05:46 +00:00
85de28d6c3 Merge branch 'minor-next' into major-next 2024-11-03 14:02:06 +00:00
3c96e72f7d Merge remote-tracking branch 'origin/stable' into minor-next 2024-11-03 14:01:47 +00:00
0376e37966 5.20.2 is next
Commit created by: https://github.com/pmmp/RestrictedActions/actions/runs/11614028030
2024-10-31 14:38:30 +00:00
94dff74494 Prepare 5.20.1 release (#6479) 2024-10-31 14:35:42 +00:00
0065fe649f New release workflow triggered by the merge of a PR changing
IS_DEVELOPMENT_BUILD to false

This is more streamlined than the previous approach, and works better
for a world where 1 person isn't doing all the work.

Now, the flow is simpler:
- Do changes (e.g. protocol update), changelog & set IS_DEVELOPMENT_BUILD to false all in a single PR, which can be squash-merged if desired
- Once the PR is merged, a draft release will be prepared
- RestrictedActions will automatically set IS_DEVELOPMENT_BUILD back to
  true and bump the version
- Tag will be created when the release is published

Previously, multiple PRs might be needed, and the PR containing the
release changelog couldn't be squash-merged. Manual intervention was
also required to create a tag and prepare a release.

This PR also includes new CI checks to check for basic errors like
forgotten changelog files to ensure changelog links work correctly.

Note: Only PRs from PMMP Team members with **write** access to the
repository can trigger release generation. Random people cannot trigger
release generation by sending PRs.
2024-10-31 13:57:38 +00:00
8ef5e737de Temporary resolve loading old skulls from storage (#6476) 2024-10-27 01:29:34 +01:00
e7d8d99ca6 5.20.1 is next 2024-10-26 15:42:43 +01:00
414e8acf8c Release 5.20.0 2024-10-26 15:42:43 +01:00
d372af351a Fix changelog typo 2024-10-26 15:40:22 +01:00
4814db4fe7 Assemble 1.21.40 (#6471) 2024-10-25 14:21:51 +01:00
d01203d7c4 Reduce code duplication 2024-10-24 18:50:39 +01:00
847f931660 Merge branch 'minor-next' into blockstate-schema-generator-improvements 2024-10-24 17:46:57 +01:00
22718c4971 Add support for specialized flattenedProperties in schema format 2024-10-24 16:12:28 +01:00
acbfb0a3e9 Support for updating a batch of schemas using BlockPaletteArchive 2024-10-24 13:30:55 +01:00
7f9e79c83e Automatically test new schemas to ensure they produce the results predicted by the input file 2024-10-24 13:30:24 +01:00
7e343617b9 Rename ICopper to CopperMaterial (#6470) 2024-10-23 11:34:42 +01:00
d945cbf517 Merge remote-tracking branch 'origin/minor-next' into blockstate-schema-generator-improvements 2024-10-17 21:00:11 +01:00
1ef854f2d1 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11392123557
2024-10-17 19:59:15 +00:00
c4e72c880e Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/11392123557
2024-10-17 19:59:13 +00:00
3ef7001d8e Merge branch 'stable' into blockstate-schema-generator-improvements 2024-10-17 20:55:34 +01:00
f1b1a7022d and a sanity check just in case 2024-10-17 20:55:12 +01:00
59d14de1d8 generate-blockstate-upgrade-schema: fallback to exact state match when encountering ambiguous filters
this popped up due to new changes in 1.20.40. Really we need to improve the way the filters are calculated, but this workaround solves the issue for now.
2024-10-17 20:51:17 +01:00
c8f567b093 Fix missing arg count check 2024-10-17 20:24:57 +01:00
5cc1068cd4 Bump docker/build-push-action from 6.7.0 to 6.8.0 (#6462) 2024-10-03 21:29:22 +00:00
f6e6f15c63 Implemented a proper way to handle items cooldown (#6405) 2024-09-25 13:28:17 -05:00
4e6b34f573 Implement new 1.21 copper blocks (#6366)
Added the following new blocks:
- All types of Copper Bulb
- All types of Copper Door
- All types of Copper Trapdoor
- All types of Chiseled Copper
- All types of Copper Grate
2024-09-24 21:25:10 -05:00
082af9978c Merge branch 'minor-next' into major-next 2024-09-23 15:08:45 -05:00
e8620ef94d Restore travis.sh execute permission 2024-09-22 21:59:40 -05:00
83a91634c3 Merge branch 'minor-next' into sync-major-next 2024-09-22 21:44:31 -05:00
a4a07a8e5a Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/10986731877
2024-09-23 02:36:00 +00:00
0a7cbdd56d Release 5.19.0 (1.21.30 support) 2024-09-21 11:50:04 -05:00
a5babb2c9f 5.19.1 is next 2024-09-20 19:00:23 -05:00
49c2f13cf0 Release 5.19.0 2024-09-20 18:59:45 -05:00
60cac18104 Assemble 1.21.30 (#6453) 2024-09-20 18:47:25 -05:00
f6e2a1ecce Validate transaction slots (#6304) 2024-09-09 09:48:38 +02:00
00e39821f0 Release 5.18.1 (patch) 2024-09-03 06:46:21 -05:00
72d941fc1b Update 5.18.md 2024-09-03 11:33:05 +01:00
8cb2e577a1 Implement missing last interacted slot property in chiseled bookshelf (#6440) 2024-09-02 18:02:06 -05:00
2a7b183ab8 5.18.2 is next 2024-09-02 11:25:50 -05:00
e9b597af6c Release 5.18.1 2024-09-02 11:24:42 -05:00
9381fc4172 Blue Ice: No longer emits light & it's now dropped when mined with a tool with silk touch enchantment (#6438) 2024-08-31 22:33:11 -06:00
281afb6838 Bump phpstan/phpstan in the development-patch-updates group (#6435) 2024-08-26 23:05:11 +00:00
ede363eb0f Fix shift crafting (#6433)
This field was added to the action in 1.21.20. Previously, the client would behave as if clicking the crafting result slot many times. Now it behaves more like recipe book shift-clicking.
2024-08-22 21:53:21 +01:00
bdbcfd10cc Add ShellCheck (#6407)
Co-authored-by: IvanCraft623 <57236932+IvanCraft623@users.noreply.github.com>
2024-08-19 22:52:51 +01:00
e6f9cdd990 Bump docker/build-push-action from 6.6.1 to 6.7.0 (#6432) 2024-08-19 18:12:06 +00:00
5241118f0b Merge branch 'minor-next' into blockstate-schema-generator-improvements 2024-08-19 19:05:08 +01:00
3c73bd22dd Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/10458521667
2024-08-19 18:03:25 +00:00
93a270d251 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/10458521667
2024-08-19 18:03:24 +00:00
a7638cf914 Give an approving review to team member PRs automatically
Branch protection rules currently require 2 approving reviews to merge a PR. What we really want is for 2 team members to be aware of every change. If a team member makes a PR, only one other approval should be needed.

Since GitHub doesn't currently allow us to set different review thresholds for different users/teams, sending an automatic approval via GitHub Actions is the next best thing. This should reduce friction of team development work.
2024-08-19 19:02:17 +01:00
0e1824451b Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/10442250915
2024-08-18 16:50:43 +00:00
c44e6c59fc Merge pull request #6430 from pmmp/sync-minor-next
Merge branch 'stable' into minor-next
2024-08-18 17:49:25 +01:00
92f380bb9c Merge branch 'stable' into sync-minor-next 2024-08-17 11:17:48 -05:00
c32744ebc7 Release 5.18.0 (1.21.20 support) 2024-08-16 08:44:40 -05:00
e3baf3cddb 5.18.1 is next 2024-08-16 07:56:01 -05:00
9176b2494a Release 5.18.0 2024-08-16 07:54:59 -05:00
0f365886e0 Assemble 1.21.20 (#6423)
Co-authored-by: Dylan T. <dktapps@pmmp.io>
Co-authored-by: IvanCraft623 <ivancraft623@gmail.com>
2024-08-16 11:26:49 +01:00
8c3cf7a687 Use VISIBLE_MOB_EFFECTS actor metadata property to send effect bubbles (#6414)
Close #6402
2024-08-14 22:48:10 -05:00
6c5ae634fd Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/10373700926
2024-08-13 16:37:46 +00:00
994fa5f792 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/10373700926
2024-08-13 16:37:45 +00:00
3ed9615180 Merge pull request #6422 from pmmp/5.17.1
Release patch update 5.17.1
2024-08-13 17:28:27 +01:00
f5ab2979a0 5.17.2 is next 2024-08-13 10:56:03 -05:00
13f5cc9f87 ChiseledBookshelf: fixed function visibility (#6421) 2024-08-13 16:11:22 +01:00
041944ed16 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/10371827817
2024-08-13 14:36:02 +00:00
1ce774ae73 Merge 'stable' into 'minor-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/10371827817
2024-08-13 14:36:00 +00:00
603527c6e8 Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into major-next 2024-08-13 13:39:00 +00:00
e017780cc3 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2024-08-13 13:37:56 +00:00
1ac08ea73b Remove enchant properties that no longer exists on PM6 (#6417) 2024-08-10 08:51:06 -05:00
c9e8d382c5 Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into major-next 2024-08-09 13:33:07 +01:00
ee17ac5246 Merge branch 'stable' of github.com:pmmp/PocketMine-MP into minor-next 2024-08-09 13:32:07 +01:00
33dc995cc7 blockstate-upgrade-schema-utils: added a command to update old schemas to a newer format
this is useful when the generator was updated with new features & optimisations, to reduce the size and/or improve readability of existing schemas.
2024-08-09 13:12:46 +01:00
26761c2b87 Blockstate schema tool now supports testing schemas as well as generating them
this is useful when making changes to the generator, since regenerated schemas can now be tested for validity. This helps to find bugs in the generator.
2024-08-09 12:38:03 +01:00
c4a2b6494d Implement Aqua Affinity enchantment (#6408) 2024-08-06 09:12:47 -05:00
2aa64dc15e Simplify phpstan-doc type hint for better readability 2024-08-05 17:13:23 -05:00
d0d7a995fb Add a TODO in BlockStateUpgrader
this issue can be worked around by adding a dummy schema, but it's a bit clunky.
2024-08-05 22:38:32 +01:00
be2437ac6e Support for flattening TAG_Byte and TAG_Int properties
this allows optimisation in upcoming versions.
2024-08-05 22:38:02 +01:00
bdb5845cec Allow name flattening rules where multiple old values map to the same new ID
this allows more compaction in certain cases, such as tallgrass recently.
instead of blacklisting any mapping which reuses the same flattened infix, we select the flatten property which produces the smallest number of distinct rules, which produces the most compact schema possible.
this change also permits potentially flattening other types of properties such as for corals (live/dead and type), although only one may be selected at a time.
2024-08-05 22:34:40 +01:00
787afb6b00 Implement all new 1.21 tuff blocks (#6391) 2024-07-23 11:34:46 -05:00
d6c48fd3a2 Implement new 1.21 paintings (#6393) 2024-07-12 13:24:43 +01:00
ef9791eaed Merge pull request #6397 from pmmp/stable
Merge branch 'stable' into minor-next
2024-07-10 18:56:52 +01:00
accaa0acce Implement ICopper interface for blocks with common properties (#6390) 2024-07-10 11:15:06 -05:00
2ffc38c835 Implement campfire & soul campfire (#4696) 2024-07-07 15:01:34 -05:00
f6c0b228ec Add flow and guster banner patterns 2024-07-04 16:47:18 -05:00
b342c497d1 Added 1.21 banner patterns. 2024-06-23 13:27:52 +03:00
428e38f913 Merge branch 'stable' into minor-next 2024-06-21 10:42:32 -05:00
5ae13209c0 Merge branch 'stable' into merge-stable 2024-06-20 19:21:33 -05:00
Max
371eccd007 Make access modifier consistent with parent abstract class (#6341) 2024-05-07 12:02:50 +01:00
12179aa03a Merge branch 'minor-next' into major-next 2024-05-06 15:42:49 +01:00
e781c64540 Merge branch 'minor-next' into major-next 2024-03-14 12:47:18 +00:00
644693ffee Merge branch 'minor-next' into major-next 2024-02-12 11:55:36 +00:00
6b66cbfb1c Merge branch 'minor-next' into major-next 2023-12-20 15:26:57 +00:00
4d337add7c Merge branch 'minor-next' into major-next 2023-12-14 14:03:09 +00:00
9d75c45bf5 Merge branch 'minor-next' into major-next 2023-11-09 18:06:06 +00:00
c7a537abbb Merge branch 'minor-next' into major-next 2023-11-01 18:03:04 +00:00
54694df48c Merge branch 'minor-next' into major-next 2023-11-01 16:39:55 +00:00
15aae721cd Merge branch 'minor-next' into major-next 2023-10-26 12:57:24 +01:00
d565be93a8 Merge branch 'minor-next' into major-next 2023-10-24 11:57:30 +01:00
e32a90be72 Make Player->getFirstPlayed() and Player->getLastPlayed() return DateTimeImmutable (#6042) 2023-10-17 16:26:21 +01:00
d4d7d02067 Merge branch 'minor-next' into major-next 2023-10-16 21:29:11 +01:00
a45e143e81 Merge branch 'minor-next' into major-next 2023-09-21 13:29:58 +01:00
05981d2669 Merge branch 'minor-next' into major-next 2023-09-20 19:15:08 +01:00
fa9bba470c RegistryTrait: use native parameter types for __callStatic() arguments (#5944) 2023-09-08 12:03:03 +01:00
361626d236 Merge branch 'minor-next' into major-next 2023-09-08 11:27:09 +01:00
16d8522245 Farewell EnumTrait, you served us well 2023-09-08 11:26:11 +01:00
a4f3476190 Merge branch 'minor-next' into major-next 2023-09-08 11:22:44 +01:00
e96e68d221 Merge branch 'minor-next' into major-next 2023-09-07 20:33:35 +01:00
f1a6d71cc1 Merge branch 'minor-next' into major-next 2023-09-07 20:30:58 +01:00
89f42c80d4 Strip out deprecated stuff 2023-09-07 20:26:04 +01:00
cd6b780d31 Merge branch 'minor-next' into major-next 2023-09-07 20:10:31 +01:00
ed61a68013 Entity: make getNetworkTypeId non-static (#6037)
This was static to permit ItemFactory to register spawn eggs for all known entity types in early PM4. However, nowadays we provide a callback to the spawn egg instead, and spawn eggs must be manually implemented, so this is no longer needed.

In addition, having this static forces everyone to make a new entity class for every unique type of entity, which isn't ideal.
2023-09-06 15:26:32 +01:00
4dc9d696d0 Merge branch 'minor-next' into major-next 2023-09-06 13:03:51 +01:00
258038c9a9 Merge branch 'minor-next' into major-next 2023-08-21 16:08:32 +01:00
5c915a3dfe Merge branch 'minor-next' into major-next 2023-08-18 12:33:54 +01:00
8c594fd126 Merge branch 'minor-next' into major-next 2023-08-15 17:41:50 +01:00
9fd6653f36 Remove deprecated APIs 2023-08-09 16:38:09 +01:00
32d67080e5 Merge branch 'minor-next' into major-next 2023-08-09 16:35:32 +01:00
ed9d057ca2 Merge branch 'minor-next' into major-next 2023-08-08 18:27:58 +01:00
5ec0e0f20b Merge branch 'minor-next' into major-next 2023-08-08 17:48:23 +01:00
cb251069dd PluginLoader: rename parameters 2023-08-07 16:39:54 +01:00
e0ad39b70a Remove ResourceProvider cruft
this had no obvious reason for existing, and with #5958 looming, this will become altogether useless anyway.
2023-08-07 16:14:01 +01:00
9997b614bc Merge branch 'minor-next' into major-next 2023-08-01 12:53:53 +01:00
89f8f421a6 Server: stop discriminating against folder plugins when generating crashdumps
in PM6, non-development plugins may appear in folder form.
2023-07-26 10:47:39 +01:00
c4ff6d7757 Merge branch 'minor-next' into major-next 2023-07-24 16:45:55 +01:00
3c0e7ae492 Merge branch 'minor-next' into major-next 2023-07-24 12:07:55 +01:00
b944205f60 Remove useless checks for plugins disabling other plugins (#5931) 2023-07-24 11:31:19 +01:00
2ab3393568 Unlink DevTools submodule and remove references
we don't need this as a submodule anymore, since it's not used in the core.
2023-07-20 11:29:06 +01:00
1e1b95e1b8 uh oh 2023-07-19 18:06:44 +01:00
62465fa676 Integrate FolderPluginLoader
the motivation for this is described in #5917

a new version of DevTools will be required, as the current version will cause the server to abort during startup with this change due to duplicated plugin loading.
2023-07-19 18:05:41 +01:00
aac5944396 Accept Translatable permission messages in Command (#5830) 2023-07-19 16:38:15 +01:00
74cfd687d7 CraftingManagerFromDataHelper: Fix parameter name typo (#5870)
due to named parameters, this change must target PM6
2023-07-19 11:05:52 +01:00
f2f30143b0 Merge branch 'minor-next' into major-next 2023-07-18 22:22:43 +01:00
d98adf127f Merge branch 'minor-next' into major-next 2023-07-17 16:13:28 +01:00
280bf60830 Merge branch 'minor-next' into major-next 2023-07-14 13:28:07 +01:00
1ffa945fbf Disallow plugins disabling other plugins (#5872) 2023-07-13 13:44:28 +01:00
756 changed files with 23295 additions and 14693 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
* @pmmp/server-developers

View File

@ -1,19 +0,0 @@
---
name: API change request
about: Suggest a change, addition or removal to the plugin API
title: ''
labels: ''
assignees: ''
---
<!--- tell us what you want -->
## Description
<!--- explain why you want this and why it's a good idea -->
## Justification
<!--- (optional) describe alternative methods you've explored to achieve your goal -->
## Alternative methods

87
.github/ISSUE_TEMPLATE/bug-report.yml vendored Normal file
View File

@ -0,0 +1,87 @@
name: Bug report
description: Report a feature of PocketMine-MP not working as expected
body:
- type: markdown
attributes:
value: |
## Plugin information
> [!IMPORTANT]
> It's strongly recommended to test for bugs without plugins before reporting an issue.
> This helps avoid wasting maintainers' time on bugs that are not actually caused by PocketMine-MP.
>
> If you're not sure whether a plugin might be causing your issue, please seek help on our [Discord](https://discord.gg/bmSAZBG) before writing an issue.
- type: dropdown
attributes:
label: Plugin information
options:
- "I haven't tested without plugins"
- Bug happens without plugins
- Bug only happens with certain plugins (describe below)
validations:
required: true
- type: markdown
attributes:
value: |
## Bug description
> [!TIP]
> Helpful information to include:
> - Steps to reproduce the issue
> - Error backtraces
> - Crashdumps
> - Plugin code that triggers the issue
> - List of installed plugins (use /plugins)
> [!IMPORTANT]
> **Steps to reproduce are critical to finding the cause of the problem!**
> Without reproducing steps, the issue will probably not be solvable and may be closed.
- type: textarea
attributes:
label: Problem description
description: Describe the problem, and how you encountered it
placeholder: e.g. Steps to reproduce the issue
validations:
required: true
- type: textarea
attributes:
label: Expected behaviour
description: What did you expect to happen?
validations:
required: true
- type: markdown
attributes:
value: |
## Version, OS and game info
> [!WARNING]
> "Latest" is not a valid version.
> Failure to fill these fields with valid information may result in your issue being closed.
- type: input
attributes:
label: PocketMine-MP version
placeholder: Use the /version command in PocketMine-MP
validations:
required: true
- type: input
attributes:
label: PHP version
placeholder: Use the /version command in PocketMine-MP
validations:
required: true
- type: input
attributes:
label: Server OS
placeholder: Use the /version command in PocketMine-MP
validations:
required: true
- type: input
attributes:
label: Game version (if applicable)
placeholder: e.g. Android, iOS, Windows, Xbox, PS4, Switch
validations:
required: false

View File

@ -1,37 +0,0 @@
---
name: Bug report
about: Unexpected non-crash behaviour (except missing gameplay features)
title: ''
labels: ''
assignees: ''
---
### Issue description
- Expected result: What were you expecting to happen?
- Actual result: What actually happened?
### Steps to reproduce the issue
1. ...
2. ...
### OS and versions
<!-- try the `version` command | LATEST IS NOT A VALID VERSION -->
* PocketMine-MP:
* PHP:
* Using JIT: yes/no (delete as appropriate) <!-- look for the giant yellow warning in the log that says you're using JIT -->
* Server OS:
* Game version: Android/iOS/Win10/Xbox/PS4/Switch (delete as appropriate)
### Plugins
<!--- use the `plugins` command and paste the output below -->
- If you remove all plugins, does the issue still occur?
- If the issue is **not** reproducible without plugins:
- Have you asked for help on our forums before creating an issue?
- Can you provide sample, *minimal* reproducing code for the issue? If so, paste it in the bottom section
### Crashdump, backtrace or other files
<!--- Submit crashdumps at https://crash.pmmp.io and paste a link -->
<!--- Use gist or anything else to add other files and add links here -->

View File

@ -3,9 +3,6 @@ contact_links:
- name: Help & support on Discord
url: https://discord.gg/bmSAZBG
about: We don't accept support requests on the issue tracker. Please try asking on Discord instead.
- name: Help & support on forums
url: https://forums.pmmp.io
about: We don't accept support requests on the issue tracker. Please try asking on forums instead.
- name: Documentation
url: https://pmmp.rtfd.io
about: PocketMine-MP documentation

View File

@ -1,16 +0,0 @@
---
name: Crash
about: Report a crash in PocketMine-MP (not plugins)
title: Server crashed
labels: ''
assignees: ''
---
<!--- submit crashdump files to https://crash.pmmp.io -->
<!--- or, copy the data between ===BEGIN CRASH DUMP=== and ===END CRASH DUMP and paste it on a site like https://pastebin.com -->
<!--- DON'T JUST PASTE the crashdump into an issue -->
Link to crashdump:
<!--- write additional information about the crash to help us find the problem -->
### Additional comments (optional)

25
.github/ISSUE_TEMPLATE/crash.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Crash
description: Report a crash in PocketMine-MP (not plugins)
title: Server crashed
body:
- type: markdown
attributes:
value: |
> [!TIP]
> Submit crashdump `.log` files to the [Crash Archive](https://crash.pmmp.io/submit).
> If you can't submit the crashdump to the Crash Archive, paste it on a site like [GitHub Gist](https://gist.github.com) or [Pastebin](https://pastebin.com).
> [!CAUTION]
> DON'T paste the crashdump data directly into an issue.
- type: input
id: crashdump-url
attributes:
label: Link to crashdump
validations:
required: true
- type: textarea
attributes:
label: Additional comments (optional)
description: Any other information that might help us solve the problem

View File

@ -0,0 +1,19 @@
name: Feature addition, change, or removal
description: Propose adding new features, or changing/removing existing ones
body:
- type: textarea
attributes:
label: Problem description
description: Explain why a change is needed
validations:
required: true
- type: textarea
attributes:
label: Proposed solution
description: Describe what changes you think should be made
validations:
required: true
- type: textarea
attributes:
label: "Alternative solutions or workarounds"
description: "Describe other ways you've explored to achieve your goal"

View File

@ -1,43 +1,32 @@
## Introduction
<!-- Summarize your PR here. Keep it short and simple. -->
<!-- Explain existing problems or why this pull request is necessary -->
### Relevant issues
<!-- List relevant issues here -->
### Related issues & PRs
<!--
* Fixes #1
* Fixes #2
* Related to #2
-->
## Changes
### API changes
<!-- Any additions to the API that should be documented in release notes? -->
<!-- If not, you can delete this section -->
### Behavioural changes
<!-- Any change in how the server behaves, or its performance? -->
<!-- If not, you can delete this section -->
## Backwards compatibility
<!-- Any possible backwards incompatible changes? How are they solved, or how can they be solved? -->
<!-- If not, you can delete this section -->
## Follow-up
<!-- Suggest any actions to be done before/after merging this pull request -->
<!--
Requires translations:
| Name | Value in eng.ini |
| :--: | :---: |
| `foo.bar` | `Foo bar` |
-->
<!-- For example, future changes that this PR lays the groundwork for -->
## Tests
<!--
PRs which have not been tested MUST be marked as draft.
If this PR affects gameplay or user experience in some way, it must be manually tested.
Include any screenshots or videos of manual testing here.
Any test plugin code should also be pasted here if it can't be adapted to a PHPUnit test.
-->
I tested this PR by doing the following (tick all that apply):
- [ ] Writing PHPUnit tests (commit these in the `tests/phpunit` folder)
- [ ] Playtesting using a Minecraft client (provide screenshots or a video)
- [ ] Writing a test plugin (provide the code and sample output)
- [ ] Other (provide details)

View File

@ -12,6 +12,10 @@ updates:
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
#since we lock this to exact versions, it causes conflicts with minor-next & major-next in composer.lock
#better to just test updates to this locally anyway since almost every version breaks something
- dependency-name: phpstan/phpstan
groups:
production-patch-updates:
dependency-type: production
@ -37,4 +41,7 @@ updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
interval: monthly
groups:
github-actions:
patterns: ["*"]

View File

@ -0,0 +1,32 @@
#Since GitHub automatically disables cron actions after 60 days of repo inactivity, we need the active repo (PM)
#to trigger the branch merge workflow explicitly. This avoids the need for TOS-violating actions which we previously
#used to keep the restricted action active, as the workflow depends on the activity of this repo anyway.
name: Trigger branch sync
on:
schedule:
- cron: "0 0 * * *" #once per day so we don't spam merge commits on busy days
workflow_dispatch: #for testing
jobs:
trigger:
name: Trigger branch sync RestrictedActions workflow
runs-on: ubuntu-22.04
steps:
- name: Generate access token
id: generate-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
owner: ${{ github.repository_owner }}
repositories: RestrictedActions
- name: Dispatch branch sync restricted action
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ steps.generate-token.outputs.token }}
repository: ${{ github.repository_owner }}/RestrictedActions
event-type: pocketmine_mp_branch_sync

View File

@ -4,11 +4,16 @@ on:
release:
types:
- published
workflow_dispatch:
inputs:
release:
description: 'Tag name to build'
required: true
jobs:
build:
name: Update Docker Hub images
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Set up Docker Buildx
@ -28,16 +33,28 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Clone pmmp/PocketMine-Docker repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
repository: pmmp/PocketMine-Docker
fetch-depth: 1
- name: Get tag names
- name: Get tag name
id: tag-name
run: |
VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
echo TAG_NAME=$VERSION >> $GITHUB_OUTPUT
if [[ "${{ github.event_name }}" == "release" ]]; then
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
else
echo "Unsupported event type: ${{ github.event_name }}"
exit 1
fi
- name: Parse version
id: version
run: |
VERSION="${{ steps.tag-name.outputs.TAG_NAME }}"
echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT
echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT
@ -53,7 +70,7 @@ jobs:
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
- name: Build image for tag
uses: docker/build-push-action@v6.6.1
uses: docker/build-push-action@v6.18.0
with:
push: true
context: ./pocketmine-mp
@ -66,33 +83,33 @@ jobs:
- name: Build image for major tag
if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v6.6.1
uses: docker/build-push-action@v6.18.0
with:
push: true
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 }}
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MAJOR }}
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MAJOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
- name: Build image for minor tag
if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v6.6.1
uses: docker/build-push-action@v6.18.0
with:
push: true
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 }}
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MINOR }}
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MINOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
- name: Build image for latest tag
if: steps.channel.outputs.CHANNEL == 'stable'
uses: docker/build-push-action@v6.6.1
uses: docker/build-push-action@v6.18.0
with:
push: true
context: ./pocketmine-mp

View File

@ -0,0 +1,47 @@
name: "Copilot Agent environment setup"
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml
pull_request:
paths:
- .github/workflows/copilot-setup-steps.yml
jobs:
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
copilot-setup-steps:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0
with:
php-version: 8.3
install-path: "./bin"
pm-version-major: 5
- name: Restore Composer package cache
uses: actions/cache@v4
with:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
key: "composer-v2-cache-8.3-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
- name: Install Composer dependencies
run: composer install --prefer-dist --no-interaction
- name: Clone extension stubs
uses: actions/checkout@v5
with:
repository: pmmp/phpstorm-stubs
path: extension-stubs

View File

@ -4,18 +4,23 @@ on:
release:
types:
- published
workflow_dispatch:
inputs:
release:
description: 'Release to make notification for'
required: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.31.1
uses: shivammathur/setup-php@2.35.4
with:
php-version: 8.2
php-version: 8.3
- name: Restore Composer package cache
uses: actions/cache@v4
@ -30,9 +35,17 @@ jobs:
- name: Install Composer dependencies
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
- name: Get actual tag name
- name: Get tag name
id: tag-name
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
run: |
if [[ "${{ github.event_name }}" == "release" ]]; then
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
else
echo "Unsupported event type: ${{ github.event_name }}"
exit 1
fi
- 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

@ -0,0 +1,111 @@
name: Release PR checks
on:
#do checks on every PR update
pull_request:
branches:
- stable
- minor-next
- major-next
- "legacy/*"
paths:
- "src/VersionInfo.php"
#allow this workflow to be invoked on PR merge, prior to creating the release
workflow_call:
outputs:
valid:
description: Whether this commit is valid for release
value: ${{ jobs.check-intent.outputs.valid && jobs.check-validity.result == 'success' }}
permissions:
contents: read #for user access check
jobs:
check-intent:
name: Check release trigger
runs-on: ubuntu-22.04
outputs:
valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }}
steps:
- uses: actions/checkout@v5
- name: Check IS_DEVELOPMENT_BUILD flag
id: validate
run: |
echo DEV_BUILD=$(sed -n "s/^\s*public const IS_DEVELOPMENT_BUILD = \(true\|false\);$/\1/p" src/VersionInfo.php) >> $GITHUB_OUTPUT
check-validity:
name: Validate release info
needs: [check-intent]
#don't do these checks if this isn't a release - we don't want to generate unnecessary failed statuses
if: needs.check-intent.outputs.valid == 'true'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- name: Setup PHP
uses: shivammathur/setup-php@2.35.4
with:
php-version: 8.3
- name: Restore Composer package cache
uses: actions/cache@v4
with:
path: |
~/.cache/composer/files
~/.cache/composer/vcs
key: "composer-v2-cache-${{ hashFiles('./composer.lock') }}"
restore-keys: |
composer-v2-cache-
- name: Install Composer dependencies
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
- name: Check author permissions
id: check-permission
uses: actions-cool/check-user-permission@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
require: write
username: ${{ github.event.pull_request.user.login }}
#technically this would be fine for dependabot but generally bots don't count as team members
check-bot: true
- name: Abort if user permissions are insufficient
#user doesn't have permission or is a bot
if: steps.check-permission.outputs.require-result != 'true' || steps.check-permission.outputs.check-result != 'false'
run: |
echo "::error::This user is not authorized to trigger releases"
exit 1
- name: Check changelog file is present
id: file-presence
run: |
CHANGELOG_FILE="changelogs/$(php build/dump-version-info.php changelog_file_name)"
if [ ! -f "${{ github.workspace }}/$CHANGELOG_FILE" ]; then
echo "::error::$CHANGELOG_FILE does not exist"
exit 1
fi
echo FILE="$CHANGELOG_FILE" >> $GITHUB_OUTPUT
- name: Check header is present in changelog file
run: |
FILE="${{ steps.file-presence.outputs.FILE }}"
VERSION="$(php build/dump-version-info.php base_version)"
if ! grep -Fqx "# $VERSION" "${{ github.workspace }}/$FILE"; then
echo "::error::Header for $VERSION not found in $FILE"
exit 1
fi
- name: Check version is valid for the selected channel
run: |
CHANNEL="$(php build/dump-version-info.php channel)"
if [ "$(php build/dump-version-info.php suffix_valid)" != "true" ]; then
echo "::error::Version $(php build/dump-version-info.php base_version) is not allowed on the $CHANNEL channel"
exit 1
fi

View File

@ -1,28 +1,95 @@
name: Draft release
on:
#presume that pull_request_target is safe at this point, since the PR was approved and merged
#we need write access to prepare the release & create comments
pull_request_target:
types:
- closed
branches:
- stable
- minor-next
- major-next
- "legacy/*"
paths:
- "src/VersionInfo.php"
push:
tags: "*"
tags:
- "*"
env:
PHP_VERSION: "8.3"
jobs:
draft:
name: Create GitHub draft release
if: "startsWith(github.event.head_commit.message, 'Release ')"
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
php-version: [8.2]
skip:
name: Check whether to ignore this tag
runs-on: ubuntu-22.04
outputs:
skip: ${{ steps.exists.outputs.exists == 'true' }}
steps:
- uses: actions/checkout@v4
- name: Check if release already exists
id: exists
env:
GH_TOKEN: ${{ github.token }}
run: |
exists=false
if [[ "${{ github.ref_type }}" == "tag" ]]; then
tag="$(echo "${{ github.ref }}" | cut -d/ -f3-)"
if gh release view "$tag" --repo "${{ github.repository }}"; then
exists=true
fi
fi
echo exists=$exists >> $GITHUB_OUTPUT
check:
needs: [skip]
if: needs.skip.outputs.skip != 'true'
name: Check release
uses: ./.github/workflows/draft-release-pr-check.yml
trigger-post-release-workflow:
name: Trigger post-release RestrictedActions workflow
needs: [check]
if: needs.check.outputs.valid == 'true' && github.ref_type != 'tag' #can't do post-commit for a tag
runs-on: ubuntu-22.04
steps:
- name: Generate access token
id: generate-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
owner: ${{ github.repository_owner }}
repositories: RestrictedActions
- name: Dispatch post-release restricted action
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ steps.generate-token.outputs.token }}
repository: ${{ github.repository_owner }}/RestrictedActions
event-type: pocketmine_mp_post_release
client-payload: '{"branch": "${{ github.ref }}"}'
draft:
name: Create GitHub draft release
needs: [check]
if: needs.check.outputs.valid == 'true' || github.ref_type == 'tag' #ignore validity check for tags
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
with:
submodules: true
- name: Setup PHP
uses: shivammathur/setup-php@2.31.1
uses: shivammathur/setup-php@2.35.4
with:
php-version: ${{ matrix.php-version }}
php-version: ${{ env.PHP_VERSION }}
- name: Restore Composer package cache
uses: actions/cache@v4
@ -40,7 +107,7 @@ jobs:
- name: Calculate build number
id: build-number
run: |
BUILD_NUMBER=$((2000+$GITHUB_RUN_NUMBER)) #to stay above jenkins
BUILD_NUMBER=$((2300+$GITHUB_RUN_NUMBER)) #to stay above jenkins
echo "Build number: $BUILD_NUMBER"
echo BUILD_NUMBER=$BUILD_NUMBER >> $GITHUB_OUTPUT
@ -53,23 +120,31 @@ jobs:
- name: Get PocketMine-MP release version
id: get-pm-version
run: |
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
PM_VERSION=$(php build/dump-version-info.php base_version)
echo PM_VERSION=$PM_VERSION >> $GITHUB_OUTPUT
echo PM_MAJOR=$(php build/dump-version-info.php major_version) >> $GITHUB_OUTPUT
echo MCPE_VERSION=$(php build/dump-version-info.php mcpe_version) >> $GITHUB_OUTPUT
echo CHANGELOG_FILE_NAME=$(php build/dump-version-info.php changelog_file_name) >> $GITHUB_OUTPUT
echo CHANGELOG_MD_HEADER=$(php build/dump-version-info.php changelog_md_header) >> $GITHUB_OUTPUT
echo PRERELEASE=$(php build/dump-version-info.php prerelease) >> $GITHUB_OUTPUT
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
tag="$(echo "${{ github.ref }}" | cut -d/ -f3-)"
else
tag="$PM_VERSION"
fi
echo TAG_NAME=$tag >> $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
echo PHP_BINARY_URL="${{ github.server_url }}/${{ github.repository_owner }}/PHP-Binaries/releases/tag/pm${{ steps.get-pm-version.outputs.PM_MAJOR }}-php-${{ env.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 }} \
${{ steps.get-pm-version.outputs.TAG_NAME }} \
${{ github.repository }} \
${{ steps.build-number.outputs.BUILD_NUMBER }} \
${{ github.run_id }} \
@ -90,18 +165,27 @@ jobs:
${{ github.workspace }}/core-permissions.rst
- name: Create draft release
uses: ncipollo/release-action@v1.14.0
uses: ncipollo/release-action@v1.18.0
id: create-draft
with:
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json,${{ github.workspace }}/core-permissions.rst
commit: ${{ github.sha }}
draft: true
prerelease: ${{ steps.get-pm-version.outputs.PRERELEASE }}
name: PocketMine-MP ${{ steps.get-pm-version.outputs.PM_VERSION }}
tag: ${{ steps.get-pm-version.outputs.PM_VERSION }}
tag: ${{ steps.get-pm-version.outputs.TAG_NAME }}
token: ${{ secrets.GITHUB_TOKEN }}
body: |
**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.
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.CHANGELOG_FILE_NAME }}#${{ steps.get-pm-version.outputs.CHANGELOG_MD_HEADER }}) for details.
:information_source: Download the recommended PHP binary [here](${{ steps.php-binary-url.outputs.PHP_BINARY_URL }}).
:warning: Found a bug? Report it on our [issue tracker](${{ github.server_url }}/${{ github.repository }}/issues). **We can't fix bugs if you don't report them.**
- name: Post draft release URL on PR
if: github.event_name == 'pull_request_target'
uses: thollander/actions-comment-pull-request@v3
with:
message: "${{ vars.DRAFT_RELEASE_NOTIFICATION_MENTION }} [Draft release ${{ steps.get-pm-version.outputs.PM_VERSION }}](${{ steps.create-draft.outputs.html_url }}) has been created for commit ${{ github.sha }}. Please review and publish it."

View File

@ -15,7 +15,7 @@ on:
type: number
image:
description: 'Runner image to use'
default: 'ubuntu-20.04'
default: 'ubuntu-22.04'
type: string
jobs:
@ -27,10 +27,10 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.1.0
uses: pmmp/setup-php-action@3.2.0
with:
php-version: ${{ inputs.php }}
install-path: "./bin"
@ -59,10 +59,10 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.1.0
uses: pmmp/setup-php-action@3.2.0
with:
php-version: ${{ inputs.php }}
install-path: "./bin"
@ -91,12 +91,12 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: true
- name: Setup PHP
uses: pmmp/setup-php-action@3.1.0
uses: pmmp/setup-php-action@3.2.0
with:
php-version: ${{ inputs.php }}
install-path: "./bin"
@ -125,10 +125,10 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.1.0
uses: pmmp/setup-php-action@3.2.0
with:
php-version: ${{ inputs.php }}
install-path: "./bin"

View File

@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php: ["8.1", "8.2", "8.3"]
php: ["8.3", "8.4"]
uses: ./.github/workflows/main-php-matrix.yml
with:
@ -20,20 +20,32 @@ jobs:
codestyle:
name: Code Style checks
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.31.1
uses: shivammathur/setup-php@2.35.4
with:
php-version: 8.2
tools: php-cs-fixer:3.49
php-version: 8.3
tools: php-cs-fixer:3.75
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run PHP-CS-Fixer
run: php-cs-fixer fix --dry-run --diff --ansi
shellcheck:
name: ShellCheck
runs-on: ubuntu-22.04
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v5
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@2.0.0

View File

@ -0,0 +1,37 @@
name: Remove waiting label from PRs
on:
pull_request_target:
types: synchronize
jobs:
delabel:
name: Remove label
runs-on: ubuntu-latest
steps:
- name: Remove label
uses: actions/github-script@v7
with:
github-token: ${{ github.token }}
script: |
async function removeLabel(owner, repo, issue_number, name) {
try {
await github.rest.issues.removeLabel({
owner: owner,
repo: repo,
issue_number: issue_number,
name: name,
});
} catch (error) {
if (error.status === 404) {
//probably label wasn't set on the issue
console.log('Failed to remove label ' + name + ' (probably label isn\'t on the PR): ' + error.message);
} else {
throw error;
}
}
}
const [owner, repo] = context.payload.repository.full_name.split('/');
removeLabel(owner, repo, context.payload.number, "Status: Waiting on Author");
removeLabel(owner, repo, context.payload.number, "Stale");

29
.github/workflows/pr-stale.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: 'Clean up stale PRs'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
days-before-issue-stale: -1
days-before-issue-close: -1
stale-pr-message: |
This PR has been marked as "Waiting on Author", but we haven't seen any activity in 7 days.
If there is no further activity, it will be closed in 28 days.
Note for maintainers: Adding an assignee to the PR will prevent it from being marked as stale.
close-pr-message: |
As this PR hasn't been updated for a while, unfortunately we'll have to close it.
days-before-pr-stale: 7
days-before-pr-close: 28
only-labels: "Status: Waiting on Author"
close-pr-label: "Resolution: Abandoned"
exempt-all-assignees: true

View File

@ -20,10 +20,7 @@ jobs:
- Check our [Documentation](https://doc.pmmp.io) to see if you can find answers there
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG) or our [Forums](https://forums.pmmp.io)
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG)
close-issue: true
lock-issue: false

View File

@ -0,0 +1,38 @@
#Due to GitHub awkwardness, it's not easy to reduce the review requirement for collaborators.
#Our policy is that 2 collaborators should be aware of every change.
#For outside PRs, this means 2 collaborator reviews.
#For PRs made by collaborators, this means 1 reviewer + the author.
#We trust that collaborators don't need as much oversight.
name: Auto approve collaborator PRs
on:
pull_request_target:
types:
- opened
- reopened
- ready_for_review
- synchronize
jobs:
dispatch:
name: Request approval
runs-on: ubuntu-latest
if: '! github.event.pull_request.draft'
steps:
- name: Generate access token
id: generate-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
owner: ${{ github.repository_owner }}
repositories: RestrictedActions
- name: Dispatch restricted action
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ steps.generate-token.outputs.token }}
repository: ${{ github.repository_owner }}/RestrictedActions
event-type: auto_approve_collaborator_pr
client-payload: '{"repo": "${{ github.repository }}", "pull_request_id": "${{ github.event.pull_request.number }}", "reviewer_id": "0" }'

View File

@ -4,6 +4,11 @@ on:
release:
types:
- published
workflow_dispatch:
inputs:
release:
description: 'Release to publish info for'
required: true
jobs:
build:
@ -14,14 +19,22 @@ jobs:
- name: Install jq
run: sudo apt update && sudo apt install jq -y
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
repository: ${{ github.repository_owner }}/update.pmmp.io
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
- name: Get actual tag name
- name: Get tag name
id: tag-name
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
run: |
if [[ "${{ github.event_name }}" == "release" ]]; then
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
else
echo "Unsupported event type: ${{ github.event_name }}"
exit 1
fi
- 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

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "tests/plugins/DevTools"]
path = tests/plugins/DevTools
url = https://github.com/pmmp/DevTools.git
[submodule "build/php"]
path = build/php
url = https://github.com/pmmp/php-build-scripts.git

View File

@ -5,7 +5,13 @@ $finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/build')
->in(__DIR__ . '/tests')
->in(__DIR__ . '/tools')
->notPath('plugins/DevTools')
//JsonMapper will break if the FQNs in the doc comments for these are shortened :(
->notPath('crafting/json')
->notPath('inventory/json')
->notPath('data/bedrock/block/upgrade/model')
->notPath('data/bedrock/item/upgrade/model')
->notName('PocketMine.php');
return (new PhpCsFixer\Config)

View File

@ -123,7 +123,7 @@ The following are required as a minimum for pull requests. PRs that don't meet t
- Remember, PRs with small diffs are much easier to review. Small PRs are generally reviewed and merged much faster than large ones.
- **Start small.** Try fixing minor bugs or doing something isolated (e.g. adding a new block or item) before attempting larger changes.
- This helps you get familiar with the codebase, the contribution process, and the expectations of maintainers.
- Check out the [issues page]() for something that you could tackle without too much effort.
- Check out ["Easy task" issues](https://github.com/pmmp/PocketMine-MP/issues?q=is%3Aissue+is%3Aopen+label%3A%22Easy+task%22) on the issues page for something that you could tackle without too much effort.
- **Do not copy-paste other people's code**. Many PRs involve discussion about the changes, and changes are often requested by reviewers. If you don't understand the code you're copy-pasting, your PR is likely to fail.
- **Do not edit code directly on github.com.** We recommend learning how to use [`git`](https://git-scm.com). `git` allows you to "clone" a repository onto your computer, so that you can make changes using an IDE.
- **Use an IDE, not a text editor.** We recommend PhpStorm or VSCode.

View File

@ -12,7 +12,7 @@
</p>
<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/actions/workflows/main.yml"><img src="https://github.com/pmmp/PocketMine-MP/actions/workflows/main.yml/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://discord.gg/bmSAZBG"><img src="https://img.shields.io/discord/373199722573201408?label=discord&color=7289DA&logo=discord" alt="Discord" /></a>
<br>
@ -65,6 +65,8 @@ PocketMine-MP accepts community contributions! The following resources will be u
* [Building and running PocketMine-MP from source](BUILDING.md)
* [Contributing Guidelines](CONTRIBUTING.md)
New here? Check out [issues with the "Easy task" label](https://github.com/pmmp/PocketMine-MP/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Easy%20task%22) for things you could work to familiarise yourself with the codebase.
## Donate
PocketMine-MP is free, but it requires a lot of time and effort from unpaid volunteers to develop. Donations enable us to keep delivering support for new versions and adding features your players love.

View File

@ -0,0 +1,87 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\VersionInfo;
require dirname(__DIR__) . '/vendor/autoload.php';
/*
* Dumps version info in a machine-readable format for use in GitHub Actions workflows
*/
/**
* @var string[]|Closure[] $options
* @phpstan-var array<string, string|Closure() : string> $options
*/
$options = [
"base_version" => VersionInfo::BASE_VERSION,
"major_version" => fn() => explode(".", VersionInfo::BASE_VERSION, limit: 2)[0],
"mcpe_version" => ProtocolInfo::MINECRAFT_VERSION_NETWORK,
"is_dev" => VersionInfo::IS_DEVELOPMENT_BUILD,
"changelog_file_name" => function() : string{
$version = VersionInfo::VERSION();
$result = $version->getMajor() . "." . $version->getMinor();
$suffix = $version->getSuffix();
if($suffix !== ""){
if(preg_match('/^([A-Za-z]+)(\d+)$/', $suffix, $matches) !== 1){
fwrite(STDERR, "error: invalid current version suffix \"$suffix\"; aborting" . PHP_EOL);
exit(1);
}
$baseSuffix = $matches[1];
$result .= "-" . strtolower($baseSuffix);
}
return $result . ".md";
},
"changelog_md_header" => fn() : string => str_replace(".", "", VersionInfo::BASE_VERSION),
"prerelease" => fn() : bool => VersionInfo::VERSION()->getSuffix() !== "",
"channel" => VersionInfo::BUILD_CHANNEL,
"suffix_valid" => function() : bool{
//TODO: maybe this should be put into its own script?
$suffix = VersionInfo::VERSION()->getSuffix();
if(VersionInfo::BUILD_CHANNEL === "stable"){
//stable builds may not have suffixes
return $suffix === "";
}
if(VersionInfo::BUILD_CHANNEL === "alpha" || VersionInfo::BUILD_CHANNEL === "beta"){
$upperChannel = strtoupper(VersionInfo::BUILD_CHANNEL);
$upperSuffix = strtoupper($suffix);
return str_starts_with($upperSuffix, $upperChannel) && is_numeric(substr($upperSuffix, strlen($upperChannel)));
}
return true;
}
];
if(count($argv) !== 2 || !isset($options[$argv[1]])){
fwrite(STDERR, "Please provide an option (one of: " . implode(", ", array_keys($options)) . PHP_EOL);
exit(1);
}
$result = $options[$argv[1]];
if($result instanceof Closure){
$result = $result();
}
if(is_bool($result)){
echo $result ? "true" : "false";
}else{
echo $result;
}

View File

@ -28,6 +28,7 @@ use function dirname;
use function fclose;
use function fopen;
use function fwrite;
use function is_dir;
use function is_file;
use function scandir;
use function str_replace;
@ -59,7 +60,7 @@ foreach($files as $file){
continue;
}
$path = Path::join(BEDROCK_DATA_PATH, $file);
if(!is_file($path)){
if(!is_file($path) && !is_dir($path)){
continue;
}
@ -67,6 +68,7 @@ foreach($files as $file){
'README.md',
'LICENSE',
'composer.json',
'.github'
] as $ignored){
if($file === $ignored){
continue 2;

View File

@ -122,7 +122,7 @@ if(!is_array($ids)){
throw new \RuntimeException("Invalid biome ID map, expected array for root JSON object");
}
$cleanedIds = [];
foreach($ids as $name => $id){
foreach(Utils::promoteKeys($ids) as $name => $id){
if(!is_string($name) || !is_int($id)){
throw new \RuntimeException("Invalid biome ID map, expected string => int map");
}

View File

@ -42,7 +42,7 @@ $constants = [];
* @phpstan-param-out array<string, string> $constants
*/
function collectProperties(string $prefix, array $properties, array &$constants) : void{
foreach($properties as $propertyName => $property){
foreach(Utils::promoteKeys($properties) as $propertyName => $property){
$fullPropertyName = ($prefix !== "" ? $prefix . "." : "") . $propertyName;
$constName = str_replace([".", "-"], "_", strtoupper($fullPropertyName));

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\build\update_registry_annotations;
use pocketmine\utils\Utils;
use function basename;
use function class_exists;
use function count;
@ -48,6 +49,7 @@ if(count($argv) !== 2){
/**
* @param object[] $members
* @phpstan-param array<string, object> $members
*/
function generateMethodAnnotations(string $namespaceName, array $members) : string{
$selfName = basename(__FILE__);
@ -60,7 +62,7 @@ function generateMethodAnnotations(string $namespaceName, array $members) : stri
static $lineTmpl = " * @method static %2\$s %s()";
$memberLines = [];
foreach($members as $name => $member){
foreach(Utils::stringifyKeys($members) as $name => $member){
$reflect = new \ReflectionClass($member);
while($reflect !== false && $reflect->isAnonymous()){
$reflect = $reflect->getParentClass();

View File

@ -1,164 +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\make_release;
use pocketmine\utils\Filesystem;
use pocketmine\utils\Utils;
use pocketmine\utils\VersionString;
use pocketmine\VersionInfo;
use function array_keys;
use function array_map;
use function dirname;
use function fgets;
use function file_put_contents;
use function fwrite;
use function getopt;
use function is_string;
use function max;
use function preg_match;
use function preg_replace;
use function sprintf;
use function str_pad;
use function strlen;
use function strtolower;
use function system;
use const STDERR;
use const STDIN;
use const STDOUT;
use const STR_PAD_LEFT;
require_once dirname(__DIR__) . '/vendor/autoload.php';
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev, string $channel) : void{
$versionInfo = Filesystem::fileGetContents($versionInfoPath);
$versionInfo = preg_replace(
$pattern = '/^([\t ]*public )?const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m',
'$1const BASE_VERSION = "' . $newVersion . '";',
$versionInfo
);
$versionInfo = preg_replace(
'/^([\t ]*public )?const IS_DEVELOPMENT_BUILD = (?:true|false);$/m',
'$1const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false') . ';',
$versionInfo
);
$versionInfo = preg_replace(
'/^([\t ]*public )?const BUILD_CHANNEL = ".*";$/m',
'$1const BUILD_CHANNEL = "' . $channel . '";',
$versionInfo
);
file_put_contents($versionInfoPath, $versionInfo);
}
const ACCEPTED_OPTS = [
"current" => "Version to insert and tag",
"next" => "Version to put in the file after tagging",
"channel" => "Release channel to post this build into"
];
function systemWrapper(string $command, string $errorMessage) : void{
system($command, $result);
if($result !== 0){
echo "error: $errorMessage; aborting\n";
exit(1);
}
}
function main() : void{
$filteredOpts = [];
foreach(Utils::stringifyKeys(getopt("", ["current:", "next:", "channel:", "help"])) as $optName => $optValue){
if($optName === "help"){
fwrite(STDOUT, "Options:\n");
$maxLength = max(array_map(fn(string $str) => strlen($str), array_keys(ACCEPTED_OPTS)));
foreach(ACCEPTED_OPTS as $acceptedName => $description){
fwrite(STDOUT, str_pad("--$acceptedName", $maxLength + 4, " ", STR_PAD_LEFT) . ": $description\n");
}
exit(0);
}
if(!is_string($optValue)){
fwrite(STDERR, "--$optName expects exactly 1 value\n");
exit(1);
}
$filteredOpts[$optName] = $optValue;
}
$channel = $filteredOpts["channel"] ?? null;
if(isset($filteredOpts["current"])){
$currentVer = new VersionString($filteredOpts["current"]);
}else{
$currentVer = new VersionString(VersionInfo::BASE_VERSION);
}
$nextVer = isset($filteredOpts["next"]) ? new VersionString($filteredOpts["next"]) : null;
$suffix = $currentVer->getSuffix();
if($suffix !== ""){
if($channel === "stable"){
fwrite(STDERR, "error: cannot release a suffixed build into the stable channel\n");
exit(1);
}
if(preg_match('/^([A-Za-z]+)(\d+)$/', $suffix, $matches) !== 1){
echo "error: invalid current version suffix \"$suffix\"; aborting\n";
exit(1);
}
$nextVer ??= new VersionString(sprintf(
"%u.%u.%u-%s%u",
$currentVer->getMajor(),
$currentVer->getMinor(),
$currentVer->getPatch(),
$matches[1],
((int) $matches[2]) + 1
));
$channel ??= strtolower($matches[1]);
}else{
$nextVer ??= new VersionString(sprintf(
"%u.%u.%u",
$currentVer->getMajor(),
$currentVer->getMinor(),
$currentVer->getPatch() + 1
));
$channel ??= "stable";
}
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
echo "$currentVer will be published on release channel \"$channel\".\n";
echo "please add appropriate notes to the changelog and press enter...";
fgets(STDIN);
systemWrapper('git add "' . dirname(__DIR__) . '/changelogs"', "failed to stage changelog changes");
system('git diff --cached --quiet "' . dirname(__DIR__) . '/changelogs"', $result);
if($result === 0){
echo "error: no changelog changes detected; aborting\n";
exit(1);
}
$versionInfoPath = dirname(__DIR__) . '/src/VersionInfo.php';
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel);
systemWrapper('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"', "failed to create release commit");
systemWrapper('git tag ' . $currentVer->getBaseVersion(), "failed to create release tag");
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");
}
main();

View File

@ -25,6 +25,7 @@ namespace pocketmine\server_phar_stub;
use function clearstatcache;
use function copy;
use function define;
use function fclose;
use function fflush;
use function flock;
@ -165,4 +166,5 @@ $start = hrtime(true);
$cacheName = preparePharCache($tmpDir, __FILE__);
echo "Cache ready at $cacheName in " . number_format((hrtime(true) - $start) / 1e9, 2) . "s\n";
define('pocketmine\ORIGINAL_PHAR_PATH', __FILE__);
require 'phar://' . str_replace(DIRECTORY_SEPARATOR, '/', $cacheName) . '/src/PocketMine.php';

View File

@ -129,7 +129,7 @@ function buildPhar(string $pharPath, string $basePath, array $includedPaths, arr
}
function main() : void{
if(ini_get("phar.readonly") == 1){
if(ini_get("phar.readonly") === "1"){
echo "Set phar.readonly to 0 with -dphar.readonly=0" . PHP_EOL;
exit(1);
}

30
changelogs/5.18.md Normal file
View File

@ -0,0 +1,30 @@
# 5.18.0
Released 16th August 2024.
**For Minecraft: Bedrock Edition 1.21.20**
This is a support release for Minecraft: Bedrock Edition 1.21.20.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.21.20.
- Removed support for earlier versions.
## Fixes
- Use `VISIBLE_MOB_EFFECTS` actor metadata property to send effect bubbles, this fixes effect bubbles not showing
# 5.18.1
Released 3rd September 2024.
## Fixes
- Fixed shift-crafting.
- Blue Ice block no longer emits light & it's now dropped when mined with a tool with silk touch enchantment.
## Internals
- Pull Requests from team members now get an approval automatically. This means that if a team member makes a PR, only one other approval should be needed.
- Added [ShellCheck](https://github.com/koalaman/shellcheck) to the CI tests.

16
changelogs/5.19.md Normal file
View File

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

25
changelogs/5.20.md Normal file
View File

@ -0,0 +1,25 @@
# 5.20.0
Released 26th October 2024.
**For Minecraft: Bedrock Edition 1.21.40**
This is a support release for Minecraft: Bedrock Edition 1.21.40.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.21.40.
- Removed support for earlier versions.
## Fixes
- Fixed a bug in `tools/generate-blockstate-upgrade-schema.php` that caused it to fail on 1.21.40 with the new mushroom block changes.
# 5.20.1
Released 31st October 2024.
## Fixes
- Workaround old mob heads in world saves not being upgraded correctly and causing crashes.

128
changelogs/5.21.md Normal file
View File

@ -0,0 +1,128 @@
# 5.21.0
Released 3rd November 2024.
This is a minor feature release, including gameplay features and minor internals improvements.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## Gameplay
- Added the following new blocks:
- Campfire
- Chiseled Copper
- Chiseled Tuff
- Chiseled Tuff Bricks
- Copper Bulb
- Copper Door
- Copper Grate
- Copper Trapdoor
- Polished Tuff, Slabs, Stairs and Walls
- Soul Campfire
- Tuff Bricks, Slabs, Stairs and Walls
- Tuff Slab, Stairs and Walls
- Added the following new types of painting:
- backyard
- baroque
- bouquet
- cavebird
- changing
- cotan
- endboss
- fern
- finding
- humble
- lowmist
- meditative
- orb
- owlemons
- passage
- pond
- prairie_ride
- sunflowers
- tides
- unpacked
- Armor slots are now properly restricted (on the server side) to only contain the appropriate type of armor or headwear.
- Implemented Aqua Affinity enchantment. Since the server doesn't currently enforce any movement restrictions in water, this enchantment works based on client-side behaviour only.
## API
### `pocketmine\block`
- The following new API methods have been added:
- `public ChiseledBookshelf->getLastInteractedSlot() : ?ChiseledBookshelfSlot`
- `public ChiseledBookshelf->setLastInteractedSlot(?ChiseledBookshelfSlot $lastInteractedSlot) : $this`
- The following new classes have been added:
- `utils\CopperMaterial` - interface implemented by all copper-like blocks with oxidation and waxed properties
- `CopperBulb`
- `CopperDoor`
- `CopperGrate`
- `CopperTrapdoor`
- `SoulCampfire`
- `Campfire`
- The following enums have new cases:
- `utils\BannerPatternType` has new cases `FLOW` and `GUSTER`
### `pocketmine\crafting`
- The following enums have new cases:
- `FurnaceType` has new cases `CAMPFIRE` and `SOUL_CAMPFIRE`
### `pocketmine\event`
- The following new classes have been added:
- `block\CampfireCookEvent` - called when a campfire finishes cooking an item
### `pocketmine\inventory`
- Added support for slot validators, which permit restricting the types of items a player can put into an inventory slot.
- The following new classes have been added:
- `transaction\action\SlotValidator` - interface
- `transaction\action\CallbackSlotValidator` - class allowing a closure to be used for slot content validation
- `SlotValidatedInventory` - implemented by inventories which support the use of slot validators
### `pocketmine\item`
- The following new API methods have been added:
- `public Item->getCooldownTag() : ?string` - returns the cooldown group this item belongs to, used for ensuring that, for example, different types of goat horns all respect a general horn cooldown
- The following new classes have been added:
- `ItemCooldownTags` - list of cooldown group tags used by PocketMine-MP
### `pocketmine\world\sound`
- The following new classes have been added
- `CampfireSound` - sound made by campfires while lit
## Tools
- `tools/blockstate-upgrade-schema-utils.php` (formerly `generate-blockstate-upgrade-schema.php`) has several improvements:
- Support for generating `flattenedProperties` rules as per [BedrockBlockUpgradeSchema 5.0.0](https://github.com/pmmp/BedrockBlockUpgradeSchema/releases/tag/5.0.0)
- Improved criteria for flattened property selection to minimize the amount of rules required
- Several subcommands are now available:
- `generate` - generates a schema from provided data
- `update` - regenerates an existing schema in a newer format
- `update-all` - regenerates a folder of existing schemas in a newer format (useful for updating `BedrockBlockUpgradeSchema` en masse)
- `test` - verifies that a schema produces the results expected by provided data
## Internals
- Fixed incorrect visibility of `createEntity` in spawn eggs.
- Added support for newer `BedrockBlockUpgradeSchema` in `BlockStateUpgrader`.
# 5.21.1
Released 12th November 2024.
## Fixes
- Fixed server crash when applying a cooldown to an item with 1 count.
- Fixed garbage collector cycle count increase on player disconnect.
- Fixed weakness effect being applied to all attack types, causing damage splash potions to become weaker.
- Fixed Enchanted Golden Apple regeneration effect amplifier to match vanilla.
# 5.21.2
Released 29th November 2024.
## Fixes
- Fixed blocks destroyable by water being able to be placed inside water.
- Fixed deprecation warnings about nullable typehints on PHP 8.4.
- Fixed `Utils::getNiceClosureName()` not working correctly on PHP 8.4.
- Fixed incorrect break animations when breaking the block behind an instantly-breakable block like a torch.
- Fixed candle extinguish logic.
- Fixed various documentation issues around array key types.
- Introduced a new PHPStan rule along with `Utils::promoteKeys()` to improve PHPStan error reporting around unspecified array key types. Previously, some errors were missed due to PHPStan's BenevolentUnionType.
## DevOps
- `pmmp/server-developers` team is now automatically requested for review on any new PR.
- `Status: Waiting on Author` label is now automatically removed from PRs when they are updated.

16
changelogs/5.22.md Normal file
View File

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

139
changelogs/5.23.md Normal file
View File

@ -0,0 +1,139 @@
# 5.23.0
Released 5th December 2024.
This is a minor feature release, including new gameplay features, internals improvements, API additions and
deprecations, and improvements to timings.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- `/timings` now supports collecting timings from async task workers. These new timings will be shown alongside `Full Server Tick` timings, but will not be counted in total load.
- Added `/xp` command.
- `start.sh` will now emit warnings when the server process exits with an unusual exit code. This helps to detect unexpected segmentation faults and other kinds of native errors.
## Gameplay
- Added the following new items:
- End Crystal
- Goat Horn (all variants)
- Ice Bomb (from Education Edition)
- Recovery Compass
- Added the following enchantments:
- Frost Walker
- Sugarcane now self-destructs when there is no water adjacent to the base block.
- Added basic support for middle-clicking on entities to get their spawn eggs.
- Added sounds when drinking potions.
- Eating food is now allowed in creative mode and in peaceful difficulty.
## API
### `pocketmine\block`
- Extracted `MultiAnyFacingTrait` and `MultiAnySupportTrait` from `GlowLichen` to enable reuse in other blocks.
- The following API methods have been deprecated:
- `Campfire->getInventory()` - this was added by mistake and can't be well-supported given the way that blocks work
### `pocketmine\command`
- The following classes have been added:
- `ClosureCommand` - allows registering a closure to execute a command
### `pocketmine\event`
- Added APIs to `PlayerInteractEvent` to allow toggling item and block interactions.
- This allows various customisations, such as allowing interactions when sneaking, selectively disabling item or block reactions, etc.
- If both item and block interactions are disabled, the event is **not** cancelled (blocks can still be placed).
- The following API methods have been added:
- `public PlayerInteractEvent->setUseBlock(bool $useBlock) : void`
- `public PlayerInteractEvent->setUseItem(bool $useItem) : void`
- `public PlayerInteractEvent->useBlock() : bool` - returns whether the block can respond to the interaction (toggling levers, opening/closing doors, etc).
- `public PlayerInteractEvent->useItem() : bool` - returns whether the item can respond to the interaction (spawn eggs, flint & steel, etc).
- The following new classes have been added:
- `player\PlayerEntityPickEvent` - called when a player middle-clicks on an entity
### `pocketmine\inventory\transaction`
- The following API methods have been deprecated:
- `InventoryAction->onAddToTransaction()`
### `pocketmine\permission`
- The following API methods have been deprecated:
- `PermissionManager->getPermissionSubscriptions()`
- `PermissionManager->subscribeToPermission()`
- `PermissionManager->unsubscribeFromAllPermissions()`
- `PermissionManager->unsubscribeFromPermission()`
### `pocketmine\plugin`
- The following classes have been deprecated:
- `DiskResourceProvider`
- `ResourceProvider`
### `pocketmine\promise`
- `Promise::all()` now accepts zero promises. This will return an already-resolved promise with an empty array.
### `pocketmine\scheduler`
- Added PHPStan generic types to `TaskHandler` and related APIs in `TaskScheduler` and `Task`.
- The following API methods have been deprecated
- `AsyncTask->publishProgress()`
- `AsyncTask->onProgressUpdate()`
### `pocketmine\timings`
- Timings can now notify other code when timings are enabled/disabled, reloaded, or collected.
- The intent of this is to facilitate timings usage on other threads, and have the results collected into a single timings report.
- Timings cannot directly control timings on other threads, so these callbacks allow plugins to use custom mechanisms to toggle, reset and collect timings.
- PocketMine-MP currently uses this to collect timings from async task workers. More internal threads may be supported in the future.
- The following API methods have been added:
- `public static TimingsHandler::getCollectCallbacks() : ObjectSet<\Closure() : list<Promise<list<string>>>` - callbacks for (asynchronously) collecting timings (typically from other threads). The returned promises should be resolved with the result of `TimingsHandler::printCurrentThreadRecords()`.
- `public static TimingsHandler::getReloadCallbacks() : ObjectSet<\Closure() : void>` - callbacks called when timings are reset
- `public static TimingsHandler::getToggleCallbacks() : ObjectSet<\Closure(bool $enable) : void>` - callbacks called when timings are enabled/disabled
- `public static TimingsHandler::requestPrintTimings() : Promise<list<string>>` - asynchronously collects timing results from all threads and assembles them into a single report
- The following API methods have been deprecated:
- `TimingsHandler::printTimings()` - this function cannot support async timings collection. Use `TimingsHandler::requestPrintTimings()` instead.
- `Timings::getAsyncTaskErrorTimings()` - internal method that is no longer needed
- The following constants have been deprecated:
- `Timings::GROUP_BREAKDOWN` - no longer used
### `pocketmine\utils`
- The following API methods have been added:
- `public static Utils::getRandomFloat() : float` - returns a random float between 0 and 1. Drop-in replacement for `lcg_value()` in PHP 8.4.
## Internals
- Blocks are now always synced with the client during a right-click-block interaction. This clears mispredictions on the client in case the new `PlayerInteractEvent` flags were customized by plugins.
- `VanillaBlocks` and `VanillaItems` now use reflection to lookup TypeId constants by registration name, instead of requiring TypeIds to be manually specified.
- While this is obviously a hack, it prevents incorrect constants from being used when adding new blocks, and guarantees that the names of constants in `BlockTypeIds` and `ItemTypeIds` will match their corresponding entries in `VanillaBlocks` and `VanillaItems` respectively.
- It also significantly improves readability of `VanillaBlocks` and `VanillaItems`, as well as eliminating ugly code like `WoodLikeBlockIdHelper`.
- In PM6, the team is exploring options to redesign `VanillaBlocks` and `VanillaItems` to eliminate the need for defining separate TypeIds entirely.
- `ConsoleReader` now uses socket support in `proc_open()` to transmit IPC messages to the server process. Previously, a temporary socket server was used, which was unreliable in some conditions.
- Event handler tests have been converted to PHPUnit tests by mocking `Server` and `Plugin` instances. Previously, these required integration tests for these dependencies.
- Fixed various deprecation warnings in PHP 8.4.
- `netresearch/jsonmapper` is now used at `5.0.0`. The PMMP fork of this library has been removed, as it is no longer needed.
# 5.23.1
Released 5th December 2024.
## Fixes
- Fixed signs not creating a tile when placed.
## Internals
- Improved blockstate consistency check to detect tiles disappearing during refactors.
# 5.23.2
Released 9th December 2024.
## General
- Updated translations for Russian and Korean.
## Fixes
- Fixed server build number.
- Fixed some crashes being misreported as plugin-involved.
## Internals
- Removed legacy `build/make-release.php` script. This script is no longer used, as all releases should now follow the PR workflow.
# 5.23.3
Released 22nd January 2025.
## Fixes
- Fixed crashes with PHP internal stack frames being flagged as plugin crashes.
- Fixed note block instrument sounds in 1.21.50.
## Internals
- Updated GitHub issue templates to use issue forms.

108
changelogs/5.24.md Normal file
View File

@ -0,0 +1,108 @@
# 5.24.0
Released 22nd January 2025.
This is a minor feature release, including new gameplay features, performance improvements, and minor API additions.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## Performance
- PHP garbage collection is now managed by the server, instead of being automatically triggered by PHP.
- The mechanism for GC triggering is designed to mimic PHP's to avoid behavioural changes. Only the place it's triggered from should be significantly different.
- This change also avoids unnecessary GCs during object-heavy operations, such as encoding `CraftingDataPacket`. As such, performance during server join should see an improvement.
- Timings is now able to directly measure the impact of GC. Previously, GC would show up as random spikes under random timers, skewing timing results.
- `ChunkCache` now uses `string` for completed caches directly instead of keeping them wrapped in `CompressBatchPromise`s. This reduces memory usage, improves performance, and reduces GC workload.
## Configuration
- The following settings have been removed from `pocketmine.yml` and will no longer have any effect:
- `memory.garbage-collection.collect-async-worker` (now always `true`)
- `memory.garbage-collection.low-memory-trigger` (now always `true`)
- `memory.max-chunks.trigger-chunk-collect` (now always `true`)
- `memory.world-caches.disable-chunk-cache` (now always `true`)
- `memory.world-caches.low-memory-trigger` (now always `true`)
## Gameplay
- Added the following new blocks:
- All types of pale oak wood, and leaves
- Resin
- Resin Bricks, Slabs, Stairs, and Walls
- Resin Clump
- Chiseled Resin Bricks
- Some blocks have had their tool tier requirements adjusted to match latest Bedrock updates.
- Added the following new items:
- Resin Brick
- Music Disc - Creator
- Music Disc - Creator (Music Box)
- Music Disc - Precipice
- Music Disc - Relic
## API
### General
- Many places had their PHPDoc improved to address issues highlighted by PHPStan 2.x. This may cause new, previously unreported issues to be reported in plugins using PHPStan.
### `pocketmine`
- The following methods have been deprecated:
- `MemoryManager->canUseChunkCache()`
- `MemoryManager::dumpMemory()` - relocated to `MemoryDump` class
### `pocketmine\item`
- The following new enum cases have been added:
- `RecordType::DISK_CREATOR`
- `RecordType::DISK_CREATOR_MUSIC_BOX`
- `RecordType::DISK_PRECIPICE`
- `RecordType::DISK_RELIC`
### `pocketmine\player`
- The following new methods have been added:
- `public Player->getFlightSpeedMultiplier() : float` - a base multiplier for player's flight speed
- `public Player->setFlightSpeedMultiplier(float $flightSpeedMultiplier) : void` - sets the player's flight speed multiplier
- The following new constants have been added:
- `Player::DEFAULT_FLIGHT_SPEED_MULTIPLIER`
### `pocketmine\utils`
- The following new methods have been added:
- `public static TextFormat::javaToBedrock(string $string) : string` - removes unsupported Java Edition format codes to prevent them being incorrectly displayed on Bedrock
- The following methods have behavioural changes:
- `TextFormat::toHTML()` now converts `§m` to redstone red (instead of strikethrough), and `§n` to copper orange (instead of underline). This is because the codes previously used for `STRIKETHROUGH` and `UNDERLINE` conflict with the new material codes introduced by Minecraft Bedrock.
- `Terminal::toANSI()` now converts `§m` to redstone red (instead of strikethrough), and `§n` to copper orange (instead of underline), as above. However, underline and strikethrough can still be used on the terminal using `Terminal::$FORMAT_UNDERLINE` and `Terminal::$FORMAT_STRIKETHROUGH` respectively.
- The following new constants have been added:
- `TextFormat::MATERIAL_QUARTZ`
- `TextFormat::MATERIAL_IRON`
- `TextFormat::MATERIAL_NETHERITE`
- `TextFormat::MATERIAL_REDSTONE`
- `TextFormat::MATERIAL_COPPER`
- `TextFormat::MATERIAL_GOLD`
- `TextFormat::MATERIAL_EMERALD`
- `TextFormat::MATERIAL_DIAMOND`
- `TextFormat::MATERIAL_LAPIS`
- `TextFormat::MATERIAL_AMETHYST`
- The following constants have been deprecated:
- `TextFormat::STRIKETHROUGH`
- `TextFormat::UNDERLINE`
- The following static properties have been added:
- `Terminal::$COLOR_MATERIAL_QUARTZ`
- `Terminal::$COLOR_MATERIAL_IRON`
- `Terminal::$COLOR_MATERIAL_NETHERITE`
- `Terminal::$COLOR_MATERIAL_REDSTONE`
- `Terminal::$COLOR_MATERIAL_COPPER`
- `Terminal::$COLOR_MATERIAL_GOLD`
- `Terminal::$COLOR_MATERIAL_EMERALD`
- `Terminal::$COLOR_MATERIAL_DIAMOND`
- `Terminal::$COLOR_MATERIAL_LAPIS`
- `Terminal::$COLOR_MATERIAL_AMETHYST`
## Tools
- Fixed some UI issues in `tools/convert-world.php`
## Internals
- Block cache in `World` is now size-limited. This prevents memory exhaustion when plugins call `getBlock()` many thousands of times with cache misses.
- `RakLibServer` now disables PHP GC. As RakLib doesn't generate any unmanaged cycles, GC is just a waste of CPU time in this context.
- `MemoryManager` now has the responsibility for triggering cycle GC. It's checked every tick, but GC won't take place unless the GC threshold is exceeded, similar to PHP.
- This mechanism could probably do with alterations to better suit PocketMine-MP, but it was chosen to mimic PHP's own GC to minimize behavioural changes for now.
- `AsyncTask` now triggers cycle GC after `onRun()` completes. As with `MemoryManager`, this is based on a threshold designed to mimic PHP's own behaviour.
- `FormatConverter` now performs world provider GC periodically. This is not needed with current active providers, but was found to be a problem while developing custom providers.
- Various internal adjustments were made to avoid returning incorrectly-keyed arrays in the code. These changes shouldn't affect anything as the arrays should have been properly ordered anyway.
- Many places that previously used `==` and `!=` have been updated to use strict variants. This kind of change needs to be done carefully to avoid breaking `int|float` comparisons.

52
changelogs/5.25.md Normal file
View File

@ -0,0 +1,52 @@
# 5.25.0
Released 16th February 2025.
This is a support release for Minecraft: Bedrock Edition 1.21.60. It also includes some minor API additions supporting new features in this version.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.21.60.
- Removed support for earlier versions.
## Documentation
- Fixed the documentation of `Utils::getOS()`. It now refers to the `Utils::OS_*` constants instead of a list of hardcoded strings.
## API
### `pocketmine\inventory`
This release allows plugins to decide which creative tab they want to add their new items to.
It also allows creating new collapsible groups of items, and modifying or removing existing ones.
- The following new methods have been added:
- `public CreativeInventory->getAllEntries() : list<CreativeInventoryEntry>` - returns an array of objects, each containing a creative item and information about its category and collapsible group (if applicable).
- `public CreativeInventory->getEntry(int $index) : ?CreativeInventoryEntry` - returns the creative item with the specified identifier, or `null` if not found
- The following methods have signature changes:
- `CreativeInventory->add()` now accepts two additional optional parameters: `CreativeCategory $category, ?CreativeGroup $group`. If not specified, the item will be added to the Items tab without a group.
- The following new classes have been added:
- `CreativeCategory` - enum of possible creative inventory categories (each has its own tab on the GUI)
- `CreativeGroup` - contains information about a collapsible group of creative items, including tooltip text and icon
- `CreativeInventoryEntry` - contains information about a creative inventory item, including its category and collapsible group (if applicable)
## Internals
- `CreativeContentPacket` is no longer fully cached due to the requirement for translation context during construction. The individual items are still cached (which is the most expensive part), but the packet itself is now constructed on demand, and group entries are constructed on the fly. This may affect performance, but this has not been investigated.
- `BedrockDataFiles` now includes constants for folders at the top level of `BedrockData` as well as files.
- The structure of creative data in `BedrockData` was changed to accommodate item category and grouping information. `creativeitems.json` has been replaced by `creative/*.json`, which contain information about item grouping and also segregates item lists per category.
- New information was added to `required_item_list.json` in `BedrockData`, as the server is now required to send item component NBT data in some cases.
# 5.25.1
Released 26th February 2025.
## Fixes
- Fixed confusing exception message when a block-breaking tool has an efficiency value of zero.
- Fixed incorrect facing of doors since 1.21.60 (resulted in mismatched AABBs between client & server, rendering glitches etc.)
- Resource pack UUIDs are now validated on load. Previously, invalid UUIDs would be accepted, and potentially cause a server crash on player join.
# 5.25.2
Released 4th March 2025.
## Fixes
- Added limits to various `explode()` calls.

71
changelogs/5.26.md Normal file
View File

@ -0,0 +1,71 @@
# 5.26.0
Released 22nd March 2025.
This is a minor feature release focused on performance improvements.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## Performance
- Significantly improved performance of entity movement. Load testing with item entities showed a 3x increase in the number of entities supported without lag.
- Significantly improved performance of on-ground checks for player movement. This still needs further work, but optimisations implemented in this version should improve performance substantially.
- Updated `pocketmine/nbt` dependency with performance improvements to `TAG_Compound` and `TAG_List` comparison. This should improve performance of inventory-related actions.
- `InventoryTransaction` now avoids useless item clones when processing transactions, which should improve performance of inventory-related actions.
## Dependencies
- `pocketmine/bedrock-protocol` has been updated to `36.2.0`, which adds new functions to access some packet fields.
- `pocketmine/nbt` has been updated to `1.1.0`, which improves performance when comparing NBT object trees.
## Gameplay
- Block breaking animation speed now takes into account the following: jumping, being in water, haste, mining fatigue
## Tools
- `blockstate-upgrade-schema-utils.php` now has a new `dump-table` command, which turns a `.bin` palette table file into human-readable text for debugging.
## API
### `pocketmine\block`
- The following methods have been added:
- `public RuntimeBlockStateRegistry->hasStateId(int $stateId) : bool` - checks whether the given state ID is registered
### `pocketmine\crafting`
- The following methods have been deprecated:
- `CraftingManager::sort()` - this was implicitly internal anyway
### `pocketmine\utils`
- The following constants have been added:
- `TextFormat::MATERIAL_RESIN`
- The following static properties have been added:
- `Terminal::$COLOR_MATERIAL_RESIN`
### `pocketmine\data\bedrock\block`
- `BlockStateToObjectDeserializer` now permits overriding **deserializers** for Bedrock IDs. This may be useful to implement custom state handling, or to implement missing block variants (such as snow cauldron).
- This was originally prohibited since 5.0.0. However, there is no technical reason to disallow overriding **deserializers**.
- Overriding **serializers** is still **not permitted**. Reusing type IDs doesn't make any sense and would break internal design contracts.
- If you want to make a custom version of a vanilla block, create a custom type ID for it, exactly as you would for a regular custom block.
- The following methods have been added:
- `public BlockStateToObjectDeserializer->getDeserializerForId(string $id) : ?(\Closure(BlockStateReader) : Block)`
### `pocketmine\data\bedrock\item`
- `ItemDeserializer` now permits overriding **deserializers** for Bedrock IDs. As above, this may be useful to implement custom data handling, or to implement missing variants of existing items.
- This was originally prohibited since 5.0.0. However, there is no technical reason to disallow overriding **deserializers**.
- Overriding **serializers** is still **not permitted**. Reusing type IDs doesn't make any sense and would break internal design contracts.
- As above, if you want to make a custom version of a vanilla item, create a custom type ID for it, exactly as you would for a regular custom item.
- The following methods have been added:
- `public ItemDeserializer->getDeserializerForId(string $id) : ?(\Closure(SavedItemData) : Item)`
## Internals
- `new $class` is now banned on new internals code by a PHPStan rule. Closures or factory objects should be used instead for greater flexibility and better static analysis.
- `CraftingManager` now uses a more stable hash function for recipe output filtering.
- `ChunkCache` now accepts `int $dimensionId` in the constructor. This may be useful for plugins which implement the nether.
- `RuntimeBlockStateRegistry` now precomputes basic collision info about known states for fast paths.
- This permits specialization for common shapes like cubes and collisionless blocks, which allows skipping complex logic in entity movement calculation. This vastly improves performance.
- Any block whose class overrides `readStateFromWorld()` or `getModelPositionOffset()` will *not* be optimised.
- `Block->recalculateCollisionBoxes()` now has a hard requirement not to depend on anything other than available properties. It must not use `World` or its position.
- This change was problematic for `ChorusPlant`, which used nearby blocks to calculate its collision boxes.
- Blocks which need nearby blocks should override `readStateFromWorld()` and set dynamic state properties, similar to fences.
- This design flaw will be corrected with a major change to `Block` internals currently in planning for a future major version.
- `Block->getCollisionBoxes()` may not be called at all during gameplay for blocks with shapes determined to be simple, like cubes and collisionless blocks.
- `BlockStateToObjectDeserializer` now checks if the returned blockstate is registered in `RuntimeBlockStateRegistry` to promote earlier error detection (instead of crashing in random code paths).

24
changelogs/5.27.md Normal file
View File

@ -0,0 +1,24 @@
# 5.27.0
Released 27th March 2025.
This is a support release for Minecraft: Bedrock Edition 1.21.70.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## Interim releases
If you're upgrading from 5.25.x directly to 5.27.0, please also read the following changelogs, as the interim releases contain important changes:
- [5.26.0](https://github.com/pmmp/PocketMine-MP/blob/5.26.0/changelogs/5.26.md#5260) - Performance improvements and other internal improvements
## General
- Aded support for Minecraft: Bedrock Edition 1.21.70.
- Removed support for earlier versions.
# 5.27.1
Released 6th April 2025.
## Fixes
- Updated RakLib to get ping timestamp handling fixes.

34
changelogs/5.28.md Normal file
View File

@ -0,0 +1,34 @@
# 5.28.0
Released 9th May 2025.
This is a support release for Minecraft: Bedrock Edition 1.21.80.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.21.80.
- Removed support for earlier versions.
## Fixes
- `AvailableEnchantmentRegistry` now requires provided tags to always be `string`. Previously, this wasn't enforced, leading to random crashes in core code related to enchanting.
- `Entity->setFireTicks()` and `Entity->setOnFire()` now truncate the fire time to the max value instead of throwing exceptions.
## Internals
- Improved PHPStan error reporting for unsafe foreaches. Foreach on an array with implicit keys now generates different errors than foreach on an array with string keys.
# 5.28.1
Released 17th May 2025.
## Fixes
- Fixed errors when PlayStation players attempt to join due to null `TitleID`.
# 5.28.2
Released 17th May 2025.
## Fixes
- Fixed version constraints which were incorrectly updated during the 1.21.80 update. This led to an unnoticed failure to update BedrockProtocol in the previous patch release.
- Actually fixed PlayStation issues this time

25
changelogs/5.29.md Normal file
View File

@ -0,0 +1,25 @@
# 5.29.0
Released 18th June 2025.
This is a support release for Minecraft: Bedrock Edition 1.21.90.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.21.90.
- Removed support for earlier versions.
## Fixes
- Fixed thread crashes sometimes not reporting proper cause information in crashdumps.
- Fixed crash when a plugin replaced a player's held tool with a different tool with a damage exceeding the old tool's max damage during an action.
- Fixed performance issue of `PlayerAuthInputPacket` input flags handling (broken change detection).
- Fixed `BaseInventory->addItem()` triggering updates on empty slots when no items were added.
- Fixed slow check in `SubChunk` block layer garbage collection.
## Internals
- `LoginPacketHandler->processLogin()` signature has changed. This will break any plugins overriding `LoginPacketHandler`. As noted above, this is _not_ covered by the API version guarantee.
- Automated branch sync for `minor-next` and `major-next` is now triggered by `repository_dispatch` from a cron job in this repository instead of `RestrictedActions`. The `RestrictedActions` cron job was getting automatically disabled by GitHub due to repo inactivity.

73
changelogs/5.30.md Normal file
View File

@ -0,0 +1,73 @@
# 5.30.0
Released 18th June 2025.
This is a minor feature release containing API additions, internals cleanup and user experience improvements.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Significantly reduced log spam when unknown blocks, tiles and entities are found in saved worlds.
- The file name structure for crashdumps has been changed to improve sorting order in file browsers.
- Buffering is now skipped on the RakLib layer. In theory this could reduce player network latency by 10 ms (YMMV).
## Gameplay
### Blocks
- Many blocks have had their hardness and blast resistance updated to match vanilla.
- Implemented Respawn Anchor.
- Melon Stem and Pumpkin Stem drop amounts should now match vanilla (using binomial distribution).
## API
## General
- Verification of save registration has been added for blocks, entities and tiles. This is intended to make it easier to find mistakes when registering custom things, which previously would produce obscure core crashes.
### `pocketmine\event\block`
- The following classes have been added:
- `BlockPreExplodeEvent` - called before a block tries to explode
- `BlockExplodeEvent` - called when after a block's explosion calculation has been done, but before any changes are applied
### `pocketmine\event\entity`
- The following classes have been added:
- `EntityExtinguishEvent` - called when a burning entity is extinguished by water or other sources
- `EntityFrostWalkerEvent` - called every tick upon which an entity wearing Frost Walker boots moves; this can be used to customise or cancel the behaviour of the Frost Walker enchantment
### `pocketmine\event\player`
- The following classes have been added:
- `PlayerRespawnAnchorUseEvent` - called when a player interacts with a charged respawn anchor
### `pocketmine\entity`
- The following methods have been added:
- `public Entity->getStepHeight() : float`
- `public Entity->setStepHeight(float $stepHeight) : void`
### `pocketmine\world\generator`
- Generator execution has been decoupled from `PopulationTask` and async tasks in general. The following classes have been added:
- `executor\GeneratorExecutor`
- `executor\SyncGeneratorExecutor` - runs a generator on the main thread (used for flat world generation, which doesn't need threads)
- `executor\AsyncGeneratorExecutor` - runs a generator inside an async task, as before
- `PopulationUtils` - contains population business logic previously baked into `PopulationTask` - this permits the reuse of that logic outside async tasks
- The following methods have signature changes:
- `GeneratorManager->addGenerator()` now accepts an optional `bool $fast` parameter, defaulting to `false`; setting this to `true` will cause your generator to run on the main thread
- The following methods have been added:
- `public GeneratorManagerEntry->isFast() : bool` - returns whether this generator should run on the main thread
- `PopulationTask` has been marked as `@internal`. In the next major version, it will move to the `generator\executor` namespace; however, for now it stays put because plugins currently have no other way to regenerate chunks.
## Internals
- World data version numbers have been consolidated in `pocketmine\data\bedrock\WorldDataVersions`. This removes the need to modify several different files to support new world versions, and reduces the chances of things getting missed.
- Block hardness and blast resistance is now unit-tested against `block_properties_table.json` in `BedrockData`. This file comes from vanilla BDS, so we can use it to verify compliance.
- Protocol-layer "server auth block breaking" has been enabled. Functionally, this is no different from the previous system, it just works differently on the network layer.
- Various internal classes in the `pocketmine\world\generator` namespace have been moved to the `generator\executor` namespace.
- Removed `World->registerGenerator()` and `World->unregisterGenerator()`.
- Removed redundant calls to `curl_close()` (obsolete since PHP 8.0).
# 5.30.1
Released 23rd June 2025.
## Fixes
- Fixed accidental break of backwards compatibility in `EntityExplodeEvent` introduced in the previous release.
- Fixed placement of player holding block when exploding respawn anchor.
- Updated BedrockProtocol to fix incorrect encoding of `ServerScriptDebugDrawerPacket`.
- Disabled client-side locator bar, allowing plugins to write their own implementations.

14
changelogs/5.31.md Normal file
View File

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

25
changelogs/5.32.md Normal file
View File

@ -0,0 +1,25 @@
# 5.32.0
Released 6th August 2025.
This is a support release for Minecraft: Bedrock Edition 1.21.100.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## General
- Added support for Minecraft: Bedrock Edition 1.21.100.
- Removed support for earlier versions.
## Fixes
- Fixed deadlock on RakLib thread crash (e.g. due to port binding failure).
# 5.32.1
Released 14th August 2025.
## Fixes
- Hardened checks when processing resource pack sending during player logins.
- Fixed content log warning about crafting recipe with missing ID.
- Fixed packets in a batch still being processed after one of them caused the session to be terminated.

135
changelogs/5.33.md Normal file
View File

@ -0,0 +1,135 @@
# 5.33.0
Released 30th August 2025.
This is a minor feature release containing internals improvements, API improvements and new gameplay features.
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
Do not update plugin minimum API versions unless you need new features added in this release.
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
## Performance
- Worlds now remember when a chunk isn't generated. This reduces world I/O during world generation.
- `BlockObjectToStateSerializer` now creates fewer objects in certain cases.
## Gameplay
- The following blocks have been added and/or are now properly supported:
- Hanging signs
- Illager banners
## Tools
- `generate-bedrock-data-from-packets.php` now represents items as strings directly when only an ID is present. This significantly improves readability in `BedrockData` and reduces file sizes.
## API
### `pocketmine\block`
- Added (and implemented) interfaces for many common block properties, to allow `instanceof` to be used:
- `Ageable`: for blocks with age, such as crops
- `AnyFacing`: for blocks which can face up, down, and horizontal directions (not the same as `HorizontalFacing`!)
- `Colored`: for blocks with 16 `DyeColor` variants
- `CoralMaterial`: for coral blocks, provides access to coral type and dead/alive
- `HorizontalFacing`: for blocks which can **only** face horizontal directions (not the same as `AnyFacing`!)
- `Lightable`: for light-source blocks which can be turned on and off, e.g. redstone lamp
- `MultiAnyFacing`: for blocks which can appear in multiple faces of the same block (including up, down, and horizontal faces), e.g. glow lichen
- `PillarRotation`: for blocks which can be oriented on an axis, e.g. logs
- `PoweredByRedstone`: for blocks which receive power from a redstone component, e.g. redstone lamp
- `SignLikeRotation`: for blocks which can be rotated 16 ways, e.g. signs, banners
- `WoodMaterial`: for blocks made from wood
- These interfaces have been implemented on many blocks. For the sake of brevity, they are not listed here, but you can expect to see them wherever the corresponding traits were used.
- The following classes have been added:
- `BaseOminousBanner`
- `CeilingCenterHangingSign` - both chains connected to the same point on the block above, can face 16 directions
- `CeilingEdgesHangingSign` - each chain connected to separate edges of the block above, can face 4 directions
- `OminousFloorBanner` - floor version of illager banner, can face 16 directions
- `OminousWallBanner` - wall version of illager banner, can face 4 directions
- `WallHangingSign` - hangs from a horizontal beam, can face 4 directions
- The following API methods have been added:
- `public ChiseledBookshelf->setSlots(list<ChiseledBookshelfSlot> $slots) : $this`
- `public static VanillaBlocks` methods:
- `ACACIA_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `ACACIA_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `ACACIA_WALL_HANGING_SIGN() : WallHangingSign`
- `BIRCH_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `BIRCH_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `BIRCH_WALL_HANGING_SIGN() : WallHangingSign`
- `CHERRY_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `CHERRY_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `CHERRY_WALL_HANGING_SIGN() : WallHangingSign`
- `CRIMSON_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `CRIMSON_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `CRIMSON_WALL_HANGING_SIGN() : WallHangingSign`
- `DARK_OAK_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `DARK_OAK_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `DARK_OAK_WALL_HANGING_SIGN() : WallHangingSign`
- `JUNGLE_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `JUNGLE_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `JUNGLE_WALL_HANGING_SIGN() : WallHangingSign`
- `MANGROVE_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `MANGROVE_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `MANGROVE_WALL_HANGING_SIGN() : WallHangingSign`
- `OAK_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `OAK_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `OAK_WALL_HANGING_SIGN() : WallHangingSign`
- `OMINOUS_FLOOR_BANNER() : OminousFloorBanner`
- `OMINOUS_WALL_BANNER() : OminousWallBanner`
- `PALE_OAK_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `PALE_OAK_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `PALE_OAK_WALL_HANGING_SIGN() : WallHangingSign`
- `SPRUCE_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `SPRUCE_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `SPRUCE_WALL_HANGING_SIGN() : WallHangingSign`
- `WARPED_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
- `WARPED_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
- `WARPED_WALL_HANGING_SIGN() : WallHangingSign`
- `public AgeableTrait->getMaxAge() : int` (included by all growable plant-like blocks, e.g. crops)
### `pocketmine\data\bedrock\block\convert`
- A new system for symmetric block serializers and deserializers has been introduced.
- This allows registering both a serializer and a deserializer with the same code, meaning way less code
- It also eliminates information duplication and potential inconsistencies, improving maintainability.
- A proper way to deal with flattened IDs (e.g. color blocks) has been introduced which _doesn't_ require hardcoding a giant mess of IDs
- This symmetric system covers 99% of blocks which have a 1:1 association between PM and vanilla blocks, or 1:N where IDs are flattened
- However, there are still some special cases which require registering separate serializers and deserializers (usually in cases where the PM implementation deviates from Mojang where Mojang's implementation sucks, such as hanging signs or big dripleaf).
- No backwards compatibility breaks are expected as a result of this change. However, it's recommended to migrate old code to this new system for maintainability.
- The following new classes have been added:
- `BlockSerializerDeserializerRegistrar` - handles unified registration of block serializers and deserializers, based on a provided block model
- `FlattenedIdModel` - represents a block with some properties baked into its Minecraft ID, e.g. coral or color blocks
- `Model` - represents a regular block with all properties in its `states` NBT
- `property\BoolFromStringProperty<TBlock>` - property mapping a bool value from a string NBT state
- `property\BoolProperty<TBlock>`
- `property\CommonProperties` - singleton containing commonly-used block property definitions and groups, e.g. facing, stair properties
- `property\EnumFromRawStateMap<TEnum, TRaw>` - maps a raw NBT value to a PHP `enum` and vice versa
- `property\IntFromRawStateMap<TRaw>` - maps a raw NBT value to PM integer constants and vice versa
- `property\IntProperty<TBlock>` - an integer range property with a min, max, and optional offset
- `property\Property<TBlock>` - interface implemented by all property definitions accepted by a `Model` or `FlattenedIdModel`
- `property\StateMap<TValue, TRaw>` - interface implemented by classes accepted by mapping properties, e.g. `BoolFromStringProperty`
- `property\StringProperty<TBlock>` - interface implemented by properties whose raw outputs are strings - these can be used as ID components in `FlattenedIdModel`
- `property\ValueFromIntProperty<TBlock, TValue>` - property mapping a generic PM value from an int NBT state
- `property\ValueFromStringProperty<TBlock, TValue>` - same as above, but for a string NBT state
- `property\ValueSetFromIntProperty<TBlock, TOption>` - a property mapping an `int[]` or `enum[]` from a set of flags in NBT states
- `property\ValueMappings` - singleton containing commonly-needed `StateMap`s
- The following classes have been deprecated:
- `BlockStateDeserializerHelper`
- `BlockStateSerializerHelper`
- The following methods have been deprecated:
- All methods for decoding mapped property types in `BlockStateReader`, e.g. `readFacingDirection()`
- All methods for encoding mapped property types in `BlockStateWriter`, e.g. `writeFacingDirection()`
- All specific blocktype mapping functions in `BlockStateToObjectDeserializer`, e.g. `mapStairs()`
- All specific blocktype mapping functions in `BlockObjectToStateSerializer`, e.g. `mapStairs()`
### `pocketmine\item`
- The following hooks have been added:
- `public Item->getPlacementTransaction(Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : ?BlockTransaction` - allows more complex logic for itemblocks to place blocks, without duplicating their placement conditions (used for hanging signs)
### `pocketmine\world`
- `World->setChunk()` now verifies that blockstate IDs in the provided chunk are all registered in `RuntimeBlockStateRegistry`. This should provide earlier detection for custom block registration errors by plugins.
## Internals
- `BlockStateUpgrader` is now almost entirely independent from `BlockStateData`. It's anticipated that the upgrader library will be separable from the core in the future.
- `Block->readStateFromWorld()` is now triggered on chunk load for any position containing a tile. This should allow more effective updating of blocks with properties in their tiles.
# 5.33.1
Released 31st August 2025.
## Fixes
- Fixed banners placed in prior versions getting their tiles deleted (due to missing `Type` tags).

View File

@ -5,7 +5,7 @@
"homepage": "https://pmmp.io",
"license": "LGPL-3.0",
"require": {
"php": "^8.1",
"php": "^8.3",
"php-64bit": "*",
"ext-chunkutils2": "^0.3.1",
"ext-crypto": "^0.3.1",
@ -32,30 +32,34 @@
"ext-zlib": ">=1.2.11",
"composer-runtime-api": "^2.0",
"adhocore/json-comment": "~1.2.0",
"pocketmine/netresearch-jsonmapper": "~v4.4.999",
"pocketmine/bedrock-block-upgrade-schema": "~4.2.0+bedrock-1.21.0",
"pocketmine/bedrock-data": "~2.11.0+bedrock-1.21.0",
"pocketmine/bedrock-item-upgrade-schema": "~1.10.0+bedrock-1.21.0",
"pocketmine/bedrock-protocol": "~32.1.0+bedrock-1.21.2",
"netresearch/jsonmapper": "~v5.0.0",
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
"pocketmine/bedrock-data": "~6.0.0+bedrock-1.21.100",
"pocketmine/bedrock-item-upgrade-schema": "~1.15.0+bedrock-1.21.100",
"pocketmine/bedrock-protocol": "~40.0.0+bedrock-1.21.100",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/callback-validator": "dev-rewrite",
"pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.7.0",
"pocketmine/locale-data": "~2.19.0",
"pocketmine/locale-data": "~2.25.0",
"pocketmine/log": "^0.4.0",
"pocketmine/math": "~1.0.0",
"pocketmine/nbt": "~1.0.0",
"pocketmine/raklib": "~1.1.0",
"pocketmine/math": "dev-major-next as 1.0.0",
"pocketmine/nbt": "~1.1.0",
"pocketmine/raklib": "~1.2.0",
"pocketmine/raklib-ipc": "~1.0.0",
"pocketmine/snooze": "^0.5.0",
"ramsey/uuid": "~4.7.0",
"symfony/filesystem": "~6.4.0"
"ramsey/uuid": "~4.9.0",
"symfony/filesystem": "~7.3.0"
},
"require-dev": {
"phpstan/phpstan": "1.11.10",
"phpstan/phpstan-phpunit": "^1.1.0",
"phpstan/phpstan-strict-rules": "^1.2.0",
"phpunit/phpunit": "^10.5.24"
"phpstan/phpstan": "2.1.17",
"phpstan/phpstan-phpunit": "^2.0.0",
"phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^12.2.1"
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-mbstring": "*"
},
"autoload": {
"psr-4": {
@ -73,12 +77,11 @@
},
"config": {
"platform": {
"php": "8.1.0"
"php": "8.3.0"
},
"sort-packages": true
},
"scripts": {
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make ./ --relative tests/plugins/DevTools --out plugins/DevTools.phar",
"make-server": [
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
"@php -dphar.readonly=0 build/server-phar.php"

1275
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,23 +2,25 @@ includes:
- tests/phpstan/analyse-for-current-php-version.neon.php
- tests/phpstan/configs/actual-problems.neon
- tests/phpstan/configs/impossible-generics.neon
- tests/phpstan/configs/php-bugs.neon
- tests/phpstan/configs/phpstan-bugs.neon
- tests/phpstan/configs/property-hook-sadness.neon
- tests/phpstan/configs/reflection-class-sadness.neon
- tests/phpstan/configs/spl-fixed-array-sucks.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
rules:
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
- pocketmine\phpstan\rules\DisallowDynamicNewRule
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
- pocketmine\phpstan\rules\ExplodeLimitRule
- pocketmine\phpstan\rules\UnsafeForeachRule
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
parameters:
level: 9
checkMissingCallableSignature: true
rememberPossiblyImpureFunctionValues: false #risky to remember these, better for performance to avoid repeated calls anyway
treatPhpDocTypesAsCertain: false
bootstrapFiles:
- tests/phpstan/bootstrap.php
@ -31,6 +33,7 @@ parameters:
paths:
- build
- src
- tests/phpstan/DummyPluginOwned.php
- tests/phpstan/rules
- tests/phpunit
- tests/plugins/TesterPlugin
@ -40,15 +43,15 @@ parameters:
- build/php
dynamicConstantNames:
- pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD
- pocketmine\VersionInfo::BUILD_CHANNEL
- pocketmine\DEBUG
- pocketmine\IS_DEVELOPMENT_BUILD
stubFiles:
- tests/phpstan/stubs/chunkutils2.stub
- tests/phpstan/stubs/JsonMapper.stub
- tests/phpstan/stubs/leveldb.stub
- tests/phpstan/stubs/pmmpthread.stub
reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
staticReflectionClassNamePatterns:
- "#^COM$#"
typeAliases:
#variadics don't work for this - mixed probably shouldn't work either, but for now it does
#what we actually need is something that accepts an infinite number of parameters, but in the absence of that,

View File

@ -54,12 +54,6 @@ memory:
#This only affects the main thread. Other threads should fire their own collections
period: 36000
#Fire asynchronous tasks to collect garbage from workers
collect-async-worker: true
#Trigger on low memory
low-memory-trigger: true
#Settings controlling memory dump handling.
memory-dump:
#Dump memory from async workers as well as the main thread. If you have issues with segfaults when dumping memory, disable this setting.
@ -69,16 +63,6 @@ memory:
#Cap maximum render distance per player when low memory is triggered. Set to 0 to disable cap.
chunk-radius: 4
#Do chunk garbage collection on trigger
trigger-chunk-collect: true
world-caches:
#Disallow adding to world chunk-packet caches when memory is low
disable-chunk-cache: true
#Clear world caches when memory is low
low-memory-trigger: true
network:
#Threshold for batching packets, in bytes. Only these packets will be compressed
#Set to 0 to compress everything, -1 to disable.

View File

@ -0,0 +1,114 @@
<?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;
use pocketmine\timings\TimingsHandler;
use function gc_collect_cycles;
use function gc_disable;
use function gc_status;
use function hrtime;
use function max;
use function min;
use function number_format;
use function sprintf;
/**
* Allows threads to manually trigger the cyclic garbage collector using a threshold like PHP's own garbage collector,
* but triggered at a time that suits the thread instead of in random code pathways.
*
* The GC trigger behaviour in this class was adapted from Zend/zend_gc.c as of PHP 8.3.14.
*/
final class GarbageCollectorManager{
//TODO: These values could be adjusted to better suit PM, but for now we just want to mirror PHP GC to minimize
//behavioural changes.
private const GC_THRESHOLD_TRIGGER = 100;
private const GC_THRESHOLD_MAX = 1_000_000_000;
private const GC_THRESHOLD_DEFAULT = 10_001;
private const GC_THRESHOLD_STEP = 10_000;
private int $threshold = self::GC_THRESHOLD_DEFAULT;
private int $collectionTimeTotalNs = 0;
private int $runs = 0;
private \Logger $logger;
private TimingsHandler $timings;
public function __construct(
\Logger $logger,
?TimingsHandler $parentTimings,
){
gc_disable();
$this->logger = new \PrefixedLogger($logger, "Cyclic Garbage Collector");
$this->timings = new TimingsHandler("Cyclic Garbage Collector", $parentTimings);
}
private function adjustGcThreshold(int $cyclesCollected, int $rootsAfterGC) : void{
//TODO Very simple heuristic for dynamic GC buffer resizing:
//If there are "too few" collections, increase the collection threshold
//by a fixed step
//Adapted from zend_gc.c/gc_adjust_threshold() as of PHP 8.3.14
if($cyclesCollected < self::GC_THRESHOLD_TRIGGER || $rootsAfterGC >= $this->threshold){
$this->threshold = min(self::GC_THRESHOLD_MAX, $this->threshold + self::GC_THRESHOLD_STEP);
}elseif($this->threshold > self::GC_THRESHOLD_DEFAULT){
$this->threshold = max(self::GC_THRESHOLD_DEFAULT, $this->threshold - self::GC_THRESHOLD_STEP);
}
}
public function getThreshold() : int{ return $this->threshold; }
public function getCollectionTimeTotalNs() : int{ return $this->collectionTimeTotalNs; }
public function maybeCollectCycles() : int{
$rootsBefore = gc_status()["roots"];
if($rootsBefore < $this->threshold){
return 0;
}
$this->timings->startTiming();
$start = hrtime(true);
$cycles = gc_collect_cycles();
$end = hrtime(true);
$rootsAfter = gc_status()["roots"];
$this->adjustGcThreshold($cycles, $rootsAfter);
$this->timings->stopTiming();
$time = $end - $start;
$this->collectionTimeTotalNs += $time;
$this->runs++;
$this->logger->info(sprintf(
"Run #%d took %s ms (%s -> %s roots, %s cycles collected) - cumulative GC time: %s ms",
$this->runs,
number_format($time / 1_000_000, 2),
$rootsBefore,
$rootsAfter,
$cycles,
number_format($this->collectionTimeTotalNs / 1_000_000, 2)
));
return $cycles;
}
}

305
src/MemoryDump.php Normal file
View File

@ -0,0 +1,305 @@
<?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;
use pocketmine\utils\Utils;
use Symfony\Component\Filesystem\Path;
use function arsort;
use function count;
use function fclose;
use function file_exists;
use function file_put_contents;
use function fopen;
use function fwrite;
use function gc_disable;
use function gc_enable;
use function gc_enabled;
use function get_class;
use function get_declared_classes;
use function get_defined_functions;
use function ini_get;
use function ini_set;
use function is_array;
use function is_float;
use function is_object;
use function is_resource;
use function is_string;
use function json_encode;
use function mkdir;
use function print_r;
use function spl_object_hash;
use function strlen;
use function substr;
use const JSON_PRETTY_PRINT;
use const JSON_THROW_ON_ERROR;
use const JSON_UNESCAPED_SLASHES;
use const SORT_NUMERIC;
final class MemoryDump{
private function __construct(){
//NOOP
}
/**
* Static memory dumper accessible from any thread.
*/
public static function dumpMemory(mixed $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');
$gcEnabled = gc_enabled();
gc_disable();
if(!file_exists($outputFolder)){
mkdir($outputFolder, 0777, true);
}
$obData = Utils::assumeNotFalse(fopen(Path::join($outputFolder, "objects.js"), "wb+"));
$objects = [];
$refCounts = [];
$instanceCounts = [];
$staticProperties = [];
$staticCount = 0;
$functionStaticVars = [];
$functionStaticVarsCount = 0;
foreach(get_declared_classes() as $className){
$reflection = new \ReflectionClass($className);
$staticProperties[$className] = [];
foreach($reflection->getProperties() as $property){
if(!$property->isStatic() || $property->getDeclaringClass()->getName() !== $className){
continue;
}
if(!$property->isInitialized()){
continue;
}
$staticCount++;
$staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($staticProperties[$className]) === 0){
unset($staticProperties[$className]);
}
foreach($reflection->getMethods() as $method){
if($method->getDeclaringClass()->getName() !== $reflection->getName()){
continue;
}
$methodStatics = [];
foreach(Utils::promoteKeys($method->getStaticVariables()) as $name => $variable){
$methodStatics[$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($methodStatics) > 0){
$functionStaticVars[$className . "::" . $method->getName()] = $methodStatics;
$functionStaticVarsCount += count($functionStaticVars);
}
}
}
file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Wrote $staticCount static properties");
$globalVariables = [];
$globalCount = 0;
$ignoredGlobals = [
'GLOBALS' => true,
'_SERVER' => true,
'_REQUEST' => true,
'_POST' => true,
'_GET' => true,
'_FILES' => true,
'_ENV' => true,
'_COOKIE' => true,
'_SESSION' => true
];
foreach(Utils::promoteKeys($GLOBALS) as $varName => $value){
if(isset($ignoredGlobals[$varName])){
continue;
}
$globalCount++;
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Wrote $globalCount global variables");
foreach(get_defined_functions()["user"] as $function){
$reflect = new \ReflectionFunction($function);
$vars = [];
foreach(Utils::promoteKeys($reflect->getStaticVariables()) as $varName => $variable){
$vars[$varName] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($vars) > 0){
$functionStaticVars[$function] = $vars;
$functionStaticVarsCount += count($vars);
}
}
file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Wrote $functionStaticVarsCount function static variables");
$data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
do{
$continue = false;
foreach(Utils::stringifyKeys($objects) as $hash => $object){
if(!is_object($object)){
continue;
}
$continue = true;
$className = get_class($object);
if(!isset($instanceCounts[$className])){
$instanceCounts[$className] = 1;
}else{
$instanceCounts[$className]++;
}
$objects[$hash] = true;
$info = [
"information" => "$hash@$className",
];
if($object instanceof \Closure){
$info["definition"] = Utils::getNiceClosureName($object);
$info["referencedVars"] = [];
$reflect = new \ReflectionFunction($object);
if(($closureThis = $reflect->getClosureThis()) !== null){
$info["this"] = self::continueDump($closureThis, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
foreach(Utils::promoteKeys($reflect->getStaticVariables()) as $name => $variable){
$info["referencedVars"][$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
}else{
$reflection = new \ReflectionObject($object);
$info["properties"] = [];
for($original = $reflection; $reflection !== false; $reflection = $reflection->getParentClass()){
foreach($reflection->getProperties() as $property){
if($property->isStatic()){
continue;
}
$name = $property->getName();
if($reflection !== $original){
if($property->isPrivate()){
$name = $reflection->getName() . ":" . $name;
}else{
continue;
}
}
if(!$property->isInitialized($object)){
continue;
}
$info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
}
}
fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n");
}
}while($continue);
$logger->info("Wrote " . count($objects) . " objects");
fclose($obData);
file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
arsort($instanceCounts, SORT_NUMERIC);
file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Finished!");
ini_set('memory_limit', $hardLimit);
if($gcEnabled){
gc_enable();
}
}
/**
* @param object[]|true[] $objects reference parameter
* @param int[] $refCounts reference parameter
*
* @phpstan-param array<string, object|true> $objects
* @phpstan-param array<string, int> $refCounts
* @phpstan-param-out array<string, object|true> $objects
* @phpstan-param-out array<string, int> $refCounts
*/
private static function continueDump(mixed $from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : mixed{
if($maxNesting <= 0){
return "(error) NESTING LIMIT REACHED";
}
--$maxNesting;
if(is_object($from)){
if(!isset($objects[$hash = spl_object_hash($from)])){
$objects[$hash] = $from;
$refCounts[$hash] = 0;
}
++$refCounts[$hash];
$data = "(object) $hash";
}elseif(is_array($from)){
if($recursion >= 5){
return "(error) ARRAY RECURSION LIMIT REACHED";
}
$data = [];
$numeric = 0;
foreach(Utils::promoteKeys($from) as $key => $value){
$data[$numeric] = [
"k" => self::continueDump($key, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
"v" => self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
];
$numeric++;
}
}elseif(is_string($from)){
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
}elseif(is_resource($from)){
$data = "(resource) " . print_r($from, true);
}elseif(is_float($from)){
$data = "(float) $from";
}else{
$data = $from;
}
return $data;
}
}

View File

@ -29,52 +29,24 @@ use pocketmine\scheduler\DumpWorkerMemoryTask;
use pocketmine\scheduler\GarbageCollectionTask;
use pocketmine\timings\Timings;
use pocketmine\utils\Process;
use pocketmine\utils\Utils;
use pocketmine\YmlServerProperties as Yml;
use Symfony\Component\Filesystem\Path;
use function arsort;
use function count;
use function fclose;
use function file_exists;
use function file_put_contents;
use function fopen;
use function fwrite;
use function gc_collect_cycles;
use function gc_disable;
use function gc_enable;
use function gc_mem_caches;
use function get_class;
use function get_declared_classes;
use function get_defined_functions;
use function ini_get;
use function ini_set;
use function intdiv;
use function is_array;
use function is_float;
use function is_object;
use function is_resource;
use function is_string;
use function json_encode;
use function mb_strtoupper;
use function min;
use function mkdir;
use function preg_match;
use function print_r;
use function round;
use function spl_object_hash;
use function sprintf;
use function strlen;
use function substr;
use const JSON_PRETTY_PRINT;
use const JSON_THROW_ON_ERROR;
use const JSON_UNESCAPED_SLASHES;
use const SORT_NUMERIC;
class MemoryManager{
private const DEFAULT_CHECK_RATE = Server::TARGET_TICKS_PER_SECOND;
private const DEFAULT_CONTINUOUS_TRIGGER_RATE = Server::TARGET_TICKS_PER_SECOND * 2;
private const DEFAULT_TICKS_PER_GC = 30 * 60 * Server::TARGET_TICKS_PER_SECOND;
private GarbageCollectorManager $cycleGcManager;
private int $memoryLimit;
private int $globalMemoryLimit;
private int $checkRate;
@ -88,14 +60,8 @@ class MemoryManager{
private int $garbageCollectionPeriod;
private int $garbageCollectionTicker = 0;
private bool $garbageCollectionTrigger;
private bool $garbageCollectionAsync;
private int $lowMemChunkRadiusOverride;
private bool $lowMemChunkGC;
private bool $lowMemDisableChunkCache;
private bool $lowMemClearWorldCache;
private bool $dumpWorkers = true;
@ -105,6 +71,7 @@ class MemoryManager{
private Server $server
){
$this->logger = new \PrefixedLogger($server->getLogger(), "Memory Manager");
$this->cycleGcManager = new GarbageCollectorManager($this->logger, Timings::$memoryManager);
$this->init($server->getConfigGroup());
}
@ -142,17 +109,10 @@ class MemoryManager{
$this->continuousTriggerRate = $config->getPropertyInt(Yml::MEMORY_CONTINUOUS_TRIGGER_RATE, self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
$this->garbageCollectionPeriod = $config->getPropertyInt(Yml::MEMORY_GARBAGE_COLLECTION_PERIOD, self::DEFAULT_TICKS_PER_GC);
$this->garbageCollectionTrigger = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER, true);
$this->garbageCollectionAsync = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER, true);
$this->lowMemChunkRadiusOverride = $config->getPropertyInt(Yml::MEMORY_MAX_CHUNKS_CHUNK_RADIUS, 4);
$this->lowMemChunkGC = $config->getPropertyBool(Yml::MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT, true);
$this->lowMemDisableChunkCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE, true);
$this->lowMemClearWorldCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER, true);
$this->dumpWorkers = $config->getPropertyBool(Yml::MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER, true);
gc_enable();
}
public function isLowMemory() : bool{
@ -163,10 +123,6 @@ class MemoryManager{
return $this->globalMemoryLimit;
}
public function canUseChunkCache() : bool{
return !$this->lowMemory || !$this->lowMemDisableChunkCache;
}
/**
* Returns the allowed chunk radius based on the current memory usage.
*/
@ -180,26 +136,19 @@ class MemoryManager{
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0) : void{
$this->logger->debug(sprintf("%sLow memory triggered, limit %gMB, using %gMB",
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
if($this->lowMemClearWorldCache){
foreach($this->server->getWorldManager()->getWorlds() as $world){
$world->clearCache(true);
}
ChunkCache::pruneCaches();
foreach($this->server->getWorldManager()->getWorlds() as $world){
$world->clearCache(true);
}
ChunkCache::pruneCaches();
if($this->lowMemChunkGC){
foreach($this->server->getWorldManager()->getWorlds() as $world){
$world->doChunkGarbageCollection();
}
foreach($this->server->getWorldManager()->getWorlds() as $world){
$world->doChunkGarbageCollection();
}
$ev = new LowMemoryEvent($memory, $limit, $global, $triggerCount);
$ev->call();
$cycles = 0;
if($this->garbageCollectionTrigger){
$cycles = $this->triggerGarbageCollector();
}
$cycles = $this->triggerGarbageCollector();
$this->logger->debug(sprintf("Freed %gMB, $cycles cycles", round(($ev->getMemoryFreed() / 1024) / 1024, 2)));
}
@ -239,6 +188,8 @@ class MemoryManager{
if($this->garbageCollectionPeriod > 0 && ++$this->garbageCollectionTicker >= $this->garbageCollectionPeriod){
$this->garbageCollectionTicker = 0;
$this->triggerGarbageCollector();
}else{
$this->cycleGcManager->maybeCollectCycles();
}
Timings::$memoryManager->stopTiming();
@ -247,14 +198,12 @@ class MemoryManager{
public function triggerGarbageCollector() : int{
Timings::$garbageCollector->startTiming();
if($this->garbageCollectionAsync){
$pool = $this->server->getAsyncPool();
if(($w = $pool->shutdownUnusedWorkers()) > 0){
$this->logger->debug("Shut down $w idle async pool workers");
}
foreach($pool->getRunningWorkers() as $i){
$pool->submitTaskToWorker(new GarbageCollectionTask(), $i);
}
$pool = $this->server->getAsyncPool();
if(($w = $pool->shutdownUnusedWorkers()) > 0){
$this->logger->debug("Shut down $w idle async pool workers");
}
foreach($pool->getRunningWorkers() as $i){
$pool->submitTaskToWorker(new GarbageCollectionTask(), $i);
}
$cycles = gc_collect_cycles();
@ -271,7 +220,7 @@ class MemoryManager{
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize) : void{
$logger = new \PrefixedLogger($this->server->getLogger(), "Memory Dump");
$logger->notice("After the memory dump is done, the server might crash");
self::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize, $logger);
MemoryDump::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize, $logger);
if($this->dumpWorkers){
$pool = $this->server->getAsyncPool();
@ -280,242 +229,4 @@ class MemoryManager{
}
}
}
/**
* Static memory dumper accessible from any thread.
*/
public static function dumpMemory(mixed $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();
if(!file_exists($outputFolder)){
mkdir($outputFolder, 0777, true);
}
$obData = Utils::assumeNotFalse(fopen(Path::join($outputFolder, "objects.js"), "wb+"));
$objects = [];
$refCounts = [];
$instanceCounts = [];
$staticProperties = [];
$staticCount = 0;
$functionStaticVars = [];
$functionStaticVarsCount = 0;
foreach(get_declared_classes() as $className){
$reflection = new \ReflectionClass($className);
$staticProperties[$className] = [];
foreach($reflection->getProperties() as $property){
if(!$property->isStatic() || $property->getDeclaringClass()->getName() !== $className){
continue;
}
if(!$property->isInitialized()){
continue;
}
$staticCount++;
$staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($staticProperties[$className]) === 0){
unset($staticProperties[$className]);
}
foreach($reflection->getMethods() as $method){
if($method->getDeclaringClass()->getName() !== $reflection->getName()){
continue;
}
$methodStatics = [];
foreach($method->getStaticVariables() as $name => $variable){
$methodStatics[$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($methodStatics) > 0){
$functionStaticVars[$className . "::" . $method->getName()] = $methodStatics;
$functionStaticVarsCount += count($functionStaticVars);
}
}
}
file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Wrote $staticCount static properties");
$globalVariables = [];
$globalCount = 0;
$ignoredGlobals = [
'GLOBALS' => true,
'_SERVER' => true,
'_REQUEST' => true,
'_POST' => true,
'_GET' => true,
'_FILES' => true,
'_ENV' => true,
'_COOKIE' => true,
'_SESSION' => true
];
foreach($GLOBALS as $varName => $value){
if(isset($ignoredGlobals[$varName])){
continue;
}
$globalCount++;
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Wrote $globalCount global variables");
foreach(get_defined_functions()["user"] as $function){
$reflect = new \ReflectionFunction($function);
$vars = [];
foreach($reflect->getStaticVariables() as $varName => $variable){
$vars[$varName] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
if(count($vars) > 0){
$functionStaticVars[$function] = $vars;
$functionStaticVarsCount += count($vars);
}
}
file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Wrote $functionStaticVarsCount function static variables");
$data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
do{
$continue = false;
foreach(Utils::stringifyKeys($objects) as $hash => $object){
if(!is_object($object)){
continue;
}
$continue = true;
$className = get_class($object);
if(!isset($instanceCounts[$className])){
$instanceCounts[$className] = 1;
}else{
$instanceCounts[$className]++;
}
$objects[$hash] = true;
$info = [
"information" => "$hash@$className",
];
if($object instanceof \Closure){
$info["definition"] = Utils::getNiceClosureName($object);
$info["referencedVars"] = [];
$reflect = new \ReflectionFunction($object);
if(($closureThis = $reflect->getClosureThis()) !== null){
$info["this"] = self::continueDump($closureThis, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
foreach($reflect->getStaticVariables() as $name => $variable){
$info["referencedVars"][$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
}else{
$reflection = new \ReflectionObject($object);
$info["properties"] = [];
for($original = $reflection; $reflection !== false; $reflection = $reflection->getParentClass()){
foreach($reflection->getProperties() as $property){
if($property->isStatic()){
continue;
}
$name = $property->getName();
if($reflection !== $original){
if($property->isPrivate()){
$name = $reflection->getName() . ":" . $name;
}else{
continue;
}
}
if(!$property->isInitialized($object)){
continue;
}
$info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
}
}
}
fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n");
}
}while($continue);
$logger->info("Wrote " . count($objects) . " objects");
fclose($obData);
file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
arsort($instanceCounts, SORT_NUMERIC);
file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$logger->info("Finished!");
ini_set('memory_limit', $hardLimit);
gc_enable();
}
/**
* @param object[] $objects reference parameter
* @param int[] $refCounts reference parameter
*
* @phpstan-param array<string, object> $objects
* @phpstan-param array<string, int> $refCounts
* @phpstan-param-out array<string, object> $objects
* @phpstan-param-out array<string, int> $refCounts
*/
private static function continueDump(mixed $from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : mixed{
if($maxNesting <= 0){
return "(error) NESTING LIMIT REACHED";
}
--$maxNesting;
if(is_object($from)){
if(!isset($objects[$hash = spl_object_hash($from)])){
$objects[$hash] = $from;
$refCounts[$hash] = 0;
}
++$refCounts[$hash];
$data = "(object) $hash";
}elseif(is_array($from)){
if($recursion >= 5){
return "(error) ARRAY RECURSION LIMIT REACHED";
}
$data = [];
$numeric = 0;
foreach($from as $key => $value){
$data[$numeric] = [
"k" => self::continueDump($key, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
"v" => self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
];
$numeric++;
}
}elseif(is_string($from)){
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
}elseif(is_resource($from)){
$data = "(resource) " . print_r($from, true);
}elseif(is_float($from)){
$data = "(float) $from";
}else{
$data = $from;
}
return $data;
}
}

View File

@ -55,7 +55,7 @@ namespace pocketmine {
require_once __DIR__ . '/VersionInfo.php';
const MIN_PHP_VERSION = "8.1.0";
const MIN_PHP_VERSION = "8.3.0";
/**
* @param string $message
@ -264,7 +264,7 @@ JIT_WARNING
$composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp');
if($composerGitHash !== null){
//we can't verify dependency versions if we were installed without using git
$currentGitHash = explode("-", VersionInfo::GIT_HASH())[0];
$currentGitHash = explode("-", VersionInfo::GIT_HASH(), 2)[0];
if($currentGitHash !== $composerGitHash){
critical_error("Composer dependencies and/or autoloader are out of sync.");
critical_error("- Current revision is $currentGitHash");
@ -282,6 +282,11 @@ JIT_WARNING
exit(0);
}
if(defined('pocketmine\ORIGINAL_PHAR_PATH')){
//if we're inside a phar cache, \pocketmine\PATH will not include the original phar
Filesystem::addCleanedPath(ORIGINAL_PHAR_PATH, Filesystem::CLEAN_PATH_SRC_PREFIX);
}
$cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
$dataPath = getopt_string(BootstrapOptions::DATA) ?? $cwd;
$pluginPath = getopt_string(BootstrapOptions::PLUGINS) ?? $cwd . DIRECTORY_SEPARATOR . "plugins";

View File

@ -36,6 +36,7 @@ use pocketmine\crafting\CraftingManager;
use pocketmine\crafting\CraftingManagerFromDataHelper;
use pocketmine\crash\CrashDump;
use pocketmine\crash\CrashDumpRenderer;
use pocketmine\data\bedrock\BedrockDataFiles;
use pocketmine\entity\EntityDataHelper;
use pocketmine\entity\Location;
use pocketmine\event\HandlerListManager;
@ -79,6 +80,7 @@ use pocketmine\player\PlayerDataLoadException;
use pocketmine\player\PlayerDataProvider;
use pocketmine\player\PlayerDataSaveException;
use pocketmine\player\PlayerInfo;
use pocketmine\plugin\FolderPluginLoader;
use pocketmine\plugin\PharPluginLoader;
use pocketmine\plugin\PluginEnableOrder;
use pocketmine\plugin\PluginGraylist;
@ -89,6 +91,8 @@ use pocketmine\promise\Promise;
use pocketmine\promise\PromiseResolver;
use pocketmine\resourcepacks\ResourcePackManager;
use pocketmine\scheduler\AsyncPool;
use pocketmine\scheduler\TimingsCollectionTask;
use pocketmine\scheduler\TimingsControlTask;
use pocketmine\snooze\SleeperHandler;
use pocketmine\stats\SendUsageTask;
use pocketmine\thread\log\AttachableThreadSafeLogger;
@ -136,6 +140,7 @@ use function file_put_contents;
use function filemtime;
use function fopen;
use function get_class;
use function gettype;
use function ini_set;
use function is_array;
use function is_dir;
@ -342,6 +347,10 @@ class Server{
return $this->maxPlayers;
}
public function setMaxPlayers(int $maxPlayers) : void{
$this->maxPlayers = $maxPlayers;
}
/**
* Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
* are not logged into Xbox Live will be disconnected.
@ -695,7 +704,7 @@ class Server{
public function removeOp(string $name) : void{
$lowercaseName = strtolower($name);
foreach($this->operators->getAll() as $operatorName => $_){
foreach(Utils::promoteKeys($this->operators->getAll()) as $operatorName => $_){
$operatorName = (string) $operatorName;
if($lowercaseName === strtolower($operatorName)){
$this->operators->remove($operatorName);
@ -736,12 +745,15 @@ class Server{
/**
* @return string[][]
* @phpstan-return array<string, list<string>>
*/
public function getCommandAliases() : array{
$section = $this->configGroup->getProperty(Yml::ALIASES);
$result = [];
if(is_array($section)){
foreach($section as $key => $value){
foreach(Utils::promoteKeys($section) as $key => $value){
//TODO: more validation needed here
//key might not be a string, value might not be list<string>
$commands = [];
if(is_array($value)){
$commands = $value;
@ -749,7 +761,7 @@ class Server{
$commands[] = (string) $value;
}
$result[$key] = $commands;
$result[(string) $key] = $commands;
}
}
@ -891,7 +903,37 @@ class Server{
$poolSize = max(1, (int) $poolSize);
}
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
$this->asyncPool = new AsyncPool($poolSize, max(-1, $this->configGroup->getPropertyInt(Yml::MEMORY_ASYNC_WORKER_HARD_LIMIT, 256)), $this->autoloader, $this->logger, $this->tickSleeper);
$this->asyncPool->addWorkerStartHook(function(int $i) : void{
if(TimingsHandler::isEnabled()){
$this->asyncPool->submitTaskToWorker(TimingsControlTask::setEnabled(true), $i);
}
});
TimingsHandler::getToggleCallbacks()->add(function(bool $enable) : void{
foreach($this->asyncPool->getRunningWorkers() as $workerId){
$this->asyncPool->submitTaskToWorker(TimingsControlTask::setEnabled($enable), $workerId);
}
});
TimingsHandler::getReloadCallbacks()->add(function() : void{
foreach($this->asyncPool->getRunningWorkers() as $workerId){
$this->asyncPool->submitTaskToWorker(TimingsControlTask::reload(), $workerId);
}
});
TimingsHandler::getCollectCallbacks()->add(function() : array{
$promises = [];
foreach($this->asyncPool->getRunningWorkers() as $workerId){
/** @phpstan-var PromiseResolver<list<string>> $resolver */
$resolver = new PromiseResolver();
$this->asyncPool->submitTaskToWorker(new TimingsCollectionTask($resolver), $workerId);
$promises[] = $resolver->getPromise();
}
return $promises;
});
$netCompressionThreshold = -1;
if($this->configGroup->getPropertyInt(Yml::NETWORK_BATCH_THRESHOLD, 256) >= 0){
@ -965,14 +1007,11 @@ class Server{
)));
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
DefaultPermissions::registerCorePermissions();
$this->commandMap = new SimpleCommandMap($this);
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes"));
$this->craftingManager = CraftingManagerFromDataHelper::make(BedrockDataFiles::RECIPES);
$this->resourceManager = new ResourcePackManager(Path::join($this->dataPath, "resource_packs"), $this->logger);
@ -982,7 +1021,11 @@ class Server{
copy(Path::join(\pocketmine\RESOURCE_PATH, 'plugin_list.yml'), $graylistFile);
}
try{
$pluginGraylist = PluginGraylist::fromArray(yaml_parse(Filesystem::fileGetContents($graylistFile)));
$array = yaml_parse(Filesystem::fileGetContents($graylistFile));
if(!is_array($array)){
throw new \InvalidArgumentException("Expected array for root, but have " . gettype($array));
}
$pluginGraylist = PluginGraylist::fromArray($array);
}catch(\InvalidArgumentException $e){
$this->logger->emergency("Failed to load $graylistFile: " . $e->getMessage());
$this->forceShutdownExit();
@ -991,6 +1034,7 @@ class Server{
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->dataPath, "plugin_data"), $pluginGraylist);
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
$this->pluginManager->registerInterface(new ScriptPluginLoader());
$this->pluginManager->registerInterface(new FolderPluginLoader($this->autoloader));
$providerManager = new WorldProviderManager();
if(
@ -1094,7 +1138,11 @@ class Server{
$anyWorldFailedToLoad = false;
foreach((array) $this->configGroup->getProperty(Yml::WORLDS, []) as $name => $options){
foreach(Utils::promoteKeys((array) $this->configGroup->getProperty(Yml::WORLDS, [])) as $name => $options){
if(!is_string($name)){
//TODO: this probably should be an error
continue;
}
if($options === null){
$options = [];
}elseif(!is_array($options)){
@ -1139,7 +1187,7 @@ class Server{
if($this->worldManager->getDefaultWorld() === null){
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
if(trim($default) == ""){
if(trim($default) === ""){
$this->logger->warning("level-name cannot be null, using default");
$default = "world";
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
@ -1576,7 +1624,7 @@ class Server{
if(!is_dir($crashFolder)){
mkdir($crashFolder);
}
$crashDumpPath = Path::join($crashFolder, date("D_M_j-H.i.s-T_Y", (int) $dump->getData()->time) . ".log");
$crashDumpPath = Path::join($crashFolder, date("Y-m-d_H.i.s_T", (int) $dump->getData()->time) . ".log");
$fp = @fopen($crashDumpPath, "wb");
if(!is_resource($fp)){

View File

@ -31,8 +31,8 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "5.17.1";
public const IS_DEVELOPMENT_BUILD = false;
public const BASE_VERSION = "5.33.2";
public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";
/**

View File

@ -75,20 +75,14 @@ final class YmlServerProperties{
public const MEMORY_CONTINUOUS_TRIGGER = 'memory.continuous-trigger';
public const MEMORY_CONTINUOUS_TRIGGER_RATE = 'memory.continuous-trigger-rate';
public const MEMORY_GARBAGE_COLLECTION = 'memory.garbage-collection';
public const MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER = 'memory.garbage-collection.collect-async-worker';
public const MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER = 'memory.garbage-collection.low-memory-trigger';
public const MEMORY_GARBAGE_COLLECTION_PERIOD = 'memory.garbage-collection.period';
public const MEMORY_GLOBAL_LIMIT = 'memory.global-limit';
public const MEMORY_MAIN_HARD_LIMIT = 'memory.main-hard-limit';
public const MEMORY_MAIN_LIMIT = 'memory.main-limit';
public const MEMORY_MAX_CHUNKS = 'memory.max-chunks';
public const MEMORY_MAX_CHUNKS_CHUNK_RADIUS = 'memory.max-chunks.chunk-radius';
public const MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT = 'memory.max-chunks.trigger-chunk-collect';
public const MEMORY_MEMORY_DUMP = 'memory.memory-dump';
public const MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER = 'memory.memory-dump.dump-async-worker';
public const MEMORY_WORLD_CACHES = 'memory.world-caches';
public const MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE = 'memory.world-caches.disable-chunk-cache';
public const MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER = 'memory.world-caches.low-memory-trigger';
public const NETWORK = 'network';
public const NETWORK_ASYNC_COMPRESSION = 'network.async-compression';
public const NETWORK_ASYNC_COMPRESSION_THRESHOLD = 'network.async-compression-threshold';

View File

@ -23,9 +23,10 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\RailPoweredByRedstoneTrait;
class ActivatorRail extends StraightOnlyRail{
class ActivatorRail extends StraightOnlyRail implements PoweredByRedstone{
use RailPoweredByRedstoneTrait;
//TODO

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\AmethystTrait;
use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\FortuneDropHelper;
use pocketmine\block\utils\SupportType;
@ -38,7 +39,7 @@ use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
final class AmethystCluster extends Transparent{
final class AmethystCluster extends Transparent implements AnyFacing{
use AmethystTrait;
use AnyFacingTrait;
@ -81,22 +82,22 @@ final class AmethystCluster extends Transparent{
if($axis === $myAxis){
continue;
}
$box->squash($axis, $this->stage === self::STAGE_SMALL_BUD ? 4 / 16 : 3 / 16);
$box = $box->squashedCopy($axis, $this->stage === self::STAGE_SMALL_BUD ? 4 / 16 : 3 / 16);
}
$box->trim($this->facing, 1 - ($this->stage === self::STAGE_CLUSTER ? 7 / 16 : ($this->stage + 3) / 16));
$box = $box->trimmedCopy($this->facing, 1 - ($this->stage === self::STAGE_CLUSTER ? 7 / 16 : ($this->stage + 3) / 16));
return [$box];
}
private function canBeSupportedAt(Block $block, int $facing) : bool{
private function canBeSupportedAt(Block $block, Facing $facing) : bool{
return $block->getAdjacentSupportType($facing) === SupportType::FULL;
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
return false;
}

View File

@ -23,10 +23,14 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\AnvilInventory;
use pocketmine\block\inventory\window\AnvilInventoryWindow;
use pocketmine\block\utils\Fallable;
use pocketmine\block\utils\FallableTrait;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\MenuAccessor;
use pocketmine\block\utils\MenuAccessorTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\object\FallingBlock;
@ -35,15 +39,17 @@ use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\Utils;
use pocketmine\world\BlockTransaction;
use pocketmine\world\Position;
use pocketmine\world\sound\AnvilFallSound;
use pocketmine\world\sound\Sound;
use function lcg_value;
use function round;
class Anvil extends Transparent implements Fallable{
class Anvil extends Transparent implements Fallable, HorizontalFacing, MenuAccessor{
use FallableTrait;
use HorizontalFacingTrait;
use MenuAccessorTrait;
public const UNDAMAGED = 0;
public const SLIGHTLY_DAMAGED = 1;
@ -56,7 +62,7 @@ class Anvil extends Transparent implements Fallable{
}
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
}
public function getDamage() : int{ return $this->damage; }
@ -70,34 +76,27 @@ class Anvil extends Transparent implements Fallable{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->squash(Facing::axis(Facing::rotateY($this->facing, false)), 1 / 8)];
return [AxisAlignedBB::one()->squashedCopy(Facing::axis(Facing::rotateY($this->facing->toFacing(), false)), 1 / 8)];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player instanceof Player){
$player->setCurrentWindow(new AnvilInventory($this->position));
}
return true;
protected function newMenu(Player $player, Position $position) : AnvilInventoryWindow{
return new AnvilInventoryWindow($player, $position);
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
$this->facing = Facing::rotateY($player->getHorizontalFacing(), false);
$this->facing = HorizontalFacingOption::fromFacing(Facing::rotateY($player->getHorizontalFacing(), false));
}
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(Utils::getRandomFloat() < 0.05 + (round($blockEntity->getFallDistance()) - 1) * 0.05){
if($this->damage !== self::VERY_DAMAGED){
$this->damage = $this->damage + 1;
}else{

View File

@ -87,16 +87,13 @@ class Bamboo extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
//this places the BB at the northwest corner, not the center
$inset = 1 - (($this->thick ? 3 : 2) / 16);
return [AxisAlignedBB::one()->trim(Facing::SOUTH, $inset)->trim(Facing::EAST, $inset)];
return [AxisAlignedBB::one()->trimmedCopy(Facing::SOUTH, $inset)->trimmedCopy(Facing::EAST, $inset)];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -141,7 +138,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, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof Fertilizer){
$top = $this->seekToTop();
if($top->grow(self::getMaxHeight($top->position->getFloorX(), $top->position->getFloorZ()), mt_rand(1, 2), $player)){

View File

@ -61,7 +61,7 @@ final class BambooSapling extends Flowable{
$supportBlock->hasTypeTag(BlockTypeTags::SAND);
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof Fertilizer || $item instanceof ItemBamboo){
if($this->grow($player)){
$item->pop();

View File

@ -23,23 +23,33 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Barrel as TileBarrel;
use pocketmine\block\utils\AnimatedContainerLike;
use pocketmine\block\utils\AnimatedContainerLikeTrait;
use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\block\utils\Container;
use pocketmine\block\utils\ContainerTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\Position;
use pocketmine\world\sound\BarrelCloseSound;
use pocketmine\world\sound\BarrelOpenSound;
use pocketmine\world\sound\Sound;
use function abs;
class Barrel extends Opaque{
class Barrel extends Opaque implements AnimatedContainerLike, AnyFacing, Container{
use AnimatedContainerLikeTrait;
use AnyFacingTrait;
use ContainerTrait;
protected bool $open = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->facing($this->facing);
$w->enum($this->facing);
$w->bool($this->open);
}
@ -53,7 +63,7 @@ class Barrel extends Opaque{
return $this;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
if(abs($player->getPosition()->x - $this->position->x) < 2 && abs($player->getPosition()->z - $this->position->z) < 2){
$y = $player->getEyePos()->y;
@ -73,22 +83,23 @@ 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{
if($player instanceof Player){
$barrel = $this->position->getWorld()->getTile($this->position);
if($barrel instanceof TileBarrel){
if(!$barrel->canOpenWith($item->getCustomName())){
return true;
}
$player->setCurrentWindow($barrel->getInventory());
}
}
return true;
}
public function getFuelTime() : int{
return 300;
}
protected function getOpenSound() : Sound{
return new BarrelOpenSound();
}
protected function getCloseSound() : Sound{
return new BarrelCloseSound();
}
protected function playAnimationVisual(Position $position, bool $isOpen) : void{
$world = $position->getWorld();
$block = $world->getBlock($position);
if($block instanceof Barrel){
$world->setBlock($position, $block->setOpen($isOpen));
}
}
}

View File

@ -25,19 +25,20 @@ namespace pocketmine\block;
use pocketmine\block\tile\Banner as TileBanner;
use pocketmine\block\utils\BannerPatternLayer;
use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Banner as ItemBanner;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function assert;
use function count;
abstract class BaseBanner extends Transparent{
abstract class BaseBanner extends Transparent implements Colored{
use ColoredTrait;
/**
@ -50,6 +51,10 @@ abstract class BaseBanner extends Transparent{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBanner){
if($tile->getType() === TileBanner::TYPE_OMINOUS){
//illager banner is implemented as a separate block, as it doesn't support base color or custom patterns
return $this->getOminousVersion();
}
$this->color = $tile->getBaseColor();
$this->setPatterns($tile->getPatterns());
}
@ -57,6 +62,13 @@ abstract class BaseBanner extends Transparent{
return $this;
}
/**
* TODO: make this abstract in PM6 (BC break)
*/
protected function getOminousVersion() : Block{
return VanillaBlocks::AIR();
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
@ -97,14 +109,11 @@ abstract class BaseBanner extends Transparent{
return $this;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -112,7 +121,7 @@ abstract class BaseBanner extends Transparent{
return $block->isSolid();
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
return false;
}
@ -124,7 +133,7 @@ abstract class BaseBanner extends Transparent{
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
abstract protected function getSupportingFace() : int;
abstract protected function getSupportingFace() : Facing;
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\StructureGrowEvent;
@ -33,7 +35,7 @@ use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
abstract class BaseBigDripleaf extends Transparent{
abstract class BaseBigDripleaf extends Transparent implements HorizontalFacing{
use HorizontalFacingTrait;
abstract protected function isHead() : bool;
@ -56,13 +58,13 @@ abstract class BaseBigDripleaf extends Transparent{
}
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
$block = $blockReplace->getSide(Facing::DOWN);
if(!$this->canBeSupportedBy($block, true)){
return false;
}
if($player !== null){
$this->facing = Facing::opposite($player->getHorizontalFacing());
$this->facing = HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing()));
}
if($block instanceof BaseBigDripleaf){
$this->facing = $block->facing;
@ -71,7 +73,7 @@ abstract class BaseBigDripleaf extends Transparent{
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, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof Fertilizer && $this->grow($player)){
$item->pop();
return true;
@ -130,7 +132,7 @@ abstract class BaseBigDripleaf extends Transparent{
return 100;
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -36,7 +36,7 @@ use pocketmine\player\Player;
abstract class BaseCake extends Transparent implements FoodSource{
use StaticSupportTrait;
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -44,7 +44,7 @@ abstract class BaseCake extends Transparent implements FoodSource{
return $block->getSide(Facing::DOWN)->getTypeId() !== BlockTypeIds::AIR;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player !== null){
return $player->consumeObject($this);
}

View File

@ -24,12 +24,14 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\CoralMaterial;
use pocketmine\block\utils\CoralTypeTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use function mt_rand;
abstract class BaseCoral extends Transparent{
abstract class BaseCoral extends Transparent implements CoralMaterial{
use CoralTypeTrait;
public function onNearbyBlockChange() : void{
@ -71,7 +73,7 @@ abstract class BaseCoral extends Transparent{
protected function recalculateCollisionBoxes() : array{ return []; }
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -0,0 +1,91 @@
<?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\Banner as TileBanner;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function assert;
abstract class BaseOminousBanner extends Transparent{
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileBanner);
$tile->setBaseColor(DyeColor::WHITE);
$tile->setPatterns([]);
$tile->setType(TileBanner::TYPE_OMINOUS);
}
public function isSolid() : bool{
return false;
}
public function getMaxStackSize() : int{
return 16;
}
public function getFuelTime() : int{
return 300;
}
protected function recalculateCollisionBoxes() : array{
return [];
}
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
private function canBeSupportedBy(Block $block) : bool{
return $block->isSolid();
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
abstract protected function getSupportingFace() : Facing;
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function asItem() : Item{
return VanillaItems::OMINOUS_BANNER();
}
}

View File

@ -37,7 +37,7 @@ use function in_array;
abstract class BaseRail extends Flowable{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($blockReplace->getAdjacentSupportType(Facing::DOWN)->hasEdgeSupport()){
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
@ -89,8 +89,9 @@ abstract class BaseRail extends Flowable{
/** @var int $connection */
foreach($this->getCurrentShapeConnections() as $connection){
$other = $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND);
$otherConnection = Facing::opposite($connection & ~RailConnectionInfo::FLAG_ASCEND);
$connectionFace = Facing::from($connection & ~RailConnectionInfo::FLAG_ASCEND);
$other = $this->getSide($connectionFace);
$otherConnection = Facing::opposite($connectionFace)->value;
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0){
$other = $other->getSide(Facing::UP);
@ -122,10 +123,10 @@ abstract class BaseRail extends Flowable{
case 0:
//No constraints, can connect in any direction
$possible = [
Facing::NORTH => true,
Facing::SOUTH => true,
Facing::WEST => true,
Facing::EAST => true
Facing::NORTH->value => true,
Facing::SOUTH->value => true,
Facing::WEST->value => true,
Facing::EAST->value => true
];
foreach($possible as $p => $_){
$possible[$p | RailConnectionInfo::FLAG_ASCEND] = true;
@ -146,13 +147,13 @@ abstract class BaseRail extends Flowable{
* @phpstan-return array<int, true>
*/
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
$opposite = Facing::opposite($constraint & ~RailConnectionInfo::FLAG_ASCEND);
$opposite = Facing::opposite(Facing::from($constraint & ~RailConnectionInfo::FLAG_ASCEND));
$possible = [$opposite => true];
$possible = [$opposite->value => true];
if(($constraint & RailConnectionInfo::FLAG_ASCEND) === 0){
//We can slope the other way if this connection isn't already a slope
$possible[$opposite | RailConnectionInfo::FLAG_ASCEND] = true;
$possible[$opposite->value | RailConnectionInfo::FLAG_ASCEND] = true;
}
return $possible;
@ -168,9 +169,10 @@ abstract class BaseRail extends Flowable{
$continue = false;
foreach($possible as $thisSide => $_){
$otherSide = Facing::opposite($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
$thisSideEnum = Facing::from($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
$otherSide = Facing::opposite($thisSideEnum)->value;
$other = $this->getSide($thisSide & ~RailConnectionInfo::FLAG_ASCEND);
$other = $this->getSide($thisSideEnum);
if(($thisSide & RailConnectionInfo::FLAG_ASCEND) !== 0){
$other = $other->getSide(Facing::UP);
@ -212,7 +214,7 @@ abstract class BaseRail extends Flowable{
*/
private function setConnections(array $connections) : void{
if(count($connections) === 1){
$connections[] = Facing::opposite($connections[0] & ~RailConnectionInfo::FLAG_ASCEND);
$connections[] = Facing::opposite(Facing::from($connections[0] & ~RailConnectionInfo::FLAG_ASCEND))->value;
}elseif(count($connections) !== 2){
throw new \InvalidArgumentException("Expected exactly 2 connections, got " . count($connections));
}
@ -226,7 +228,7 @@ abstract class BaseRail extends Flowable{
$world->useBreakOn($this->position);
}else{
foreach($this->getCurrentShapeConnections() as $connection){
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && !$this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->getSupportType(Facing::UP)->hasEdgeSupport()){
if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && !$this->getSide(Facing::from($connection & ~RailConnectionInfo::FLAG_ASCEND))->getSupportType(Facing::UP)->hasEdgeSupport()){
$world->useBreakOn($this->position);
break;
}

View File

@ -27,6 +27,7 @@ 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\WoodMaterial;
use pocketmine\block\utils\WoodType;
use pocketmine\block\utils\WoodTypeTrait;
use pocketmine\color\Color;
@ -34,21 +35,26 @@ use pocketmine\event\block\SignChangeEvent;
use pocketmine\item\Dye;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
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 abs;
use function array_map;
use function assert;
use function atan2;
use function fmod;
use function rad2deg;
use function strlen;
abstract class BaseSign extends Transparent{
abstract class BaseSign extends Transparent implements WoodMaterial{
use WoodTypeTrait;
protected SignText $text;
protected SignText $text; //TODO: rename this (BC break)
protected SignText $backText;
private bool $waxed = false;
protected ?int $editorEntityRuntimeId = null;
@ -63,6 +69,7 @@ abstract class BaseSign extends Transparent{
$this->woodType = $woodType;
parent::__construct($idInfo, $name, $typeInfo);
$this->text = new SignText();
$this->backText = new SignText();
$this->asItemCallback = $asItemCallback;
}
@ -71,6 +78,7 @@ abstract class BaseSign extends Transparent{
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileSign){
$this->text = $tile->getText();
$this->backText = $tile->getBackText();
$this->waxed = $tile->isWaxed();
$this->editorEntityRuntimeId = $tile->getEditorEntityRuntimeId();
}
@ -83,6 +91,7 @@ abstract class BaseSign extends Transparent{
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileSign);
$tile->setText($this->text);
$tile->setBackText($this->backText);
$tile->setWaxed($this->waxed);
$tile->setEditorEntityRuntimeId($this->editorEntityRuntimeId);
}
@ -95,18 +104,15 @@ abstract class BaseSign extends Transparent{
return 16;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
abstract protected function getSupportingFace() : int;
abstract protected function getSupportingFace() : Facing;
public function onNearbyBlockChange() : void{
if($this->getSide($this->getSupportingFace())->getTypeId() === BlockTypeIds::AIR){
@ -114,7 +120,7 @@ abstract class BaseSign extends Transparent{
}
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($player !== null){
$this->editorEntityRuntimeId = $player->getId();
}
@ -130,11 +136,11 @@ abstract class BaseSign extends Transparent{
}
}
private function doSignChange(SignText $newText, Player $player, Item $item) : bool{
$ev = new SignChangeEvent($this, $player, $newText);
private function doSignChange(SignText $newText, Player $player, Item $item, bool $frontFace) : bool{
$ev = new SignChangeEvent($this, $player, $newText, $frontFace);
$ev->call();
if(!$ev->isCancelled()){
$this->text = $ev->getNewText();
$this->setFaceText($frontFace, $ev->getNewText());
$this->position->getWorld()->setBlock($this->position, $this);
$item->pop();
return true;
@ -143,8 +149,9 @@ abstract class BaseSign extends Transparent{
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)){
private function changeSignGlowingState(bool $glowing, Player $player, Item $item, bool $frontFace) : bool{
$text = $this->getFaceText($frontFace);
if($text->isGlowing() !== $glowing && $this->doSignChange(new SignText($text->getLines(), $text->getBaseColor(), $glowing), $player, $item, $frontFace)){
$this->position->getWorld()->addSound($this->position, new InkSacUseSound());
return true;
}
@ -163,7 +170,7 @@ abstract class BaseSign extends Transparent{
return true;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player === null){
return false;
}
@ -171,6 +178,8 @@ abstract class BaseSign extends Transparent{
return true;
}
$frontFace = $this->interactsFront($this->getHitboxCenter(), $player->getPosition(), $this->getFacingDegrees());
$dyeColor = $item instanceof Dye ? $item->getColor() : match($item->getTypeId()){
ItemTypeIds::BONE_MEAL => DyeColor::WHITE,
ItemTypeIds::LAPIS_LAZULI => DyeColor::BLUE,
@ -179,40 +188,82 @@ abstract class BaseSign extends Transparent{
};
if($dyeColor !== null){
$color = $dyeColor === DyeColor::BLACK ? new Color(0, 0, 0) : $dyeColor->getRgbValue();
$text = $this->getFaceText($frontFace);
if(
$color->toARGB() !== $this->text->getBaseColor()->toARGB() &&
$this->doSignChange(new SignText($this->text->getLines(), $color, $this->text->isGlowing()), $player, $item)
$color->toARGB() !== $text->getBaseColor()->toARGB() &&
$this->doSignChange(new SignText($text->getLines(), $color, $text->isGlowing()), $player, $item, $frontFace)
){
$this->position->getWorld()->addSound($this->position, new DyeUseSound());
return true;
}
}elseif(match($item->getTypeId()){
ItemTypeIds::INK_SAC => $this->changeSignGlowingState(false, $player, $item),
ItemTypeIds::GLOW_INK_SAC => $this->changeSignGlowingState(true, $player, $item),
ItemTypeIds::INK_SAC => $this->changeSignGlowingState(false, $player, $item, $frontFace),
ItemTypeIds::GLOW_INK_SAC => $this->changeSignGlowingState(true, $player, $item, $frontFace),
ItemTypeIds::HONEYCOMB => $this->wax($player, $item),
default => false
}){
return true;
}
$player->openSignEditor($this->position);
$player->openSignEditor($this->position, $frontFace);
return true;
}
private function interactsFront(Vector3 $hitboxCenter, Vector3 $playerPosition, float $signFacingDegrees) : bool{
$playerCenterDiffX = $playerPosition->x - $hitboxCenter->x;
$playerCenterDiffZ = $playerPosition->z - $hitboxCenter->z;
$f1 = rad2deg(atan2($playerCenterDiffZ, $playerCenterDiffX)) - 90.0;
$rotationDiff = $signFacingDegrees - $f1;
$rotation = fmod($rotationDiff + 180.0, 360.0) - 180.0; // Normalize to [-180, 180]
return abs($rotation) <= 90.0;
}
/**
* Returns the center of the sign's hitbox. Used to decide which face of the sign to open when a player interacts.
*/
protected function getHitboxCenter() : Vector3{
return $this->position->add(0.5, 0.5, 0.5);
}
/**
* TODO: make this abstract (BC break)
*/
protected function getFacingDegrees() : float{
return 0;
}
/**
* Returns an object containing information about the sign text.
* @deprecated
* @see self::getFaceText()
*/
public function getText() : SignText{
return $this->text;
}
/** @return $this */
/**
* @deprecated
* @see self::setFaceText()
* @return $this
*/
public function setText(SignText $text) : self{
$this->text = $text;
return $this;
}
public function getFaceText(bool $frontFace) : SignText{
return $frontFace ? $this->text : $this->backText;
}
/** @return $this */
public function setFaceText(bool $frontFace, SignText $text) : self{
$frontFace ? $this->text = $text : $this->backText = $text;
return $this;
}
/**
* Returns whether the sign has been waxed using a honeycomb. If true, the sign cannot be edited by a player.
*/
@ -237,13 +288,21 @@ abstract class BaseSign extends Transparent{
return $this;
}
/**
* @deprecated
* @see self::updateFaceText()
*/
public function updateText(Player $author, SignText $text) : bool{
return $this->updateFaceText($author, true, $text);
}
/**
* Called by the player controller (network session) to update the sign text, firing events as appropriate.
*
* @return bool if the sign update was successful.
* @throws \UnexpectedValueException if the text payload is too large
*/
public function updateText(Player $author, SignText $text) : bool{
public function updateFaceText(Player $author, bool $frontFace, SignText $text) : bool{
$size = 0;
foreach($text->getLines() as $line){
$size += strlen($line);
@ -251,15 +310,16 @@ abstract class BaseSign extends Transparent{
if($size > 1000){
throw new \UnexpectedValueException($author->getName() . " tried to write $size bytes of text onto a sign (bigger than max 1000)");
}
$oldText = $this->getFaceText($frontFace);
$ev = new SignChangeEvent($this, $author, new SignText(array_map(function(string $line) : string{
return TextFormat::clean($line, false);
}, $text->getLines()), $this->text->getBaseColor(), $this->text->isGlowing()));
}, $text->getLines()), $oldText->getBaseColor(), $oldText->isGlowing()), $frontFace);
if($this->waxed || $this->editorEntityRuntimeId !== $author->getId()){
$ev->cancel();
}
$ev->call();
if(!$ev->isCancelled()){
$this->setText($ev->getNewText());
$this->setFaceText($frontFace, $ev->getNewText());
$this->setEditorEntityRuntimeId(null);
$this->position->getWorld()->setBlock($this->position, $this);
return true;

View File

@ -24,8 +24,11 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Bed as TileBed;
use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@ -41,7 +44,7 @@ use pocketmine\utils\TextFormat;
use pocketmine\world\BlockTransaction;
use pocketmine\world\World;
class Bed extends Transparent{
class Bed extends Transparent implements Colored, HorizontalFacing{
use ColoredTrait;
use HorizontalFacingTrait;
@ -49,7 +52,7 @@ class Bed extends Transparent{
protected bool $head = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->bool($this->occupied);
$w->bool($this->head);
}
@ -76,14 +79,11 @@ class Bed extends Transparent{
}
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 16)];
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 7 / 16)];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -107,8 +107,8 @@ class Bed extends Transparent{
return $this;
}
private function getOtherHalfSide() : int{
return $this->head ? Facing::opposite($this->facing) : $this->facing;
private function getOtherHalfSide() : Facing{
return $this->head ? Facing::opposite($this->facing->toFacing()) : $this->facing->toFacing();
}
public function getOtherHalf() : ?Bed{
@ -120,7 +120,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, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player !== null){
$other = $this->getOtherHalf();
$playerPos = $player->getPosition();
@ -173,9 +173,11 @@ class Bed extends Transparent{
return $entity->getMotion()->y * -3 / 4; // 2/3 in Java, according to the wiki
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedAt($blockReplace)){
$this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH;
if($player !== null){
$this->facing = HorizontalFacingOption::fromFacing($player->getHorizontalFacing());
}
$next = $this->getSide($this->getOtherHalfSide());
if($next->canBeReplaced() && $this->canBeSupportedAt($next)){

View File

@ -25,6 +25,8 @@ namespace pocketmine\block;
use pocketmine\block\tile\Bell as TileBell;
use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@ -38,39 +40,40 @@ use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\BellRingSound;
final class Bell extends Transparent{
final class Bell extends Transparent implements HorizontalFacing{
use HorizontalFacingTrait;
private BellAttachmentType $attachmentType = BellAttachmentType::FLOOR;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->enum($this->attachmentType);
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
}
protected function recalculateCollisionBoxes() : array{
$realFacing = $this->facing->toFacing();
if($this->attachmentType === BellAttachmentType::FLOOR){
return [
AxisAlignedBB::one()->squash(Facing::axis($this->facing), 1 / 4)->trim(Facing::UP, 3 / 16)
AxisAlignedBB::one()->squashedCopy(Facing::axis($realFacing), 1 / 4)->trimmedCopy(Facing::UP, 3 / 16)
];
}
if($this->attachmentType === BellAttachmentType::CEILING){
return [
AxisAlignedBB::one()->contract(1 / 4, 0, 1 / 4)->trim(Facing::DOWN, 1 / 4)
AxisAlignedBB::one()->contractedCopy(1 / 4, 0, 1 / 4)->trimmedCopy(Facing::DOWN, 1 / 4)
];
}
$box = AxisAlignedBB::one()
->squash(Facing::axis(Facing::rotateY($this->facing, true)), 1 / 4)
->trim(Facing::UP, 1 / 16)
->trim(Facing::DOWN, 1 / 4);
->squashedCopy(Facing::axis(Facing::rotateY($realFacing, true)), 1 / 4)
->trimmedCopy(Facing::UP, 1 / 16)
->trimmedCopy(Facing::DOWN, 1 / 4);
return [
$this->attachmentType === BellAttachmentType::ONE_WALL ? $box->trim($this->facing, 3 / 16) : $box
$this->attachmentType === BellAttachmentType::ONE_WALL ? $box->trimmedCopy($realFacing, 3 / 16) : $box
];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -82,23 +85,23 @@ final class Bell extends Transparent{
return $this;
}
private function canBeSupportedAt(Block $block, int $face) : bool{
private function canBeSupportedAt(Block $block, Facing $face) : bool{
return $block->getAdjacentSupportType($face) !== SupportType::NONE;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
return false;
}
if($face === Facing::UP){
if($player !== null){
$this->setFacing(Facing::opposite($player->getHorizontalFacing()));
$this->setFacing(HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing())));
}
$this->setAttachmentType(BellAttachmentType::FLOOR);
}elseif($face === Facing::DOWN){
$this->setAttachmentType(BellAttachmentType::CEILING);
}else{
$this->setFacing($face);
$this->setFacing(HorizontalFacingOption::fromFacing($face));
$this->setAttachmentType(
$this->canBeSupportedAt($blockReplace, $face) ?
BellAttachmentType::TWO_WALLS :
@ -112,8 +115,8 @@ final class Bell extends Transparent{
foreach(match($this->attachmentType){
BellAttachmentType::CEILING => [Facing::UP],
BellAttachmentType::FLOOR => [Facing::DOWN],
BellAttachmentType::ONE_WALL => [Facing::opposite($this->facing)],
BellAttachmentType::TWO_WALLS => [$this->facing, Facing::opposite($this->facing)]
BellAttachmentType::ONE_WALL => [Facing::opposite($this->facing->toFacing())],
BellAttachmentType::TWO_WALLS => [$this->facing->toFacing(), Facing::opposite($this->facing->toFacing())]
} as $supportBlockDirection){
if(!$this->canBeSupportedAt($this, $supportBlockDirection)){
$this->position->getWorld()->useBreakOn($this->position);
@ -122,7 +125,7 @@ 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, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player !== null){
$faceHit = Facing::opposite($player->getHorizontalFacing());
if($this->isValidFaceToRing($faceHit)){
@ -141,7 +144,7 @@ final class Bell extends Transparent{
}
}
public function ring(int $faceHit) : void{
public function ring(Facing $faceHit) : void{
$world = $this->position->getWorld();
$world->addSound($this->position, new BellRingSound());
$tile = $world->getTile($this->position);
@ -154,11 +157,11 @@ final class Bell extends Transparent{
return [$this->asItem()];
}
private function isValidFaceToRing(int $faceHit) : bool{
private function isValidFaceToRing(Facing $faceHit) : bool{
return match($this->attachmentType){
BellAttachmentType::CEILING => true,
BellAttachmentType::FLOOR => Facing::axis($faceHit) === Facing::axis($this->facing),
BellAttachmentType::ONE_WALL, BellAttachmentType::TWO_WALLS => $faceHit === Facing::rotateY($this->facing, false) || $faceHit === Facing::rotateY($this->facing, true),
BellAttachmentType::FLOOR => Facing::axis($faceHit) === Facing::axis($this->facing->toFacing()),
BellAttachmentType::ONE_WALL, BellAttachmentType::TWO_WALLS => $faceHit === Facing::rotateY($this->facing->toFacing(), false) || $faceHit === Facing::rotateY($this->facing->toFacing(), true),
};
}
}

View File

@ -80,8 +80,8 @@ class BigDripleafHead extends BaseBigDripleaf{
if(!$entity instanceof Projectile && $this->leafState === DripleafState::STABLE){
//the entity must be standing on top of the leaf - do not collapse if the entity is standing underneath
$intersection = AxisAlignedBB::one()
->offset($this->position->x, $this->position->y, $this->position->z)
->trim(Facing::DOWN, 1 - $this->getLeafTopOffset());
->offsetCopy($this->position->x, $this->position->y, $this->position->z)
->trimmedCopy(Facing::DOWN, 1 - $this->getLeafTopOffset());
if($entity->getBoundingBox()->intersectsWith($intersection)){
$this->setTiltAndScheduleTick(DripleafState::UNSTABLE);
return false;
@ -116,8 +116,8 @@ class BigDripleafHead extends BaseBigDripleaf{
if($this->leafState !== DripleafState::FULL_TILT){
return [
AxisAlignedBB::one()
->trim(Facing::DOWN, 11 / 16)
->trim(Facing::UP, $this->getLeafTopOffset())
->trimmedCopy(Facing::DOWN, 11 / 16)
->trimmedCopy(Facing::UP, $this->getLeafTopOffset())
];
}
return [];

View File

@ -75,7 +75,10 @@ class Block{
protected BlockTypeInfo $typeInfo;
protected Position $position;
/** @var AxisAlignedBB[]|null */
/**
* @var AxisAlignedBB[]|null
* @phpstan-var list<AxisAlignedBB>|null
*/
protected ?array $collisionBoxes = null;
private int $requiredBlockItemStateDataBits;
@ -362,6 +365,8 @@ class Block{
*
* 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).
*
* @phpstan-impure
*/
public function readStateFromWorld() : Block{
return $this;
@ -419,7 +424,7 @@ class Block{
* Returns whether this block can replace the given block in the given placement conditions.
* This is used to allow slabs of the same type to combine into double slabs.
*/
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, Facing $face, bool $isClickedBlock) : bool{
return $blockReplace->canBeReplaced();
}
@ -431,13 +436,13 @@ class Block{
* @param Item $item Item used to place the block
* @param Block $blockReplace Block expected to be replaced
* @param Block $blockClicked Block that was clicked using the item
* @param int $face Face of the clicked block which was clicked
* @param Facing $face Face of the clicked block which was clicked
* @param Vector3 $clickVector Exact position inside the clicked block where the click occurred, relative to the block's position
* @param Player|null $player Player who placed the block, or null if it was not a player
*
* @return bool whether the placement should go ahead
*/
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
$tx->addBlock($blockReplace->position, $this);
return true;
}
@ -519,7 +524,7 @@ class Block{
* @param Vector3 $clickVector Exact position where the click occurred, relative to the block's integer position
* @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, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
return false;
}
@ -528,7 +533,7 @@ class Block{
*
* @return bool if an action took place, prevents starting to break the block if true.
*/
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
public function onAttack(Item $item, Facing $face, ?Player $player = null) : bool{
return false;
}
@ -765,10 +770,10 @@ class Block{
*
* @return Block
*/
public function getSide(int $side, int $step = 1){
public function getSide(Facing $side, int $step = 1){
$position = $this->position;
if($position->isValid()){
[$dx, $dy, $dz] = Facing::OFFSET[$side] ?? [0, 0, 0];
[$dx, $dy, $dz] = Facing::OFFSET[$side->value] ?? [0, 0, 0];
return $position->getWorld()->getBlockAt(
$position->x + ($dx * $step),
$position->y + ($dy * $step),
@ -788,7 +793,7 @@ class Block{
public function getHorizontalSides() : \Generator{
$world = $this->position->getWorld();
foreach(Facing::HORIZONTAL as $facing){
[$dx, $dy, $dz] = Facing::OFFSET[$facing];
[$dx, $dy, $dz] = Facing::OFFSET[$facing->value];
//TODO: yield Facing as the key?
yield $world->getBlockAt(
$this->position->x + $dx,
@ -905,14 +910,16 @@ class Block{
* - anti-cheat checks in plugins
*
* @return AxisAlignedBB[]
* @phpstan-return list<AxisAlignedBB>
*/
final public function getCollisionBoxes() : array{
if($this->collisionBoxes === null){
$this->collisionBoxes = $this->recalculateCollisionBoxes();
$collisionBoxes = $this->recalculateCollisionBoxes();
$extraOffset = $this->getModelPositionOffset();
$offset = $extraOffset !== null ? $this->position->addVector($extraOffset) : $this->position;
foreach($this->collisionBoxes as $bb){
$bb->offset($offset->x, $offset->y, $offset->z);
$this->collisionBoxes = [];
foreach($collisionBoxes as $bb){
$this->collisionBoxes[] = $bb->offsetCopy($offset->x, $offset->y, $offset->z);
}
}
@ -929,6 +936,7 @@ class Block{
/**
* @return AxisAlignedBB[]
* @phpstan-return list<AxisAlignedBB>
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()];
@ -938,11 +946,11 @@ class Block{
* Returns the type of support that the block can provide on the given face. This is used to determine whether
* blocks placed on the given face can be supported by this block.
*/
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::FULL;
}
protected function getAdjacentSupportType(int $facing) : SupportType{
protected function getAdjacentSupportType(Facing $facing) : SupportType{
return $this->getSide($facing)->getSupportType(Facing::opposite($facing));
}

View File

@ -73,7 +73,7 @@ class BlockBreakInfo{
return new self(0.0, $toolType, $toolHarvestLevel, 0.0);
}
public static function indestructible(float $blastResistance = 18000000.0) : self{
public static function indestructible(float $blastResistance = 18000003.75) : self{
return new self(-1.0, BlockToolType::NONE, 0, $blastResistance);
}
@ -95,7 +95,7 @@ class BlockBreakInfo{
* Returns whether this block can be instantly broken.
*/
public function breaksInstantly() : bool{
return $this->hardness == 0.0;
return $this->hardness === 0.0;
}
/**
@ -154,7 +154,7 @@ class BlockBreakInfo{
$efficiency = $item->getMiningEfficiency(($this->toolType & $item->getBlockToolType()) !== 0);
if($efficiency <= 0){
throw new \InvalidArgumentException(get_class($item) . " has invalid mining efficiency: expected >= 0, got $efficiency");
throw new \InvalidArgumentException(get_class($item) . " must have a positive mining efficiency, but got $efficiency");
}
$base /= $efficiency;

View File

@ -745,8 +745,85 @@ final class BlockTypeIds{
public const PITCHER_PLANT = 10715;
public const PITCHER_CROP = 10716;
public const DOUBLE_PITCHER_CROP = 10717;
public const CAMPFIRE = 10718;
public const SOUL_CAMPFIRE = 10719;
public const TUFF_SLAB = 10720;
public const TUFF_STAIRS = 10721;
public const TUFF_WALL = 10722;
public const CHISELED_TUFF = 10723;
public const TUFF_BRICKS = 10724;
public const TUFF_BRICK_SLAB = 10725;
public const TUFF_BRICK_STAIRS = 10726;
public const TUFF_BRICK_WALL = 10727;
public const CHISELED_TUFF_BRICKS = 10728;
public const POLISHED_TUFF = 10729;
public const POLISHED_TUFF_SLAB = 10730;
public const POLISHED_TUFF_STAIRS = 10731;
public const POLISHED_TUFF_WALL = 10732;
public const COPPER_BULB = 10733;
public const COPPER_DOOR = 10734;
public const COPPER_TRAPDOOR = 10735;
public const CHISELED_COPPER = 10736;
public const COPPER_GRATE = 10737;
public const PALE_OAK_BUTTON = 10738;
public const PALE_OAK_DOOR = 10739;
public const PALE_OAK_FENCE = 10740;
public const PALE_OAK_FENCE_GATE = 10741;
public const PALE_OAK_LEAVES = 10742;
public const PALE_OAK_LOG = 10743;
public const PALE_OAK_PLANKS = 10744;
public const PALE_OAK_PRESSURE_PLATE = 10745;
public const PALE_OAK_SIGN = 10746;
public const PALE_OAK_SLAB = 10747;
public const PALE_OAK_STAIRS = 10748;
public const PALE_OAK_TRAPDOOR = 10749;
public const PALE_OAK_WALL_SIGN = 10750;
public const PALE_OAK_WOOD = 10751;
public const RESIN = 10752;
public const RESIN_BRICK_SLAB = 10753;
public const RESIN_BRICK_STAIRS = 10754;
public const RESIN_BRICK_WALL = 10755;
public const RESIN_BRICKS = 10756;
public const RESIN_CLUMP = 10757;
public const CHISELED_RESIN_BRICKS = 10758;
public const RESPAWN_ANCHOR = 10759;
public const OMINOUS_BANNER = 10760;
public const OMINOUS_WALL_BANNER = 10761;
public const ACACIA_CEILING_CENTER_HANGING_SIGN = 10762;
public const ACACIA_CEILING_EDGES_HANGING_SIGN = 10763;
public const ACACIA_WALL_HANGING_SIGN = 10764;
public const BIRCH_CEILING_CENTER_HANGING_SIGN = 10765;
public const BIRCH_CEILING_EDGES_HANGING_SIGN = 10766;
public const BIRCH_WALL_HANGING_SIGN = 10767;
public const CHERRY_CEILING_CENTER_HANGING_SIGN = 10768;
public const CHERRY_CEILING_EDGES_HANGING_SIGN = 10769;
public const CHERRY_WALL_HANGING_SIGN = 10770;
public const CRIMSON_CEILING_CENTER_HANGING_SIGN = 10771;
public const CRIMSON_CEILING_EDGES_HANGING_SIGN = 10772;
public const CRIMSON_WALL_HANGING_SIGN = 10773;
public const DARK_OAK_CEILING_CENTER_HANGING_SIGN = 10774;
public const DARK_OAK_CEILING_EDGES_HANGING_SIGN = 10775;
public const DARK_OAK_WALL_HANGING_SIGN = 10776;
public const JUNGLE_CEILING_CENTER_HANGING_SIGN = 10777;
public const JUNGLE_CEILING_EDGES_HANGING_SIGN = 10778;
public const JUNGLE_WALL_HANGING_SIGN = 10779;
public const MANGROVE_CEILING_CENTER_HANGING_SIGN = 10780;
public const MANGROVE_CEILING_EDGES_HANGING_SIGN = 10781;
public const MANGROVE_WALL_HANGING_SIGN = 10782;
public const OAK_CEILING_CENTER_HANGING_SIGN = 10783;
public const OAK_CEILING_EDGES_HANGING_SIGN = 10784;
public const OAK_WALL_HANGING_SIGN = 10785;
public const PALE_OAK_CEILING_CENTER_HANGING_SIGN = 10786;
public const PALE_OAK_CEILING_EDGES_HANGING_SIGN = 10787;
public const PALE_OAK_WALL_HANGING_SIGN = 10788;
public const SPRUCE_CEILING_CENTER_HANGING_SIGN = 10789;
public const SPRUCE_CEILING_EDGES_HANGING_SIGN = 10790;
public const SPRUCE_WALL_HANGING_SIGN = 10791;
public const WARPED_CEILING_CENTER_HANGING_SIGN = 10792;
public const WARPED_CEILING_EDGES_HANGING_SIGN = 10793;
public const WARPED_WALL_HANGING_SIGN = 10794;
public const FIRST_UNUSED_BLOCK_ID = 10718;
public const FIRST_UNUSED_BLOCK_ID = 10795;
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;

View File

@ -31,4 +31,5 @@ final class BlockTypeTags{
public const SAND = self::PREFIX . "sand";
public const POTTABLE_PLANTS = self::PREFIX . "pottable";
public const FIRE = self::PREFIX . "fire";
public const HANGING_SIGN = self::PREFIX . "hanging_sign";
}

View File

@ -27,10 +27,6 @@ use pocketmine\item\Item;
class BlueIce extends Opaque{
public function getLightLevel() : int{
return 1;
}
public function getFrictionFactor() : float{
return 0.99;
}
@ -38,4 +34,8 @@ class BlueIce extends Opaque{
public function getDropsForCompatibleTool(Item $item) : array{
return [];
}
public function isAffectedBySilkTouch() : bool{
return true;
}
}

View File

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

View File

@ -23,20 +23,24 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\window\BrewingStandInventoryWindow;
use pocketmine\block\tile\BrewingStand as TileBrewingStand;
use pocketmine\block\utils\BrewingStandSlot;
use pocketmine\block\utils\Container;
use pocketmine\block\utils\ContainerTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\inventory\Inventory;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\Position;
use function array_key_exists;
use function spl_object_id;
class BrewingStand extends Transparent{
class BrewingStand extends Transparent implements Container{
use ContainerTrait;
/**
* @var BrewingStandSlot[]
@ -51,17 +55,17 @@ class BrewingStand extends Transparent{
protected function recalculateCollisionBoxes() : array{
return [
//bottom slab part - in PC this is also inset on X/Z by 1/16, but Bedrock sucks
AxisAlignedBB::one()->trim(Facing::UP, 7 / 8),
AxisAlignedBB::one()->trimmedCopy(Facing::UP, 7 / 8),
//center post
AxisAlignedBB::one()
->squash(Axis::X, 7 / 16)
->squash(Axis::Z, 7 / 16)
->trim(Facing::UP, 1 / 8)
->squashedCopy(Axis::X, 7 / 16)
->squashedCopy(Axis::Z, 7 / 16)
->trimmedCopy(Facing::UP, 1 / 8)
];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -95,15 +99,8 @@ class BrewingStand extends Transparent{
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player instanceof Player){
$stand = $this->position->getWorld()->getTile($this->position);
if($stand instanceof TileBrewingStand && $stand->canOpenWith($item->getCustomName())){
$player->setCurrentWindow($stand->getInventory());
}
}
return true;
protected function newMenu(Player $player, Inventory $inventory, Position $position) : BrewingStandInventoryWindow{
return new BrewingStandInventoryWindow($player, $inventory, $position);
}
public function onScheduledUpdate() : void{

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\AnyFacingTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
@ -33,13 +34,13 @@ use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\RedstonePowerOffSound;
use pocketmine\world\sound\RedstonePowerOnSound;
abstract class Button extends Flowable{
abstract class Button extends Flowable implements AnyFacing{
use AnyFacingTrait;
protected bool $pressed = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->facing($this->facing);
$w->enum($this->facing);
$w->bool($this->pressed);
}
@ -51,7 +52,7 @@ abstract class Button extends Flowable{
return $this;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->canBeSupportedAt($blockReplace, $face)){
$this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
@ -61,7 +62,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, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if(!$this->pressed){
$this->pressed = true;
$world = $this->position->getWorld();
@ -88,7 +89,7 @@ abstract class Button extends Flowable{
}
}
private function canBeSupportedAt(Block $block, int $face) : bool{
private function canBeSupportedAt(Block $block, Facing $face) : bool{
return $block->getAdjacentSupportType(Facing::opposite($face))->hasCenterSupport();
}
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\StaticSupportTrait;
@ -33,7 +34,7 @@ use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
class Cactus extends Transparent{
class Cactus extends Transparent implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
@ -43,15 +44,12 @@ class Cactus extends Transparent{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
$shrinkSize = 1 / 16;
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];
return [AxisAlignedBB::one()->contractedCopy($shrinkSize, 0, $shrinkSize)->trimmedCopy(Facing::UP, $shrinkSize)];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}

View File

@ -40,15 +40,12 @@ class Cake extends BaseCake{
$w->boundedIntAuto(0, self::MAX_BITES, $this->bites);
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()
->contract(1 / 16, 0, 1 / 16)
->trim(Facing::UP, 0.5)
->trim(Facing::WEST, $this->bites / 8)
->contractedCopy(1 / 16, 0, 1 / 16)
->trimmedCopy(Facing::UP, 0.5)
->trimmedCopy(Facing::WEST, $this->bites / 8)
];
}
@ -63,7 +60,7 @@ class Cake extends BaseCake{
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($this->bites === 0 && $item instanceof ItemBlock){
$block = $item->getBlock();
$resultBlock = null;

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CandleTrait;
use pocketmine\block\utils\Lightable;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
@ -31,19 +32,16 @@ use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
class CakeWithCandle extends BaseCake{
class CakeWithCandle extends BaseCake implements Lightable{
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
->contractedCopy(1 / 16, 0, 1 / 16)
->trimmedCopy(Facing::UP, 0.5) //TODO: not sure if the candle affects height
];
}
@ -51,7 +49,10 @@ class CakeWithCandle extends BaseCake{
return VanillaBlocks::CANDLE();
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($this->lit && $face !== Facing::UP){
return true;
}
if($this->onInteractCandle($item, $face, $clickVector, $player, $returnedItems)){
return true;
}

View File

@ -23,10 +23,11 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\DyeColor;
class CakeWithDyedCandle extends CakeWithCandle{
class CakeWithDyedCandle extends CakeWithCandle implements Colored{
use ColoredTrait;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo){

290
src/block/Campfire.php Normal file
View File

@ -0,0 +1,290 @@
<?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\Campfire as TileCampfire;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\LightableTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\crafting\FurnaceRecipe;
use pocketmine\crafting\FurnaceType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\entity\Living;
use pocketmine\entity\projectile\Projectile;
use pocketmine\entity\projectile\SplashPotion;
use pocketmine\event\block\CampfireCookEvent;
use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\inventory\Inventory;
use pocketmine\item\Durable;
use pocketmine\item\enchantment\VanillaEnchantments;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\item\PotionType;
use pocketmine\item\Shovel;
use pocketmine\item\VanillaItems;
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\sound\BlazeShootSound;
use pocketmine\world\sound\FireExtinguishSound;
use pocketmine\world\sound\FlintSteelSound;
use pocketmine\world\sound\ItemFrameAddItemSound;
use function count;
use function min;
use function mt_rand;
class Campfire extends Transparent implements Lightable, HorizontalFacing{
use HorizontalFacingTrait{
HorizontalFacingTrait::describeBlockOnlyState as encodeFacingState;
}
use LightableTrait{
LightableTrait::describeBlockOnlyState as encodeLitState;
}
private const UPDATE_INTERVAL_TICKS = 10;
/**
* @deprecated This was added by mistake. It can't be relied on as the inventory won't be initialized if this block
* has never been set in the world.
*/
protected ?Inventory $inventory = null;
/**
* @var int[] slot => ticks
* @phpstan-var array<int, int>
*/
protected array $cookingTimes = [];
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$this->encodeFacingState($w);
$this->encodeLitState($w);
}
public function readStateFromWorld() : Block{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileCampfire){
$this->inventory = $tile->getInventory();
$this->cookingTimes = $tile->getCookingTimes();
}else{
$this->inventory = null;
$this->cookingTimes = [];
}
return $this;
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileCampfire){
$tile->setCookingTimes($this->cookingTimes);
}
}
public function hasEntityCollision() : bool{
return true;
}
public function getLightLevel() : int{
return $this->lit ? 15 : 0;
}
public function isAffectedBySilkTouch() : bool{
return true;
}
public function getDropsForCompatibleTool(Item $item) : array{
return [
VanillaItems::CHARCOAL()->setCount(2)
];
}
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 9 / 16)];
}
/**
* @deprecated This was added by mistake. It can't be relied on as the inventory won't be initialized if this block
* has never been set in the world.
*/
public function getInventory() : ?Inventory{
return $this->inventory;
}
protected function getFurnaceType() : FurnaceType{
return FurnaceType::CAMPFIRE;
}
protected function getEntityCollisionDamage() : int{
return 1;
}
/**
* Sets the number of ticks during the item in the given slot has been cooked.
*/
public function setCookingTime(int $slot, int $time) : void{
if($slot < 0 || $slot > 3){
throw new \InvalidArgumentException("Slot must be in range 0-3");
}
if($time < 0 || $time > $this->getFurnaceType()->getCookDurationTicks()){
throw new \InvalidArgumentException("CookingTime must be in range 0-" . $this->getFurnaceType()->getCookDurationTicks());
}
$this->cookingTimes[$slot] = $time;
}
/**
* Returns the number of ticks during the item in the given slot has been cooked.
*/
public function getCookingTime(int $slot) : int{
return $this->cookingTimes[$slot] ?? 0;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($this->getSide(Facing::DOWN) instanceof Campfire){
return false;
}
if($player !== null){
$this->facing = HorizontalFacingOption::fromFacing($player->getHorizontalFacing());
}
$this->lit = true;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if(!$this->lit){
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE){
$item->pop();
$this->ignite();
$this->position->getWorld()->addSound($this->position, new BlazeShootSound());
return true;
}elseif($item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
if($item instanceof Durable){
$item->applyDamage(1);
}
$this->ignite();
return true;
}
}elseif($item instanceof Shovel){
$item->applyDamage(1);
$this->extinguish();
return true;
}
$inventory = $this->inventory;
if($inventory !== null && $this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($this->getFurnaceType())->match($item) !== null){
$ingredient = clone $item;
$ingredient->setCount(1);
if(count($inventory->addItem($ingredient)) === 0){
$item->pop();
$this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
return true;
}
}
return false;
}
public function onNearbyBlockChange() : void{
if($this->lit && $this->getSide(Facing::UP)->getTypeId() === BlockTypeIds::WATER){
$this->extinguish();
//TODO: Waterlogging
}
}
public function onEntityInside(Entity $entity) : bool{
if(!$this->lit){
if($entity->isOnFire()){
$this->ignite();
return false;
}
}elseif($entity instanceof Living){
$entity->attack(new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, $this->getEntityCollisionDamage()));
}
return true;
}
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
if($this->lit && $projectile instanceof SplashPotion && $projectile->getPotionType() === PotionType::WATER){
$this->extinguish();
}
}
public function onScheduledUpdate() : void{
if($this->lit && ($inventory = $this->inventory) !== null){
$items = $inventory->getContents();
$furnaceType = $this->getFurnaceType();
$maxCookDuration = $furnaceType->getCookDurationTicks();
foreach($items as $slot => $item){
$this->setCookingTime($slot, min($maxCookDuration, $this->getCookingTime($slot) + self::UPDATE_INTERVAL_TICKS));
if($this->getCookingTime($slot) >= $maxCookDuration){
$result =
($recipe = $this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($furnaceType)->match($item)) instanceof FurnaceRecipe ?
$recipe->getResult() :
VanillaItems::AIR();
$ev = new CampfireCookEvent($this, $slot, $item, $result);
$ev->call();
if ($ev->isCancelled()){
continue;
}
$inventory->setItem($slot, VanillaItems::AIR());
$this->setCookingTime($slot, 0);
$this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $ev->getResult());
}
}
if(count($items) > 0){
$this->position->getWorld()->setBlock($this->position, $this);
}
if(mt_rand(1, 6) === 1){
$this->position->getWorld()->addSound($this->position, $furnaceType->getCookSound());
}
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS);
}
}
private function extinguish() : void{
$this->position->getWorld()->addSound($this->position, new FireExtinguishSound());
$this->position->getWorld()->setBlock($this->position, $this->setLit(false));
}
private function ignite() : void{
$this->position->getWorld()->addSound($this->position, new FlintSteelSound());
$this->position->getWorld()->setBlock($this->position, $this->setLit(true));
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS);
}
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\CandleTrait;
use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
@ -35,7 +36,7 @@ use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
class Candle extends Transparent{
class Candle extends Transparent implements Lightable{
use CandleTrait {
describeBlockOnlyState as encodeLitState;
getLightLevel as getBaseLightLevel;
@ -70,27 +71,27 @@ class Candle extends Transparent{
return [
(match($this->count){
1 => AxisAlignedBB::one()
->squash(Axis::X, 7 / 16)
->squash(Axis::Z, 7 / 16),
->squashedCopy(Axis::X, 7 / 16)
->squashedCopy(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),
->squashedCopy(Axis::X, 5 / 16)
->trimmedCopy(Facing::NORTH, 7 / 16) //0.3 thick on the Z axis
->trimmedCopy(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),
->trimmedCopy(Facing::WEST, 5 / 16)
->trimmedCopy(Facing::EAST, 6 / 16)
->trimmedCopy(Facing::NORTH, 6 / 16)
->trimmedCopy(Facing::SOUTH, 5 / 16),
4 => AxisAlignedBB::one()
->squash(Axis::X, 5 / 16)
->trim(Facing::NORTH, 5 / 16)
->trim(Facing::SOUTH, 6 / 16),
->squashedCopy(Axis::X, 5 / 16)
->trimmedCopy(Facing::NORTH, 5 / 16)
->trimmedCopy(Facing::SOUTH, 6 / 16),
default => throw new AssumptionFailedError("Unreachable")
})->trim(Facing::UP, 10 / 16)
})->trimmedCopy(Facing::UP, 10 / 16)
];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -98,12 +99,12 @@ class Candle extends Transparent{
return $block instanceof Candle && $block->hasSameTypeId($this) ? $block : null;
}
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, Facing $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{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$blockReplace->getAdjacentSupportType(Facing::DOWN)->hasCenterSupport()){
return false;
}

View File

@ -23,12 +23,13 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\Colored;
use pocketmine\block\utils\ColoredTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
class Carpet extends Flowable{
class Carpet extends Flowable implements Colored{
use ColoredTrait;
use StaticSupportTrait;
@ -36,11 +37,8 @@ class Carpet extends Flowable{
return true;
}
/**
* @return AxisAlignedBB[]
*/
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 15 / 16)];
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 15 / 16)];
}
private function canBeSupportedAt(Block $block) : bool{

View File

@ -23,19 +23,17 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\CartographyTableInventory;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\block\inventory\window\CartographyTableInventoryWindow;
use pocketmine\block\utils\MenuAccessor;
use pocketmine\block\utils\MenuAccessorTrait;
use pocketmine\player\Player;
use pocketmine\world\Position;
final class CartographyTable extends Opaque{
final class CartographyTable extends Opaque implements MenuAccessor{
use MenuAccessorTrait;
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;
protected function newMenu(Player $player, Position $position) : CartographyTableInventoryWindow{
return new CartographyTableInventoryWindow($player, $position);
}
public function getFuelTime() : int{

View File

@ -24,7 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacing;
class CarvedPumpkin extends Opaque{
class CarvedPumpkin extends Opaque implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
}

View File

@ -51,16 +51,16 @@ final class Cauldron extends Transparent{
protected function recalculateCollisionBoxes() : array{
$result = [
AxisAlignedBB::one()->trim(Facing::UP, 11 / 16) //bottom of the cauldron
AxisAlignedBB::one()->trimmedCopy(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);
$result[] = AxisAlignedBB::one()->trimmedCopy($f, 14 / 16);
}
return $result;
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return $facing === Facing::UP ? SupportType::EDGE : SupportType::NONE;
}
@ -75,7 +75,7 @@ final class Cauldron extends Transparent{
$returnedItems[] = $returnedItem;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $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){

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\StaticSupportTrait;
@ -39,7 +40,7 @@ use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\GlowBerriesPickSound;
use function mt_rand;
class CaveVines extends Flowable{
class CaveVines extends Flowable implements Ageable{
use AgeableTrait;
use StaticSupportTrait;
@ -83,12 +84,12 @@ class CaveVines extends Flowable{
return $supportBlock->getSupportType(Facing::DOWN) === SupportType::FULL || $supportBlock->hasSameTypeId($this);
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
$this->age = mt_rand(0, self::MAX_AGE);
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, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($this->berries){
$this->position->getWorld()->dropItem($this->position, $this->asItem());
$this->position->getWorld()->addSound($this->position, new GlowBerriesPickSound());
@ -158,7 +159,7 @@ class CaveVines extends Flowable{
return VanillaItems::GLOW_BERRIES();
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -0,0 +1,65 @@
<?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\SignLikeRotation;
use pocketmine\block\utils\SignLikeRotationTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class CeilingCenterHangingSign extends BaseSign implements SignLikeRotation{
use SignLikeRotationTrait;
use StaticSupportTrait;
protected function getSupportingFace() : Facing{
return Facing::UP;
}
//TODO: duplicated code :(
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::DOWN){
return false;
}
if($player !== null){
$this->rotation = self::getRotationFromYaw($player->getLocation()->getYaw());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
private function canBeSupportedAt(Block $block) : bool{
$supportBlock = $block->getSide(Facing::UP);
return
$supportBlock->getSupportType(Facing::DOWN)->hasCenterSupport() ||
$supportBlock->hasTypeTag(BlockTypeTags::HANGING_SIGN);
}
protected function getFacingDegrees() : float{
return $this->rotation * 22.5;
}
}

View File

@ -0,0 +1,78 @@
<?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\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class CeilingEdgesHangingSign extends BaseSign implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : Facing{
return Facing::UP;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::DOWN){
return false;
}
if($player !== null){
$this->facing = HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing()));
}
if(!$this->canBeSupportedAt($blockReplace)){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position);
}
}
private function canBeSupportedAt(Block $block) : bool{
$supportBlock = $block->getSide(Facing::UP);
return
$supportBlock->getSupportType(Facing::DOWN) === SupportType::FULL ||
(($supportBlock instanceof WallHangingSign || $supportBlock instanceof CeilingEdgesHangingSign) && Facing::axis($supportBlock->getFacing()->toFacing()) === Facing::axis($this->facing->toFacing()));
}
protected function getFacingDegrees() : float{
return match($this->facing){
HorizontalFacingOption::SOUTH => 0,
HorizontalFacingOption::WEST => 90,
HorizontalFacingOption::NORTH => 180,
HorizontalFacingOption::EAST => 270,
};
}
}

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