Compare commits

..

86 Commits

Author SHA1 Message Date
26767acb68 Pull registration functionality out of BlockTypeIds 2025-08-31 21:02:06 +01:00
a8cb8601ab Remove dead test 2025-08-31 20:52:49 +01:00
bb84bef3f4 First look at strings for block type IDs
This solves the following issues:
- Conflicts on BlockTypeIds every time someone makes a PR to add a new block
- Type IDs not consistent on different threads

We still have an auto assigned type number internally, which is used to compute
state IDs for runtime chunk storage. However, this is not directly exposed to
plugins, and is fully dynamic.
FastChunkSerializer, instead of directly passing state IDs to the next thread,
now deconstructs state IDs into their type number and state data componets,
and writes a string type name + state data separately. This allows the blocks
to be consistently decoded on the destination thread, particularly when custom
blocks are involved, as custom blocks are expected to claim unique string type
IDs

Plugins implementing custom blocks **may** use their Minecraft save ID as their
type ID, however this is not required. A type ID must, however, be globally
unique and must not conflict with any other blocks.

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

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

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

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

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

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

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

instead we check for isTerminated and then get the crash info outside
of the synchronized block.
2025-08-06 15:49:52 +01:00
c65f740ce5 Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/16710901339
2025-08-04 00:03:46 +00:00
5139800e13 BlockStateUpgrader: All but removed dependency on BlockStateData 2025-08-03 15:47:12 +01:00
329 changed files with 7445 additions and 7020 deletions

View File

@ -4,6 +4,11 @@ on:
release:
types:
- published
workflow_dispatch:
inputs:
release:
description: 'Tag name to build'
required: true
jobs:
build:
@ -28,16 +33,28 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Clone pmmp/PocketMine-Docker repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
repository: pmmp/PocketMine-Docker
fetch-depth: 1
- name: Get tag names
- name: Get tag name
id: tag-name
run: |
VERSION=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{')
echo TAG_NAME=$VERSION >> $GITHUB_OUTPUT
if [[ "${{ github.event_name }}" == "release" ]]; then
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
else
echo "Unsupported event type: ${{ github.event_name }}"
exit 1
fi
- name: Parse version
id: version
run: |
VERSION="${{ steps.tag-name.outputs.TAG_NAME }}"
echo MAJOR=$(echo $VERSION | cut -d. -f1) >> $GITHUB_OUTPUT
echo MINOR=$(echo $VERSION | cut -d. -f1-2) >> $GITHUB_OUTPUT
@ -71,8 +88,8 @@ jobs:
push: true
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MAJOR }}
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MAJOR }}
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MAJOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}
@ -84,8 +101,8 @@ jobs:
push: true
context: ./pocketmine-mp
tags: |
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.tag-name.outputs.MINOR }}
${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MINOR }}
ghcr.io/${{ steps.docker-repo-name.outputs.NAME }}:${{ steps.version.outputs.MINOR }}
build-args: |
PMMP_TAG=${{ steps.tag-name.outputs.TAG_NAME }}
PMMP_REPO=${{ github.repository }}

View File

@ -18,7 +18,7 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0
@ -41,7 +41,7 @@ jobs:
run: composer install --prefer-dist --no-interaction
- name: Clone extension stubs
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
repository: pmmp/phpstorm-stubs
path: extension-stubs

View File

@ -4,16 +4,21 @@ on:
release:
types:
- published
workflow_dispatch:
inputs:
release:
description: 'Release to make notification for'
required: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.34.1
uses: shivammathur/setup-php@2.35.3
with:
php-version: 8.3
@ -30,9 +35,17 @@ jobs:
- name: Install Composer dependencies
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
- name: Get actual tag name
- name: Get tag name
id: tag-name
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
run: |
if [[ "${{ github.event_name }}" == "release" ]]; then
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
else
echo "Unsupported event type: ${{ github.event_name }}"
exit 1
fi
- name: Run webhook post script
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }} ${{ secrets.DISCORD_NEWS_PING_ROLE_ID }}

