Compare commits

...

240 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
12f404b20d Merge branch 'minor-next' into major-next 2025-08-08 01:09:17 +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
e630fc2dd6 Merge remote-tracking branch 'origin/minor-next' into major-next 2025-07-31 13:00:12 +01: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
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
c02feba056 Merge remote-tracking branch 'origin/minor-next' into major-next 2025-07-10 01:58:34 +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
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
afcd6b4e12 Merge remote-tracking branch 'origin/minor-next' into major-next 2025-06-25 01:07:16 +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
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
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
6340d12881 Merge branch 'minor-next' into major-next 2025-06-18 19:56:54 +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
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
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
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
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
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
18b6b1742c Rename PlayerExhaustEvent to EntityExhaustEvent (#6674)
Removed the `getPlayer` function
2025-05-25 10:04:33 +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
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
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
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
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
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
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
7847524df6 Merge branch 'minor-next' into major-next 2025-05-08 02:28:09 +01:00
1d26b21fe0 Merge branch 'minor-next' into major-next 2025-05-04 17:21:24 +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
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
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
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
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
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
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
0bbe56beb4 Merge branch 'minor-next' into major-next 2025-04-06 20:01:23 +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
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
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
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
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
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
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
d3f40b7b0c Merge branch 'minor-next' into major-next 2025-03-15 20:37:37 +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
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
95a324755b Merge branch 'minor-next' into major-next 2025-03-10 01:31:34 +00:00
1d13054608 Merge branch 'minor-next' into major-next 2025-03-09 01:18:55 +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
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
5d24d8de0b Merge branch 'minor-next' into major-next 2025-02-26 17:32:14 +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
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
c637d852e2 Merge branch 'minor-next' into major-next 2025-02-18 01:26:08 +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
694aa17cc9 Merge branch 'minor-next' into major-next 2025-02-16 23:18:56 +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
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
e9df0baffb Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into major-next 2025-02-05 01:37:00 +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
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
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
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
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
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
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
02ac512b4e Merge branch 'minor-next' into major-next 2025-01-08 15:25:12 +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
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
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
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
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
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
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
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
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
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
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
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
7a2427ace2 Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into major-next 2024-12-14 02:40:03 +00: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
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
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
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
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
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
5e9dbace90 Merge branch 'minor-next' into major-next 2024-12-05 10:13:24 +00:00
205aabe11f Fixed merge error 2024-12-04 15:27:09 +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
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
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
0dae786a21 feat(Server): add a setter for maxPlayers (#6261) 2024-12-01 20:24:50 +00:00
02d181d0c8 Merge branch 'minor-next' into major-next 2024-12-01 15:02:36 +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
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
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
c3c917bb05 Merge branch 'minor-next' into major-next 2024-11-27 17:56:45 +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
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
15eaf67a0c Merge branch 'minor-next' into major-next 2024-11-25 14:36:25 +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
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
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
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
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
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
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
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
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
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
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
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
ab5176baf9 Merge branch 'minor-next' into major-next 2024-11-14 23:16:44 +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
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
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
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
85de28d6c3 Merge branch 'minor-next' into major-next 2024-11-03 14:02:06 +00: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
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
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
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
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
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
603527c6e8 Merge branch 'minor-next' of github.com:pmmp/PocketMine-MP into major-next 2024-08-13 13:39:00 +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
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
409 changed files with 4218 additions and 6806 deletions

View File

@ -20,7 +20,7 @@ jobs:
- name: Setup PHP and tools
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

View File

@ -51,7 +51,7 @@ jobs:
- name: Setup PHP
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

View File

@ -18,7 +18,7 @@ on:
- "*"
env:
PHP_VERSION: "8.2"
PHP_VERSION: "8.3"
jobs:
skip:

View File

@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php: ["8.1", "8.2", "8.3", "8.4"]
php: ["8.3", "8.4"]
uses: ./.github/workflows/main-php-matrix.yml
with:

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,7 @@ $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')

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",
@ -38,24 +38,24 @@
"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.25.0",
"pocketmine/log": "^0.4.0",
"pocketmine/math": "~1.0.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.9.0",
"symfony/filesystem": "~6.4.0"
"symfony/filesystem": "~7.3.0"
},
"require-dev": {
"phpstan/phpstan": "2.1.17",
"phpstan/phpstan-phpunit": "^2.0.0",
"phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^10.5.24"
"phpunit/phpunit": "^12.2.1"
},
"replace": {
"symfony/polyfill-ctype": "*",
@ -77,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"

723
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@ 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
@ -12,9 +11,7 @@ includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
rules:
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
- pocketmine\phpstan\rules\DisallowDynamicNewRule
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
- pocketmine\phpstan\rules\ExplodeLimitRule
- pocketmine\phpstan\rules\UnsafeForeachRule

View File

@ -123,13 +123,6 @@ class MemoryManager{
return $this->globalMemoryLimit;
}
/**
* @deprecated
*/
public function canUseChunkCache() : bool{
return !$this->lowMemory;
}
/**
* Returns the allowed chunk radius based on the current memory usage.
*/
@ -236,13 +229,4 @@ class MemoryManager{
}
}
}
/**
* Static memory dumper accessible from any thread.
* @deprecated
* @see MemoryDump
*/
public static function dumpMemory(mixed $startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
MemoryDump::dumpMemory($startingObject, $outputFolder, $maxNesting, $maxStringSize, $logger);
}
}

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

View File

@ -80,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;
@ -346,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.
@ -1029,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(

View File

@ -82,22 +82,22 @@ final class AmethystCluster extends Transparent implements AnyFacing{
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,11 +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;
@ -38,13 +41,15 @@ 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 round;
class Anvil extends Transparent implements Fallable, HorizontalFacing{
class Anvil extends Transparent implements Fallable, HorizontalFacing, MenuAccessor{
use FallableTrait;
use HorizontalFacingTrait;
use MenuAccessorTrait;
public const UNDAMAGED = 0;
public const SLIGHTLY_DAMAGED = 1;
@ -57,7 +62,7 @@ class Anvil extends Transparent implements Fallable, HorizontalFacing{
}
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
}
public function getDamage() : int{ return $this->damage; }
@ -72,24 +77,20 @@ class Anvil extends Transparent implements Fallable, HorizontalFacing{
}
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);
}

View File

@ -90,10 +90,10 @@ class Bamboo extends Transparent{
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;
}
@ -138,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,24 +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 implements AnyFacing{
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);
}
@ -54,7 +63,7 @@ class Barrel extends Opaque implements AnyFacing{
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;
@ -74,22 +83,23 @@ class Barrel extends Opaque implements AnyFacing{
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

@ -31,6 +31,7 @@ use pocketmine\block\utils\SupportType;
use pocketmine\item\Banner as ItemBanner;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
@ -112,7 +113,7 @@ abstract class BaseBanner extends Transparent implements Colored{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -120,7 +121,7 @@ abstract class BaseBanner extends Transparent implements Colored{
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;
}
@ -132,7 +133,7 @@ abstract class BaseBanner extends Transparent implements Colored{
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

@ -24,6 +24,7 @@ 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;
@ -57,13 +58,13 @@ abstract class BaseBigDripleaf extends Transparent implements HorizontalFacing{
}
}
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;
@ -72,7 +73,7 @@ abstract class BaseBigDripleaf extends Transparent implements HorizontalFacing{
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;
@ -131,7 +132,7 @@ abstract class BaseBigDripleaf extends Transparent implements HorizontalFacing{
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

@ -28,6 +28,7 @@ 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 implements CoralMaterial{
@ -72,7 +73,7 @@ abstract class BaseCoral extends Transparent implements CoralMaterial{
protected function recalculateCollisionBoxes() : array{ return []; }
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -28,6 +28,7 @@ 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;
@ -60,7 +61,7 @@ abstract class BaseOminousBanner extends Transparent{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -68,7 +69,7 @@ abstract class BaseOminousBanner 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;
}
@ -76,7 +77,7 @@ abstract class BaseOminousBanner 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

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

@ -35,20 +35,26 @@ use pocketmine\event\block\SignChangeEvent;
use pocketmine\item\Dye;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
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 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 implements WoodMaterial{
$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 implements WoodMaterial{
$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 implements WoodMaterial{
$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);
}
@ -99,11 +108,11 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
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){
@ -111,7 +120,7 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
}
}
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();
}
@ -127,11 +136,11 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
}
}
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;
@ -140,8 +149,9 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
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;
}
@ -160,7 +170,7 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
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;
}
@ -168,6 +178,8 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
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,
@ -176,40 +188,82 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
};
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.
*/
@ -234,13 +288,21 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
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);
@ -248,15 +310,16 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
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

@ -28,6 +28,7 @@ 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;
@ -51,7 +52,7 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
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);
}
@ -79,10 +80,10 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
}
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;
}
@ -106,8 +107,8 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
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{
@ -119,7 +120,7 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
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();
@ -172,9 +173,11 @@ class Bed extends Transparent implements Colored, HorizontalFacing{
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

@ -26,6 +26,7 @@ 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;
@ -46,32 +47,33 @@ final class Bell extends Transparent implements HorizontalFacing{
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;
}
@ -83,23 +85,23 @@ final class Bell extends Transparent implements HorizontalFacing{
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 :
@ -113,8 +115,8 @@ final class Bell extends Transparent implements HorizontalFacing{
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);
@ -123,7 +125,7 @@ final class Bell extends Transparent implements HorizontalFacing{
}
}
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)){
@ -142,7 +144,7 @@ final class Bell extends Transparent implements HorizontalFacing{
}
}
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);
@ -155,11 +157,11 @@ final class Bell extends Transparent implements HorizontalFacing{
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

@ -424,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();
}
@ -436,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;
}
@ -524,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;
}
@ -533,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;
}
@ -770,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),
@ -793,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,
@ -914,11 +914,12 @@ class Block{
*/
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);
}
}
@ -945,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

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

