mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-09-11 12:08:05 +00:00
Compare commits
75 Commits
command-al
...
new-auth
Author | SHA1 | Date | |
---|---|---|---|
95bbca7c33 | |||
1bdd1c380d | |||
2d7d2223c0 | |||
fecdbe6bd2 | |||
f913f79da1 | |||
b867e21be2 | |||
87ffb9ac89 | |||
82dceaaf38 | |||
094196cbf8 | |||
c5d017208d | |||
b3170913f7 | |||
dc04992ba9 | |||
bddab47ee8 | |||
3411103e11 | |||
1868536916 | |||
9a0a8a55b1 | |||
09cc76ae2b | |||
a540de1e3c | |||
9eee1a9a6e | |||
f673159471 | |||
831c5a0464 | |||
5c363965f0 | |||
95679b5a29 | |||
f1b1e1977e | |||
23d612f1af | |||
8f7e16a9ad | |||
beaedc3627 | |||
48ba334218 | |||
0be15a7403 | |||
2404d63b1f | |||
dd9030f1f5 | |||
de234d1f38 | |||
db54c481aa | |||
ac2c07c3fe | |||
ec56d65bcc | |||
c548923116 | |||
4a2c7dc684 | |||
f04c458e54 | |||
5c0a109f18 | |||
31f6f5d252 | |||
0e498720bd | |||
00d6171463 | |||
be90c6c399 | |||
17ecf11a1b | |||
93e33dad8e | |||
4cdf064344 | |||
5bf0cbec87 | |||
ef53676a59 | |||
8f9478e82f | |||
7c521b456e | |||
47140cb8d7 | |||
e824266457 | |||
2bb78f2a94 | |||
547544b5b4 | |||
eea4f40138 | |||
237ac0f802 | |||
431790a319 | |||
c0fad353a2 | |||
e89523ce66 | |||
1e8612cfc8 | |||
cb7a562c8b | |||
edb8dcbe90 | |||
f633416f05 | |||
442049d564 | |||
cce55e8939 | |||
e375437439 | |||
c417ecd30d | |||
1f87c67e37 | |||
11612ed0e2 | |||
959fd7e5e6 | |||
0b9e680753 | |||
275fdc4280 | |||
173b685b02 | |||
89d18f929f | |||
5139800e13 |
33
.github/workflows/build-docker-image.yml
vendored
33
.github/workflows/build-docker-image.yml
vendored
@ -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 }}
|
||||
|
4
.github/workflows/copilot-setup-steps.yml
vendored
4
.github/workflows/copilot-setup-steps.yml
vendored
@ -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
|
||||
|
23
.github/workflows/discord-release-notify.yml
vendored
23
.github/workflows/discord-release-notify.yml
vendored
@ -4,18 +4,23 @@ on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release:
|
||||
description: 'Release to make notification for'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.34.1
|
||||
uses: shivammathur/setup-php@2.35.4
|
||||
with:
|
||||
php-version: 8.3
|
||||
php-version: 8.2
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
@ -30,9 +35,17 @@ jobs:
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
|
||||
|
||||
- name: Get actual tag name
|
||||
- name: Get tag name
|
||||
id: tag-name
|
||||
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "release" ]]; then
|
||||
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Unsupported event type: ${{ github.event_name }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Run webhook post script
|
||||
run: php .github/workflows/discord-release-embed.php ${{ github.repository }} ${{ steps.tag-name.outputs.TAG_NAME }} ${{ github.token }} ${{ secrets.DISCORD_RELEASE_WEBHOOK }} ${{ secrets.DISCORD_NEWS_PING_ROLE_ID }}
|
||||
|
8
.github/workflows/draft-release-pr-check.yml
vendored
8
.github/workflows/draft-release-pr-check.yml
vendored
@ -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,12 +46,12 @@ 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.4
|
||||
with:
|
||||
php-version: 8.3
|
||||
php-version: 8.2
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
|
6
.github/workflows/draft-release.yml
vendored
6
.github/workflows/draft-release.yml
vendored
@ -18,7 +18,7 @@ on:
|
||||
- "*"
|
||||
|
||||
env:
|
||||
PHP_VERSION: "8.3"
|
||||
PHP_VERSION: "8.2"
|
||||
|
||||
jobs:
|
||||
skip:
|
||||
@ -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.4
|
||||
with:
|
||||
php-version: ${{ env.PHP_VERSION }}
|
||||
|
||||
|
8
.github/workflows/main-php-matrix.yml
vendored
8
.github/workflows/main-php-matrix.yml
vendored
@ -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
|
||||
|
8
.github/workflows/main.yml
vendored
8
.github/workflows/main.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php: ["8.3"]
|
||||
php: ["8.1", "8.2", "8.3", "8.4"]
|
||||
|
||||
uses: ./.github/workflows/main-php-matrix.yml
|
||||
with:
|
||||
@ -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.4
|
||||
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
|
||||
|
19
.github/workflows/update-updater-api.yml
vendored
19
.github/workflows/update-updater-api.yml
vendored
@ -4,6 +4,11 @@ on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release:
|
||||
description: 'Release to publish info for'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -14,14 +19,22 @@ jobs:
|
||||
- name: Install jq
|
||||
run: sudo apt update && sudo apt install jq -y
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
repository: ${{ github.repository_owner }}/update.pmmp.io
|
||||
ssh-key: ${{ secrets.UPDATE_PMMP_IO_DEPLOY_KEY }}
|
||||
|
||||
- name: Get actual tag name
|
||||
- name: Get tag name
|
||||
id: tag-name
|
||||
run: echo TAG_NAME=$(echo "${{ github.ref }}" | sed 's{^refs/tags/{{') >> $GITHUB_OUTPUT
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "release" ]]; then
|
||||
echo TAG_NAME="${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||
echo TAG_NAME="${{ github.event.inputs.release }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Unsupported event type: ${{ github.event_name }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download new release information
|
||||
run: curl -f -L ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.tag-name.outputs.TAG_NAME }}/build_info.json -o new_build_info.json
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "tests/plugins/DevTools"]
|
||||
path = tests/plugins/DevTools
|
||||
url = https://github.com/pmmp/DevTools.git
|
||||
[submodule "build/php"]
|
||||
path = build/php
|
||||
url = https://github.com/pmmp/php-build-scripts.git
|
||||
|
@ -5,7 +5,7 @@ $finder = PhpCsFixer\Finder::create()
|
||||
->in(__DIR__ . '/build')
|
||||
->in(__DIR__ . '/tests')
|
||||
->in(__DIR__ . '/tools')
|
||||
|
||||
->notPath('plugins/DevTools')
|
||||
//JsonMapper will break if the FQNs in the doc comments for these are shortened :(
|
||||
->notPath('crafting/json')
|
||||
->notPath('inventory/json')
|
||||
|
Submodule build/php updated: ce1b095a9c...b839e5227b
25
changelogs/5.32.md
Normal file
25
changelogs/5.32.md
Normal file
@ -0,0 +1,25 @@
|
||||
# 5.32.0
|
||||
Released 6th August 2025.
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.100.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.100.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed deadlock on RakLib thread crash (e.g. due to port binding failure).
|
||||
|
||||
# 5.32.1
|
||||
Released 14th August 2025.
|
||||
|
||||
## Fixes
|
||||
- Hardened checks when processing resource pack sending during player logins.
|
||||
- Fixed content log warning about crafting recipe with missing ID.
|
||||
- Fixed packets in a batch still being processed after one of them caused the session to be terminated.
|
135
changelogs/5.33.md
Normal file
135
changelogs/5.33.md
Normal file
@ -0,0 +1,135 @@
|
||||
# 5.33.0
|
||||
Released 30th August 2025.
|
||||
|
||||
This is a minor feature release containing internals improvements, API improvements and new gameplay features.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Performance
|
||||
- Worlds now remember when a chunk isn't generated. This reduces world I/O during world generation.
|
||||
- `BlockObjectToStateSerializer` now creates fewer objects in certain cases.
|
||||
|
||||
## Gameplay
|
||||
- The following blocks have been added and/or are now properly supported:
|
||||
- Hanging signs
|
||||
- Illager banners
|
||||
|
||||
## Tools
|
||||
- `generate-bedrock-data-from-packets.php` now represents items as strings directly when only an ID is present. This significantly improves readability in `BedrockData` and reduces file sizes.
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- Added (and implemented) interfaces for many common block properties, to allow `instanceof` to be used:
|
||||
- `Ageable`: for blocks with age, such as crops
|
||||
- `AnyFacing`: for blocks which can face up, down, and horizontal directions (not the same as `HorizontalFacing`!)
|
||||
- `Colored`: for blocks with 16 `DyeColor` variants
|
||||
- `CoralMaterial`: for coral blocks, provides access to coral type and dead/alive
|
||||
- `HorizontalFacing`: for blocks which can **only** face horizontal directions (not the same as `AnyFacing`!)
|
||||
- `Lightable`: for light-source blocks which can be turned on and off, e.g. redstone lamp
|
||||
- `MultiAnyFacing`: for blocks which can appear in multiple faces of the same block (including up, down, and horizontal faces), e.g. glow lichen
|
||||
- `PillarRotation`: for blocks which can be oriented on an axis, e.g. logs
|
||||
- `PoweredByRedstone`: for blocks which receive power from a redstone component, e.g. redstone lamp
|
||||
- `SignLikeRotation`: for blocks which can be rotated 16 ways, e.g. signs, banners
|
||||
- `WoodMaterial`: for blocks made from wood
|
||||
- These interfaces have been implemented on many blocks. For the sake of brevity, they are not listed here, but you can expect to see them wherever the corresponding traits were used.
|
||||
- The following classes have been added:
|
||||
- `BaseOminousBanner`
|
||||
- `CeilingCenterHangingSign` - both chains connected to the same point on the block above, can face 16 directions
|
||||
- `CeilingEdgesHangingSign` - each chain connected to separate edges of the block above, can face 4 directions
|
||||
- `OminousFloorBanner` - floor version of illager banner, can face 16 directions
|
||||
- `OminousWallBanner` - wall version of illager banner, can face 4 directions
|
||||
- `WallHangingSign` - hangs from a horizontal beam, can face 4 directions
|
||||
- The following API methods have been added:
|
||||
- `public ChiseledBookshelf->setSlots(list<ChiseledBookshelfSlot> $slots) : $this`
|
||||
- `public static VanillaBlocks` methods:
|
||||
- `ACACIA_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `ACACIA_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `ACACIA_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `BIRCH_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `BIRCH_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `BIRCH_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `CHERRY_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `CHERRY_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `CHERRY_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `CRIMSON_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `CRIMSON_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `CRIMSON_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `DARK_OAK_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `DARK_OAK_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `DARK_OAK_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `JUNGLE_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `JUNGLE_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `JUNGLE_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `MANGROVE_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `MANGROVE_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `MANGROVE_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `OAK_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `OAK_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `OAK_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `OMINOUS_FLOOR_BANNER() : OminousFloorBanner`
|
||||
- `OMINOUS_WALL_BANNER() : OminousWallBanner`
|
||||
- `PALE_OAK_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `PALE_OAK_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `PALE_OAK_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `SPRUCE_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `SPRUCE_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `SPRUCE_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `WARPED_CEILING_CENTER_HANGING_SIGN() : CeilingCenterHangingSign`
|
||||
- `WARPED_CEILING_EDGES_HANGING_SIGN() : CeilingEdgesHangingSign`
|
||||
- `WARPED_WALL_HANGING_SIGN() : WallHangingSign`
|
||||
- `public AgeableTrait->getMaxAge() : int` (included by all growable plant-like blocks, e.g. crops)
|
||||
|
||||
### `pocketmine\data\bedrock\block\convert`
|
||||
- A new system for symmetric block serializers and deserializers has been introduced.
|
||||
- This allows registering both a serializer and a deserializer with the same code, meaning way less code
|
||||
- It also eliminates information duplication and potential inconsistencies, improving maintainability.
|
||||
- A proper way to deal with flattened IDs (e.g. color blocks) has been introduced which _doesn't_ require hardcoding a giant mess of IDs
|
||||
- This symmetric system covers 99% of blocks which have a 1:1 association between PM and vanilla blocks, or 1:N where IDs are flattened
|
||||
- However, there are still some special cases which require registering separate serializers and deserializers (usually in cases where the PM implementation deviates from Mojang where Mojang's implementation sucks, such as hanging signs or big dripleaf).
|
||||
- No backwards compatibility breaks are expected as a result of this change. However, it's recommended to migrate old code to this new system for maintainability.
|
||||
- The following new classes have been added:
|
||||
- `BlockSerializerDeserializerRegistrar` - handles unified registration of block serializers and deserializers, based on a provided block model
|
||||
- `FlattenedIdModel` - represents a block with some properties baked into its Minecraft ID, e.g. coral or color blocks
|
||||
- `Model` - represents a regular block with all properties in its `states` NBT
|
||||
- `property\BoolFromStringProperty<TBlock>` - property mapping a bool value from a string NBT state
|
||||
- `property\BoolProperty<TBlock>`
|
||||
- `property\CommonProperties` - singleton containing commonly-used block property definitions and groups, e.g. facing, stair properties
|
||||
- `property\EnumFromRawStateMap<TEnum, TRaw>` - maps a raw NBT value to a PHP `enum` and vice versa
|
||||
- `property\IntFromRawStateMap<TRaw>` - maps a raw NBT value to PM integer constants and vice versa
|
||||
- `property\IntProperty<TBlock>` - an integer range property with a min, max, and optional offset
|
||||
- `property\Property<TBlock>` - interface implemented by all property definitions accepted by a `Model` or `FlattenedIdModel`
|
||||
- `property\StateMap<TValue, TRaw>` - interface implemented by classes accepted by mapping properties, e.g. `BoolFromStringProperty`
|
||||
- `property\StringProperty<TBlock>` - interface implemented by properties whose raw outputs are strings - these can be used as ID components in `FlattenedIdModel`
|
||||
- `property\ValueFromIntProperty<TBlock, TValue>` - property mapping a generic PM value from an int NBT state
|
||||
- `property\ValueFromStringProperty<TBlock, TValue>` - same as above, but for a string NBT state
|
||||
- `property\ValueSetFromIntProperty<TBlock, TOption>` - a property mapping an `int[]` or `enum[]` from a set of flags in NBT states
|
||||
- `property\ValueMappings` - singleton containing commonly-needed `StateMap`s
|
||||
- The following classes have been deprecated:
|
||||
- `BlockStateDeserializerHelper`
|
||||
- `BlockStateSerializerHelper`
|
||||
- The following methods have been deprecated:
|
||||
- All methods for decoding mapped property types in `BlockStateReader`, e.g. `readFacingDirection()`
|
||||
- All methods for encoding mapped property types in `BlockStateWriter`, e.g. `writeFacingDirection()`
|
||||
- All specific blocktype mapping functions in `BlockStateToObjectDeserializer`, e.g. `mapStairs()`
|
||||
- All specific blocktype mapping functions in `BlockObjectToStateSerializer`, e.g. `mapStairs()`
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following hooks have been added:
|
||||
- `public Item->getPlacementTransaction(Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : ?BlockTransaction` - allows more complex logic for itemblocks to place blocks, without duplicating their placement conditions (used for hanging signs)
|
||||
|
||||
### `pocketmine\world`
|
||||
- `World->setChunk()` now verifies that blockstate IDs in the provided chunk are all registered in `RuntimeBlockStateRegistry`. This should provide earlier detection for custom block registration errors by plugins.
|
||||
|
||||
## Internals
|
||||
- `BlockStateUpgrader` is now almost entirely independent from `BlockStateData`. It's anticipated that the upgrader library will be separable from the core in the future.
|
||||
- `Block->readStateFromWorld()` is now triggered on chunk load for any position containing a tile. This should allow more effective updating of blocks with properties in their tiles.
|
||||
|
||||
# 5.33.1
|
||||
Released 31st August 2025.
|
||||
|
||||
## Fixes
|
||||
- Fixed banners placed in prior versions getting their tiles deleted (due to missing `Type` tags).
|
@ -5,7 +5,7 @@
|
||||
"homepage": "https://pmmp.io",
|
||||
"license": "LGPL-3.0",
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"php": "^8.1",
|
||||
"php-64bit": "*",
|
||||
"ext-chunkutils2": "^0.3.1",
|
||||
"ext-crypto": "^0.3.1",
|
||||
@ -34,9 +34,9 @@
|
||||
"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": "~41.0.0+bedrock-1.21.100",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
@ -49,13 +49,13 @@
|
||||
"pocketmine/raklib-ipc": "~1.0.0",
|
||||
"pocketmine/snooze": "^0.5.0",
|
||||
"ramsey/uuid": "~4.9.0",
|
||||
"symfony/filesystem": "~7.3.0"
|
||||
"symfony/filesystem": "~6.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "2.1.17",
|
||||
"phpstan/phpstan-phpunit": "^2.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0.0",
|
||||
"phpunit/phpunit": "^12.2.1"
|
||||
"phpunit/phpunit": "^10.5.24"
|
||||
},
|
||||
"replace": {
|
||||
"symfony/polyfill-ctype": "*",
|
||||
@ -77,11 +77,12 @@
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "8.3.0"
|
||||
"php": "8.1.0"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"scripts": {
|
||||
"make-devtools": "@php -dphar.readonly=0 tests/plugins/DevTools/src/ConsoleScript.php --make ./ --relative tests/plugins/DevTools --out plugins/DevTools.phar",
|
||||
"make-server": [
|
||||
"@composer install --no-dev --classmap-authoritative --ignore-platform-reqs",
|
||||
"@php -dphar.readonly=0 build/server-phar.php"
|
||||
|
809
composer.lock
generated
809
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -4,13 +4,17 @@ includes:
|
||||
- tests/phpstan/configs/impossible-generics.neon
|
||||
- tests/phpstan/configs/php-bugs.neon
|
||||
- tests/phpstan/configs/phpstan-bugs.neon
|
||||
- tests/phpstan/configs/property-hook-sadness.neon
|
||||
- tests/phpstan/configs/reflection-class-sadness.neon
|
||||
- tests/phpstan/configs/spl-fixed-array-sucks.neon
|
||||
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||
- vendor/phpstan/phpstan-phpunit/rules.neon
|
||||
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||
|
||||
rules:
|
||||
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
|
||||
- pocketmine\phpstan\rules\DisallowDynamicNewRule
|
||||
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
|
||||
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
|
||||
- pocketmine\phpstan\rules\ExplodeLimitRule
|
||||
- pocketmine\phpstan\rules\UnsafeForeachRule
|
||||
|
@ -123,6 +123,13 @@ class MemoryManager{
|
||||
return $this->globalMemoryLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function canUseChunkCache() : bool{
|
||||
return !$this->lowMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the allowed chunk radius based on the current memory usage.
|
||||
*/
|
||||
@ -229,4 +236,13 @@ class MemoryManager{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static memory dumper accessible from any thread.
|
||||
* @deprecated
|
||||
* @see MemoryDump
|
||||
*/
|
||||
public static function dumpMemory(mixed $startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
|
||||
MemoryDump::dumpMemory($startingObject, $outputFolder, $maxNesting, $maxStringSize, $logger);
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ namespace pocketmine {
|
||||
|
||||
require_once __DIR__ . '/VersionInfo.php';
|
||||
|
||||
const MIN_PHP_VERSION = "8.3.0";
|
||||
const MIN_PHP_VERSION = "8.1.0";
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
|
@ -50,6 +50,7 @@ use pocketmine\lang\Language;
|
||||
use pocketmine\lang\LanguageNotFoundException;
|
||||
use pocketmine\lang\Translatable;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\network\mcpe\auth\AuthKeyProvider;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchPromise;
|
||||
use pocketmine\network\mcpe\compression\CompressBatchTask;
|
||||
use pocketmine\network\mcpe\compression\Compressor;
|
||||
@ -80,7 +81,6 @@ use pocketmine\player\PlayerDataLoadException;
|
||||
use pocketmine\player\PlayerDataProvider;
|
||||
use pocketmine\player\PlayerDataSaveException;
|
||||
use pocketmine\player\PlayerInfo;
|
||||
use pocketmine\plugin\FolderPluginLoader;
|
||||
use pocketmine\plugin\PharPluginLoader;
|
||||
use pocketmine\plugin\PluginEnableOrder;
|
||||
use pocketmine\plugin\PluginGraylist;
|
||||
@ -271,6 +271,7 @@ class Server{
|
||||
private int $maxPlayers;
|
||||
|
||||
private bool $onlineMode = true;
|
||||
private AuthKeyProvider $authKeyProvider;
|
||||
|
||||
private Network $network;
|
||||
private bool $networkCompressionAsync = true;
|
||||
@ -347,10 +348,6 @@ class Server{
|
||||
return $this->maxPlayers;
|
||||
}
|
||||
|
||||
public function setMaxPlayers(int $maxPlayers) : void{
|
||||
$this->maxPlayers = $maxPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the server requires that players be authenticated to Xbox Live. If true, connecting players who
|
||||
* are not logged into Xbox Live will be disconnected.
|
||||
@ -987,6 +984,8 @@ class Server{
|
||||
$this->logger->warning($this->language->translate(KnownTranslationFactory::pocketmine_server_authProperty_disabled()));
|
||||
}
|
||||
|
||||
$this->authKeyProvider = new AuthKeyProvider(new \PrefixedLogger($this->logger, "Minecraft Auth Key Provider"), $this->asyncPool);
|
||||
|
||||
if($this->configGroup->getConfigBool(ServerProperties::HARDCORE, false) && $this->getDifficulty() < World::DIFFICULTY_HARD){
|
||||
$this->configGroup->setConfigInt(ServerProperties::DIFFICULTY, World::DIFFICULTY_HARD);
|
||||
}
|
||||
@ -1034,7 +1033,6 @@ class Server{
|
||||
$this->pluginManager = new PluginManager($this, $this->configGroup->getPropertyBool(Yml::PLUGINS_LEGACY_DATA_DIR, true) ? null : Path::join($this->dataPath, "plugin_data"), $pluginGraylist);
|
||||
$this->pluginManager->registerInterface(new PharPluginLoader($this->autoloader));
|
||||
$this->pluginManager->registerInterface(new ScriptPluginLoader());
|
||||
$this->pluginManager->registerInterface(new FolderPluginLoader($this->autoloader));
|
||||
|
||||
$providerManager = new WorldProviderManager();
|
||||
if(
|
||||
@ -1806,6 +1804,10 @@ class Server{
|
||||
return $this->forceLanguage;
|
||||
}
|
||||
|
||||
public function getAuthKeyProvider() : AuthKeyProvider{
|
||||
return $this->authKeyProvider;
|
||||
}
|
||||
|
||||
public function getNetwork() : Network{
|
||||
return $this->network;
|
||||
}
|
||||
|
@ -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.2";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
|
@ -50,6 +50,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 +61,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);
|
||||
|
90
src/block/BaseOminousBanner.php
Normal file
90
src/block/BaseOminousBanner.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?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\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(int $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, int $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() : int;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@ -787,8 +787,43 @@ final class BlockTypeIds{
|
||||
public const RESIN_CLUMP = 10757;
|
||||
public const CHISELED_RESIN_BRICKS = 10758;
|
||||
public const RESPAWN_ANCHOR = 10759;
|
||||
public const OMINOUS_BANNER = 10760;
|
||||
public const OMINOUS_WALL_BANNER = 10761;
|
||||
public const ACACIA_CEILING_CENTER_HANGING_SIGN = 10762;
|
||||
public const ACACIA_CEILING_EDGES_HANGING_SIGN = 10763;
|
||||
public const ACACIA_WALL_HANGING_SIGN = 10764;
|
||||
public const BIRCH_CEILING_CENTER_HANGING_SIGN = 10765;
|
||||
public const BIRCH_CEILING_EDGES_HANGING_SIGN = 10766;
|
||||
public const BIRCH_WALL_HANGING_SIGN = 10767;
|
||||
public const CHERRY_CEILING_CENTER_HANGING_SIGN = 10768;
|
||||
public const CHERRY_CEILING_EDGES_HANGING_SIGN = 10769;
|
||||
public const CHERRY_WALL_HANGING_SIGN = 10770;
|
||||
public const CRIMSON_CEILING_CENTER_HANGING_SIGN = 10771;
|
||||
public const CRIMSON_CEILING_EDGES_HANGING_SIGN = 10772;
|
||||
public const CRIMSON_WALL_HANGING_SIGN = 10773;
|
||||
public const DARK_OAK_CEILING_CENTER_HANGING_SIGN = 10774;
|
||||
public const DARK_OAK_CEILING_EDGES_HANGING_SIGN = 10775;
|
||||
public const DARK_OAK_WALL_HANGING_SIGN = 10776;
|
||||
public const JUNGLE_CEILING_CENTER_HANGING_SIGN = 10777;
|
||||
public const JUNGLE_CEILING_EDGES_HANGING_SIGN = 10778;
|
||||
public const JUNGLE_WALL_HANGING_SIGN = 10779;
|
||||
public const MANGROVE_CEILING_CENTER_HANGING_SIGN = 10780;
|
||||
public const MANGROVE_CEILING_EDGES_HANGING_SIGN = 10781;
|
||||
public const MANGROVE_WALL_HANGING_SIGN = 10782;
|
||||
public const OAK_CEILING_CENTER_HANGING_SIGN = 10783;
|
||||
public const OAK_CEILING_EDGES_HANGING_SIGN = 10784;
|
||||
public const OAK_WALL_HANGING_SIGN = 10785;
|
||||
public const PALE_OAK_CEILING_CENTER_HANGING_SIGN = 10786;
|
||||
public const PALE_OAK_CEILING_EDGES_HANGING_SIGN = 10787;
|
||||
public const PALE_OAK_WALL_HANGING_SIGN = 10788;
|
||||
public const SPRUCE_CEILING_CENTER_HANGING_SIGN = 10789;
|
||||
public const SPRUCE_CEILING_EDGES_HANGING_SIGN = 10790;
|
||||
public const SPRUCE_WALL_HANGING_SIGN = 10791;
|
||||
public const WARPED_CEILING_CENTER_HANGING_SIGN = 10792;
|
||||
public const WARPED_CEILING_EDGES_HANGING_SIGN = 10793;
|
||||
public const WARPED_WALL_HANGING_SIGN = 10794;
|
||||
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10760;
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10795;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;
|
||||
|
||||
|
@ -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";
|
||||
}
|
||||
|
61
src/block/CeilingCenterHangingSign.php
Normal file
61
src/block/CeilingCenterHangingSign.php
Normal 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() : int{
|
||||
return Facing::UP;
|
||||
}
|
||||
|
||||
//TODO: duplicated code :(
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
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);
|
||||
}
|
||||
}
|
68
src/block/CeilingEdgesHangingSign.php
Normal file
68
src/block/CeilingEdgesHangingSign.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?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\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() : int{
|
||||
return Facing::UP;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($face !== Facing::DOWN){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
$this->facing = 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()) === Facing::axis($this->facing));
|
||||
}
|
||||
}
|
@ -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.
|
||||
*/
|
||||
|
@ -34,6 +34,10 @@ use pocketmine\world\BlockTransaction;
|
||||
final class FloorBanner extends BaseBanner implements SignLikeRotation{
|
||||
use SignLikeRotationTrait;
|
||||
|
||||
protected function getOminousVersion() : Block{
|
||||
return VanillaBlocks::OMINOUS_BANNER()->setRotation($this->rotation);
|
||||
}
|
||||
|
||||
protected function getSupportingFace() : int{
|
||||
return Facing::DOWN;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ 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;
|
||||
@ -34,7 +35,7 @@ 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;
|
||||
|
||||
|
@ -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{
|
||||
|
53
src/block/OminousFloorBanner.php
Normal file
53
src/block/OminousFloorBanner.php
Normal 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() : int{
|
||||
return Facing::DOWN;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $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);
|
||||
}
|
||||
}
|
49
src/block/OminousWallBanner.php
Normal file
49
src/block/OminousWallBanner.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?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\HorizontalFacingTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
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() : int{
|
||||
return Facing::opposite($this->facing);
|
||||
}
|
||||
|
||||
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){
|
||||
return false;
|
||||
}
|
||||
$this->facing = $face;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
}
|
@ -23,11 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\Lightable;
|
||||
use pocketmine\block\utils\PoweredByRedstone;
|
||||
use pocketmine\block\utils\PoweredByRedstoneTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
|
||||
class RedstoneLamp extends Opaque implements PoweredByRedstone{
|
||||
class RedstoneLamp extends Opaque implements PoweredByRedstone, Lightable{
|
||||
use PoweredByRedstoneTrait;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
@ -37,4 +38,14 @@ class RedstoneLamp extends Opaque implements PoweredByRedstone{
|
||||
public function getLightLevel() : int{
|
||||
return $this->powered ? 15 : 0;
|
||||
}
|
||||
|
||||
public function isLit() : bool{
|
||||
return $this->powered;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function setLit(bool $lit = true) : self{
|
||||
$this->powered = $lit;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\MultiAnyFacing;
|
||||
use pocketmine\block\utils\MultiAnySupportTrait;
|
||||
use pocketmine\block\utils\MultiFacing;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
|
||||
final class ResinClump extends Transparent implements MultiFacing{
|
||||
final class ResinClump extends Transparent implements MultiAnyFacing{
|
||||
use MultiAnySupportTrait;
|
||||
|
||||
public function isSolid() : bool{
|
||||
|
@ -59,10 +59,17 @@ class SweetBerryBush extends Flowable implements Ageable{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
protected function canBeSupportedBy(Block $block) : bool{
|
||||
return $block->getTypeId() !== BlockTypeIds::FARMLAND && //bedrock-specific thing (bug?)
|
||||
($block->hasTypeTag(BlockTypeTags::DIRT) || $block->hasTypeTag(BlockTypeTags::MUD));
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block) : bool{
|
||||
$supportBlock = $block->getSide(Facing::DOWN);
|
||||
return $supportBlock->getTypeId() !== BlockTypeIds::FARMLAND && //bedrock-specific thing (bug?)
|
||||
($supportBlock->hasTypeTag(BlockTypeTags::DIRT) || $supportBlock->hasTypeTag(BlockTypeTags::MUD));
|
||||
return $this->canBeSupportedBy($supportBlock);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
|
@ -45,6 +45,7 @@ use pocketmine\block\tile\EnchantTable as TileEnchantingTable;
|
||||
use pocketmine\block\tile\EnderChest as TileEnderChest;
|
||||
use pocketmine\block\tile\FlowerPot as TileFlowerPot;
|
||||
use pocketmine\block\tile\GlowingItemFrame as TileGlowingItemFrame;
|
||||
use pocketmine\block\tile\HangingSign as TileHangingSign;
|
||||
use pocketmine\block\tile\Hopper as TileHopper;
|
||||
use pocketmine\block\tile\ItemFrame as TileItemFrame;
|
||||
use pocketmine\block\tile\Jukebox as TileJukebox;
|
||||
@ -80,6 +81,8 @@ use function strtolower;
|
||||
* @generate-registry-docblock
|
||||
*
|
||||
* @method static WoodenButton ACACIA_BUTTON()
|
||||
* @method static CeilingCenterHangingSign ACACIA_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign ACACIA_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor ACACIA_DOOR()
|
||||
* @method static WoodenFence ACACIA_FENCE()
|
||||
* @method static FenceGate ACACIA_FENCE_GATE()
|
||||
@ -92,6 +95,7 @@ use function strtolower;
|
||||
* @method static WoodenSlab ACACIA_SLAB()
|
||||
* @method static WoodenStairs ACACIA_STAIRS()
|
||||
* @method static WoodenTrapdoor ACACIA_TRAPDOOR()
|
||||
* @method static WallHangingSign ACACIA_WALL_HANGING_SIGN()
|
||||
* @method static WallSign ACACIA_WALL_SIGN()
|
||||
* @method static Wood ACACIA_WOOD()
|
||||
* @method static ActivatorRail ACTIVATOR_RAIL()
|
||||
@ -122,6 +126,8 @@ use function strtolower;
|
||||
* @method static BigDripleafHead BIG_DRIPLEAF_HEAD()
|
||||
* @method static BigDripleafStem BIG_DRIPLEAF_STEM()
|
||||
* @method static WoodenButton BIRCH_BUTTON()
|
||||
* @method static CeilingCenterHangingSign BIRCH_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign BIRCH_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor BIRCH_DOOR()
|
||||
* @method static WoodenFence BIRCH_FENCE()
|
||||
* @method static FenceGate BIRCH_FENCE_GATE()
|
||||
@ -134,6 +140,7 @@ use function strtolower;
|
||||
* @method static WoodenSlab BIRCH_SLAB()
|
||||
* @method static WoodenStairs BIRCH_STAIRS()
|
||||
* @method static WoodenTrapdoor BIRCH_TRAPDOOR()
|
||||
* @method static WallHangingSign BIRCH_WALL_HANGING_SIGN()
|
||||
* @method static WallSign BIRCH_WALL_SIGN()
|
||||
* @method static Wood BIRCH_WOOD()
|
||||
* @method static Opaque BLACKSTONE()
|
||||
@ -170,6 +177,8 @@ use function strtolower;
|
||||
* @method static Chain CHAIN()
|
||||
* @method static ChemicalHeat CHEMICAL_HEAT()
|
||||
* @method static WoodenButton CHERRY_BUTTON()
|
||||
* @method static CeilingCenterHangingSign CHERRY_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign CHERRY_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor CHERRY_DOOR()
|
||||
* @method static WoodenFence CHERRY_FENCE()
|
||||
* @method static FenceGate CHERRY_FENCE_GATE()
|
||||
@ -181,6 +190,7 @@ use function strtolower;
|
||||
* @method static WoodenSlab CHERRY_SLAB()
|
||||
* @method static WoodenStairs CHERRY_STAIRS()
|
||||
* @method static WoodenTrapdoor CHERRY_TRAPDOOR()
|
||||
* @method static WallHangingSign CHERRY_WALL_HANGING_SIGN()
|
||||
* @method static WallSign CHERRY_WALL_SIGN()
|
||||
* @method static Wood CHERRY_WOOD()
|
||||
* @method static Chest CHEST()
|
||||
@ -231,6 +241,8 @@ use function strtolower;
|
||||
* @method static Opaque CRACKED_STONE_BRICKS()
|
||||
* @method static CraftingTable CRAFTING_TABLE()
|
||||
* @method static WoodenButton CRIMSON_BUTTON()
|
||||
* @method static CeilingCenterHangingSign CRIMSON_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign CRIMSON_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor CRIMSON_DOOR()
|
||||
* @method static WoodenFence CRIMSON_FENCE()
|
||||
* @method static FenceGate CRIMSON_FENCE_GATE()
|
||||
@ -243,6 +255,7 @@ use function strtolower;
|
||||
* @method static WoodenStairs CRIMSON_STAIRS()
|
||||
* @method static Wood CRIMSON_STEM()
|
||||
* @method static WoodenTrapdoor CRIMSON_TRAPDOOR()
|
||||
* @method static WallHangingSign CRIMSON_WALL_HANGING_SIGN()
|
||||
* @method static WallSign CRIMSON_WALL_SIGN()
|
||||
* @method static Opaque CRYING_OBSIDIAN()
|
||||
* @method static Copper CUT_COPPER()
|
||||
@ -254,6 +267,8 @@ use function strtolower;
|
||||
* @method static Slab CUT_SANDSTONE_SLAB()
|
||||
* @method static Flower DANDELION()
|
||||
* @method static WoodenButton DARK_OAK_BUTTON()
|
||||
* @method static CeilingCenterHangingSign DARK_OAK_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign DARK_OAK_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor DARK_OAK_DOOR()
|
||||
* @method static WoodenFence DARK_OAK_FENCE()
|
||||
* @method static FenceGate DARK_OAK_FENCE_GATE()
|
||||
@ -266,6 +281,7 @@ use function strtolower;
|
||||
* @method static WoodenSlab DARK_OAK_SLAB()
|
||||
* @method static WoodenStairs DARK_OAK_STAIRS()
|
||||
* @method static WoodenTrapdoor DARK_OAK_TRAPDOOR()
|
||||
* @method static WallHangingSign DARK_OAK_WALL_HANGING_SIGN()
|
||||
* @method static WallSign DARK_OAK_WALL_SIGN()
|
||||
* @method static Wood DARK_OAK_WOOD()
|
||||
* @method static Opaque DARK_PRISMARINE()
|
||||
@ -488,6 +504,8 @@ use function strtolower;
|
||||
* @method static ItemFrame ITEM_FRAME()
|
||||
* @method static Jukebox JUKEBOX()
|
||||
* @method static WoodenButton JUNGLE_BUTTON()
|
||||
* @method static CeilingCenterHangingSign JUNGLE_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign JUNGLE_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor JUNGLE_DOOR()
|
||||
* @method static WoodenFence JUNGLE_FENCE()
|
||||
* @method static FenceGate JUNGLE_FENCE_GATE()
|
||||
@ -500,6 +518,7 @@ use function strtolower;
|
||||
* @method static WoodenSlab JUNGLE_SLAB()
|
||||
* @method static WoodenStairs JUNGLE_STAIRS()
|
||||
* @method static WoodenTrapdoor JUNGLE_TRAPDOOR()
|
||||
* @method static WallHangingSign JUNGLE_WALL_HANGING_SIGN()
|
||||
* @method static WallSign JUNGLE_WALL_SIGN()
|
||||
* @method static Wood JUNGLE_WOOD()
|
||||
* @method static ChemistryTable LAB_TABLE()
|
||||
@ -522,6 +541,8 @@ use function strtolower;
|
||||
* @method static Loom LOOM()
|
||||
* @method static Magma MAGMA()
|
||||
* @method static WoodenButton MANGROVE_BUTTON()
|
||||
* @method static CeilingCenterHangingSign MANGROVE_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign MANGROVE_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor MANGROVE_DOOR()
|
||||
* @method static WoodenFence MANGROVE_FENCE()
|
||||
* @method static FenceGate MANGROVE_FENCE_GATE()
|
||||
@ -534,6 +555,7 @@ use function strtolower;
|
||||
* @method static WoodenSlab MANGROVE_SLAB()
|
||||
* @method static WoodenStairs MANGROVE_STAIRS()
|
||||
* @method static WoodenTrapdoor MANGROVE_TRAPDOOR()
|
||||
* @method static WallHangingSign MANGROVE_WALL_HANGING_SIGN()
|
||||
* @method static WallSign MANGROVE_WALL_SIGN()
|
||||
* @method static Wood MANGROVE_WOOD()
|
||||
* @method static ChemistryTable MATERIAL_REDUCER()
|
||||
@ -572,6 +594,8 @@ use function strtolower;
|
||||
* @method static Opaque NETHER_WART_BLOCK()
|
||||
* @method static Note NOTE_BLOCK()
|
||||
* @method static WoodenButton OAK_BUTTON()
|
||||
* @method static CeilingCenterHangingSign OAK_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign OAK_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor OAK_DOOR()
|
||||
* @method static WoodenFence OAK_FENCE()
|
||||
* @method static FenceGate OAK_FENCE_GATE()
|
||||
@ -584,14 +608,19 @@ use function strtolower;
|
||||
* @method static WoodenSlab OAK_SLAB()
|
||||
* @method static WoodenStairs OAK_STAIRS()
|
||||
* @method static WoodenTrapdoor OAK_TRAPDOOR()
|
||||
* @method static WallHangingSign OAK_WALL_HANGING_SIGN()
|
||||
* @method static WallSign OAK_WALL_SIGN()
|
||||
* @method static Wood OAK_WOOD()
|
||||
* @method static Opaque OBSIDIAN()
|
||||
* @method static OminousFloorBanner OMINOUS_BANNER()
|
||||
* @method static OminousWallBanner OMINOUS_WALL_BANNER()
|
||||
* @method static Flower ORANGE_TULIP()
|
||||
* @method static Flower OXEYE_DAISY()
|
||||
* @method static PackedIce PACKED_ICE()
|
||||
* @method static Opaque PACKED_MUD()
|
||||
* @method static WoodenButton PALE_OAK_BUTTON()
|
||||
* @method static CeilingCenterHangingSign PALE_OAK_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign PALE_OAK_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor PALE_OAK_DOOR()
|
||||
* @method static WoodenFence PALE_OAK_FENCE()
|
||||
* @method static FenceGate PALE_OAK_FENCE_GATE()
|
||||
@ -603,6 +632,7 @@ use function strtolower;
|
||||
* @method static WoodenSlab PALE_OAK_SLAB()
|
||||
* @method static WoodenStairs PALE_OAK_STAIRS()
|
||||
* @method static WoodenTrapdoor PALE_OAK_TRAPDOOR()
|
||||
* @method static WallHangingSign PALE_OAK_WALL_HANGING_SIGN()
|
||||
* @method static WallSign PALE_OAK_WALL_SIGN()
|
||||
* @method static Wood PALE_OAK_WOOD()
|
||||
* @method static DoublePlant PEONY()
|
||||
@ -733,6 +763,8 @@ use function strtolower;
|
||||
* @method static Sponge SPONGE()
|
||||
* @method static SporeBlossom SPORE_BLOSSOM()
|
||||
* @method static WoodenButton SPRUCE_BUTTON()
|
||||
* @method static CeilingCenterHangingSign SPRUCE_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign SPRUCE_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor SPRUCE_DOOR()
|
||||
* @method static WoodenFence SPRUCE_FENCE()
|
||||
* @method static FenceGate SPRUCE_FENCE_GATE()
|
||||
@ -745,6 +777,7 @@ use function strtolower;
|
||||
* @method static WoodenSlab SPRUCE_SLAB()
|
||||
* @method static WoodenStairs SPRUCE_STAIRS()
|
||||
* @method static WoodenTrapdoor SPRUCE_TRAPDOOR()
|
||||
* @method static WallHangingSign SPRUCE_WALL_HANGING_SIGN()
|
||||
* @method static WallSign SPRUCE_WALL_SIGN()
|
||||
* @method static Wood SPRUCE_WOOD()
|
||||
* @method static StainedHardenedClay STAINED_CLAY()
|
||||
@ -788,6 +821,8 @@ use function strtolower;
|
||||
* @method static WallBanner WALL_BANNER()
|
||||
* @method static WallCoralFan WALL_CORAL_FAN()
|
||||
* @method static WoodenButton WARPED_BUTTON()
|
||||
* @method static CeilingCenterHangingSign WARPED_CEILING_CENTER_HANGING_SIGN()
|
||||
* @method static CeilingEdgesHangingSign WARPED_CEILING_EDGES_HANGING_SIGN()
|
||||
* @method static WoodenDoor WARPED_DOOR()
|
||||
* @method static WoodenFence WARPED_FENCE()
|
||||
* @method static FenceGate WARPED_FENCE_GATE()
|
||||
@ -800,13 +835,14 @@ use function strtolower;
|
||||
* @method static WoodenStairs WARPED_STAIRS()
|
||||
* @method static Wood WARPED_STEM()
|
||||
* @method static WoodenTrapdoor WARPED_TRAPDOOR()
|
||||
* @method static WallHangingSign WARPED_WALL_HANGING_SIGN()
|
||||
* @method static WallSign WARPED_WALL_SIGN()
|
||||
* @method static Opaque WARPED_WART_BLOCK()
|
||||
* @method static Water WATER()
|
||||
* @method static WaterCauldron WATER_CAULDRON()
|
||||
* @method static NetherVines WEEPING_VINES()
|
||||
* @method static WeightedPressurePlate WEIGHTED_PRESSURE_PLATE_HEAVY()
|
||||
* @method static WeightedPressurePlate WEIGHTED_PRESSURE_PLATE_LIGHT()
|
||||
* @method static WeightedPressurePlateHeavy WEIGHTED_PRESSURE_PLATE_HEAVY()
|
||||
* @method static WeightedPressurePlateLight WEIGHTED_PRESSURE_PLATE_LIGHT()
|
||||
* @method static Wheat WHEAT()
|
||||
* @method static Flower WHITE_TULIP()
|
||||
* @method static WitherRose WITHER_ROSE()
|
||||
@ -873,6 +909,8 @@ final class VanillaBlocks{
|
||||
$bannerBreakInfo = new Info(BreakInfo::axe(1.0));
|
||||
self::register("banner", fn(BID $id) => new FloorBanner($id, "Banner", $bannerBreakInfo), TileBanner::class);
|
||||
self::register("wall_banner", fn(BID $id) => new WallBanner($id, "Wall Banner", $bannerBreakInfo), TileBanner::class);
|
||||
self::register("ominous_banner", fn(BID $id) => new OminousFloorBanner($id, "Ominous Banner", $bannerBreakInfo), TileBanner::class);
|
||||
self::register("ominous_wall_banner", fn(BID $id) => new OminousWallBanner($id, "Ominous Wall Banner", $bannerBreakInfo), TileBanner::class);
|
||||
self::register("barrel", fn(BID $id) => new Barrel($id, "Barrel", new Info(BreakInfo::axe(2.5))), TileBarrel::class);
|
||||
self::register("barrier", fn(BID $id) => new Transparent($id, "Barrier", new Info(BreakInfo::indestructible())));
|
||||
self::register("beacon", fn(BID $id) => new Beacon($id, "Beacon", new Info(new BreakInfo(3.0))), TileBeacon::class);
|
||||
@ -1203,14 +1241,14 @@ final class VanillaBlocks{
|
||||
self::register("lily_pad", fn(BID $id) => new WaterLily($id, "Lily Pad", new Info(BreakInfo::instant())));
|
||||
|
||||
$weightedPressurePlateBreakInfo = new Info(BreakInfo::pickaxe(0.5));
|
||||
self::register("weighted_pressure_plate_heavy", fn(BID $id) => new WeightedPressurePlate(
|
||||
self::register("weighted_pressure_plate_heavy", fn(BID $id) => new WeightedPressurePlateHeavy(
|
||||
$id,
|
||||
"Weighted Pressure Plate Heavy",
|
||||
$weightedPressurePlateBreakInfo,
|
||||
deactivationDelayTicks: 10,
|
||||
signalStrengthFactor: 0.1
|
||||
));
|
||||
self::register("weighted_pressure_plate_light", fn(BID $id) => new WeightedPressurePlate(
|
||||
self::register("weighted_pressure_plate_light", fn(BID $id) => new WeightedPressurePlateLight(
|
||||
$id,
|
||||
"Weighted Pressure Plate Light",
|
||||
$weightedPressurePlateBreakInfo,
|
||||
@ -1353,6 +1391,7 @@ final class VanillaBlocks{
|
||||
private static function registerWoodenBlocks() : void{
|
||||
$planksBreakInfo = new Info(BreakInfo::axe(2.0, null, 15.0));
|
||||
$signBreakInfo = new Info(BreakInfo::axe(1.0));
|
||||
$hangingSignBreakInfo = new Info(BreakInfo::axe(1.0), [Tags::HANGING_SIGN]);
|
||||
$logBreakInfo = new Info(BreakInfo::axe(2.0));
|
||||
$woodenDoorBreakInfo = new Info(BreakInfo::axe(3.0, null, 15.0));
|
||||
$woodenButtonBreakInfo = new Info(BreakInfo::axe(0.5));
|
||||
@ -1392,6 +1431,23 @@ final class VanillaBlocks{
|
||||
};
|
||||
self::register($idName("sign"), fn(BID $id) => new FloorSign($id, $name . " Sign", $signBreakInfo, $woodType, $signAsItem), TileSign::class);
|
||||
self::register($idName("wall_sign"), fn(BID $id) => new WallSign($id, $name . " Wall Sign", $signBreakInfo, $woodType, $signAsItem), TileSign::class);
|
||||
|
||||
$hangingSignAsItem = match($woodType){
|
||||
WoodType::OAK => VanillaItems::OAK_HANGING_SIGN(...),
|
||||
WoodType::SPRUCE => VanillaItems::SPRUCE_HANGING_SIGN(...),
|
||||
WoodType::BIRCH => VanillaItems::BIRCH_HANGING_SIGN(...),
|
||||
WoodType::JUNGLE => VanillaItems::JUNGLE_HANGING_SIGN(...),
|
||||
WoodType::ACACIA => VanillaItems::ACACIA_HANGING_SIGN(...),
|
||||
WoodType::DARK_OAK => VanillaItems::DARK_OAK_HANGING_SIGN(...),
|
||||
WoodType::MANGROVE => VanillaItems::MANGROVE_HANGING_SIGN(...),
|
||||
WoodType::CRIMSON => VanillaItems::CRIMSON_HANGING_SIGN(...),
|
||||
WoodType::WARPED => VanillaItems::WARPED_HANGING_SIGN(...),
|
||||
WoodType::CHERRY => VanillaItems::CHERRY_HANGING_SIGN(...),
|
||||
WoodType::PALE_OAK => VanillaItems::PALE_OAK_HANGING_SIGN(...),
|
||||
};
|
||||
self::register($idName("ceiling_center_hanging_sign"), fn(BID $id) => new CeilingCenterHangingSign($id, $name . " Center Hanging Sign", $hangingSignBreakInfo, $woodType, $hangingSignAsItem), TileHangingSign::class);
|
||||
self::register($idName("ceiling_edges_hanging_sign"), fn(BID $id) => new CeilingEdgesHangingSign($id, $name . " Edges Hanging Sign", $hangingSignBreakInfo, $woodType, $hangingSignAsItem), TileHangingSign::class);
|
||||
self::register($idName("wall_hanging_sign"), fn(BID $id) => new WallHangingSign($id, $name . " Wall Hanging Sign", $hangingSignBreakInfo, $woodType, $hangingSignAsItem), TileHangingSign::class);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,10 @@ use pocketmine\world\BlockTransaction;
|
||||
final class WallBanner extends BaseBanner implements HorizontalFacing{
|
||||
use HorizontalFacingTrait;
|
||||
|
||||
protected function getOminousVersion() : Block{
|
||||
return VanillaBlocks::OMINOUS_WALL_BANNER()->setFacing($this->facing);
|
||||
}
|
||||
|
||||
protected function getSupportingFace() : int{
|
||||
return Facing::opposite($this->facing);
|
||||
}
|
||||
|
81
src/block/WallHangingSign.php
Normal file
81
src/block/WallHangingSign.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?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\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
final class WallHangingSign extends BaseSign implements HorizontalFacing{
|
||||
use HorizontalFacingTrait;
|
||||
|
||||
protected function getSupportingFace() : int{
|
||||
return Facing::rotateY($this->facing, clockwise: true);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
//NOOP - disable default self-destruct behaviour
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//only the cross bar is collidable
|
||||
return [AxisAlignedBB::one()->trim(Facing::DOWN, 7 / 8)->squash(Facing::axis($this->facing), 3 / 4)];
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($player === null){
|
||||
return false;
|
||||
}
|
||||
$attachFace = Facing::axis($face) === Axis::Y ? Facing::rotateY($player->getHorizontalFacing(), clockwise: true) : $face;
|
||||
|
||||
if($this->canBeSupportedAt($blockReplace->getSide($attachFace), $attachFace)){
|
||||
$direction = $attachFace;
|
||||
}elseif($this->canBeSupportedAt($blockReplace->getSide($opposite = Facing::opposite($attachFace)), $opposite)){
|
||||
$direction = $opposite;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->facing = Facing::rotateY(Facing::opposite($direction), clockwise: true);
|
||||
//the front should always face the player if possible
|
||||
if($this->facing === $player->getHorizontalFacing()){
|
||||
$this->facing = Facing::opposite($this->facing);
|
||||
}
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
private function canBeSupportedAt(Block $block, int $face) : bool{
|
||||
return
|
||||
($block instanceof WallHangingSign && Facing::axis(Facing::rotateY($block->getFacing(), clockwise: true)) === Facing::axis($face)) ||
|
||||
$block->getSupportType(Facing::opposite($face)) === SupportType::FULL;
|
||||
}
|
||||
}
|
31
src/block/WeightedPressurePlateHeavy.php
Normal file
31
src/block/WeightedPressurePlateHeavy.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class WeightedPressurePlateHeavy extends WeightedPressurePlate{
|
||||
|
||||
}
|
31
src/block/WeightedPressurePlateLight.php
Normal file
31
src/block/WeightedPressurePlateLight.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
class WeightedPressurePlateLight extends WeightedPressurePlate{
|
||||
|
||||
}
|
@ -41,6 +41,10 @@ class Banner extends Spawnable{
|
||||
public const TAG_PATTERNS = "Patterns";
|
||||
public const TAG_PATTERN_COLOR = "Color";
|
||||
public const TAG_PATTERN_NAME = "Pattern";
|
||||
public const TAG_TYPE = "Type";
|
||||
|
||||
public const TYPE_NORMAL = 0;
|
||||
public const TYPE_OMINOUS = 1;
|
||||
|
||||
private DyeColor $baseColor = DyeColor::BLACK;
|
||||
|
||||
@ -50,6 +54,8 @@ class Banner extends Spawnable{
|
||||
*/
|
||||
private array $patterns = [];
|
||||
|
||||
private int $type = self::TYPE_NORMAL;
|
||||
|
||||
public function readSaveData(CompoundTag $nbt) : void{
|
||||
$colorIdMap = DyeColorIdMap::getInstance();
|
||||
if(
|
||||
@ -75,6 +81,8 @@ class Banner extends Spawnable{
|
||||
$this->patterns[] = new BannerPatternLayer($patternType, $patternColor);
|
||||
}
|
||||
}
|
||||
|
||||
$this->type = $nbt->getInt(self::TAG_TYPE, self::TYPE_NORMAL);
|
||||
}
|
||||
|
||||
protected function writeSaveData(CompoundTag $nbt) : void{
|
||||
@ -89,6 +97,7 @@ class Banner extends Spawnable{
|
||||
);
|
||||
}
|
||||
$nbt->setTag(self::TAG_PATTERNS, $patterns);
|
||||
$nbt->setInt(self::TAG_TYPE, $this->type);
|
||||
}
|
||||
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
@ -103,6 +112,7 @@ class Banner extends Spawnable{
|
||||
);
|
||||
}
|
||||
$nbt->setTag(self::TAG_PATTERNS, $patterns);
|
||||
$nbt->setInt(self::TAG_TYPE, $this->type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,6 +146,10 @@ class Banner extends Spawnable{
|
||||
$this->patterns = $patterns;
|
||||
}
|
||||
|
||||
public function getType() : int{ return $this->type; }
|
||||
|
||||
public function setType(int $type) : void{ $this->type = $type; }
|
||||
|
||||
public function getDefaultName() : string{
|
||||
return "Banner";
|
||||
}
|
||||
|
31
src/block/tile/HangingSign.php
Normal file
31
src/block/tile/HangingSign.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?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\tile;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
final class HangingSign extends Sign{
|
||||
|
||||
}
|
@ -37,6 +37,7 @@ use function array_slice;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function mb_scrub;
|
||||
use function rtrim;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
@ -117,7 +118,7 @@ class Sign extends Spawnable{
|
||||
|
||||
protected function writeSaveData(CompoundTag $nbt) : void{
|
||||
$nbt->setTag(self::TAG_FRONT_TEXT, CompoundTag::create()
|
||||
->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text->getLines()))
|
||||
->setString(self::TAG_TEXT_BLOB, rtrim(implode("\n", $this->text->getLines()), "\n"))
|
||||
->setInt(self::TAG_TEXT_COLOR, Binary::signInt($this->text->getBaseColor()->toARGB()))
|
||||
->setByte(self::TAG_GLOWING_TEXT, $this->text->isGlowing() ? 1 : 0)
|
||||
->setByte(self::TAG_PERSIST_FORMATTING, 1)
|
||||
@ -162,7 +163,7 @@ class Sign extends Spawnable{
|
||||
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
$nbt->setTag(self::TAG_FRONT_TEXT, CompoundTag::create()
|
||||
->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text->getLines()))
|
||||
->setString(self::TAG_TEXT_BLOB, rtrim(implode("\n", $this->text->getLines()), "\n"))
|
||||
->setInt(self::TAG_TEXT_COLOR, Binary::signInt($this->text->getBaseColor()->toARGB()))
|
||||
->setByte(self::TAG_GLOWING_TEXT, $this->text->isGlowing() ? 1 : 0)
|
||||
->setByte(self::TAG_PERSIST_FORMATTING, 1) //TODO: not sure what this is used for
|
||||
|
@ -35,6 +35,20 @@ abstract class Spawnable extends Tile{
|
||||
/** @phpstan-var CacheableNbt<CompoundTag>|null */
|
||||
private ?CacheableNbt $spawnCompoundCache = null;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function isDirty() : bool{
|
||||
return $this->spawnCompoundCache === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function setDirty(bool $dirty = true) : void{
|
||||
$this->clearSpawnCompoundCache();
|
||||
}
|
||||
|
||||
public function clearSpawnCompoundCache() : void{
|
||||
$this->spawnCompoundCache = null;
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ final class TileFactory{
|
||||
$this->register(SporeBlossom::class, ["SporeBlossom", "minecraft:spore_blossom"]);
|
||||
$this->register(MobHead::class, ["Skull", "minecraft:skull"]);
|
||||
$this->register(GlowingItemFrame::class, ["GlowItemFrame"]);
|
||||
$this->register(HangingSign::class, ["HangingSign", "minecraft:hanging_sign"]);
|
||||
|
||||
//TODO: ChalkboardBlock
|
||||
//TODO: ChemistryTable
|
||||
|
@ -27,7 +27,10 @@ interface Ageable{
|
||||
|
||||
public function getAge() : int;
|
||||
|
||||
public function getMaxAge() : int;
|
||||
|
||||
/**
|
||||
* Must be in range 0 - getMaxAge()
|
||||
* @return $this
|
||||
*/
|
||||
public function setAge(int $age) : self;
|
||||
|
@ -38,6 +38,8 @@ trait AgeableTrait{
|
||||
|
||||
public function getAge() : int{ return $this->age; }
|
||||
|
||||
public function getMaxAge() : int{ return self::MAX_AGE; }
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
|
@ -23,7 +23,54 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static BannerPatternType BORDER()
|
||||
* @method static BannerPatternType BRICKS()
|
||||
* @method static BannerPatternType CIRCLE()
|
||||
* @method static BannerPatternType CREEPER()
|
||||
* @method static BannerPatternType CROSS()
|
||||
* @method static BannerPatternType CURLY_BORDER()
|
||||
* @method static BannerPatternType DIAGONAL_LEFT()
|
||||
* @method static BannerPatternType DIAGONAL_RIGHT()
|
||||
* @method static BannerPatternType DIAGONAL_UP_LEFT()
|
||||
* @method static BannerPatternType DIAGONAL_UP_RIGHT()
|
||||
* @method static BannerPatternType FLOWER()
|
||||
* @method static BannerPatternType GRADIENT()
|
||||
* @method static BannerPatternType GRADIENT_UP()
|
||||
* @method static BannerPatternType HALF_HORIZONTAL()
|
||||
* @method static BannerPatternType HALF_HORIZONTAL_BOTTOM()
|
||||
* @method static BannerPatternType HALF_VERTICAL()
|
||||
* @method static BannerPatternType HALF_VERTICAL_RIGHT()
|
||||
* @method static BannerPatternType MOJANG()
|
||||
* @method static BannerPatternType RHOMBUS()
|
||||
* @method static BannerPatternType SKULL()
|
||||
* @method static BannerPatternType SMALL_STRIPES()
|
||||
* @method static BannerPatternType SQUARE_BOTTOM_LEFT()
|
||||
* @method static BannerPatternType SQUARE_BOTTOM_RIGHT()
|
||||
* @method static BannerPatternType SQUARE_TOP_LEFT()
|
||||
* @method static BannerPatternType SQUARE_TOP_RIGHT()
|
||||
* @method static BannerPatternType STRAIGHT_CROSS()
|
||||
* @method static BannerPatternType STRIPE_BOTTOM()
|
||||
* @method static BannerPatternType STRIPE_CENTER()
|
||||
* @method static BannerPatternType STRIPE_DOWNLEFT()
|
||||
* @method static BannerPatternType STRIPE_DOWNRIGHT()
|
||||
* @method static BannerPatternType STRIPE_LEFT()
|
||||
* @method static BannerPatternType STRIPE_MIDDLE()
|
||||
* @method static BannerPatternType STRIPE_RIGHT()
|
||||
* @method static BannerPatternType STRIPE_TOP()
|
||||
* @method static BannerPatternType TRIANGLES_BOTTOM()
|
||||
* @method static BannerPatternType TRIANGLES_TOP()
|
||||
* @method static BannerPatternType TRIANGLE_BOTTOM()
|
||||
* @method static BannerPatternType TRIANGLE_TOP()
|
||||
*/
|
||||
enum BannerPatternType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case BORDER;
|
||||
case BRICKS;
|
||||
case CIRCLE;
|
||||
|
@ -23,7 +23,20 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static BellAttachmentType CEILING()
|
||||
* @method static BellAttachmentType FLOOR()
|
||||
* @method static BellAttachmentType ONE_WALL()
|
||||
* @method static BellAttachmentType TWO_WALLS()
|
||||
*/
|
||||
enum BellAttachmentType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case CEILING;
|
||||
case FLOOR;
|
||||
case ONE_WALL;
|
||||
|
@ -24,8 +24,19 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\block\inventory\BrewingStandInventory;
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static BrewingStandSlot EAST()
|
||||
* @method static BrewingStandSlot NORTHWEST()
|
||||
* @method static BrewingStandSlot SOUTHWEST()
|
||||
*/
|
||||
enum BrewingStandSlot{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case EAST;
|
||||
case NORTHWEST;
|
||||
case SOUTHWEST;
|
||||
|
@ -23,7 +23,20 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static CopperOxidation EXPOSED()
|
||||
* @method static CopperOxidation NONE()
|
||||
* @method static CopperOxidation OXIDIZED()
|
||||
* @method static CopperOxidation WEATHERED()
|
||||
*/
|
||||
enum CopperOxidation : int{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case NONE = 0;
|
||||
case EXPOSED = 1;
|
||||
case WEATHERED = 2;
|
||||
|
@ -23,7 +23,21 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static CoralType BRAIN()
|
||||
* @method static CoralType BUBBLE()
|
||||
* @method static CoralType FIRE()
|
||||
* @method static CoralType HORN()
|
||||
* @method static CoralType TUBE()
|
||||
*/
|
||||
enum CoralType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case TUBE;
|
||||
case BRAIN;
|
||||
case BUBBLE;
|
||||
|
@ -23,7 +23,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static DirtType COARSE()
|
||||
* @method static DirtType NORMAL()
|
||||
* @method static DirtType ROOTED()
|
||||
*/
|
||||
enum DirtType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case NORMAL;
|
||||
case COARSE;
|
||||
case ROOTED;
|
||||
|
@ -23,7 +23,20 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static DripleafState FULL_TILT()
|
||||
* @method static DripleafState PARTIAL_TILT()
|
||||
* @method static DripleafState STABLE()
|
||||
* @method static DripleafState UNSTABLE()
|
||||
*/
|
||||
enum DripleafState{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case STABLE;
|
||||
case UNSTABLE;
|
||||
case PARTIAL_TILT;
|
||||
|
@ -24,12 +24,35 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\color\Color;
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static DyeColor BLACK()
|
||||
* @method static DyeColor BLUE()
|
||||
* @method static DyeColor BROWN()
|
||||
* @method static DyeColor CYAN()
|
||||
* @method static DyeColor GRAY()
|
||||
* @method static DyeColor GREEN()
|
||||
* @method static DyeColor LIGHT_BLUE()
|
||||
* @method static DyeColor LIGHT_GRAY()
|
||||
* @method static DyeColor LIME()
|
||||
* @method static DyeColor MAGENTA()
|
||||
* @method static DyeColor ORANGE()
|
||||
* @method static DyeColor PINK()
|
||||
* @method static DyeColor PURPLE()
|
||||
* @method static DyeColor RED()
|
||||
* @method static DyeColor WHITE()
|
||||
* @method static DyeColor YELLOW()
|
||||
*
|
||||
* @phpstan-type TMetadata array{0: string, 1: Color}
|
||||
*/
|
||||
enum DyeColor{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case WHITE;
|
||||
case ORANGE;
|
||||
case MAGENTA;
|
||||
|
@ -23,7 +23,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static FroglightType OCHRE()
|
||||
* @method static FroglightType PEARLESCENT()
|
||||
* @method static FroglightType VERDANT()
|
||||
*/
|
||||
enum FroglightType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case OCHRE;
|
||||
case PEARLESCENT;
|
||||
case VERDANT;
|
||||
|
@ -23,7 +23,26 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static LeavesType ACACIA()
|
||||
* @method static LeavesType AZALEA()
|
||||
* @method static LeavesType BIRCH()
|
||||
* @method static LeavesType CHERRY()
|
||||
* @method static LeavesType DARK_OAK()
|
||||
* @method static LeavesType FLOWERING_AZALEA()
|
||||
* @method static LeavesType JUNGLE()
|
||||
* @method static LeavesType MANGROVE()
|
||||
* @method static LeavesType OAK()
|
||||
* @method static LeavesType SPRUCE()
|
||||
*/
|
||||
enum LeavesType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case OAK;
|
||||
case SPRUCE;
|
||||
case BIRCH;
|
||||
|
@ -24,8 +24,24 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static LeverFacing DOWN_AXIS_X()
|
||||
* @method static LeverFacing DOWN_AXIS_Z()
|
||||
* @method static LeverFacing EAST()
|
||||
* @method static LeverFacing NORTH()
|
||||
* @method static LeverFacing SOUTH()
|
||||
* @method static LeverFacing UP_AXIS_X()
|
||||
* @method static LeverFacing UP_AXIS_Z()
|
||||
* @method static LeverFacing WEST()
|
||||
*/
|
||||
enum LeverFacing{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case UP_AXIS_X;
|
||||
case UP_AXIS_Z;
|
||||
case DOWN_AXIS_X;
|
||||
|
@ -23,7 +23,23 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static MobHeadType CREEPER()
|
||||
* @method static MobHeadType DRAGON()
|
||||
* @method static MobHeadType PIGLIN()
|
||||
* @method static MobHeadType PLAYER()
|
||||
* @method static MobHeadType SKELETON()
|
||||
* @method static MobHeadType WITHER_SKELETON()
|
||||
* @method static MobHeadType ZOMBIE()
|
||||
*/
|
||||
enum MobHeadType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case SKELETON;
|
||||
case WITHER_SKELETON;
|
||||
case ZOMBIE;
|
||||
|
@ -25,7 +25,7 @@ namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\math\Facing;
|
||||
|
||||
interface MultiFacing{
|
||||
interface MultiAnyFacing{
|
||||
|
||||
/**
|
||||
* @return int[]
|
@ -23,7 +23,27 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static MushroomBlockType ALL_CAP()
|
||||
* @method static MushroomBlockType CAP_EAST()
|
||||
* @method static MushroomBlockType CAP_MIDDLE()
|
||||
* @method static MushroomBlockType CAP_NORTH()
|
||||
* @method static MushroomBlockType CAP_NORTHEAST()
|
||||
* @method static MushroomBlockType CAP_NORTHWEST()
|
||||
* @method static MushroomBlockType CAP_SOUTH()
|
||||
* @method static MushroomBlockType CAP_SOUTHEAST()
|
||||
* @method static MushroomBlockType CAP_SOUTHWEST()
|
||||
* @method static MushroomBlockType CAP_WEST()
|
||||
* @method static MushroomBlockType PORES()
|
||||
*/
|
||||
enum MushroomBlockType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case PORES;
|
||||
case CAP_NORTHWEST;
|
||||
case CAP_NORTH;
|
||||
|
@ -26,12 +26,34 @@ namespace pocketmine\block\utils;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\lang\Translatable;
|
||||
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
use function spl_object_id;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static RecordType DISK_11()
|
||||
* @method static RecordType DISK_13()
|
||||
* @method static RecordType DISK_5()
|
||||
* @method static RecordType DISK_BLOCKS()
|
||||
* @method static RecordType DISK_CAT()
|
||||
* @method static RecordType DISK_CHIRP()
|
||||
* @method static RecordType DISK_FAR()
|
||||
* @method static RecordType DISK_MALL()
|
||||
* @method static RecordType DISK_MELLOHI()
|
||||
* @method static RecordType DISK_OTHERSIDE()
|
||||
* @method static RecordType DISK_PIGSTEP()
|
||||
* @method static RecordType DISK_STAL()
|
||||
* @method static RecordType DISK_STRAD()
|
||||
* @method static RecordType DISK_WAIT()
|
||||
* @method static RecordType DISK_WARD()
|
||||
*
|
||||
* @phpstan-type TMetadata array{0: string, 1: LevelSoundEvent::*, 2: Translatable}
|
||||
*/
|
||||
enum RecordType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case DISK_13;
|
||||
case DISK_5;
|
||||
case DISK_CAT;
|
||||
|
@ -23,9 +23,23 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
use pocketmine\world\generator\object\TreeType;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static SaplingType ACACIA()
|
||||
* @method static SaplingType BIRCH()
|
||||
* @method static SaplingType DARK_OAK()
|
||||
* @method static SaplingType JUNGLE()
|
||||
* @method static SaplingType OAK()
|
||||
* @method static SaplingType SPRUCE()
|
||||
*/
|
||||
enum SaplingType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case OAK;
|
||||
case SPRUCE;
|
||||
case BIRCH;
|
||||
|
@ -23,7 +23,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static SlabType BOTTOM()
|
||||
* @method static SlabType DOUBLE()
|
||||
* @method static SlabType TOP()
|
||||
*/
|
||||
enum SlabType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case BOTTOM;
|
||||
case TOP;
|
||||
case DOUBLE;
|
||||
|
@ -23,7 +23,21 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static StairShape INNER_LEFT()
|
||||
* @method static StairShape INNER_RIGHT()
|
||||
* @method static StairShape OUTER_LEFT()
|
||||
* @method static StairShape OUTER_RIGHT()
|
||||
* @method static StairShape STRAIGHT()
|
||||
*/
|
||||
enum StairShape{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case STRAIGHT;
|
||||
case INNER_LEFT;
|
||||
case INNER_RIGHT;
|
||||
|
@ -23,7 +23,20 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static SupportType CENTER()
|
||||
* @method static SupportType EDGE()
|
||||
* @method static SupportType FULL()
|
||||
* @method static SupportType NONE()
|
||||
*/
|
||||
enum SupportType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case FULL;
|
||||
case CENTER;
|
||||
case EDGE;
|
||||
|
@ -23,7 +23,18 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static WallConnectionType SHORT()
|
||||
* @method static WallConnectionType TALL()
|
||||
*/
|
||||
enum WallConnectionType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case SHORT;
|
||||
case TALL;
|
||||
}
|
||||
|
@ -23,7 +23,26 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\utils\LegacyEnumShimTrait;
|
||||
|
||||
/**
|
||||
* TODO: These tags need to be removed once we get rid of LegacyEnumShimTrait (PM6)
|
||||
* These are retained for backwards compatibility only.
|
||||
*
|
||||
* @method static WoodType ACACIA()
|
||||
* @method static WoodType BIRCH()
|
||||
* @method static WoodType CHERRY()
|
||||
* @method static WoodType CRIMSON()
|
||||
* @method static WoodType DARK_OAK()
|
||||
* @method static WoodType JUNGLE()
|
||||
* @method static WoodType MANGROVE()
|
||||
* @method static WoodType OAK()
|
||||
* @method static WoodType SPRUCE()
|
||||
* @method static WoodType WARPED()
|
||||
*/
|
||||
enum WoodType{
|
||||
use LegacyEnumShimTrait;
|
||||
|
||||
case OAK;
|
||||
case SPRUCE;
|
||||
case BIRCH;
|
||||
|
@ -38,17 +38,19 @@ final class ClosureCommand extends Command{
|
||||
* @phpstan-param Execute $execute
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
\Closure $execute,
|
||||
array $permissions,
|
||||
Translatable|string $description = "",
|
||||
Translatable|string|null $usageMessage = null,
|
||||
array $aliases = []
|
||||
){
|
||||
Utils::validateCallableSignature(
|
||||
fn(CommandSender $sender, Command $command, string $commandLabel, array $args) : mixed => 1,
|
||||
$execute,
|
||||
);
|
||||
$this->execute = $execute;
|
||||
parent::__construct($description, $usageMessage);
|
||||
parent::__construct($name, $description, $usageMessage, $aliases);
|
||||
$this->setPermissions($permissions);
|
||||
}
|
||||
|
||||
|
@ -33,20 +33,52 @@ use pocketmine\permission\PermissionManager;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\utils\BroadcastLoggerForwarder;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use function array_values;
|
||||
use function explode;
|
||||
use function implode;
|
||||
use function str_replace;
|
||||
use const PHP_INT_MAX;
|
||||
|
||||
abstract class Command{
|
||||
|
||||
private string $name;
|
||||
|
||||
private string $nextLabel;
|
||||
private string $label;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @phpstan-var list<string>
|
||||
*/
|
||||
private array $aliases = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @phpstan-var list<string>
|
||||
*/
|
||||
private array $activeAliases = [];
|
||||
|
||||
private ?CommandMap $commandMap = null;
|
||||
|
||||
protected Translatable|string $description = "";
|
||||
|
||||
protected Translatable|string $usageMessage;
|
||||
|
||||
/** @var string[] */
|
||||
private array $permission = [];
|
||||
private Translatable|string|null $permissionMessage = null;
|
||||
private ?string $permissionMessage = null;
|
||||
|
||||
public function __construct(
|
||||
private Translatable|string $description = "",
|
||||
private Translatable|string|null $usageMessage = null
|
||||
){}
|
||||
/**
|
||||
* @param string[] $aliases
|
||||
* @phpstan-param list<string> $aliases
|
||||
*/
|
||||
public function __construct(string $name, Translatable|string $description = "", Translatable|string|null $usageMessage = null, array $aliases = []){
|
||||
$this->name = $name;
|
||||
$this->setLabel($name);
|
||||
$this->setDescription($description);
|
||||
$this->usageMessage = $usageMessage ?? ("/" . $name);
|
||||
$this->setAliases($aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $args
|
||||
@ -57,6 +89,10 @@ abstract class Command{
|
||||
*/
|
||||
abstract public function execute(CommandSender $sender, string $commandLabel, array $args);
|
||||
|
||||
public function getName() : string{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
@ -81,21 +117,15 @@ abstract class Command{
|
||||
$this->setPermissions($permission === null ? [] : explode(";", $permission, limit: PHP_INT_MAX));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $context usually the command name, but may include extra args if useful (e.g. for subcommands)
|
||||
* @param CommandSender $target the target to check the permission for
|
||||
* @param string|null $permission the permission to check, if null, will check if the target has any of the command's permissions
|
||||
*/
|
||||
public function testPermission(string $context, CommandSender $target, ?string $permission = null) : bool{
|
||||
public function testPermission(CommandSender $target, ?string $permission = null) : bool{
|
||||
if($this->testPermissionSilent($target, $permission)){
|
||||
return true;
|
||||
}
|
||||
|
||||
$message = $this->permissionMessage ?? KnownTranslationFactory::pocketmine_command_error_permission($context);
|
||||
if($message instanceof Translatable){
|
||||
$target->sendMessage($message->prefix(TextFormat::RED));
|
||||
}elseif($message !== ""){
|
||||
$target->sendMessage(str_replace("<permission>", $permission ?? implode(";", $this->permission), $message));
|
||||
if($this->permissionMessage === null){
|
||||
$target->sendMessage(KnownTranslationFactory::pocketmine_command_error_permission($this->name)->prefix(TextFormat::RED));
|
||||
}elseif($this->permissionMessage !== ""){
|
||||
$target->sendMessage(str_replace("<permission>", $permission ?? implode(";", $this->permission), $this->permissionMessage));
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -112,7 +142,63 @@ abstract class Command{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getPermissionMessage() : Translatable|string|null{
|
||||
public function getLabel() : string{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
public function setLabel(string $name) : bool{
|
||||
$this->nextLabel = $name;
|
||||
if(!$this->isRegistered()){
|
||||
$this->label = $name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the command into a Command map
|
||||
*/
|
||||
public function register(CommandMap $commandMap) : bool{
|
||||
if($this->allowChangesFrom($commandMap)){
|
||||
$this->commandMap = $commandMap;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function unregister(CommandMap $commandMap) : bool{
|
||||
if($this->allowChangesFrom($commandMap)){
|
||||
$this->commandMap = null;
|
||||
$this->activeAliases = $this->aliases;
|
||||
$this->label = $this->nextLabel;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function allowChangesFrom(CommandMap $commandMap) : bool{
|
||||
return $this->commandMap === null || $this->commandMap === $commandMap;
|
||||
}
|
||||
|
||||
public function isRegistered() : bool{
|
||||
return $this->commandMap !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @phpstan-return list<string>
|
||||
*/
|
||||
public function getAliases() : array{
|
||||
return $this->activeAliases;
|
||||
}
|
||||
|
||||
public function getPermissionMessage() : ?string{
|
||||
return $this->permissionMessage;
|
||||
}
|
||||
|
||||
@ -120,19 +206,31 @@ abstract class Command{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function getUsage() : Translatable|string|null{
|
||||
public function getUsage() : Translatable|string{
|
||||
return $this->usageMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $aliases
|
||||
* @phpstan-param list<string> $aliases
|
||||
*/
|
||||
public function setAliases(array $aliases) : void{
|
||||
$aliases = array_values($aliases); //because plugins can and will pass crap
|
||||
$this->aliases = $aliases;
|
||||
if(!$this->isRegistered()){
|
||||
$this->activeAliases = $aliases;
|
||||
}
|
||||
}
|
||||
|
||||
public function setDescription(Translatable|string $description) : void{
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
public function setPermissionMessage(Translatable|string $permissionMessage) : void{
|
||||
public function setPermissionMessage(string $permissionMessage) : void{
|
||||
$this->permissionMessage = $permissionMessage;
|
||||
}
|
||||
|
||||
public function setUsage(Translatable|string|null $usage) : void{
|
||||
public function setUsage(Translatable|string $usage) : void{
|
||||
$this->usageMessage = $usage;
|
||||
}
|
||||
|
||||
@ -153,4 +251,8 @@ abstract class Command{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString() : string{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,13 @@ declare(strict_types=1);
|
||||
namespace pocketmine\command;
|
||||
|
||||
interface CommandMap{
|
||||
|
||||
/**
|
||||
* @param string[] $otherAliases
|
||||
*
|
||||
* @phpstan-param list<string> $otherAliases
|
||||
* @param Command[] $commands
|
||||
*/
|
||||
public function register(string $fallbackPrefix, Command $command, string $preferredAlias, array $otherAliases = []) : CommandMapEntry;
|
||||
public function registerAll(string $fallbackPrefix, array $commands) : void;
|
||||
|
||||
public function register(string $fallbackPrefix, Command $command, ?string $label = null) : bool;
|
||||
|
||||
public function dispatch(CommandSender $sender, string $cmdLine) : bool;
|
||||
|
||||
|
@ -50,9 +50,10 @@ class FormattedCommandAlias extends Command{
|
||||
* @param string[] $formatStrings
|
||||
*/
|
||||
public function __construct(
|
||||
string $alias,
|
||||
private array $formatStrings
|
||||
){
|
||||
parent::__construct(KnownTranslationFactory::pocketmine_command_userDefined_description());
|
||||
parent::__construct($alias, KnownTranslationFactory::pocketmine_command_userDefined_description());
|
||||
}
|
||||
|
||||
public function execute(CommandSender $sender, string $commandLabel, array $args){
|
||||
@ -94,14 +95,12 @@ class FormattedCommandAlias extends Command{
|
||||
throw new AssumptionFailedError("This should have been checked before construction");
|
||||
}
|
||||
|
||||
if(($target = $commandMap->getEntry($commandLabel)) !== null){
|
||||
//TODO: using labels for command dispatch is problematic - what if the label changes?
|
||||
//maybe this should use command class instead?
|
||||
$timings = Timings::getCommandDispatchTimings($target->getPreferredAlias());
|
||||
if(($target = $commandMap->getCommand($commandLabel)) !== null){
|
||||
$timings = Timings::getCommandDispatchTimings($target->getLabel());
|
||||
$timings->startTiming();
|
||||
|
||||
try{
|
||||
$target->command->execute($sender, $commandLabel, $commandArgs);
|
||||
$target->execute($sender, $commandLabel, $commandArgs);
|
||||
}catch(InvalidCommandSyntaxException $e){
|
||||
$sender->sendMessage($sender->getLanguage()->translate(KnownTranslationFactory::commands_generic_usage($target->getUsage())));
|
||||
}finally{
|
||||
|
@ -24,23 +24,17 @@ declare(strict_types=1);
|
||||
namespace pocketmine\command;
|
||||
|
||||
use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\lang\Translatable;
|
||||
use pocketmine\plugin\Plugin;
|
||||
use pocketmine\plugin\PluginOwned;
|
||||
|
||||
final class PluginCommand extends Command implements PluginOwned{
|
||||
public function __construct(
|
||||
private string $name,
|
||||
string $name,
|
||||
private Plugin $owner,
|
||||
private CommandExecutor $executor,
|
||||
Translatable|string $description = "",
|
||||
Translatable|string|null $usageMessage = null
|
||||
private CommandExecutor $executor
|
||||
){
|
||||
parent::__construct($description, $usageMessage);
|
||||
}
|
||||
|
||||
public function getName() : string{
|
||||
return $this->name;
|
||||
parent::__construct($name);
|
||||
$this->usageMessage = "";
|
||||
}
|
||||
|
||||
public function execute(CommandSender $sender, string $commandLabel, array $args){
|
||||
@ -49,11 +43,13 @@ final class PluginCommand extends Command implements PluginOwned{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!$this->executor->onCommand($sender, $this, $commandLabel, $args)){
|
||||
$success = $this->executor->onCommand($sender, $this, $commandLabel, $args);
|
||||
|
||||
if(!$success && $this->usageMessage !== ""){
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
return true;
|
||||
return $success;
|
||||
}
|
||||
|
||||
public function getOwningPlugin() : Plugin{
|
||||
|
@ -61,6 +61,7 @@ use pocketmine\command\defaults\TimeCommand;
|
||||
use pocketmine\command\defaults\TimingsCommand;
|
||||
use pocketmine\command\defaults\TitleCommand;
|
||||
use pocketmine\command\defaults\TransferServerCommand;
|
||||
use pocketmine\command\defaults\VanillaCommand;
|
||||
use pocketmine\command\defaults\VersionCommand;
|
||||
use pocketmine\command\defaults\WhitelistCommand;
|
||||
use pocketmine\command\defaults\XpCommand;
|
||||
@ -69,15 +70,12 @@ use pocketmine\command\utils\InvalidCommandSyntaxException;
|
||||
use pocketmine\lang\KnownTranslationFactory;
|
||||
use pocketmine\Server;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\AssumptionFailedError;
|
||||
use pocketmine\utils\TextFormat;
|
||||
use pocketmine\utils\Utils;
|
||||
use function array_filter;
|
||||
use function array_shift;
|
||||
use function array_values;
|
||||
use function count;
|
||||
use function implode;
|
||||
use function spl_object_id;
|
||||
use function str_contains;
|
||||
use function strcasecmp;
|
||||
use function strtolower;
|
||||
@ -89,138 +87,122 @@ class SimpleCommandMap implements CommandMap{
|
||||
* @var Command[]
|
||||
* @phpstan-var array<string, Command>
|
||||
*/
|
||||
protected array $aliasToCommandMap = [];
|
||||
|
||||
/**
|
||||
* @var CommandMapEntry[]
|
||||
* @phpstan-var array<int, CommandMapEntry>
|
||||
*/
|
||||
private array $uniqueCommands = [];
|
||||
protected array $knownCommands = [];
|
||||
|
||||
public function __construct(private Server $server){
|
||||
$this->setDefaultCommands();
|
||||
}
|
||||
|
||||
private function setDefaultCommands() : void{
|
||||
$pmPrefix = "pocketmine";
|
||||
$this->register($pmPrefix, new BanCommand(), "ban");
|
||||
$this->register($pmPrefix, new BanIpCommand(), "ban-ip");
|
||||
$this->register($pmPrefix, new BanListCommand(), "banlist");
|
||||
$this->register($pmPrefix, new ClearCommand(), "clear");
|
||||
$this->register($pmPrefix, new DefaultGamemodeCommand(), "defaultgamemode");
|
||||
$this->register($pmPrefix, new DeopCommand(), "deop");
|
||||
$this->register($pmPrefix, new DifficultyCommand(), "difficulty");
|
||||
$this->register($pmPrefix, new DumpMemoryCommand(), "dumpmemory");
|
||||
$this->register($pmPrefix, new EffectCommand(), "effect");
|
||||
$this->register($pmPrefix, new EnchantCommand(), "enchant");
|
||||
$this->register($pmPrefix, new GamemodeCommand(), "gamemode");
|
||||
$this->register($pmPrefix, new GarbageCollectorCommand(), "gc");
|
||||
$this->register($pmPrefix, new GiveCommand(), "give");
|
||||
$this->register($pmPrefix, new HelpCommand(), "help", ["?"]);
|
||||
$this->register($pmPrefix, new KickCommand(), "kick");
|
||||
$this->register($pmPrefix, new KillCommand(), "kill", ["suicide"]);
|
||||
$this->register($pmPrefix, new ListCommand(), "list");
|
||||
$this->register($pmPrefix, new MeCommand(), "me");
|
||||
$this->register($pmPrefix, new OpCommand(), "op");
|
||||
$this->register($pmPrefix, new PardonCommand(), "pardon", ["unban"]);
|
||||
$this->register($pmPrefix, new PardonIpCommand(), "pardon-ip", ["unban-ip"]);
|
||||
$this->register($pmPrefix, new ParticleCommand(), "particle");
|
||||
$this->register($pmPrefix, new PluginsCommand(), "plugins", ["pl"]);
|
||||
$this->register($pmPrefix, new SaveCommand(), "save-all");
|
||||
$this->register($pmPrefix, new SaveOffCommand(), "save-off");
|
||||
$this->register($pmPrefix, new SaveOnCommand(), "save-on");
|
||||
$this->register($pmPrefix, new SayCommand(), "say");
|
||||
$this->register($pmPrefix, new SeedCommand(), "seed");
|
||||
$this->register($pmPrefix, new SetWorldSpawnCommand(), "setworldspawn");
|
||||
$this->register($pmPrefix, new SpawnpointCommand(), "spawnpoint");
|
||||
$this->register($pmPrefix, new StatusCommand(), "status");
|
||||
$this->register($pmPrefix, new StopCommand(), "stop");
|
||||
$this->register($pmPrefix, new TeleportCommand(), "tp", ["teleport"]);
|
||||
$this->register($pmPrefix, new TellCommand(), "tell", ["w", "msg"]);
|
||||
$this->register($pmPrefix, new TimeCommand(), "time");
|
||||
$this->register($pmPrefix, new TimingsCommand(), "timings");
|
||||
$this->register($pmPrefix, new TitleCommand(), "title");
|
||||
$this->register($pmPrefix, new TransferServerCommand(), "transferserver");
|
||||
$this->register($pmPrefix, new VersionCommand(), "version", ["ver", "about"]);
|
||||
$this->register($pmPrefix, new WhitelistCommand(), "whitelist");
|
||||
$this->register($pmPrefix, new XpCommand(), "xp");
|
||||
$this->registerAll("pocketmine", [
|
||||
new BanCommand(),
|
||||
new BanIpCommand(),
|
||||
new BanListCommand(),
|
||||
new ClearCommand(),
|
||||
new DefaultGamemodeCommand(),
|
||||
new DeopCommand(),
|
||||
new DifficultyCommand(),
|
||||
new DumpMemoryCommand(),
|
||||
new EffectCommand(),
|
||||
new EnchantCommand(),
|
||||
new GamemodeCommand(),
|
||||
new GarbageCollectorCommand(),
|
||||
new GiveCommand(),
|
||||
new HelpCommand(),
|
||||
new KickCommand(),
|
||||
new KillCommand(),
|
||||
new ListCommand(),
|
||||
new MeCommand(),
|
||||
new OpCommand(),
|
||||
new PardonCommand(),
|
||||
new PardonIpCommand(),
|
||||
new ParticleCommand(),
|
||||
new PluginsCommand(),
|
||||
new SaveCommand(),
|
||||
new SaveOffCommand(),
|
||||
new SaveOnCommand(),
|
||||
new SayCommand(),
|
||||
new SeedCommand(),
|
||||
new SetWorldSpawnCommand(),
|
||||
new SpawnpointCommand(),
|
||||
new StatusCommand(),
|
||||
new StopCommand(),
|
||||
new TeleportCommand(),
|
||||
new TellCommand(),
|
||||
new TimeCommand(),
|
||||
new TimingsCommand(),
|
||||
new TitleCommand(),
|
||||
new TransferServerCommand(),
|
||||
new VersionCommand(),
|
||||
new WhitelistCommand(),
|
||||
new XpCommand(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function register(string $fallbackPrefix, Command $command, string $preferredAlias, array $otherAliases = []) : CommandMapEntry{
|
||||
public function registerAll(string $fallbackPrefix, array $commands) : void{
|
||||
foreach($commands as $command){
|
||||
$this->register($fallbackPrefix, $command);
|
||||
}
|
||||
}
|
||||
|
||||
public function register(string $fallbackPrefix, Command $command, ?string $label = null) : bool{
|
||||
if(count($command->getPermissions()) === 0){
|
||||
throw new \InvalidArgumentException("Commands must have a permission set");
|
||||
}
|
||||
if(isset($this->uniqueCommands[spl_object_id($command)])){
|
||||
throw new \InvalidArgumentException("This Command object has already been registered");
|
||||
}
|
||||
|
||||
$preferredAlias = trim($preferredAlias);
|
||||
if($label === null){
|
||||
$label = $command->getLabel();
|
||||
}
|
||||
$label = trim($label);
|
||||
$fallbackPrefix = strtolower(trim($fallbackPrefix));
|
||||
|
||||
$registeredAliases = [];
|
||||
//primary labels take precedence over any existing registrations
|
||||
$this->mapAlias($preferredAlias, $command, $registeredAliases);
|
||||
$this->mapAlias($fallbackPrefix . ":" . $preferredAlias, $command, $registeredAliases);
|
||||
$registered = $this->registerAlias($command, false, $fallbackPrefix, $label);
|
||||
|
||||
foreach($otherAliases as $alias){
|
||||
$this->mapAlias($fallbackPrefix . ":" . $alias, $command, $registeredAliases);
|
||||
if(!isset($this->aliasToCommandMap[$alias])){
|
||||
$this->mapAlias($alias, $command, $registeredAliases);
|
||||
$aliases = $command->getAliases();
|
||||
foreach($aliases as $index => $alias){
|
||||
if(!$this->registerAlias($command, true, $fallbackPrefix, $alias)){
|
||||
unset($aliases[$index]);
|
||||
}
|
||||
}
|
||||
$command->setAliases(array_values($aliases));
|
||||
|
||||
$entry = new CommandMapEntry($command, $registeredAliases);
|
||||
$this->uniqueCommands[spl_object_id($command)] = $entry;
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] &$registeredAliases
|
||||
* @phpstan-param list<string> &$registeredAliases
|
||||
* @phpstan-param-out non-empty-list<string> $registeredAliases
|
||||
*/
|
||||
private function mapAlias(string $alias, Command $command, array &$registeredAliases) : void{
|
||||
$this->unregisterAlias($alias);
|
||||
$this->aliasToCommandMap[$alias] = $command;
|
||||
$registeredAliases[] = $alias;
|
||||
}
|
||||
|
||||
public function registerAlias(string $existingAlias, string $newAlias) : void{
|
||||
$existingCommand = $this->aliasToCommandMap[$existingAlias] ?? null;
|
||||
if($existingCommand === null){
|
||||
throw new \InvalidArgumentException("No command is currently using the alias \"$existingAlias\", cannot create an alias to it");
|
||||
if(!$registered){
|
||||
$command->setLabel($fallbackPrefix . ":" . $label);
|
||||
}
|
||||
$registration = $this->uniqueCommands[spl_object_id($existingCommand)];
|
||||
$newAliases = $registration->aliases;
|
||||
$this->mapAlias($newAlias, $existingCommand, $newAliases);
|
||||
$this->uniqueCommands[spl_object_id($existingCommand)] = new CommandMapEntry($existingCommand, $newAliases);
|
||||
}
|
||||
|
||||
public function unregisterAlias(string $alias) : void{
|
||||
$oldCommand = $this->aliasToCommandMap[$alias] ?? null;
|
||||
if($oldCommand !== null){
|
||||
unset($this->aliasToCommandMap[$alias]);
|
||||
$oldCommandKey = spl_object_id($oldCommand);
|
||||
$oldCommandEntry = $this->uniqueCommands[$oldCommandKey];
|
||||
$filteredAliases = array_values(array_filter($oldCommandEntry->aliases, fn(string $oldAlias) => $oldAlias !== $alias));
|
||||
if(count($filteredAliases) > 0){
|
||||
$this->uniqueCommands[$oldCommandKey] = new CommandMapEntry($oldCommand, $filteredAliases);
|
||||
}else{
|
||||
unset($this->uniqueCommands[$oldCommandKey]);
|
||||
}
|
||||
}
|
||||
$command->register($this);
|
||||
|
||||
return $registered;
|
||||
}
|
||||
|
||||
public function unregister(Command $command) : bool{
|
||||
$entry = $this->uniqueCommands[spl_object_id($command)] ?? null;
|
||||
if($entry !== null){
|
||||
unset($this->uniqueCommands[spl_object_id($command)]);
|
||||
foreach($entry->aliases as $alias){
|
||||
unset($this->aliasToCommandMap[$alias]);
|
||||
foreach(Utils::promoteKeys($this->knownCommands) as $lbl => $cmd){
|
||||
if($cmd === $command){
|
||||
unset($this->knownCommands[$lbl]);
|
||||
}
|
||||
}
|
||||
|
||||
$command->unregister($this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function registerAlias(Command $command, bool $isAlias, string $fallbackPrefix, string $label) : bool{
|
||||
$this->knownCommands[$fallbackPrefix . ":" . $label] = $command;
|
||||
if(($command instanceof VanillaCommand || $isAlias) && isset($this->knownCommands[$label])){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isset($this->knownCommands[$label]) && $this->knownCommands[$label]->getLabel() === $label){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!$isAlias){
|
||||
$command->setLabel($label);
|
||||
}
|
||||
|
||||
$this->knownCommands[$label] = $command;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -228,15 +210,13 @@ class SimpleCommandMap implements CommandMap{
|
||||
$args = CommandStringHelper::parseQuoteAware($commandLine);
|
||||
|
||||
$sentCommandLabel = array_shift($args);
|
||||
if($sentCommandLabel !== null && ($target = $this->getEntry($sentCommandLabel)) !== null){
|
||||
//TODO: using labels for command dispatch is problematic - what if the label changes?
|
||||
//maybe this should use command class instead?
|
||||
$timings = Timings::getCommandDispatchTimings($target->getPreferredAlias());
|
||||
if($sentCommandLabel !== null && ($target = $this->getCommand($sentCommandLabel)) !== null){
|
||||
$timings = Timings::getCommandDispatchTimings($target->getLabel());
|
||||
$timings->startTiming();
|
||||
|
||||
try{
|
||||
if($target->command->testPermission($sentCommandLabel, $sender)){
|
||||
$target->command->execute($sender, $sentCommandLabel, $args);
|
||||
if($target->testPermission($sender)){
|
||||
$target->execute($sender, $sentCommandLabel, $args);
|
||||
}
|
||||
}catch(InvalidCommandSyntaxException $e){
|
||||
$sender->sendMessage($sender->getLanguage()->translate(KnownTranslationFactory::commands_generic_usage($target->getUsage())));
|
||||
@ -251,36 +231,23 @@ class SimpleCommandMap implements CommandMap{
|
||||
}
|
||||
|
||||
public function clearCommands() : void{
|
||||
$this->aliasToCommandMap = [];
|
||||
$this->uniqueCommands = [];
|
||||
foreach($this->knownCommands as $command){
|
||||
$command->unregister($this);
|
||||
}
|
||||
$this->knownCommands = [];
|
||||
$this->setDefaultCommands();
|
||||
}
|
||||
|
||||
public function getCommand(string $name) : ?Command{
|
||||
return $this->aliasToCommandMap[$name] ?? null;
|
||||
return $this->knownCommands[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Command[]
|
||||
* @phpstan-return array<string, Command>
|
||||
*/
|
||||
public function getAliasToCommandMap() : array{
|
||||
return $this->aliasToCommandMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CommandMapEntry[]
|
||||
* @phpstan-return array<int, CommandMapEntry>
|
||||
*/
|
||||
public function getUniqueCommands() : array{
|
||||
return $this->uniqueCommands;
|
||||
}
|
||||
|
||||
public function getEntry(string $name) : ?CommandMapEntry{
|
||||
$command = $this->getCommand($name);
|
||||
return $command !== null ?
|
||||
$this->uniqueCommands[spl_object_id($command)] ?? throw new AssumptionFailedError("This should never be unset") :
|
||||
null;
|
||||
public function getCommands() : array{
|
||||
return $this->knownCommands;
|
||||
}
|
||||
|
||||
public function registerServerAliases() : void{
|
||||
@ -322,13 +289,12 @@ class SimpleCommandMap implements CommandMap{
|
||||
|
||||
//These registered commands have absolute priority
|
||||
$lowerAlias = strtolower($alias);
|
||||
$this->unregisterAlias($lowerAlias);
|
||||
if(count($targets) > 0){
|
||||
$aliasInstance = new FormattedCommandAlias($targets);
|
||||
$registeredAliases = [];
|
||||
$this->mapAlias($lowerAlias, $aliasInstance, $registeredAliases);
|
||||
$this->uniqueCommands[spl_object_id($aliasInstance)] = new CommandMapEntry($aliasInstance, $registeredAliases);
|
||||
$this->knownCommands[$lowerAlias] = new FormattedCommandAlias($lowerAlias, $targets);
|
||||
}else{
|
||||
unset($this->knownCommands[$lowerAlias]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ class BanCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"ban",
|
||||
KnownTranslationFactory::pocketmine_command_ban_player_description(),
|
||||
KnownTranslationFactory::commands_ban_usage()
|
||||
);
|
||||
|
@ -38,6 +38,7 @@ class BanIpCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"ban-ip",
|
||||
KnownTranslationFactory::pocketmine_command_ban_ip_description(),
|
||||
KnownTranslationFactory::commands_banip_usage()
|
||||
);
|
||||
|
@ -39,6 +39,7 @@ class BanListCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"banlist",
|
||||
KnownTranslationFactory::pocketmine_command_banlist_description(),
|
||||
KnownTranslationFactory::commands_banlist_usage()
|
||||
);
|
||||
|
@ -41,6 +41,7 @@ class ClearCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"clear",
|
||||
KnownTranslationFactory::pocketmine_command_clear_description(),
|
||||
KnownTranslationFactory::pocketmine_command_clear_usage()
|
||||
);
|
||||
@ -52,7 +53,7 @@ class ClearCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$target = $this->fetchPermittedPlayerTarget($commandLabel, $sender, $args[0] ?? null, DefaultPermissionNames::COMMAND_CLEAR_SELF, DefaultPermissionNames::COMMAND_CLEAR_OTHER);
|
||||
$target = $this->fetchPermittedPlayerTarget($sender, $args[0] ?? null, DefaultPermissionNames::COMMAND_CLEAR_SELF, DefaultPermissionNames::COMMAND_CLEAR_OTHER);
|
||||
if($target === null){
|
||||
return true;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class DefaultGamemodeCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"defaultgamemode",
|
||||
KnownTranslationFactory::pocketmine_command_defaultgamemode_description(),
|
||||
KnownTranslationFactory::commands_defaultgamemode_usage()
|
||||
);
|
||||
|
@ -37,6 +37,7 @@ class DeopCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"deop",
|
||||
KnownTranslationFactory::pocketmine_command_deop_description(),
|
||||
KnownTranslationFactory::commands_deop_usage()
|
||||
);
|
||||
|
@ -36,6 +36,7 @@ class DifficultyCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"difficulty",
|
||||
KnownTranslationFactory::pocketmine_command_difficulty_description(),
|
||||
KnownTranslationFactory::commands_difficulty_usage()
|
||||
);
|
||||
|
@ -33,6 +33,7 @@ class DumpMemoryCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"dumpmemory",
|
||||
KnownTranslationFactory::pocketmine_command_dumpmemory_description(),
|
||||
"/dumpmemory [path]"
|
||||
);
|
||||
|
@ -38,6 +38,7 @@ class EffectCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"effect",
|
||||
KnownTranslationFactory::pocketmine_command_effect_description(),
|
||||
KnownTranslationFactory::commands_effect_usage()
|
||||
);
|
||||
@ -52,7 +53,7 @@ class EffectCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $this->fetchPermittedPlayerTarget($commandLabel, $sender, $args[0], DefaultPermissionNames::COMMAND_EFFECT_SELF, DefaultPermissionNames::COMMAND_EFFECT_OTHER);
|
||||
$player = $this->fetchPermittedPlayerTarget($sender, $args[0], DefaultPermissionNames::COMMAND_EFFECT_SELF, DefaultPermissionNames::COMMAND_EFFECT_OTHER);
|
||||
if($player === null){
|
||||
return true;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ class EnchantCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"enchant",
|
||||
KnownTranslationFactory::pocketmine_command_enchant_description(),
|
||||
KnownTranslationFactory::commands_enchant_usage()
|
||||
);
|
||||
@ -50,7 +51,7 @@ class EnchantCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $this->fetchPermittedPlayerTarget($commandLabel, $sender, $args[0], DefaultPermissionNames::COMMAND_ENCHANT_SELF, DefaultPermissionNames::COMMAND_ENCHANT_OTHER);
|
||||
$player = $this->fetchPermittedPlayerTarget($sender, $args[0], DefaultPermissionNames::COMMAND_ENCHANT_SELF, DefaultPermissionNames::COMMAND_ENCHANT_OTHER);
|
||||
if($player === null){
|
||||
return true;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class GamemodeCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"gamemode",
|
||||
KnownTranslationFactory::pocketmine_command_gamemode_description(),
|
||||
KnownTranslationFactory::commands_gamemode_usage()
|
||||
);
|
||||
@ -55,7 +56,7 @@ class GamemodeCommand extends VanillaCommand{
|
||||
return true;
|
||||
}
|
||||
|
||||
$target = $this->fetchPermittedPlayerTarget($commandLabel, $sender, $args[1] ?? null, DefaultPermissionNames::COMMAND_GAMEMODE_SELF, DefaultPermissionNames::COMMAND_GAMEMODE_OTHER);
|
||||
$target = $this->fetchPermittedPlayerTarget($sender, $args[1] ?? null, DefaultPermissionNames::COMMAND_GAMEMODE_SELF, DefaultPermissionNames::COMMAND_GAMEMODE_OTHER);
|
||||
if($target === null){
|
||||
return true;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ class GarbageCollectorCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"gc",
|
||||
KnownTranslationFactory::pocketmine_command_gc_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_GC);
|
||||
|
@ -43,6 +43,7 @@ class GiveCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"give",
|
||||
KnownTranslationFactory::pocketmine_command_give_description(),
|
||||
KnownTranslationFactory::pocketmine_command_give_usage()
|
||||
);
|
||||
@ -57,7 +58,7 @@ class GiveCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $this->fetchPermittedPlayerTarget($commandLabel, $sender, $args[0], DefaultPermissionNames::COMMAND_GIVE_SELF, DefaultPermissionNames::COMMAND_GIVE_OTHER);
|
||||
$player = $this->fetchPermittedPlayerTarget($sender, $args[0], DefaultPermissionNames::COMMAND_GIVE_SELF, DefaultPermissionNames::COMMAND_GIVE_OTHER);
|
||||
if($player === null){
|
||||
return true;
|
||||
}
|
||||
|
@ -47,8 +47,10 @@ class HelpCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"help",
|
||||
KnownTranslationFactory::pocketmine_command_help_description(),
|
||||
KnownTranslationFactory::commands_help_usage()
|
||||
KnownTranslationFactory::commands_help_usage(),
|
||||
["?"]
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_HELP);
|
||||
}
|
||||
@ -70,13 +72,11 @@ class HelpCommand extends VanillaCommand{
|
||||
|
||||
$pageHeight = $sender->getScreenLineHeight();
|
||||
|
||||
//TODO: maybe inject this in the constructor instead of assuming the server's command map?
|
||||
$commandMap = $sender->getServer()->getCommandMap();
|
||||
if($commandName === ""){
|
||||
$commands = [];
|
||||
foreach($commandMap->getUniqueCommands() as $commandEntry){
|
||||
if($commandEntry->command->testPermissionSilent($sender)){
|
||||
$commands[$commandEntry->getPreferredAlias()] = $commandEntry;
|
||||
foreach($sender->getServer()->getCommandMap()->getCommands() as $command){
|
||||
if($command->testPermissionSilent($sender)){
|
||||
$commands[$command->getLabel()] = $command;
|
||||
}
|
||||
}
|
||||
ksort($commands, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
@ -88,31 +88,31 @@ class HelpCommand extends VanillaCommand{
|
||||
$sender->sendMessage(KnownTranslationFactory::commands_help_header((string) $pageNumber, (string) count($commands)));
|
||||
$lang = $sender->getLanguage();
|
||||
if(isset($commands[$pageNumber - 1])){
|
||||
foreach($commands[$pageNumber - 1] as $commandEntry){
|
||||
$description = $commandEntry->command->getDescription();
|
||||
foreach($commands[$pageNumber - 1] as $command){
|
||||
$description = $command->getDescription();
|
||||
$descriptionString = $description instanceof Translatable ? $lang->translate($description) : $description;
|
||||
$sender->sendMessage(TextFormat::DARK_GREEN . "/" . $commandEntry->getPreferredAlias() . ": " . TextFormat::RESET . $descriptionString);
|
||||
$sender->sendMessage(TextFormat::DARK_GREEN . "/" . $command->getLabel() . ": " . TextFormat::RESET . $descriptionString);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}else{
|
||||
if(($commandEntry = $commandMap->getEntry(strtolower($commandName))) !== null){
|
||||
if($commandEntry->command->testPermissionSilent($sender)){
|
||||
if(($cmd = $sender->getServer()->getCommandMap()->getCommand(strtolower($commandName))) instanceof Command){
|
||||
if($cmd->testPermissionSilent($sender)){
|
||||
$lang = $sender->getLanguage();
|
||||
$description = $commandEntry->command->getDescription();
|
||||
$description = $cmd->getDescription();
|
||||
$descriptionString = $description instanceof Translatable ? $lang->translate($description) : $description;
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_header($commandEntry->getPreferredAlias())
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_header($cmd->getLabel())
|
||||
->format(TextFormat::YELLOW . "--------- " . TextFormat::RESET, TextFormat::YELLOW . " ---------"));
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_description(TextFormat::RESET . $descriptionString)
|
||||
->prefix(TextFormat::GOLD));
|
||||
|
||||
$usage = $commandEntry->getUsage();
|
||||
$usage = $cmd->getUsage();
|
||||
$usageString = $usage instanceof Translatable ? $lang->translate($usage) : $usage;
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_usage(TextFormat::RESET . implode("\n" . TextFormat::RESET, explode("\n", $usageString, limit: PHP_INT_MAX)))
|
||||
->prefix(TextFormat::GOLD));
|
||||
|
||||
$aliases = $commandEntry->aliases;
|
||||
$aliases = $cmd->getAliases();
|
||||
sort($aliases, SORT_NATURAL);
|
||||
$sender->sendMessage(KnownTranslationFactory::pocketmine_command_help_specificCommand_aliases(TextFormat::RESET . implode(", ", $aliases))
|
||||
->prefix(TextFormat::GOLD));
|
||||
|
@ -39,6 +39,7 @@ class KickCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"kick",
|
||||
KnownTranslationFactory::pocketmine_command_kick_description(),
|
||||
KnownTranslationFactory::commands_kick_usage()
|
||||
);
|
||||
|
@ -35,8 +35,10 @@ class KillCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"kill",
|
||||
KnownTranslationFactory::pocketmine_command_kill_description(),
|
||||
KnownTranslationFactory::pocketmine_command_kill_usage()
|
||||
KnownTranslationFactory::pocketmine_command_kill_usage(),
|
||||
["suicide"]
|
||||
);
|
||||
$this->setPermissions([DefaultPermissionNames::COMMAND_KILL_SELF, DefaultPermissionNames::COMMAND_KILL_OTHER]);
|
||||
}
|
||||
@ -46,7 +48,7 @@ class KillCommand extends VanillaCommand{
|
||||
throw new InvalidCommandSyntaxException();
|
||||
}
|
||||
|
||||
$player = $this->fetchPermittedPlayerTarget($commandLabel, $sender, $args[0] ?? null, DefaultPermissionNames::COMMAND_KILL_SELF, DefaultPermissionNames::COMMAND_KILL_OTHER);
|
||||
$player = $this->fetchPermittedPlayerTarget($sender, $args[0] ?? null, DefaultPermissionNames::COMMAND_KILL_SELF, DefaultPermissionNames::COMMAND_KILL_OTHER);
|
||||
if($player === null){
|
||||
return true;
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ class ListCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"list",
|
||||
KnownTranslationFactory::pocketmine_command_list_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_LIST);
|
||||
|
@ -36,6 +36,7 @@ class MeCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"me",
|
||||
KnownTranslationFactory::pocketmine_command_me_description(),
|
||||
KnownTranslationFactory::commands_me_usage()
|
||||
);
|
||||
|
@ -37,6 +37,7 @@ class OpCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"op",
|
||||
KnownTranslationFactory::pocketmine_command_op_description(),
|
||||
KnownTranslationFactory::commands_op_usage()
|
||||
);
|
||||
|
@ -34,8 +34,10 @@ class PardonCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"pardon",
|
||||
KnownTranslationFactory::pocketmine_command_unban_player_description(),
|
||||
KnownTranslationFactory::commands_unban_usage()
|
||||
KnownTranslationFactory::commands_unban_usage(),
|
||||
["unban"]
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_UNBAN_PLAYER);
|
||||
}
|
||||
|
@ -35,8 +35,10 @@ class PardonIpCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"pardon-ip",
|
||||
KnownTranslationFactory::pocketmine_command_unban_ip_description(),
|
||||
KnownTranslationFactory::commands_unbanip_usage()
|
||||
KnownTranslationFactory::commands_unbanip_usage(),
|
||||
["unban-ip"]
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_UNBAN_IP);
|
||||
}
|
||||
|
@ -76,6 +76,7 @@ class ParticleCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"particle",
|
||||
KnownTranslationFactory::pocketmine_command_particle_description(),
|
||||
KnownTranslationFactory::pocketmine_command_particle_usage()
|
||||
);
|
||||
|
@ -38,8 +38,10 @@ class PluginsCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"plugins",
|
||||
KnownTranslationFactory::pocketmine_command_plugins_description(),
|
||||
null
|
||||
null,
|
||||
["pl"]
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_PLUGINS);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ class SaveCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"save-all",
|
||||
KnownTranslationFactory::pocketmine_command_save_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_SAVE_PERFORM);
|
||||
|
@ -32,6 +32,7 @@ class SaveOffCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"save-off",
|
||||
KnownTranslationFactory::pocketmine_command_saveoff_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_SAVE_DISABLE);
|
||||
|
@ -32,6 +32,7 @@ class SaveOnCommand extends VanillaCommand{
|
||||
|
||||
public function __construct(){
|
||||
parent::__construct(
|
||||
"save-on",
|
||||
KnownTranslationFactory::pocketmine_command_saveon_description()
|
||||
);
|
||||
$this->setPermission(DefaultPermissionNames::COMMAND_SAVE_ENABLE);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user