View File

@ -30,7 +30,7 @@ jobs:
valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Check IS_DEVELOPMENT_BUILD flag
id: validate
@ -46,10 +46,10 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP
uses: shivammathur/setup-php@2.34.1
uses: shivammathur/setup-php@2.35.3
with:
php-version: 8.3

View File

@ -82,12 +82,12 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: true
- name: Setup PHP
uses: shivammathur/setup-php@2.34.1
uses: shivammathur/setup-php@2.35.3
with:
php-version: ${{ env.PHP_VERSION }}

View File

@ -27,7 +27,7 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0
@ -59,7 +59,7 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0
@ -91,7 +91,7 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: true
@ -125,7 +125,7 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP
uses: pmmp/setup-php-action@3.2.0

View File

@ -25,10 +25,10 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup PHP and tools
uses: shivammathur/setup-php@2.34.1
uses: shivammathur/setup-php@2.35.3
with:
php-version: 8.3
tools: php-cs-fixer:3.75
@ -45,7 +45,7 @@ jobs:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@2.0.0

View File

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

25
changelogs/5.32.md Normal file
View File

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

129
changelogs/5.33.md Normal file
View File

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

View File

@ -34,16 +34,16 @@
"adhocore/json-comment": "~1.2.0",
"netresearch/jsonmapper": "~v5.0.0",
"pocketmine/bedrock-block-upgrade-schema": "~5.1.0+bedrock-1.21.60",
"pocketmine/bedrock-data": "~5.2.0+bedrock-1.21.93",
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
"pocketmine/bedrock-protocol": "~39.1.0+bedrock-1.21.93",
"pocketmine/bedrock-data": "~6.0.0+bedrock-1.21.100",
"pocketmine/bedrock-item-upgrade-schema": "~1.15.0+bedrock-1.21.100",
"pocketmine/bedrock-protocol": "~40.0.0+bedrock-1.21.100",
"pocketmine/binaryutils": "^0.2.1",
"pocketmine/callback-validator": "^1.0.2",
"pocketmine/callback-validator": "dev-rewrite",
"pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.7.0",
"pocketmine/locale-data": "~2.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",