@ -40,7 +40,7 @@ abstract class Button extends Flowable implements AnyFacing{
protected bool $pressed = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->facing($this->facing);
$w->enum($this->facing);
$w->bool($this->pressed);
}
@ -52,7 +52,7 @@ abstract class Button extends Flowable implements AnyFacing{
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);
@ -62,7 +62,7 @@ abstract class Button extends Flowable implements AnyFacing{
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();
@ -89,7 +89,7 @@ abstract class Button extends Flowable implements AnyFacing{
}
}
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

@ -46,10 +46,10 @@ class Cactus extends Transparent implements Ageable{
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

@ -43,9 +43,9 @@ class Cake extends BaseCake{
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)
];
}
@ -60,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

@ -40,8 +40,8 @@ class CakeWithCandle extends BaseCake implements Lightable{
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
];
}
@ -49,7 +49,7 @@ class CakeWithCandle extends BaseCake implements Lightable{
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;
}

View File

@ -23,9 +23,9 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\CampfireInventory;
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;
@ -40,6 +40,7 @@ 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;
@ -75,7 +76,7 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
* @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 CampfireInventory $inventory;
protected ?Inventory $inventory = null;
/**
* @var int[] slot => ticks
@ -95,7 +96,8 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
$this->inventory = $tile->getInventory();
$this->cookingTimes = $tile->getCookingTimes();
}else{
$this->inventory = new CampfireInventory($this->position);
$this->inventory = null;
$this->cookingTimes = [];
}
return $this;
@ -127,19 +129,19 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 9 / 16)];
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() : CampfireInventory{
public function getInventory() : ?Inventory{
return $this->inventory;
}
@ -171,18 +173,18 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
return $this->cookingTimes[$slot] ?? 0;
}
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->getSide(Facing::DOWN) instanceof Campfire){
return false;
}
if($player !== null){
$this->facing = $player->getHorizontalFacing();
$this->facing = HorizontalFacingOption::fromFacing($player->getHorizontalFacing());
}
$this->lit = true;
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->lit){
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE){
$item->pop();
@ -202,10 +204,11 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
return true;
}
if($this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($this->getFurnaceType())->match($item) !== null){
$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($this->inventory->addItem($ingredient)) === 0){
if(count($inventory->addItem($ingredient)) === 0){
$item->pop();
$this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
return true;
@ -240,8 +243,8 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
}
public function onScheduledUpdate() : void{
if($this->lit){
$items = $this->inventory->getContents();
if($this->lit && ($inventory = $this->inventory) !== null){
$items = $inventory->getContents();
$furnaceType = $this->getFurnaceType();
$maxCookDuration = $furnaceType->getCookDurationTicks();
foreach($items as $slot => $item){
@ -259,7 +262,7 @@ class Campfire extends Transparent implements Lightable, HorizontalFacing{
continue;
}
$this->inventory->setItem($slot, VanillaItems::AIR());
$inventory->setItem($slot, VanillaItems::AIR());
$this->setCookingTime($slot, 0);
$this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $ev->getResult());
}

View File

@ -71,27 +71,27 @@ class Candle extends Transparent implements Lightable{
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;
}
@ -99,12 +99,12 @@ class Candle extends Transparent implements Lightable{
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

@ -38,7 +38,7 @@ class Carpet extends Flowable implements Colored{
}
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

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

@ -84,12 +84,12 @@ class CaveVines extends Flowable implements Ageable{
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());
@ -159,7 +159,7 @@ class CaveVines extends Flowable implements Ageable{
return VanillaItems::GLOW_BERRIES();
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -36,12 +36,12 @@ final class CeilingCenterHangingSign extends BaseSign implements SignLikeRotatio
use SignLikeRotationTrait;
use StaticSupportTrait;
protected function getSupportingFace() : int{
protected function getSupportingFace() : Facing{
return Facing::UP;
}
//TODO: duplicated code :(
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($face !== Facing::DOWN){
return false;
}
@ -58,4 +58,8 @@ final class CeilingCenterHangingSign extends BaseSign implements SignLikeRotatio
$supportBlock->getSupportType(Facing::DOWN)->hasCenterSupport() ||
$supportBlock->hasTypeTag(BlockTypeTags::HANGING_SIGN);
}
protected function getFacingDegrees() : float{
return $this->rotation * 22.5;
}
}

View File

@ -24,6 +24,7 @@ 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;
@ -35,16 +36,16 @@ use pocketmine\world\BlockTransaction;
final class CeilingEdgesHangingSign extends BaseSign implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : int{
protected function getSupportingFace() : Facing{
return Facing::UP;
}
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($face !== Facing::DOWN){
return false;
}
if($player !== null){
$this->facing = Facing::opposite($player->getHorizontalFacing());
$this->facing = HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing()));
}
if(!$this->canBeSupportedAt($blockReplace)){
return false;
@ -63,6 +64,15 @@ final class CeilingEdgesHangingSign extends BaseSign implements HorizontalFacing
$supportBlock = $block->getSide(Facing::UP);
return
$supportBlock->getSupportType(Facing::DOWN) === SupportType::FULL ||
(($supportBlock instanceof WallHangingSign || $supportBlock instanceof CeilingEdgesHangingSign) && Facing::axis($supportBlock->getFacing()) === Facing::axis($this->facing));
(($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,
};
}
}

View File

@ -33,7 +33,7 @@ use pocketmine\math\Facing;
final class Chain extends Transparent implements PillarRotation{
use PillarRotationTrait;
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return $this->axis === Axis::Y && Facing::axis($facing) === Axis::Y ? SupportType::CENTER : SupportType::NONE;
}
@ -41,7 +41,7 @@ final class Chain extends Transparent implements PillarRotation{
$bb = AxisAlignedBB::one();
foreach([Axis::Y, Axis::Z, Axis::X] as $axis){
if($axis !== $this->axis){
$bb->squash($axis, 13 / 32);
$bb = $bb->squashedCopy($axis, 13 / 32);
}
}
return [$bb];

View File

@ -26,13 +26,14 @@ namespace pocketmine\block;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
final class ChemistryTable extends Opaque implements HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
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{
//TODO
return false;
}

View File

@ -23,74 +23,203 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\window\BlockInventoryWindow;
use pocketmine\block\inventory\window\DoubleChestInventoryWindow;
use pocketmine\block\tile\Chest as TileChest;
use pocketmine\block\utils\AnimatedContainerLike;
use pocketmine\block\utils\AnimatedContainerLikeTrait;
use pocketmine\block\utils\ChestPairHalf;
use pocketmine\block\utils\Container;
use pocketmine\block\utils\ContainerTrait;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\ChestPairEvent;
use pocketmine\item\Item;
use pocketmine\inventory\CombinedInventoryProxy;
use pocketmine\inventory\Inventory;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\BlockEventPacket;
use pocketmine\network\mcpe\protocol\types\BlockPosition;
use pocketmine\player\InventoryWindow;
use pocketmine\player\Player;
use pocketmine\world\Position;
use pocketmine\world\sound\ChestCloseSound;
use pocketmine\world\sound\ChestOpenSound;
use pocketmine\world\sound\Sound;
use function assert;
class Chest extends Transparent implements HorizontalFacing{
class Chest extends Transparent implements AnimatedContainerLike, Container, HorizontalFacing{
use AnimatedContainerLikeTrait;
use ContainerTrait;
use FacesOppositePlacingPlayerTrait;
protected ?ChestPairHalf $pairHalf = null;
public function getPairHalf() : ?ChestPairHalf{ return $this->pairHalf; }
public function setPairHalf(?ChestPairHalf $pairHalf) : self{
$this->pairHalf = $pairHalf;
return $this;
}
public function readStateFromWorld() : Block{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
$this->pairHalf = null;
if($tile instanceof TileChest && ($pairXZ = $tile->getPairXZ()) !== null){
[$pairX, $pairZ] = $pairXZ;
foreach(ChestPairHalf::cases() as $pairSide){
$pairDirection = $pairSide->getOtherHalfSide($this->facing);
$pairPosition = $this->position->getSide($pairDirection);
if($pairPosition->getFloorX() === $pairX && $pairPosition->getFloorZ() === $pairZ){
$this->pairHalf = $pairSide;
break;
}
}
}
return $this;
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileChest);
//TODO: this should probably use relative coordinates instead of absolute, for portability
if($this->pairHalf !== null){
$pairDirection = $this->pairHalf->getOtherHalfSide($this->facing);
$pairPosition = $this->position->getSide($pairDirection);
$pairXZ = [$pairPosition->getFloorX(), $pairPosition->getFloorZ()];
}else{
$pairXZ = null;
}
$tile->setPairXZ($pairXZ);
}
protected function recalculateCollisionBoxes() : array{
//these are slightly bigger than in PC
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];
$facing = $this->facing->toFacing();
$box = AxisAlignedBB::one()
->squashedCopy(Facing::axis($facing), 0.025)
->trimmedCopy(Facing::UP, 0.05);
$pairSide = $this->pairHalf?->getOtherHalfSide($this->facing);
return [$pairSide !== null ?
$box->trimmedCopy(Facing::opposite($pairSide), 0.025) :
$box->squashedCopy(Facing::axis(Facing::rotateY($facing, true)), 0.025)
];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
private function getPossiblePair(ChestPairHalf $pairSide) : ?Chest{
$pair = $this->getSide($pairSide->getOtherHalfSide($this->facing));
return $pair->hasSameTypeId($this) && $pair instanceof Chest && $pair->getFacing() === $this->facing ? $pair : null;
}
public function getOtherHalf() : ?Chest{
return $this->pairHalf !== null && ($pair = $this->getPossiblePair($this->pairHalf)) !== null && $pair->pairHalf === $this->pairHalf->opposite() ? $pair : null;
}
public function onPostPlace() : void{
//Not sure if this vanilla behaviour is intended, but a chest facing north or west will try to pair on the left
//side first, while a chest facing south or east will try the right side first.
$order = match($this->facing){
HorizontalFacingOption::NORTH, HorizontalFacingOption::WEST => [ChestPairHalf::LEFT, ChestPairHalf::RIGHT],
HorizontalFacingOption::SOUTH, HorizontalFacingOption::EAST => [ChestPairHalf::RIGHT, ChestPairHalf::LEFT]
};
$world = $this->position->getWorld();
$tile = $world->getTile($this->position);
if($tile instanceof TileChest){
foreach([false, true] as $clockwise){
$side = Facing::rotateY($this->facing, $clockwise);
$c = $this->getSide($side);
if($c instanceof Chest && $c->hasSameTypeId($this) && $c->facing === $this->facing){
$pair = $world->getTile($c->position);
if($pair instanceof TileChest && !$pair->isPaired()){
[$left, $right] = $clockwise ? [$c, $this] : [$this, $c];
$ev = new ChestPairEvent($left, $right);
$ev->call();
if(!$ev->isCancelled() && $world->getBlock($this->position)->hasSameTypeId($this) && $world->getBlock($c->position)->hasSameTypeId($c)){
$pair->pairWith($tile);
$tile->pairWith($pair);
break;
}
}
foreach($order as $pairSide){
$possiblePair = $this->getPossiblePair($pairSide);
if($possiblePair !== null && $possiblePair->pairHalf === null){
[$left, $right] = $pairSide === ChestPairHalf::LEFT ? [$this, $possiblePair] : [$possiblePair, $this];
$ev = new ChestPairEvent($left, $right);
if(!$ev->isCancelled() && $world->getBlock($this->position)->isSameState($this) && $world->getBlock($possiblePair->position)->isSameState($possiblePair)){
$world->setBlock($this->position, $this->setPairHalf($pairSide));
$world->setBlock($possiblePair->position, $possiblePair->setPairHalf($pairSide->opposite()));
break;
}
}
}
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player instanceof Player){
public function onNearbyBlockChange() : void{
//TODO: If the pair chunk isn't loaded, a block update of an adjacent block in loaded terrain could cause the
//chest to become unpaired. However, this is not unique to chests (think wall connections). Probably we
//should defer updates in chunks whose neighbours are not loaded?
if($this->pairHalf !== null && $this->getOtherHalf() === null){
$this->position->getWorld()->setBlock($this->position, $this->setPairHalf(null));
}
}
$chest = $this->position->getWorld()->getTile($this->position);
if($chest instanceof TileChest){
if(
!$this->getSide(Facing::UP)->isTransparent() ||
(($pair = $chest->getPair()) !== null && !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) ||
!$chest->canOpenWith($item->getCustomName())
){
return true;
}
$player->setCurrentWindow($chest->getInventory());
public function isOpeningObstructed() : bool{
foreach([$this, $this->getOtherHalf()] as $chest){
if($chest !== null && !$chest->getSide(Facing::UP)->isTransparent()){
return true;
}
}
return false;
}
return true;
protected function getTile() : ?TileChest{
$tile = $this->position->getWorld()->getTile($this->position);
return $tile instanceof TileChest ? $tile : null;
}
public function getInventory() : ?Inventory{
$thisInventory = $this->getTile()?->getRealInventory();
if($thisInventory === null){
return null;
}
$pairInventory = $this->getOtherHalf()?->getTile()?->getRealInventory();
if($pairInventory === null){
return $thisInventory;
}
[$left, $right] = $this->pairHalf === ChestPairHalf::LEFT ? [$thisInventory, $pairInventory] : [$pairInventory, $thisInventory];
return new CombinedInventoryProxy([$left, $right]);
}
protected function newMenu(Player $player, Inventory $inventory, Position $position) : InventoryWindow{
$pair = $this->getOtherHalf();
if($pair === null){
return new BlockInventoryWindow($player, $inventory, $position);
}
[$left, $right] = $this->pairHalf === ChestPairHalf::LEFT ? [$this, $pair] : [$pair, $this];
return new DoubleChestInventoryWindow($player, $inventory, $left->position, $right->position);
}
public function getFuelTime() : int{
return 300;
}
protected function getOpenSound() : Sound{
return new ChestOpenSound();
}
protected function getCloseSound() : Sound{
return new ChestCloseSound();
}
protected function playAnimationVisual(Position $position, bool $isOpen) : void{
//event ID is always 1 for a chest
//TODO: we probably shouldn't be sending a packet directly here, but it doesn't fit anywhere into existing systems
$position->getWorld()->broadcastPacketToViewers($position, BlockEventPacket::create(BlockPosition::fromVector3($position), 1, $isOpen ? 1 : 0));
}
protected function doAnimationEffects(bool $isOpen) : void{
$this->playAnimationVisual($this->position, $isOpen);
$this->playAnimationSound($this->position, $isOpen);
$pair = $this->getOtherHalf();
if($pair !== null){
$this->playAnimationVisual($pair->position, $isOpen);
$this->playAnimationSound($pair->position, $isOpen);
}
}
}

View File

@ -52,7 +52,7 @@ class ChiseledBookshelf extends Opaque implements HorizontalFacing{
private ?ChiseledBookshelfSlot $lastInteractedSlot = null;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->enumSet($this->slots, ChiseledBookshelfSlot::cases());
}
@ -143,8 +143,8 @@ class ChiseledBookshelf extends Opaque implements HorizontalFacing{
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($face !== $this->facing){
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($face !== $this->facing->toFacing()){
return false;
}

View File

@ -106,9 +106,9 @@ final class ChorusFlower extends Flowable implements Ageable{
return [$stemHeight, $endStoneBelow];
}
private function allHorizontalBlocksEmpty(World $world, Vector3 $position, ?int $except) : bool{
private function allHorizontalBlocksEmpty(World $world, Vector3 $position, ?Facing $except) : bool{
foreach($position->sidesAroundAxis(Axis::Y) as $facing => $sidePosition){
if($facing === $except){
if($facing === $except?->value){
continue;
}
if($world->getBlock($sidePosition)->getTypeId() !== BlockTypeIds::AIR){
@ -149,7 +149,7 @@ final class ChorusFlower extends Flowable implements Ageable{
return $this->allHorizontalBlocksEmpty($world, $up, null);
}
private function grow(int $facing, int $ageChange, ?BlockTransaction $tx) : BlockTransaction{
private function grow(Facing $facing, int $ageChange, ?BlockTransaction $tx) : BlockTransaction{
if($tx === null){
$tx = new BlockTransaction($this->position->getWorld());
}
@ -176,10 +176,10 @@ final class ChorusFlower extends Flowable implements Ageable{
$facingVisited = [];
for($attempts = 0, $maxAttempts = mt_rand(0, $endStoneBelow ? 4 : 3); $attempts < $maxAttempts; $attempts++){
$facing = Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)];
if(isset($facingVisited[$facing])){
if(isset($facingVisited[$facing->value])){
continue;
}
$facingVisited[$facing] = true;
$facingVisited[$facing->value] = true;
$sidePosition = $this->position->getSide($facing);
if(

View File

@ -43,8 +43,8 @@ final class ChorusPlant extends Flowable{
protected function recalculateCollisionBoxes() : array{
$bb = AxisAlignedBB::one();
foreach(Facing::ALL as $facing){
if(!isset($this->connections[$facing])){
$bb->trim($facing, 2 / 16);
if(!isset($this->connections[$facing->value])){
$bb = $bb->trimmedCopy($facing, 2 / 16);
}
}
@ -62,9 +62,9 @@ final class ChorusPlant extends Flowable{
BlockTypeIds::END_STONE, BlockTypeIds::CHORUS_FLOWER, $this->getTypeId() => true,
default => false
}){
$this->connections[$facing] = true;
$this->connections[$facing->value] = true;
}else{
unset($this->connections[$facing]);
unset($this->connections[$facing->value]);
}
}

View File

@ -27,13 +27,13 @@ use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AgeableTrait;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\WoodType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
@ -48,18 +48,19 @@ class CocoaBlock extends Flowable implements Ageable, HorizontalFacing{
public const MAX_AGE = 2;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->boundedIntAuto(0, self::MAX_AGE, $this->age);
}
protected function recalculateCollisionBoxes() : array{
$realFacing = $this->facing->toFacing();
return [
AxisAlignedBB::one()
->squash(Facing::axis(Facing::rotateY($this->facing, true)), (6 - $this->age) / 16) //sides
->trim(Facing::DOWN, (7 - $this->age * 2) / 16)
->trim(Facing::UP, 0.25)
->trim(Facing::opposite($this->facing), 1 / 16) //gap between log and pod
->trim($this->facing, (11 - $this->age * 2) / 16) //outward face
->squashedCopy(Facing::axis(Facing::rotateY($realFacing, true)), (6 - $this->age) / 16) //sides
->trimmedCopy(Facing::DOWN, (7 - $this->age * 2) / 16)
->trimmedCopy(Facing::UP, 0.25)
->trimmedCopy(Facing::opposite($realFacing), 1 / 16) //gap between log and pod
->trimmedCopy($realFacing, (11 - $this->age * 2) / 16) //outward face
];
}
@ -67,16 +68,16 @@ class CocoaBlock extends Flowable implements Ageable, HorizontalFacing{
return $block instanceof Wood && $block->getWoodType() === WoodType::JUNGLE;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(Facing::axis($face) !== Axis::Y && $this->canAttachTo($blockClicked)){
$this->facing = $face;
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(($hzFacing = HorizontalFacingOption::tryFromFacing($face)) !== null && $this->canAttachTo($blockClicked)){
$this->facing = $hzFacing;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
return false;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof Fertilizer && $this->grow($player)){
$item->pop();
@ -87,7 +88,7 @@ class CocoaBlock extends Flowable implements Ageable, HorizontalFacing{
}
public function onNearbyBlockChange() : void{
if(!$this->canAttachTo($this->getSide(Facing::opposite($this->facing)))){
if(!$this->canAttachTo($this->getSide(Facing::opposite($this->facing->toFacing())))){
$this->position->getWorld()->useBreakOn($this->position);
}
}

View File

@ -35,7 +35,7 @@ class CopperDoor extends Door implements CopperMaterial{
onInteract as onInteractCopper;
}
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 && $player->isSneaking() && $this->onInteractCopper($item, $face, $clickVector, $player, $returnedItems)) {
//copy copper properties to other half
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);

View File

@ -26,6 +26,7 @@ namespace pocketmine\block;
use pocketmine\block\utils\CopperMaterial;
use pocketmine\block\utils\CopperTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
@ -34,7 +35,7 @@ class CopperTrapdoor extends Trapdoor implements CopperMaterial{
onInteract as onInteractCopper;
}
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 && $player->isSneaking() && $this->onInteractCopper($item, $face, $clickVector, $player, $returnedItems)) {
return true;
}

View File

@ -23,19 +23,17 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\CraftingTableInventory;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\block\inventory\window\CraftingTableInventoryWindow;
use pocketmine\block\utils\MenuAccessor;
use pocketmine\block\utils\MenuAccessorTrait;
use pocketmine\player\Player;
use pocketmine\world\Position;
class CraftingTable extends Opaque{
class CraftingTable extends Opaque implements MenuAccessor{
use MenuAccessorTrait;
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player instanceof Player){
$player->setCurrentWindow(new CraftingTableInventory($this->position));
}
return true;
protected function newMenu(Player $player, Position $position) : CraftingTableInventoryWindow{
return new CraftingTableInventoryWindow($player, $position);
}
public function getFuelTime() : int{

View File

@ -45,7 +45,7 @@ abstract class Crops extends Flowable implements Ageable{
return $block->getSide(Facing::DOWN)->getTypeId() === BlockTypeIds::FARMLAND;
}
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->age < self::MAX_AGE && $item instanceof Fertilizer){
$block = clone $this;
$tempAge = $block->age + mt_rand(2, 5);

View File

@ -64,14 +64,14 @@ class DaylightSensor extends Transparent implements AnalogRedstoneSignalEmitter{
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 10 / 16)];
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 10 / 16)];
}
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{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
$this->inverted = !$this->inverted;
$this->signalStrength = $this->recalculateSignalStrength();
$this->position->getWorld()->setBlock($this->position, $this);

View File

@ -52,7 +52,7 @@ class Dirt extends Opaque{
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{
$world = $this->position->getWorld();
if($face !== Facing::DOWN && $item instanceof Hoe){
$up = $this->getSide(Facing::UP);

View File

@ -24,6 +24,7 @@ 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\data\runtime\RuntimeDataDescriber;
@ -43,7 +44,7 @@ class Door extends Transparent implements HorizontalFacing{
protected bool $open = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->bool($this->top);
$w->bool($this->hingeRight);
$w->bool($this->open);
@ -98,10 +99,10 @@ class Door extends Transparent implements HorizontalFacing{
protected function recalculateCollisionBoxes() : array{
//TODO: doors are 0.1825 blocks thick, instead of 0.1875 like JE (https://bugs.mojang.com/browse/MCPE-19214)
return [AxisAlignedBB::one()->trim($this->open ? Facing::rotateY($this->facing, !$this->hingeRight) : $this->facing, 327 / 400)];
return [AxisAlignedBB::one()->trimmedCopy($this->open ? Facing::rotateY($this->facing->toFacing(), !$this->hingeRight) : $this->facing->toFacing(), 327 / 400)];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -111,7 +112,7 @@ class Door extends Transparent implements HorizontalFacing{
}
}
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($face === Facing::UP){
$blockUp = $this->getSide(Facing::UP);
if(!$blockUp->canBeReplaced() || !$this->canBeSupportedAt($blockReplace)){
@ -119,11 +120,13 @@ class Door extends Transparent implements HorizontalFacing{
}
if($player !== null){
$this->facing = $player->getHorizontalFacing();
//TODO: not sure if entities should use HorizontalFacingOption too
$this->facing = HorizontalFacingOption::fromFacing($player->getHorizontalFacing());
}
$next = $this->getSide(Facing::rotateY($this->facing, false));
$next2 = $this->getSide(Facing::rotateY($this->facing, true));
$realFacing = $this->facing->toFacing();
$next = $this->getSide(Facing::rotateY($realFacing, false));
$next2 = $this->getSide(Facing::rotateY($realFacing, true));
if($next->hasSameTypeId($this) || (!$next2->isTransparent() && $next->isTransparent())){ //Door hinge
$this->hingeRight = true;
@ -139,7 +142,7 @@ class Door extends Transparent implements HorizontalFacing{
return false;
}
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{
$this->open = !$this->open;
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);

View File

@ -58,10 +58,10 @@ final class DoublePitcherCrop extends DoublePlant implements Ageable{
//the pod exists only in the bottom half of the plant
return [
AxisAlignedBB::one()
->trim(Facing::UP, 11 / 16)
->squash(Axis::X, 3 / 16)
->squash(Axis::Z, 3 / 16)
->extend(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
->trimmedCopy(Facing::UP, 11 / 16)
->squashedCopy(Axis::X, 3 / 16)
->squashedCopy(Axis::Z, 3 / 16)
->extendedCopy(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
];
}
@ -89,7 +89,7 @@ final class DoublePitcherCrop extends DoublePlant implements Ageable{
}
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;

View File

@ -45,7 +45,7 @@ class DoublePlant 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{
$down = $blockReplace->getSide(Facing::DOWN);
if($down->hasTypeTag(BlockTypeTags::DIRT) && $blockReplace->getSide(Facing::UP)->canBeReplaced()){
$top = clone $this;

View File

@ -28,6 +28,7 @@ use pocketmine\block\utils\FallableTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\event\block\BlockTeleportEvent;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\GameMode;
use pocketmine\player\Player;
@ -44,12 +45,12 @@ class DragonEgg extends Transparent implements Fallable{
return 1;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
$this->teleport();
return true;
}
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
public function onAttack(Item $item, Facing $face, ?Player $player = null) : bool{
if($player !== null && $player->getGamemode() !== GameMode::CREATIVE){
$this->teleport();
return true;
@ -81,7 +82,7 @@ class DragonEgg extends Transparent implements Fallable{
}
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -23,31 +23,27 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\EnchantInventory;
use pocketmine\block\inventory\window\EnchantingTableInventoryWindow;
use pocketmine\block\utils\MenuAccessor;
use pocketmine\block\utils\MenuAccessorTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\Position;
class EnchantingTable extends Transparent{
class EnchantingTable extends Transparent implements MenuAccessor{
use MenuAccessorTrait;
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 0.25)];
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 0.25)];
}
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){
//TODO lock
$player->setCurrentWindow(new EnchantInventory($this->position));
}
return true;
protected function newMenu(Player $player, Position $position) : EnchantingTableInventoryWindow{
return new EnchantingTableInventoryWindow($player, $position);
}
}

View File

@ -35,7 +35,7 @@ class EndPortalFrame extends Opaque implements HorizontalFacing{
protected bool $eye = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->bool($this->eye);
}
@ -52,6 +52,6 @@ class EndPortalFrame extends Opaque implements HorizontalFacing{
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 3 / 16)];
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 3 / 16)];
}
}

View File

@ -36,7 +36,7 @@ use pocketmine\world\BlockTransaction;
class EndRod extends Flowable implements AnyFacing{
use AnyFacingTrait;
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->facing = $face;
if($blockClicked instanceof EndRod && $blockClicked->facing === $this->facing){
$this->facing = Facing::opposite($face);
@ -61,7 +61,7 @@ class EndRod extends Flowable implements AnyFacing{
if($axis === $myAxis){
continue;
}
$bb->squash($axis, 6 / 16);
$bb->squashedCopy($axis, 6 / 16);
}
return [$bb];
}

View File

@ -23,18 +23,31 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\EnderChestInventory;
use pocketmine\block\inventory\window\BlockInventoryWindow;
use pocketmine\block\tile\EnderChest as TileEnderChest;
use pocketmine\block\utils\AnimatedContainerLike;
use pocketmine\block\utils\AnimatedContainerLikeTrait;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\MenuAccessorTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\BlockEventPacket;
use pocketmine\network\mcpe\protocol\types\BlockPosition;
use pocketmine\player\Player;
use pocketmine\world\Position;
use pocketmine\world\sound\EnderChestCloseSound;
use pocketmine\world\sound\EnderChestOpenSound;
use pocketmine\world\sound\Sound;
class EnderChest extends Transparent implements HorizontalFacing{
class EnderChest extends Transparent implements AnimatedContainerLike, HorizontalFacing{
use AnimatedContainerLikeTrait {
onViewerAdded as private traitOnViewerAdded;
onViewerRemoved as private traitOnViewerRemoved;
}
use MenuAccessorTrait;
use FacesOppositePlacingPlayerTrait;
public function getLightLevel() : int{
@ -43,23 +56,19 @@ class EnderChest extends Transparent implements HorizontalFacing{
protected function recalculateCollisionBoxes() : array{
//these are slightly bigger than in PC
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];
return [AxisAlignedBB::one()->contractedCopy(0.025, 0, 0.025)->trimmedCopy(Facing::UP, 0.05)];
}
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){
$enderChest = $this->position->getWorld()->getTile($this->position);
if($enderChest instanceof TileEnderChest && $this->getSide(Facing::UP)->isTransparent()){
$enderChest->setViewerCount($enderChest->getViewerCount() + 1);
$player->setCurrentWindow(new EnderChestInventory($this->position, $player->getEnderInventory()));
}
}
public function isOpeningObstructed() : bool{
return !$this->getSide(Facing::UP)->isTransparent();
}
return true;
protected function newMenu(Player $player, Position $position) : BlockInventoryWindow{
return new BlockInventoryWindow($player, $player->getEnderInventory(), $position);
}
public function getDropsForCompatibleTool(Item $item) : array{
@ -71,4 +80,43 @@ class EnderChest extends Transparent implements HorizontalFacing{
public function isAffectedBySilkTouch() : bool{
return true;
}
protected function getViewerCount() : int{
$enderChest = $this->position->getWorld()->getTile($this->position);
if(!$enderChest instanceof TileEnderChest){
return 0;
}
return $enderChest->getViewerCount();
}
private function updateViewerCount(int $amount) : void{
$enderChest = $this->position->getWorld()->getTile($this->position);
if($enderChest instanceof TileEnderChest){
$enderChest->setViewerCount($enderChest->getViewerCount() + $amount);
}
}
protected function getOpenSound() : Sound{
return new EnderChestOpenSound();
}
protected function getCloseSound() : Sound{
return new EnderChestCloseSound();
}
protected function playAnimationVisual(Position $position, bool $isOpen) : void{
//event ID is always 1 for a chest
//TODO: we probably shouldn't be sending a packet directly here, but it doesn't fit anywhere into existing systems
$position->getWorld()->broadcastPacketToViewers($position, BlockEventPacket::create(BlockPosition::fromVector3($position), 1, $isOpen ? 1 : 0));
}
public function onViewerAdded() : void{
$this->updateViewerCount(1);
$this->traitOnViewerAdded();
}
public function onViewerRemoved() : void{
$this->traitOnViewerRemoved();
$this->updateViewerCount(-1);
}
}

View File

@ -95,7 +95,7 @@ class Farmland extends Transparent{
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 1 / 16)];
}
public function onNearbyBlockChange() : void{

View File

@ -45,9 +45,9 @@ class Fence extends Transparent{
foreach(Facing::HORIZONTAL as $facing){
$block = $this->getSide($facing);
if($block instanceof static || $block instanceof FenceGate || $block->getSupportType(Facing::opposite($facing)) === SupportType::FULL){
$this->connections[$facing] = true;
$this->connections[$facing->value] = true;
}else{
unset($this->connections[$facing]);
unset($this->connections[$facing->value]);
}
}
@ -59,43 +59,43 @@ class Fence extends Transparent{
$bbs = [];
$connectWest = isset($this->connections[Facing::WEST]);
$connectEast = isset($this->connections[Facing::EAST]);
$connectWest = isset($this->connections[Facing::WEST->value]);
$connectEast = isset($this->connections[Facing::EAST->value]);
if($connectWest || $connectEast){
//X axis (west/east)
$bbs[] = AxisAlignedBB::one()
->squash(Axis::Z, $inset)
->extend(Facing::UP, 0.5)
->trim(Facing::WEST, $connectWest ? 0 : $inset)
->trim(Facing::EAST, $connectEast ? 0 : $inset);
->squashedCopy(Axis::Z, $inset)
->extendedCopy(Facing::UP, 0.5)
->trimmedCopy(Facing::WEST, $connectWest ? 0 : $inset)
->trimmedCopy(Facing::EAST, $connectEast ? 0 : $inset);
}
$connectNorth = isset($this->connections[Facing::NORTH]);
$connectSouth = isset($this->connections[Facing::SOUTH]);
$connectNorth = isset($this->connections[Facing::NORTH->value]);
$connectSouth = isset($this->connections[Facing::SOUTH->value]);
if($connectNorth || $connectSouth){
//Z axis (north/south)
$bbs[] = AxisAlignedBB::one()
->squash(Axis::X, $inset)
->extend(Facing::UP, 0.5)
->trim(Facing::NORTH, $connectNorth ? 0 : $inset)
->trim(Facing::SOUTH, $connectSouth ? 0 : $inset);
->squashedCopy(Axis::X, $inset)
->extendedCopy(Facing::UP, 0.5)
->trimmedCopy(Facing::NORTH, $connectNorth ? 0 : $inset)
->trimmedCopy(Facing::SOUTH, $connectSouth ? 0 : $inset);
}
if(count($bbs) === 0){
//centre post AABB (only needed if not connected on any axis - other BBs overlapping will do this if any connections are made)
return [
AxisAlignedBB::one()
->extend(Facing::UP, 0.5)
->contract($inset, 0, $inset)
->extendedCopy(Facing::UP, 0.5)
->contractedCopy($inset, 0, $inset)
];
}
return $bbs;
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return Facing::axis($facing) === Axis::Y ? SupportType::CENTER : SupportType::NONE;
}
}

View File

@ -24,6 +24,7 @@ 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\block\utils\WoodMaterial;
@ -45,7 +46,7 @@ class FenceGate extends Transparent implements HorizontalFacing, WoodMaterial{
protected bool $inWall = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->bool($this->open);
$w->bool($this->inWall);
}
@ -67,23 +68,24 @@ class FenceGate extends Transparent implements HorizontalFacing, WoodMaterial{
}
protected function recalculateCollisionBoxes() : array{
return $this->open ? [] : [AxisAlignedBB::one()->extend(Facing::UP, 0.5)->squash(Facing::axis($this->facing), 6 / 16)];
return $this->open ? [] : [AxisAlignedBB::one()->extendedCopy(Facing::UP, 0.5)->squashedCopy(Facing::axis($this->facing->toFacing()), 6 / 16)];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
private function checkInWall() : bool{
$realFacing = $this->facing->toFacing();
return (
$this->getSide(Facing::rotateY($this->facing, false)) instanceof Wall ||
$this->getSide(Facing::rotateY($this->facing, true)) instanceof Wall
$this->getSide(Facing::rotateY($realFacing, false)) instanceof Wall ||
$this->getSide(Facing::rotateY($realFacing, true)) instanceof Wall
);
}
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 = $player->getHorizontalFacing();
$this->facing = HorizontalFacingOption::fromFacing($player->getHorizontalFacing());
}
$this->inWall = $this->checkInWall();
@ -99,12 +101,12 @@ class FenceGate extends Transparent implements HorizontalFacing, WoodMaterial{
}
}
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{
$this->open = !$this->open;
if($this->open && $player !== null){
$playerFacing = $player->getHorizontalFacing();
if($playerFacing === Facing::opposite($this->facing)){
$this->facing = $playerFacing;
if($playerFacing === Facing::opposite($this->facing->toFacing())){
$this->facing = HorizontalFacingOption::fromFacing($playerFacing);
}
}

View File

@ -54,16 +54,16 @@ abstract class FillableCauldron 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;
}

View File

@ -38,11 +38,11 @@ final class FloorBanner extends BaseBanner implements SignLikeRotation{
return VanillaBlocks::OMINOUS_BANNER()->setRotation($this->rotation);
}
protected function getSupportingFace() : int{
protected function getSupportingFace() : Facing{
return Facing::DOWN;
}
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($face !== Facing::UP){
return false;
}

View File

@ -38,16 +38,16 @@ use function rad2deg;
final class FloorCoralFan extends BaseCoral{
use StaticSupportTrait;
private int $axis = Axis::X;
private Axis $axis = Axis::X;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalAxis($this->axis);
}
public function getAxis() : int{ return $this->axis; }
public function getAxis() : Axis{ return $this->axis; }
/** @return $this */
public function setAxis(int $axis) : self{
public function setAxis(Axis $axis) : self{
if($axis !== Axis::X && $axis !== Axis::Z){
throw new \InvalidArgumentException("Axis must be X or Z only");
}
@ -55,7 +55,7 @@ final class FloorCoralFan extends BaseCoral{
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){
$playerBlockPos = $player->getPosition()->floor();
$directionVector = $blockReplace->position->subtractVector($playerBlockPos)->normalize();

View File

@ -34,11 +34,11 @@ use pocketmine\world\BlockTransaction;
final class FloorSign extends BaseSign implements SignLikeRotation{
use SignLikeRotationTrait;
protected function getSupportingFace() : int{
protected function getSupportingFace() : Facing{
return Facing::DOWN;
}
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($face !== Facing::UP){
return false;
}
@ -48,4 +48,8 @@ final class FloorSign extends BaseSign implements SignLikeRotation{
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
protected function getFacingDegrees() : float{
return $this->rotation * 22.5;
}
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
/**
@ -40,7 +41,7 @@ abstract class Flowable extends Transparent{
return false;
}
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 (!$this->canBeFlowedInto() || !$blockReplace instanceof Liquid) &&
parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
}
@ -49,7 +50,7 @@ abstract class Flowable extends Transparent{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -84,14 +84,14 @@ class FlowerPot extends Flowable{
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->contract(3 / 16, 0, 3 / 16)->trim(Facing::UP, 5 / 8)];
return [AxisAlignedBB::one()->contractedCopy(3 / 16, 0, 3 / 16)->trimmedCopy(Facing::UP, 5 / 8)];
}
private function canBeSupportedAt(Block $block) : bool{
return $block->getAdjacentSupportType(Facing::DOWN)->hasCenterSupport();
}
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{
$world = $this->position->getWorld();
$plant = $item->getBlock();
if($this->plant !== null){

View File

@ -23,19 +23,24 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\window\FurnaceInventoryWindow;
use pocketmine\block\tile\Furnace as TileFurnace;
use pocketmine\block\utils\Container;
use pocketmine\block\utils\ContainerTrait;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\LightableTrait;
use pocketmine\crafting\FurnaceType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\inventory\Inventory;
use pocketmine\player\InventoryWindow;
use pocketmine\player\Player;
use pocketmine\world\Position;
use function mt_rand;
class Furnace extends Opaque implements Lightable, HorizontalFacing{
class Furnace extends Opaque implements Container, Lightable, HorizontalFacing{
use ContainerTrait;
use FacesOppositePlacingPlayerTrait;
use LightableTrait;
@ -47,7 +52,7 @@ class Furnace extends Opaque implements Lightable, HorizontalFacing{
}
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->bool($this->lit);
}
@ -59,15 +64,8 @@ class Furnace extends Opaque implements Lightable, HorizontalFacing{
return $this->lit ? 13 : 0;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player instanceof Player){
$furnace = $this->position->getWorld()->getTile($this->position);
if($furnace instanceof TileFurnace && $furnace->canOpenWith($item->getCustomName())){
$player->setCurrentWindow($furnace->getInventory());
}
}
return true;
protected function newMenu(Player $player, Inventory $inventory, Position $position) : InventoryWindow{
return new FurnaceInventoryWindow($player, $inventory, $position, $this->furnaceType);
}
public function onScheduledUpdate() : void{

View File

@ -51,7 +51,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -60,13 +60,13 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
}
/**
* @return int[]
* @return Facing[]
*/
protected function getInitialPlaceFaces(Block $blockReplace) : array{
return $blockReplace instanceof GlowLichen ? $blockReplace->faces : [];
}
private function getSpreadBlock(Block $replace, int $spreadFace) : ?Block{
private function getSpreadBlock(Block $replace, Facing $spreadFace) : ?Block{
if($replace instanceof self && $replace->hasSameTypeId($this)){
if($replace->hasFace($spreadFace)){
return null;
@ -81,7 +81,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
return $result->setFace($spreadFace, true);
}
private function spread(World $world, Vector3 $replacePos, int $spreadFace) : bool{
private function spread(World $world, Vector3 $replacePos, Facing $spreadFace) : bool{
$supportBlock = $world->getBlock($replacePos->getSide($spreadFace));
$supportFace = Facing::opposite($spreadFace);
@ -99,9 +99,9 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
}
/**
* @phpstan-return \Generator<int, int, void, void>
* @phpstan-return \Generator<int, Facing, void, void>
*/
private static function getShuffledSpreadFaces(int $sourceFace) : \Generator{
private static function getShuffledSpreadFaces(Facing $sourceFace) : \Generator{
$skipAxis = Facing::axis($sourceFace);
$faces = Facing::ALL;
@ -113,7 +113,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
}
}
private function spreadAroundSupport(int $sourceFace) : bool{
private function spreadAroundSupport(Facing $sourceFace) : bool{
$world = $this->position->getWorld();
$supportPos = $this->position->getSide($sourceFace);
@ -127,7 +127,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
return false;
}
private function spreadAdjacentToSupport(int $sourceFace) : bool{
private function spreadAdjacentToSupport(Facing $sourceFace) : bool{
$world = $this->position->getWorld();
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
@ -139,7 +139,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
return false;
}
private function spreadWithinSelf(int $sourceFace) : bool{
private function spreadWithinSelf(Facing $sourceFace) : bool{
foreach(self::getShuffledSpreadFaces($sourceFace) as $spreadFace){
if(!$this->hasFace($spreadFace) && $this->spread($this->position->getWorld(), $this->position, $spreadFace)){
return true;
@ -149,7 +149,7 @@ class GlowLichen extends Transparent implements MultiAnyFacing{
return false;
}
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 && count($this->faces) > 0){
$shuffledFaces = $this->faces;
shuffle($shuffledFaces);

View File

@ -81,7 +81,7 @@ class Grass extends Opaque{
}
}
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->getSide(Facing::UP)->getTypeId() !== BlockTypeIds::AIR){
return false;
}

View File

@ -30,7 +30,7 @@ use pocketmine\math\Facing;
class GrassPath extends Transparent{
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 1 / 16)];
}
public function onNearbyBlockChange() : void{

View File

@ -23,32 +23,38 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Hopper as TileHopper;
use pocketmine\block\inventory\window\HopperInventoryWindow;
use pocketmine\block\utils\Container;
use pocketmine\block\utils\ContainerTrait;
use pocketmine\block\utils\PoweredByRedstone;
use pocketmine\block\utils\PoweredByRedstoneTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\inventory\Inventory;
use pocketmine\item\Item;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\InventoryWindow;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use pocketmine\world\Position;
class Hopper extends Transparent implements PoweredByRedstone{
class Hopper extends Transparent implements Container, PoweredByRedstone{
use ContainerTrait;
use PoweredByRedstoneTrait;
private int $facing = Facing::DOWN;
private Facing $facing = Facing::DOWN;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->facingExcept($this->facing, Facing::UP);
$w->bool($this->powered);
}
public function getFacing() : int{ return $this->facing; }
public function getFacing() : Facing{ return $this->facing; }
/** @return $this */
public function setFacing(int $facing) : self{
public function setFacing(Facing $facing) : self{
if($facing === Facing::UP){
throw new \InvalidArgumentException("Hopper may not face upward");
}
@ -58,16 +64,16 @@ class Hopper extends Transparent implements PoweredByRedstone{
protected function recalculateCollisionBoxes() : array{
$result = [
AxisAlignedBB::one()->trim(Facing::UP, 6 / 16) //the empty area around the bottom is currently considered solid
AxisAlignedBB::one()->trimmedCopy(Facing::UP, 6 / 16) //the empty area around the bottom is currently considered solid
];
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 match($facing){
Facing::UP => SupportType::FULL,
Facing::DOWN => $this->facing === Facing::DOWN ? SupportType::CENTER : SupportType::NONE,
@ -75,21 +81,14 @@ class Hopper extends Transparent implements PoweredByRedstone{
};
}
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->facing = $face === Facing::DOWN ? Facing::DOWN : Facing::opposite($face);
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 !== null){
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileHopper){ //TODO: find a way to have inventories open on click without this boilerplate in every block
$player->setCurrentWindow($tile->getInventory());
}
return true;
}
return false;
protected function newMenu(Player $player, Inventory $inventory, Position $position) : InventoryWindow{
return new HopperInventoryWindow($player, $inventory, $position);
}
public function onScheduledUpdate() : void{

View File

@ -52,7 +52,7 @@ class ItemFrame extends Flowable implements AnyFacing{
protected float $itemDropChance = 1.0;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->facing($this->facing);
$w->enum($this->facing);
$w->bool($this->hasMap);
}
@ -132,7 +132,7 @@ class ItemFrame extends Flowable implements AnyFacing{
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->framedItem !== null){
$this->itemRotation = ($this->itemRotation + 1) % self::ROTATIONS;
@ -150,7 +150,7 @@ class ItemFrame extends Flowable implements AnyFacing{
return true;
}
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
public function onAttack(Item $item, Facing $face, ?Player $player = null) : bool{
if($this->framedItem === null){
return false;
}
@ -164,7 +164,7 @@ class ItemFrame extends Flowable implements AnyFacing{
return true;
}
private function canBeSupportedAt(Block $block, int $face) : bool{
private function canBeSupportedAt(Block $block, Facing $face) : bool{
return $block->getAdjacentSupportType($face) !== SupportType::NONE;
}
@ -174,7 +174,7 @@ class ItemFrame extends Flowable implements AnyFacing{
}
}
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

@ -27,6 +27,7 @@ use pocketmine\block\tile\Jukebox as JukeboxTile;
use pocketmine\item\Item;
use pocketmine\item\Record;
use pocketmine\lang\KnownTranslationFactory;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\RecordSound;
@ -40,7 +41,7 @@ class Jukebox extends Opaque{
return 300;
}
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 instanceof Player){
if($this->record !== null){
$this->ejectRecord();

View File

@ -24,12 +24,12 @@ 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\entity\Entity;
use pocketmine\entity\Living;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
@ -60,16 +60,16 @@ class Ladder extends Transparent implements HorizontalFacing{
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim($this->facing, 13 / 16)];
return [AxisAlignedBB::one()->trimmedCopy($this->facing->toFacing(), 13 / 16)];
}
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{
if($this->canBeSupportedAt($blockReplace, Facing::opposite($face)) && Facing::axis($face) !== Axis::Y){
$this->facing = $face;
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(($hzFacing = HorizontalFacingOption::tryFromFacing($face)) !== null && $this->canBeSupportedAt($blockReplace, Facing::opposite($face))){
$this->facing = $hzFacing;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
@ -77,12 +77,12 @@ class Ladder extends Transparent implements HorizontalFacing{
}
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing))){ //Replace with common break method
if(!$this->canBeSupportedAt($this, Facing::opposite($this->facing->toFacing()))){ //Replace with common break method
$this->position->getWorld()->useBreakOn($this->position);
}
}
private function canBeSupportedAt(Block $block, int $face) : bool{
private function canBeSupportedAt(Block $block, Facing $face) : bool{
return $block->getAdjacentSupportType($face) === SupportType::FULL;
}
}

View File

@ -62,18 +62,18 @@ class Lantern extends Transparent{
protected function recalculateCollisionBoxes() : array{
return [
AxisAlignedBB::one()
->trim(Facing::UP, $this->hanging ? 6 / 16 : 8 / 16)
->trim(Facing::DOWN, $this->hanging ? 2 / 16 : 0)
->squash(Axis::X, 5 / 16)
->squash(Axis::Z, 5 / 16)
->trimmedCopy(Facing::UP, $this->hanging ? 6 / 16 : 8 / 16)
->trimmedCopy(Facing::DOWN, $this->hanging ? 2 / 16 : 0)
->squashedCopy(Axis::X, 5 / 16)
->squashedCopy(Axis::Z, 5 / 16)
];
}
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{
$downSupport = $this->canBeSupportedAt($blockReplace, Facing::DOWN);
if(!$downSupport && !$this->canBeSupportedAt($blockReplace, Facing::UP)){
return false;
@ -90,7 +90,7 @@ class Lantern extends Transparent{
}
}
private function canBeSupportedAt(Block $block, int $face) : bool{
private function canBeSupportedAt(Block $block, Facing $face) : bool{
return $block->getAdjacentSupportType($face)->hasCenterSupport();
}
}

View File

@ -31,6 +31,7 @@ use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\CauldronEmptyLavaSound;
@ -61,7 +62,7 @@ final class LavaCauldron extends FillableCauldron{
return new CauldronEmptyLavaSound();
}
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{
match($item->getTypeId()){
ItemTypeIds::BUCKET => $this->removeFillLevels(self::MAX_FILL_LEVEL, $item, VanillaItems::LAVA_BUCKET(), $returnedItems),
ItemTypeIds::POWDER_SNOW_BUCKET, ItemTypeIds::WATER_BUCKET => $this->mix($item, VanillaItems::BUCKET(), $returnedItems),

View File

@ -134,7 +134,7 @@ class Leaves 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{
$this->noDecay = true; //artificial leaves don't decay
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
@ -188,7 +188,7 @@ class Leaves extends Transparent{
return 60;
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -46,7 +46,7 @@ class Lectern extends Transparent implements HorizontalFacing{
protected bool $producingSignal = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->bool($this->producingSignal);
}
@ -84,10 +84,10 @@ class Lectern extends Transparent implements HorizontalFacing{
}
protected function recalculateCollisionBoxes() : array{
return [AxisAlignedBB::one()->trim(Facing::UP, 0.1)];
return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 0.1)];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -120,7 +120,7 @@ class Lectern extends Transparent implements HorizontalFacing{
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->book === null && $item instanceof WritableBookBase){
$world = $this->position->getWorld();
$world->setBlock($this->position, $this->setBook($item));
@ -130,7 +130,7 @@ class Lectern extends Transparent implements HorizontalFacing{
return true;
}
public function onAttack(Item $item, int $face, ?Player $player = null) : bool{
public function onAttack(Item $item, Facing $face, ?Player $player = null) : bool{
if($this->book !== null){
$world = $this->position->getWorld();
$world->dropItem($this->position->up(), $this->book);

View File

@ -30,7 +30,6 @@ use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\world\BlockTransaction;
use pocketmine\world\sound\RedstonePowerOffSound;
use pocketmine\world\sound\RedstonePowerOnSound;
@ -60,7 +59,7 @@ class Lever 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, Facing::opposite($face))){
return false;
}
@ -78,7 +77,6 @@ class Lever extends Flowable{
Facing::SOUTH => LeverFacing::SOUTH,
Facing::WEST => LeverFacing::WEST,
Facing::EAST => LeverFacing::EAST,
default => throw new AssumptionFailedError("Bad facing value"),
};
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
@ -90,7 +88,7 @@ class Lever extends Flowable{
}
}
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{
$this->activated = !$this->activated;
$world = $this->position->getWorld();
$world->setBlock($this->position, $this);
@ -101,7 +99,7 @@ class Lever extends Flowable{
return true;
}
private function canBeSupportedAt(Block $block, int $face) : bool{
private function canBeSupportedAt(Block $block, Facing $face) : bool{
return $block->getAdjacentSupportType($face)->hasCenterSupport();
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
@ -51,12 +52,12 @@ final class Light extends Flowable{
public function canBeReplaced() : bool{ return true; }
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, Facing $face, bool $isClickedBlock) : bool{
//light blocks behave like solid blocks when placing them on another light block
return $blockReplace->canBeReplaced() && $blockReplace->getTypeId() !== $this->getTypeId();
}
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{
$this->level = $this->level === self::MAX_LIGHT_LEVEL ?
self::MIN_LIGHT_LEVEL :
$this->level + 1;

View File

@ -42,14 +42,14 @@ final class LightningRod extends Transparent implements AnyFacing{
$result = AxisAlignedBB::one();
foreach([Axis::X, Axis::Y, Axis::Z] as $axis){
if($axis !== $myAxis){
$result->squash($axis, 6 / 16);
$result = $result->squashedCopy($axis, 6 / 16);
}
}
return [$result];
}
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->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}

View File

@ -92,7 +92,7 @@ abstract class Liquid extends Transparent{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -170,7 +170,7 @@ abstract class Liquid extends Transparent{
$world = $this->position->getWorld();
foreach(Facing::HORIZONTAL as $j){
[$dx, $dy, $dz] = Facing::OFFSET[$j];
[$dx, $dy, $dz] = Facing::OFFSET[$j->value];
$sideX = $x + $dx;
$sideY = $y + $dy;
@ -206,7 +206,7 @@ abstract class Liquid extends Transparent{
if($this->falling){
foreach(Facing::HORIZONTAL as $facing){
[$dx, $dy, $dz] = Facing::OFFSET[$facing];
[$dx, $dy, $dz] = Facing::OFFSET[$facing->value];
if(
!$this->canFlowInto($world->getBlockAt($x + $dx, $y + $dy, $z + $dz)) ||
!$this->canFlowInto($world->getBlockAt($x + $dx, $y + $dy + 1, $z + $dz))

View File

@ -23,21 +23,19 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\inventory\LoomInventory;
use pocketmine\block\inventory\window\LoomInventoryWindow;
use pocketmine\block\utils\FacesOppositePlacingPlayerTrait;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\block\utils\MenuAccessor;
use pocketmine\block\utils\MenuAccessorTrait;
use pocketmine\player\Player;
use pocketmine\world\Position;
final class Loom extends Opaque implements HorizontalFacing{
final class Loom extends Opaque implements HorizontalFacing, MenuAccessor{
use FacesOppositePlacingPlayerTrait;
use MenuAccessorTrait;
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player !== null){
$player->setCurrentWindow(new LoomInventory($this->position));
return true;
}
return false;
protected function newMenu(Player $player, Position $position) : LoomInventoryWindow{
return new LoomInventoryWindow($player, $position);
}
}

View File

@ -41,7 +41,7 @@ class MobHead extends Flowable{
protected MobHeadType $mobHeadType = MobHeadType::SKELETON;
protected int $facing = Facing::NORTH;
protected Facing $facing = Facing::NORTH;
protected int $rotation = self::MIN_ROTATION; //TODO: split this into floor skull and wall skull handling
public function describeBlockItemState(RuntimeDataDescriber $w) : void{
@ -82,10 +82,10 @@ class MobHead extends Flowable{
return $this;
}
public function getFacing() : int{ return $this->facing; }
public function getFacing() : Facing{ return $this->facing; }
/** @return $this */
public function setFacing(int $facing) : self{
public function setFacing(Facing $facing) : self{
if($facing === Facing::DOWN){
throw new \InvalidArgumentException("Skull may not face DOWN");
}
@ -106,17 +106,17 @@ class MobHead extends Flowable{
protected function recalculateCollisionBoxes() : array{
$collisionBox = AxisAlignedBB::one()
->contract(0.25, 0, 0.25)
->trim(Facing::UP, 0.5);
->contractedCopy(0.25, 0, 0.25)
->trimmedCopy(Facing::UP, 0.5);
if($this->facing !== Facing::UP){
$collisionBox = $collisionBox
->offsetTowards(Facing::opposite($this->facing), 0.25)
->offsetTowards(Facing::UP, 0.25);
->offsetTowardsCopy(Facing::opposite($this->facing), 0.25)
->offsetTowardsCopy(Facing::UP, 0.25);
}
return [$collisionBox];
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
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;
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use function mt_rand;
class MonsterSpawner extends Transparent{
@ -41,7 +42,7 @@ class MonsterSpawner extends Transparent{
//TODO
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -28,16 +28,17 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\entity\Entity;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
class NetherPortal extends Transparent{
protected int $axis = Axis::X;
protected Axis $axis = Axis::X;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalAxis($this->axis);
}
public function getAxis() : int{
public function getAxis() : Axis{
return $this->axis;
}
@ -45,7 +46,7 @@ class NetherPortal extends Transparent{
* @throws \InvalidArgumentException
* @return $this
*/
public function setAxis(int $axis) : self{
public function setAxis(Axis $axis) : self{
if($axis !== Axis::X && $axis !== Axis::Z){
throw new \InvalidArgumentException("Invalid axis");
}
@ -65,7 +66,7 @@ class NetherPortal extends Transparent{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}

View File

@ -49,9 +49,9 @@ class NetherVines extends Flowable implements Ageable{
public const MAX_AGE = 25;
/** Direction the vine grows towards. */
private int $growthFace;
private Facing $growthFace;
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, int $growthFace){
public function __construct(BlockIdentifier $idInfo, string $name, BlockTypeInfo $typeInfo, Facing $growthFace){
$this->growthFace = $growthFace;
parent::__construct($idInfo, $name, $typeInfo);
}
@ -80,12 +80,12 @@ class NetherVines extends Flowable implements Ageable{
return $top;
}
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 - 1);
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){
if($this->grow($player, mt_rand(1, 5))){
$item->pop();
@ -159,7 +159,7 @@ class NetherVines extends Flowable implements Ageable{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
}

View File

@ -36,11 +36,11 @@ final class OminousFloorBanner extends BaseOminousBanner implements SignLikeRota
//TODO: duplicated code :(
protected function getSupportingFace() : int{
protected function getSupportingFace() : Facing{
return Facing::DOWN;
}
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($face !== Facing::UP){
return false;
}

View File

@ -24,9 +24,9 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
@ -35,15 +35,16 @@ use pocketmine\world\BlockTransaction;
final class OminousWallBanner extends BaseOminousBanner implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : int{
return Facing::opposite($this->facing);
protected function getSupportingFace() : Facing{
return Facing::opposite($this->facing->toFacing());
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(Facing::axis($face) === Axis::Y){
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
$hzFacing = HorizontalFacingOption::tryFromFacing($face);
if($hzFacing === null){
return false;
}
$this->facing = $face;
$this->facing = $hzFacing;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -25,6 +25,7 @@ namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\data\runtime\RuntimeDataDescriber;
@ -47,7 +48,7 @@ class PinkPetals extends Flowable implements HorizontalFacing{
protected int $count = self::MIN_COUNT;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->boundedIntAuto(self::MIN_COUNT, self::MAX_COUNT, $this->count);
}
@ -70,21 +71,21 @@ class PinkPetals extends Flowable implements HorizontalFacing{
return $supportBlock->hasTypeTag(BlockTypeTags::DIRT) || $supportBlock->hasTypeTag(BlockTypeTags::MUD);
}
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 instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT) || $this->supportedWhenPlacedAt($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 instanceof PinkPetals && $blockReplace->count < self::MAX_COUNT){
$this->count = $blockReplace->count + 1;
$this->facing = $blockReplace->facing;
}elseif($player !== null){
$this->facing = Facing::opposite($player->getHorizontalFacing());
$this->facing = HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing()));
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof Fertilizer){
$grew = false;
if($this->count < self::MAX_COUNT){

View File

@ -54,10 +54,10 @@ final class PitcherCrop extends Flowable implements Ageable{
$heightTrim = $this->age === 0 ? 13 : 11;
return [
AxisAlignedBB::one()
->trim(Facing::UP, $heightTrim / 16)
->squash(Axis::X, $widthTrim / 16)
->squash(Axis::Z, $widthTrim / 16)
->extend(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
->trimmedCopy(Facing::UP, $heightTrim / 16)
->squashedCopy(Axis::X, $widthTrim / 16)
->squashedCopy(Axis::Z, $widthTrim / 16)
->extendedCopy(Facing::DOWN, 1 / 16) //presumably this is to correct for farmland being 15/16 of a block tall
];
}
@ -85,7 +85,7 @@ final class PitcherCrop extends Flowable implements Ageable{
return BlockEventHelper::grow($this, (clone $this)->setAge($this->age + 1), $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;

View File

@ -27,6 +27,7 @@ use pocketmine\block\tile\Cauldron as TileCauldron;
use pocketmine\item\Item;
use pocketmine\item\ItemTypeIds;
use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\sound\CauldronEmptyPotionSound;
@ -94,7 +95,7 @@ final class PotionCauldron extends FillableCauldron{
}
}
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{
match($item->getTypeId()){
ItemTypeIds::LINGERING_POTION, ItemTypeIds::POTION, ItemTypeIds::SPLASH_POTION => $this->addFillLevelsOrMix(self::POTION_FILL_AMOUNT, $item, VanillaItems::GLASS_BOTTLE(), $returnedItems),
ItemTypeIds::GLASS_BOTTLE => $this->potionItem === null ? null : $this->removeFillLevels(self::POTION_FILL_AMOUNT, $item, clone $this->potionItem, $returnedItems),

View File

@ -57,7 +57,7 @@ abstract class PressurePlate extends Transparent{
return [];
}
public function getSupportType(int $facing) : SupportType{
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
@ -83,10 +83,10 @@ abstract class PressurePlate extends Transparent{
*/
protected function getActivationBox() : AxisAlignedBB{
return AxisAlignedBB::one()
->squash(Axis::X, 1 / 8)
->squash(Axis::Z, 1 / 8)
->trim(Facing::UP, 3 / 4)
->offset($this->position->x, $this->position->y, $this->position->z);
->squashedCopy(Axis::X, 1 / 8)
->squashedCopy(Axis::Z, 1 / 8)
->trimmedCopy(Facing::UP, 3 / 4)
->offsetCopy($this->position->x, $this->position->y, $this->position->z);
}
/**

View File

@ -23,21 +23,21 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\item\Item;
use pocketmine\item\Shears;
use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function in_array;
class Pumpkin extends Opaque{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof Shears && in_array($face, Facing::HORIZONTAL, true)){
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($item instanceof Shears && ($hzFacing = HorizontalFacingOption::tryFromFacing($face)) !== null){
$item->applyDamage(1);
$world = $this->position->getWorld();
$world->setBlock($this->position, VanillaBlocks::CARVED_PUMPKIN()->setFacing($face));
$world->setBlock($this->position, VanillaBlocks::CARVED_PUMPKIN()->setFacing($hzFacing));
$world->dropItem($this->position->add(0.5, 0.5, 0.5), VanillaItems::PUMPKIN_SEEDS()->setCount(1));
return true;
}

View File

@ -24,18 +24,16 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\RailConnectionInfo;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\block\utils\RailShape;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\math\Facing;
use function array_keys;
use function implode;
class Rail extends BaseRail{
private int $railShape = BlockLegacyMetadata::RAIL_STRAIGHT_NORTH_SOUTH;
private RailShape $railShape = RailShape::FLAT_AXIS_Z;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->railShape($this->railShape);
$w->enum($this->railShape);
}
protected function setShapeFromConnections(array $connections) : void{
@ -43,11 +41,11 @@ class Rail extends BaseRail{
if($railShape === null){
throw new \InvalidArgumentException("No rail shape matches these connections");
}
$this->railShape = $railShape;
$this->railShape = RailShape::from($railShape);
}
protected function getCurrentShapeConnections() : array{
return RailConnectionInfo::CURVE_CONNECTIONS[$this->railShape] ?? RailConnectionInfo::CONNECTIONS[$this->railShape];
return RailConnectionInfo::CURVE_CONNECTIONS[$this->railShape->value] ?? RailConnectionInfo::CONNECTIONS[$this->railShape->value];
}
protected function getPossibleConnectionDirectionsOneConstraint(int $constraint) : array{
@ -60,8 +58,8 @@ class Rail extends BaseRail{
Facing::WEST,
Facing::EAST
] as $d){
if($constraint !== $d){
$possible[$d] = true;
if($constraint !== $d->value){
$possible[$d->value] = true;
}
}
}
@ -69,13 +67,10 @@ class Rail extends BaseRail{
return $possible;
}
public function getShape() : int{ return $this->railShape; }
public function getShape() : RailShape{ return $this->railShape; }
/** @return $this */
public function setShape(int $shape) : self{
if(!isset(RailConnectionInfo::CONNECTIONS[$shape]) && !isset(RailConnectionInfo::CURVE_CONNECTIONS[$shape])){
throw new \InvalidArgumentException("Invalid shape, must be one of " . implode(", ", [...array_keys(RailConnectionInfo::CONNECTIONS), ...array_keys(RailConnectionInfo::CURVE_CONNECTIONS)]));
}
public function setShape(RailShape $shape) : self{
$this->railShape = $shape;
return $this;
}

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