92
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "3609ef73f066fbcfc0593d8aa6c94a51",
"content-hash": "deb7c003ba4a6101153256d5d590da42",
"packages": [
{
"name": "adhocore/json-comment",
@ -204,16 +204,16 @@
},
{
"name": "pocketmine/bedrock-data",
"version": "5.2.0+bedrock-1.21.93",
"version": "6.0.0+bedrock-1.21.100",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockData.git",
"reference": "740e18e490c6a102b774518ff2224a06762bcaf8"
"reference": "edc0d829175e5e1e57c87001acfd03526c63fd34"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/740e18e490c6a102b774518ff2224a06762bcaf8",
"reference": "740e18e490c6a102b774518ff2224a06762bcaf8",
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/edc0d829175e5e1e57c87001acfd03526c63fd34",
"reference": "edc0d829175e5e1e57c87001acfd03526c63fd34",
"shasum": ""
},
"type": "library",
@ -224,22 +224,22 @@
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/BedrockData/issues",
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.93"
"source": "https://github.com/pmmp/BedrockData/tree/6.0.0+bedrock-1.21.100"
},
"time": "2025-07-08T12:30:28+00:00"
"time": "2025-08-30T17:25:42+00:00"
},
{
"name": "pocketmine/bedrock-item-upgrade-schema",
"version": "1.14.0",
"version": "1.15.0",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
"reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb"
"reference": "09e0dbe9743f21a76b1fe04b2b4136785775f52b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/9fc7c9bbb558a017395c1cb7dd819c033ee971bb",
"reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb",
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/09e0dbe9743f21a76b1fe04b2b4136785775f52b",
"reference": "09e0dbe9743f21a76b1fe04b2b4136785775f52b",
"shasum": ""
},
"type": "library",
@ -250,22 +250,22 @@
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
"support": {
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.14.0"
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.15.0"
},
"time": "2024-12-04T12:22:49+00:00"
"time": "2025-08-06T15:08:48+00:00"
},
{
"name": "pocketmine/bedrock-protocol",
"version": "39.1.0+bedrock-1.21.93",
"version": "40.0.0+bedrock-1.21.100",
"source": {
"type": "git",
"url": "https://github.com/pmmp/BedrockProtocol.git",
"reference": "e9bc5fb691d18dab229a158462c13f0c6fea79c8"
"reference": "5e95cab3a6e6c24920e0c25ca4aaf887ed4b70ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/e9bc5fb691d18dab229a158462c13f0c6fea79c8",
"reference": "e9bc5fb691d18dab229a158462c13f0c6fea79c8",
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/5e95cab3a6e6c24920e0c25ca4aaf887ed4b70ca",
"reference": "5e95cab3a6e6c24920e0c25ca4aaf887ed4b70ca",
"shasum": ""
},
"require": {
@ -296,9 +296,9 @@
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
"support": {
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
"source": "https://github.com/pmmp/BedrockProtocol/tree/39.1.0+bedrock-1.21.93"
"source": "https://github.com/pmmp/BedrockProtocol/tree/40.0.0+bedrock-1.21.100"
},
"time": "2025-07-08T12:31:39+00:00"
"time": "2025-08-06T15:13:45+00:00"
},
{
"name": "pocketmine/binaryutils",
@ -344,30 +344,30 @@
},
{
"name": "pocketmine/callback-validator",
"version": "1.0.3",
"version": "dev-rewrite",
"source": {
"type": "git",
"url": "https://github.com/pmmp/CallbackValidator.git",
"reference": "64787469766bcaa7e5885242e85c23c25e8c55a2"
"reference": "4b9b375590872cdd98a2a07c5aa0e1e99af5ceda"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/CallbackValidator/zipball/64787469766bcaa7e5885242e85c23c25e8c55a2",
"reference": "64787469766bcaa7e5885242e85c23c25e8c55a2",
"url": "https://api.github.com/repos/pmmp/CallbackValidator/zipball/4b9b375590872cdd98a2a07c5aa0e1e99af5ceda",
"reference": "4b9b375590872cdd98a2a07c5aa0e1e99af5ceda",
"shasum": ""
},
"require": {
"ext-reflection": "*",
"php": "^7.1 || ^8.0"
"php": "^8.1"
},
"replace": {
"daverandom/callback-validator": "*"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "0.12.59",
"phpstan/phpstan-strict-rules": "^0.12.4",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
"phpstan/phpstan": "2.1.0",
"phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^9.0 || ^10.0 || ^11.0"
},
"type": "library",
"autoload": {
@ -388,9 +388,9 @@
"description": "Fork of daverandom/callback-validator - Tools for validating callback signatures",
"support": {
"issues": "https://github.com/pmmp/CallbackValidator/issues",
"source": "https://github.com/pmmp/CallbackValidator/tree/1.0.3"
"source": "https://github.com/pmmp/CallbackValidator/tree/rewrite"
},
"time": "2020-12-11T01:45:37+00:00"
"time": "2025-01-03T17:50:24+00:00"
},
{
"name": "pocketmine/color",
@ -535,27 +535,27 @@
},
{
"name": "pocketmine/math",
"version": "1.0.0",
"version": "dev-major-next",
"source": {
"type": "git",
"url": "https://github.com/pmmp/Math.git",
"reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf"
"reference": "7513b9504e4a9d3ebde2f9d4de50266cb1dafd23"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/Math/zipball/dc132d93595b32e9f210d78b3c8d43c662a5edbf",
"reference": "dc132d93595b32e9f210d78b3c8d43c662a5edbf",
"url": "https://api.github.com/repos/pmmp/Math/zipball/7513b9504e4a9d3ebde2f9d4de50266cb1dafd23",
"reference": "7513b9504e4a9d3ebde2f9d4de50266cb1dafd23",
"shasum": ""
},
"require": {
"php": "^8.0",
"php": "^8.2",
"php-64bit": "*"
},
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "~1.10.3",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^8.5 || ^9.5"
"phpstan/phpstan": "2.1.0",
"phpstan/phpstan-strict-rules": "^2.0",
"phpunit/phpunit": "^10.0 || ^11.0"
},
"type": "library",
"autoload": {
@ -570,9 +570,9 @@
"description": "PHP library containing math related code used in PocketMine-MP",
"support": {
"issues": "https://github.com/pmmp/Math/issues",
"source": "https://github.com/pmmp/Math/tree/1.0.0"
"source": "https://github.com/pmmp/Math/tree/major-next"
},
"time": "2023-08-03T12:56:33+00:00"
"time": "2025-08-29T18:29:53+00:00"
},
{
"name": "pocketmine/nbt",
@ -2724,9 +2724,19 @@
"time": "2024-03-03T12:36:25+00:00"
}
],
"aliases": [],
"aliases": [
{
"package": "pocketmine/math",
"version": "dev-major-next",
"alias": "1.0.0",
"alias_normalized": "1.0.0.0"
}
],
"minimum-stability": "stable",
"stability-flags": {},
"stability-flags": {
"pocketmine/callback-validator": 20,
"pocketmine/math": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {

View File

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

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

@ -27,6 +27,7 @@ use pocketmine\block\inventory\AnvilInventory;
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\SupportType;
use pocketmine\data\runtime\RuntimeDataDescriber;
@ -57,7 +58,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,14 +73,14 @@ 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{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player instanceof Player){
$player->setCurrentWindow(new AnvilInventory($this->position));
}
@ -87,9 +88,9 @@ class Anvil extends Transparent implements Fallable, HorizontalFacing{
return true;
}
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

@ -40,7 +40,7 @@ class Barrel extends Opaque implements AnyFacing{
protected bool $open = false;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->facing($this->facing);
$w->enum($this->facing);
$w->bool($this->open);
}
@ -54,7 +54,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,7 +74,7 @@ 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{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player instanceof Player){
$barrel = $this->position->getWorld()->getTile($this->position);
if($barrel instanceof TileBarrel){

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;
@ -50,6 +51,10 @@ abstract class BaseBanner extends Transparent implements Colored{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBanner){
if($tile->getType() === TileBanner::TYPE_OMINOUS){
//illager banner is implemented as a separate block, as it doesn't support base color or custom patterns
return $this->getOminousVersion();
}
$this->color = $tile->getBaseColor();
$this->setPatterns($tile->getPatterns());
}
@ -57,6 +62,13 @@ abstract class BaseBanner extends Transparent implements Colored{
return $this;
}
/**
* TODO: make this abstract in PM6 (BC break)
*/
protected function getOminousVersion() : Block{
return VanillaBlocks::AIR();
}
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
@ -101,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;
}
@ -109,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;
}
@ -121,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

@ -0,0 +1,91 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Banner as TileBanner;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function assert;
abstract class BaseOminousBanner extends Transparent{
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileBanner);
$tile->setBaseColor(DyeColor::WHITE);
$tile->setPatterns([]);
$tile->setType(TileBanner::TYPE_OMINOUS);
}
public function isSolid() : bool{
return false;
}
public function getMaxStackSize() : int{
return 16;
}
public function getFuelTime() : int{
return 300;
}
protected function recalculateCollisionBoxes() : array{
return [];
}
public function getSupportType(Facing $facing) : SupportType{
return SupportType::NONE;
}
private function canBeSupportedBy(Block $block) : bool{
return $block->isSolid();
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
abstract protected function getSupportingFace() : Facing;
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function asItem() : Item{
return VanillaItems::OMINOUS_BANNER();
}
}

View File

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

View File

@ -35,6 +35,7 @@ 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;
@ -99,11 +100,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 +112,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();
}
@ -160,7 +161,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;
}

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

@ -65,10 +65,10 @@ class Block{
/**
* @internal
* Hardcoded int is `Binary::readLong(hash('xxh3', Binary::writeLLong(BlockTypeIds::AIR), binary: true))`
* Hardcoded int is `Binary::readLong(hash('xxh3', Binary::writeLLong(BlockTypeIds::AIR_TYPE_NUMBER), binary: true))`
* TODO: it would be much easier if we could just make this 0 or some other easy value
*/
public const EMPTY_STATE_ID = (BlockTypeIds::AIR << self::INTERNAL_STATE_DATA_BITS) | (-7482769108513497636 & self::INTERNAL_STATE_DATA_MASK);
public const EMPTY_STATE_ID = (BlockIdentifier::AIR_TYPE_NUMBER << self::INTERNAL_STATE_DATA_BITS) | (-7482769108513497636 & self::INTERNAL_STATE_DATA_MASK);
protected BlockIdentifier $idInfo;
protected string $fallbackName;
@ -97,7 +97,7 @@ class Block{
* The type ID is included in the XOR mask. This is not necessary to improve distribution, but it reduces the number
* of operations required to compute the state ID (micro optimization).
*/
private static function computeStateIdXorMask(int $typeId) : int{
public static function computeStateIdXorMask(int $typeId) : int{
return
$typeId << self::INTERNAL_STATE_DATA_BITS |
(Binary::readLong(hash('xxh3', Binary::writeLLong($typeId), binary: true)) & self::INTERNAL_STATE_DATA_MASK);
@ -120,7 +120,7 @@ class Block{
$this->describeBlockOnlyState($calculator);
$this->requiredBlockOnlyStateDataBits = $calculator->getBitsUsed();
$this->stateIdXorMask = self::computeStateIdXorMask($idInfo->getBlockTypeId());
$this->stateIdXorMask = self::computeStateIdXorMask($idInfo->getBlockTypeNumber());
//this must be done last, otherwise the defaultState could have uninitialized fields
$defaultState = clone $this;
@ -156,7 +156,7 @@ class Block{
*
* @see BlockTypeIds
*/
public function getTypeId() : int{
public function getTypeId() : string{
return $this->idInfo->getBlockTypeId();
}
@ -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

@ -27,22 +27,27 @@ use pocketmine\block\tile\Tile;
use pocketmine\utils\Utils;
class BlockIdentifier{
private int $typeNumber;
/**
* @phpstan-param class-string<Tile>|null $tileClass
*/
public function __construct(
private int $blockTypeId,
private string $blockTypeId,
private ?string $tileClass = null
){
if($blockTypeId < 0){
throw new \InvalidArgumentException("Block type ID may not be negative");
}
$this->typeNumber = self::lookupTypeNumberFromTypeId($this->blockTypeId);
if($tileClass !== null){
Utils::testValidInstance($tileClass, Tile::class);
}
}
public function getBlockTypeId() : int{ return $this->blockTypeId; }
public function getBlockTypeId() : string{ return $this->blockTypeId; }
/**
* @internal
*/
public function getBlockTypeNumber() : int{ return $this->typeNumber; }
/**
* @phpstan-return class-string<Tile>|null
@ -50,4 +55,52 @@ class BlockIdentifier{
public function getTileClass() : ?string{
return $this->tileClass;
}
public const AIR_TYPE_NUMBER = 10000;
private static int $nextTypeNumber = self::AIR_TYPE_NUMBER + 1; //fixed ID reserved for air, for Block::EMPTY_STATE_ID
/**
* @var int[]
* @phpstan-var array<string, int>
*/
private static $typeIdToTypeNumber = [];
/**
* @var string[]
* @phpstan-var array<int, string>
*/
private static $typeNumberToTypeId = [];
/**
* @var int[]
* @phpstan-var array<int, int>
*/
private static $typeIdXorMasks = [];
public static function firstUnusedTypeNumber() : int{
return self::$nextTypeNumber;
}
private static function claimTypeId(string $typeId) : int{
if(isset(self::$typeIdToTypeNumber[$typeId])){
throw new \InvalidArgumentException("Type ID \"$typeId\" has already been claimed");
}
$typeNumber = $typeId === BlockTypeIds::AIR ? self::AIR_TYPE_NUMBER : self::$nextTypeNumber++;
self::$typeIdToTypeNumber[$typeId] = $typeNumber;
self::$typeNumberToTypeId[$typeNumber] = $typeId;
self::$typeIdXorMasks[$typeNumber] = Block::computeStateIdXorMask($typeNumber);
return $typeNumber;
}
public static function lookupTypeNumberFromTypeId(string $typeId) : int{
return self::$typeIdToTypeNumber[$typeId] ??= self::claimTypeId($typeId);
}
public static function stateIdXorMask(int $typeId) : int{
return self::$typeIdXorMasks[$typeId];
}
public static function lookupTypeIdFromTypeNumber(int $typeNumber) : string{
return self::$typeNumberToTypeId[$typeNumber] ?? throw new \InvalidArgumentException("Unknown type number $typeNumber (probably not registered on this thread?)");
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -51,17 +51,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,7 +95,7 @@ class BrewingStand extends Transparent{
return $this;
}
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $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())){

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

@ -26,6 +26,7 @@ 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;
@ -127,12 +128,12 @@ 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)];
}
/**
@ -171,18 +172,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();

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

@ -25,12 +25,13 @@ namespace pocketmine\block;
use pocketmine\block\inventory\CartographyTableInventory;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
final class CartographyTable extends Opaque{
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player !== null){
$player->setCurrentWindow(new CartographyTableInventory($this->position));
}

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

@ -0,0 +1,61 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SignLikeRotation;
use pocketmine\block\utils\SignLikeRotationTrait;
use pocketmine\block\utils\StaticSupportTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class CeilingCenterHangingSign extends BaseSign implements SignLikeRotation{
use SignLikeRotationTrait;
use StaticSupportTrait;
protected function getSupportingFace() : Facing{
return Facing::UP;
}
//TODO: duplicated code :(
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::DOWN){
return false;
}
if($player !== null){
$this->rotation = self::getRotationFromYaw($player->getLocation()->getYaw());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
private function canBeSupportedAt(Block $block) : bool{
$supportBlock = $block->getSide(Facing::UP);
return
$supportBlock->getSupportType(Facing::DOWN)->hasCenterSupport() ||
$supportBlock->hasTypeTag(BlockTypeTags::HANGING_SIGN);
}
}

View File

@ -0,0 +1,69 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class CeilingEdgesHangingSign extends BaseSign implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : Facing{
return Facing::UP;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::DOWN){
return false;
}
if($player !== null){
$this->facing = HorizontalFacingOption::fromFacing(Facing::opposite($player->getHorizontalFacing()));
}
if(!$this->canBeSupportedAt($blockReplace)){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedAt($this)){
$this->position->getWorld()->useBreakOn($this->position);
}
}
private function canBeSupportedAt(Block $block) : bool{
$supportBlock = $block->getSide(Facing::UP);
return
$supportBlock->getSupportType(Facing::DOWN) === SupportType::FULL ||
(($supportBlock instanceof WallHangingSign || $supportBlock instanceof CeilingEdgesHangingSign) && Facing::axis($supportBlock->getFacing()->toFacing()) === Facing::axis($this->facing->toFacing()));
}
}

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

@ -39,10 +39,10 @@ class Chest 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;
}
@ -51,7 +51,7 @@ class Chest extends Transparent implements HorizontalFacing{
$tile = $world->getTile($this->position);
if($tile instanceof TileChest){
foreach([false, true] as $clockwise){
$side = Facing::rotateY($this->facing, $clockwise);
$side = Facing::rotateY($this->facing->toFacing(), $clockwise);
$c = $this->getSide($side);
if($c instanceof Chest && $c->hasSameTypeId($this) && $c->facing === $this->facing){
$pair = $world->getTile($c->position);
@ -70,7 +70,7 @@ class Chest 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 instanceof Player){
$chest = $this->position->getWorld()->getTile($this->position);

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());
}
@ -114,6 +114,18 @@ class ChiseledBookshelf extends Opaque implements HorizontalFacing{
return $this->slots;
}
/**
* @param ChiseledBookshelfSlot[] $slots
* @return $this
*/
public function setSlots(array $slots) : self{
$this->slots = [];
foreach($slots as $slot){
$this->setSlot($slot, true);
}
return $this;
}
/**
* Returns the last slot interacted by a player or null if no slot has been interacted with yet.
*/
@ -131,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

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

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

@ -34,14 +34,14 @@ use pocketmine\player\Player;
class EnchantingTable extends Transparent{
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{
public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
if($player instanceof Player){
//TODO lock

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

@ -43,14 +43,14 @@ 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{
public function onInteract(Item $item, Facing $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()){

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

@ -34,11 +34,15 @@ use pocketmine\world\BlockTransaction;
final class FloorBanner extends BaseBanner implements SignLikeRotation{
use SignLikeRotationTrait;
protected function getSupportingFace() : int{
protected function getOminousVersion() : Block{
return VanillaBlocks::OMINOUS_BANNER()->setRotation($this->rotation);
}
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;
}

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

@ -25,16 +25,18 @@ namespace pocketmine\block;
use pocketmine\block\tile\Furnace as TileFurnace;
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\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use function mt_rand;
class Furnace extends Opaque implements Lightable{
class Furnace extends Opaque implements Lightable, HorizontalFacing{
use FacesOppositePlacingPlayerTrait;
use LightableTrait;
@ -46,7 +48,7 @@ class Furnace extends Opaque implements Lightable{
}
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
$w->horizontalFacing($this->facing);
$w->enum($this->facing);
$w->bool($this->lit);
}
@ -58,7 +60,7 @@ class Furnace extends Opaque implements Lightable{
return $this->lit ? 13 : 0;
}
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){
$furnace = $this->position->getWorld()->getTile($this->position);
if($furnace instanceof TileFurnace && $furnace->canOpenWith($item->getCustomName())){

View File

@ -24,8 +24,8 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\BlockEventHelper;
use pocketmine\block\utils\MultiAnyFacing;
use pocketmine\block\utils\MultiAnySupportTrait;
use pocketmine\block\utils\MultiFacing;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Fertilizer;
use pocketmine\item\Item;
@ -36,7 +36,7 @@ use pocketmine\world\World;
use function count;
use function shuffle;
class GlowLichen extends Transparent implements MultiFacing{
class GlowLichen extends Transparent implements MultiAnyFacing{
use MultiAnySupportTrait;
public function getLightLevel() : int{
@ -51,7 +51,7 @@ class GlowLichen extends Transparent implements MultiFacing{
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 MultiFacing{
}
/**
* @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 MultiFacing{
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 MultiFacing{
}
/**
* @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 MultiFacing{
}
}
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 MultiFacing{
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 MultiFacing{
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 MultiFacing{
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

@ -38,17 +38,17 @@ use pocketmine\world\BlockTransaction;
class Hopper extends Transparent implements PoweredByRedstone{
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 +58,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,13 +75,13 @@ 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{
public function onInteract(Item $item, Facing $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

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

@ -27,13 +27,14 @@ use pocketmine\block\inventory\LoomInventory;
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 Loom 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{
if($player !== null){
$player->setCurrentWindow(new LoomInventory($this->position));
return true;

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

@ -0,0 +1,53 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SignLikeRotation;
use pocketmine\block\utils\SignLikeRotationTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class OminousFloorBanner extends BaseOminousBanner implements SignLikeRotation{
use SignLikeRotationTrait;
//TODO: duplicated code :(
protected function getSupportingFace() : Facing{
return Facing::DOWN;
}
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;
}
if($player !== null){
$this->rotation = self::getRotationFromYaw($player->getLocation()->getYaw());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -0,0 +1,50 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingOption;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class OminousWallBanner extends BaseOminousBanner implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : Facing{
return Facing::opposite($this->facing->toFacing());
}
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 = $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;

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