mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-20 16:00:20 +00:00
Compare commits
No commits in common. "stable" and "5.18.1" have entirely different histories.
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -1 +0,0 @@
|
||||
* @pmmp/server-developers
|
19
.github/ISSUE_TEMPLATE/api-change-request.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/api-change-request.md
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
name: API change request
|
||||
about: Suggest a change, addition or removal to the plugin API
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--- tell us what you want -->
|
||||
## Description
|
||||
|
||||
|
||||
<!--- explain why you want this and why it's a good idea -->
|
||||
## Justification
|
||||
|
||||
|
||||
<!--- (optional) describe alternative methods you've explored to achieve your goal -->
|
||||
## Alternative methods
|
87
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
87
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@ -1,87 +0,0 @@
|
||||
name: Bug report
|
||||
description: Report a feature of PocketMine-MP not working as expected
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Plugin information
|
||||
|
||||
> [!IMPORTANT]
|
||||
> It's strongly recommended to test for bugs without plugins before reporting an issue.
|
||||
> This helps avoid wasting maintainers' time on bugs that are not actually caused by PocketMine-MP.
|
||||
>
|
||||
> If you're not sure whether a plugin might be causing your issue, please seek help on our [Discord](https://discord.gg/bmSAZBG) before writing an issue.
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Plugin information
|
||||
options:
|
||||
- "I haven't tested without plugins"
|
||||
- Bug happens without plugins
|
||||
- Bug only happens with certain plugins (describe below)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Bug description
|
||||
|
||||
> [!TIP]
|
||||
> Helpful information to include:
|
||||
> - Steps to reproduce the issue
|
||||
> - Error backtraces
|
||||
> - Crashdumps
|
||||
> - Plugin code that triggers the issue
|
||||
> - List of installed plugins (use /plugins)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Steps to reproduce are critical to finding the cause of the problem!**
|
||||
> Without reproducing steps, the issue will probably not be solvable and may be closed.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem description
|
||||
description: Describe the problem, and how you encountered it
|
||||
placeholder: e.g. Steps to reproduce the issue
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behaviour
|
||||
description: What did you expect to happen?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Version, OS and game info
|
||||
> [!WARNING]
|
||||
> "Latest" is not a valid version.
|
||||
> Failure to fill these fields with valid information may result in your issue being closed.
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: PocketMine-MP version
|
||||
placeholder: Use the /version command in PocketMine-MP
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: PHP version
|
||||
placeholder: Use the /version command in PocketMine-MP
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Server OS
|
||||
placeholder: Use the /version command in PocketMine-MP
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Game version (if applicable)
|
||||
placeholder: e.g. Android, iOS, Windows, Xbox, PS4, Switch
|
||||
validations:
|
||||
required: false
|
37
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
37
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Unexpected non-crash behaviour (except missing gameplay features)
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Issue description
|
||||
|
||||
- Expected result: What were you expecting to happen?
|
||||
- Actual result: What actually happened?
|
||||
|
||||
### Steps to reproduce the issue
|
||||
1. ...
|
||||
2. ...
|
||||
|
||||
### OS and versions
|
||||
<!-- try the `version` command | LATEST IS NOT A VALID VERSION -->
|
||||
* PocketMine-MP:
|
||||
* PHP:
|
||||
* Using JIT: yes/no (delete as appropriate) <!-- look for the giant yellow warning in the log that says you're using JIT -->
|
||||
* Server OS:
|
||||
* Game version: Android/iOS/Win10/Xbox/PS4/Switch (delete as appropriate)
|
||||
|
||||
### Plugins
|
||||
<!--- use the `plugins` command and paste the output below -->
|
||||
|
||||
- If you remove all plugins, does the issue still occur?
|
||||
- If the issue is **not** reproducible without plugins:
|
||||
- Have you asked for help on our forums before creating an issue?
|
||||
- Can you provide sample, *minimal* reproducing code for the issue? If so, paste it in the bottom section
|
||||
|
||||
### Crashdump, backtrace or other files
|
||||
<!--- Submit crashdumps at https://crash.pmmp.io and paste a link -->
|
||||
<!--- Use gist or anything else to add other files and add links here -->
|
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -3,6 +3,9 @@ contact_links:
|
||||
- name: Help & support on Discord
|
||||
url: https://discord.gg/bmSAZBG
|
||||
about: We don't accept support requests on the issue tracker. Please try asking on Discord instead.
|
||||
- name: Help & support on forums
|
||||
url: https://forums.pmmp.io
|
||||
about: We don't accept support requests on the issue tracker. Please try asking on forums instead.
|
||||
- name: Documentation
|
||||
url: https://pmmp.rtfd.io
|
||||
about: PocketMine-MP documentation
|
||||
|
16
.github/ISSUE_TEMPLATE/crash.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE/crash.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
name: Crash
|
||||
about: Report a crash in PocketMine-MP (not plugins)
|
||||
title: Server crashed
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--- submit crashdump files to https://crash.pmmp.io -->
|
||||
<!--- or, copy the data between ===BEGIN CRASH DUMP=== and ===END CRASH DUMP and paste it on a site like https://pastebin.com -->
|
||||
<!--- DON'T JUST PASTE the crashdump into an issue -->
|
||||
Link to crashdump:
|
||||
|
||||
<!--- write additional information about the crash to help us find the problem -->
|
||||
### Additional comments (optional)
|
25
.github/ISSUE_TEMPLATE/crash.yml
vendored
25
.github/ISSUE_TEMPLATE/crash.yml
vendored
@ -1,25 +0,0 @@
|
||||
name: Crash
|
||||
description: Report a crash in PocketMine-MP (not plugins)
|
||||
title: Server crashed
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> [!TIP]
|
||||
> Submit crashdump `.log` files to the [Crash Archive](https://crash.pmmp.io/submit).
|
||||
> If you can't submit the crashdump to the Crash Archive, paste it on a site like [GitHub Gist](https://gist.github.com) or [Pastebin](https://pastebin.com).
|
||||
|
||||
> [!CAUTION]
|
||||
> DON'T paste the crashdump data directly into an issue.
|
||||
|
||||
- type: input
|
||||
id: crashdump-url
|
||||
attributes:
|
||||
label: Link to crashdump
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional comments (optional)
|
||||
description: Any other information that might help us solve the problem
|
19
.github/ISSUE_TEMPLATE/feature-proposal.yml
vendored
19
.github/ISSUE_TEMPLATE/feature-proposal.yml
vendored
@ -1,19 +0,0 @@
|
||||
name: Feature addition, change, or removal
|
||||
description: Propose adding new features, or changing/removing existing ones
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Problem description
|
||||
description: Explain why a change is needed
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Proposed solution
|
||||
description: Describe what changes you think should be made
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Alternative solutions or workarounds"
|
||||
description: "Describe other ways you've explored to achieve your goal"
|
31
.github/PULL_REQUEST_TEMPLATE.md
vendored
31
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,32 +1,43 @@
|
||||
<!-- Summarize your PR here. Keep it short and simple. -->
|
||||
## Introduction
|
||||
<!-- Explain existing problems or why this pull request is necessary -->
|
||||
|
||||
### Related issues & PRs
|
||||
### Relevant issues
|
||||
<!-- List relevant issues here -->
|
||||
<!--
|
||||
|
||||
* Fixes #1
|
||||
* Related to #2
|
||||
* Fixes #2
|
||||
|
||||
-->
|
||||
|
||||
## Changes
|
||||
### API changes
|
||||
<!-- Any additions to the API that should be documented in release notes? -->
|
||||
<!-- If not, you can delete this section -->
|
||||
|
||||
### Behavioural changes
|
||||
<!-- Any change in how the server behaves, or its performance? -->
|
||||
<!-- If not, you can delete this section -->
|
||||
|
||||
## Backwards compatibility
|
||||
<!-- Any possible backwards incompatible changes? How are they solved, or how can they be solved? -->
|
||||
<!-- If not, you can delete this section -->
|
||||
|
||||
## Follow-up
|
||||
<!-- Suggest any actions to be done before/after merging this pull request -->
|
||||
<!-- For example, future changes that this PR lays the groundwork for -->
|
||||
<!--
|
||||
|
||||
Requires translations:
|
||||
|
||||
| Name | Value in eng.ini |
|
||||
| :--: | :---: |
|
||||
| `foo.bar` | `Foo bar` |
|
||||
|
||||
-->
|
||||
|
||||
## Tests
|
||||
<!--
|
||||
If this PR affects gameplay or user experience in some way, it must be manually tested.
|
||||
Include any screenshots or videos of manual testing here.
|
||||
Any test plugin code should also be pasted here if it can't be adapted to a PHPUnit test.
|
||||
PRs which have not been tested MUST be marked as draft.
|
||||
-->
|
||||
I tested this PR by doing the following (tick all that apply):
|
||||
- [ ] Writing PHPUnit tests (commit these in the `tests/phpunit` folder)
|
||||
- [ ] Playtesting using a Minecraft client (provide screenshots or a video)
|
||||
- [ ] Writing a test plugin (provide the code and sample output)
|
||||
- [ ] Other (provide details)
|
||||
|
9
.github/dependabot.yml
vendored
9
.github/dependabot.yml
vendored
@ -12,10 +12,6 @@ updates:
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- "version-update:semver-minor"
|
||||
|
||||
#since we lock this to exact versions, it causes conflicts with minor-next & major-next in composer.lock
|
||||
#better to just test updates to this locally anyway since almost every version breaks something
|
||||
- dependency-name: phpstan/phpstan
|
||||
groups:
|
||||
production-patch-updates:
|
||||
dependency-type: production
|
||||
@ -41,7 +37,4 @@ updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: monthly
|
||||
groups:
|
||||
github-actions:
|
||||
patterns: ["*"]
|
||||
interval: weekly
|
||||
|
10
.github/workflows/build-docker-image.yml
vendored
10
.github/workflows/build-docker-image.yml
vendored
@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Update Docker Hub images
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
@ -53,7 +53,7 @@ jobs:
|
||||
run: echo NAME=$(echo "${GITHUB_REPOSITORY,,}") >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build image for tag
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
uses: docker/build-push-action@v6.7.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
- name: Build image for major tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
uses: docker/build-push-action@v6.7.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -79,7 +79,7 @@ jobs:
|
||||
|
||||
- name: Build image for minor tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
uses: docker/build-push-action@v6.7.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
|
||||
- name: Build image for latest tag
|
||||
if: steps.channel.outputs.CHANNEL == 'stable'
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
uses: docker/build-push-action@v6.7.0
|
||||
with:
|
||||
push: true
|
||||
context: ./pocketmine-mp
|
||||
|
2
.github/workflows/discord-release-notify.yml
vendored
2
.github/workflows/discord-release-notify.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.32.0
|
||||
uses: shivammathur/setup-php@2.31.1
|
||||
with:
|
||||
php-version: 8.2
|
||||
|
||||
|
111
.github/workflows/draft-release-pr-check.yml
vendored
111
.github/workflows/draft-release-pr-check.yml
vendored
@ -1,111 +0,0 @@
|
||||
name: Release PR checks
|
||||
|
||||
on:
|
||||
#do checks on every PR update
|
||||
pull_request:
|
||||
branches:
|
||||
- stable
|
||||
- minor-next
|
||||
- major-next
|
||||
- "legacy/*"
|
||||
paths:
|
||||
- "src/VersionInfo.php"
|
||||
|
||||
#allow this workflow to be invoked on PR merge, prior to creating the release
|
||||
workflow_call:
|
||||
outputs:
|
||||
valid:
|
||||
description: Whether this commit is valid for release
|
||||
value: ${{ jobs.check-intent.outputs.valid && jobs.check-validity.result == 'success' }}
|
||||
|
||||
permissions:
|
||||
contents: read #for user access check
|
||||
|
||||
jobs:
|
||||
check-intent:
|
||||
name: Check release trigger
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
outputs:
|
||||
valid: ${{ steps.validate.outputs.DEV_BUILD == 'false' }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check IS_DEVELOPMENT_BUILD flag
|
||||
id: validate
|
||||
run: |
|
||||
echo DEV_BUILD=$(sed -n "s/^\s*public const IS_DEVELOPMENT_BUILD = \(true\|false\);$/\1/p" src/VersionInfo.php) >> $GITHUB_OUTPUT
|
||||
|
||||
check-validity:
|
||||
name: Validate release info
|
||||
needs: [check-intent]
|
||||
#don't do these checks if this isn't a release - we don't want to generate unnecessary failed statuses
|
||||
if: needs.check-intent.outputs.valid == 'true'
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.32.0
|
||||
with:
|
||||
php-version: 8.2
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/composer/files
|
||||
~/.cache/composer/vcs
|
||||
key: "composer-v2-cache-${{ hashFiles('./composer.lock') }}"
|
||||
restore-keys: |
|
||||
composer-v2-cache-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-dev --prefer-dist --no-interaction --ignore-platform-reqs
|
||||
|
||||
- name: Check author permissions
|
||||
id: check-permission
|
||||
uses: actions-cool/check-user-permission@v2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
require: write
|
||||
username: ${{ github.event.pull_request.user.login }}
|
||||
#technically this would be fine for dependabot but generally bots don't count as team members
|
||||
check-bot: true
|
||||
|
||||
- name: Abort if user permissions are insufficient
|
||||
#user doesn't have permission or is a bot
|
||||
if: steps.check-permission.outputs.require-result != 'true' || steps.check-permission.outputs.check-result != 'false'
|
||||
run: |
|
||||
echo "::error::This user is not authorized to trigger releases"
|
||||
exit 1
|
||||
|
||||
- name: Check changelog file is present
|
||||
id: file-presence
|
||||
run: |
|
||||
CHANGELOG_FILE="changelogs/$(php build/dump-version-info.php changelog_file_name)"
|
||||
if [ ! -f "${{ github.workspace }}/$CHANGELOG_FILE" ]; then
|
||||
echo "::error::$CHANGELOG_FILE does not exist"
|
||||
exit 1
|
||||
fi
|
||||
echo FILE="$CHANGELOG_FILE" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check header is present in changelog file
|
||||
run: |
|
||||
FILE="${{ steps.file-presence.outputs.FILE }}"
|
||||
VERSION="$(php build/dump-version-info.php base_version)"
|
||||
if ! grep -Fqx "# $VERSION" "${{ github.workspace }}/$FILE"; then
|
||||
echo "::error::Header for $VERSION not found in $FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check version is valid for the selected channel
|
||||
run: |
|
||||
CHANNEL="$(php build/dump-version-info.php channel)"
|
||||
if [ "$(php build/dump-version-info.php suffix_valid)" != "true" ]; then
|
||||
echo "::error::Version $(php build/dump-version-info.php base_version) is not allowed on the $CHANNEL channel"
|
||||
exit 1
|
||||
fi
|
126
.github/workflows/draft-release.yml
vendored
126
.github/workflows/draft-release.yml
vendored
@ -1,85 +1,18 @@
|
||||
name: Draft release
|
||||
|
||||
on:
|
||||
#presume that pull_request_target is safe at this point, since the PR was approved and merged
|
||||
#we need write access to prepare the release & create comments
|
||||
pull_request_target:
|
||||
types:
|
||||
- closed
|
||||
branches:
|
||||
- stable
|
||||
- minor-next
|
||||
- major-next
|
||||
- "legacy/*"
|
||||
paths:
|
||||
- "src/VersionInfo.php"
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
env:
|
||||
PHP_VERSION: "8.2"
|
||||
tags: "*"
|
||||
|
||||
jobs:
|
||||
skip:
|
||||
name: Check whether to ignore this tag
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
outputs:
|
||||
skip: ${{ steps.exists.outputs.exists == 'true' }}
|
||||
|
||||
steps:
|
||||
- name: Check if release already exists
|
||||
id: exists
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
exists=false
|
||||
if [[ "${{ github.ref_type }}" == "tag" ]]; then
|
||||
tag="$(echo "${{ github.ref }}" | cut -d/ -f3-)"
|
||||
if gh release view "$tag" --repo "${{ github.repository }}"; then
|
||||
exists=true
|
||||
fi
|
||||
fi
|
||||
echo exists=$exists >> $GITHUB_OUTPUT
|
||||
|
||||
check:
|
||||
needs: [skip]
|
||||
if: needs.skip.outputs.skip != 'true'
|
||||
name: Check release
|
||||
uses: ./.github/workflows/draft-release-pr-check.yml
|
||||
|
||||
trigger-post-release-workflow:
|
||||
name: Trigger post-release RestrictedActions workflow
|
||||
needs: [check]
|
||||
if: needs.check.outputs.valid == 'true' && github.ref_type != 'tag' #can't do post-commit for a tag
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
with:
|
||||
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
|
||||
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repositories: RestrictedActions
|
||||
|
||||
- name: Dispatch post-release restricted action
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
repository: ${{ github.repository_owner }}/RestrictedActions
|
||||
event-type: pocketmine_mp_post_release
|
||||
client-payload: '{"branch": "${{ github.ref }}"}'
|
||||
|
||||
draft:
|
||||
name: Create GitHub draft release
|
||||
needs: [check]
|
||||
if: needs.check.outputs.valid == 'true' || github.ref_type == 'tag' #ignore validity check for tags
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
if: "startsWith(github.event.head_commit.message, 'Release ')"
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-version: [8.2]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -87,9 +20,9 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@2.32.0
|
||||
uses: shivammathur/setup-php@2.31.1
|
||||
with:
|
||||
php-version: ${{ env.PHP_VERSION }}
|
||||
php-version: ${{ matrix.php-version }}
|
||||
|
||||
- name: Restore Composer package cache
|
||||
uses: actions/cache@v4
|
||||
@ -107,7 +40,7 @@ jobs:
|
||||
- name: Calculate build number
|
||||
id: build-number
|
||||
run: |
|
||||
BUILD_NUMBER=$((2300+$GITHUB_RUN_NUMBER)) #to stay above jenkins
|
||||
BUILD_NUMBER=$((2000+$GITHUB_RUN_NUMBER)) #to stay above jenkins
|
||||
echo "Build number: $BUILD_NUMBER"
|
||||
echo BUILD_NUMBER=$BUILD_NUMBER >> $GITHUB_OUTPUT
|
||||
|
||||
@ -120,31 +53,23 @@ jobs:
|
||||
- name: Get PocketMine-MP release version
|
||||
id: get-pm-version
|
||||
run: |
|
||||
PM_VERSION=$(php build/dump-version-info.php base_version)
|
||||
echo PM_VERSION=$PM_VERSION >> $GITHUB_OUTPUT
|
||||
echo PM_MAJOR=$(php build/dump-version-info.php major_version) >> $GITHUB_OUTPUT
|
||||
echo MCPE_VERSION=$(php build/dump-version-info.php mcpe_version) >> $GITHUB_OUTPUT
|
||||
echo CHANGELOG_FILE_NAME=$(php build/dump-version-info.php changelog_file_name) >> $GITHUB_OUTPUT
|
||||
echo CHANGELOG_MD_HEADER=$(php build/dump-version-info.php changelog_md_header) >> $GITHUB_OUTPUT
|
||||
echo PRERELEASE=$(php build/dump-version-info.php prerelease) >> $GITHUB_OUTPUT
|
||||
|
||||
if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
|
||||
tag="$(echo "${{ github.ref }}" | cut -d/ -f3-)"
|
||||
else
|
||||
tag="$PM_VERSION"
|
||||
fi
|
||||
echo TAG_NAME=$tag >> $GITHUB_OUTPUT
|
||||
echo PM_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BASE_VERSION;') >> $GITHUB_OUTPUT
|
||||
echo MCPE_VERSION=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\network\mcpe\protocol\ProtocolInfo::MINECRAFT_VERSION_NETWORK;') >> $GITHUB_OUTPUT
|
||||
echo PM_VERSION_SHORT=$(php -r 'require "vendor/autoload.php"; $v = explode(".", \pocketmine\VersionInfo::BASE_VERSION); array_pop($v); echo implode(".", $v);') >> $GITHUB_OUTPUT
|
||||
echo PM_VERSION_MD=$(php -r 'require "vendor/autoload.php"; echo str_replace(".", "", \pocketmine\VersionInfo::BASE_VERSION);') >> $GITHUB_OUTPUT
|
||||
echo CHANGELOG_SUFFIX=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "" : "-" . \pocketmine\VersionInfo::BUILD_CHANNEL;') >> $GITHUB_OUTPUT
|
||||
echo PRERELEASE=$(php -r 'require "vendor/autoload.php"; echo \pocketmine\VersionInfo::BUILD_CHANNEL === "stable" ? "false" : "true";') >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate PHP binary download URL
|
||||
id: php-binary-url
|
||||
run: |
|
||||
echo PHP_BINARY_URL="${{ github.server_url }}/${{ github.repository_owner }}/PHP-Binaries/releases/tag/pm${{ steps.get-pm-version.outputs.PM_MAJOR }}-php-${{ env.PHP_VERSION }}-latest" >> $GITHUB_OUTPUT
|
||||
echo PHP_BINARY_URL="${{ github.server_url }}/${{ github.repository_owner }}/PHP-Binaries/releases/tag/php-${{ matrix.php-version }}-latest" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate build info
|
||||
run: |
|
||||
php build/generate-build-info-json.php \
|
||||
${{ github.sha }} \
|
||||
${{ steps.get-pm-version.outputs.TAG_NAME }} \
|
||||
${{ steps.get-pm-version.outputs.PM_VERSION }} \
|
||||
${{ github.repository }} \
|
||||
${{ steps.build-number.outputs.BUILD_NUMBER }} \
|
||||
${{ github.run_id }} \
|
||||
@ -165,27 +90,18 @@ jobs:
|
||||
${{ github.workspace }}/core-permissions.rst
|
||||
|
||||
- name: Create draft release
|
||||
uses: ncipollo/release-action@v1.16.0
|
||||
id: create-draft
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
artifacts: ${{ github.workspace }}/PocketMine-MP.phar,${{ github.workspace }}/start.*,${{ github.workspace }}/build_info.json,${{ github.workspace }}/core-permissions.rst
|
||||
commit: ${{ github.sha }}
|
||||
draft: true
|
||||
prerelease: ${{ steps.get-pm-version.outputs.PRERELEASE }}
|
||||
name: PocketMine-MP ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||
tag: ${{ steps.get-pm-version.outputs.TAG_NAME }}
|
||||
tag: ${{ steps.get-pm-version.outputs.PM_VERSION }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
body: |
|
||||
**For Minecraft: Bedrock Edition ${{ steps.get-pm-version.outputs.MCPE_VERSION }}**
|
||||
|
||||
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.CHANGELOG_FILE_NAME }}#${{ steps.get-pm-version.outputs.CHANGELOG_MD_HEADER }}) for details.
|
||||
Please see the [changelogs](${{ github.server_url }}/${{ github.repository }}/blob/${{ steps.get-pm-version.outputs.PM_VERSION }}/changelogs/${{ steps.get-pm-version.outputs.PM_VERSION_SHORT }}${{ steps.get-pm-version.outputs.CHANGELOG_SUFFIX }}.md#${{ steps.get-pm-version.outputs.PM_VERSION_MD }}) for details.
|
||||
|
||||
:information_source: Download the recommended PHP binary [here](${{ steps.php-binary-url.outputs.PHP_BINARY_URL }}).
|
||||
|
||||
:warning: Found a bug? Report it on our [issue tracker](${{ github.server_url }}/${{ github.repository }}/issues). **We can't fix bugs if you don't report them.**
|
||||
|
||||
- name: Post draft release URL on PR
|
||||
if: github.event_name == 'pull_request_target'
|
||||
uses: thollander/actions-comment-pull-request@v3
|
||||
with:
|
||||
message: "[Draft release ${{ steps.get-pm-version.outputs.PM_VERSION }}](${{ steps.create-draft.outputs.html_url }}) has been created for commit ${{ github.sha }}. Please review and publish it."
|
||||
|
10
.github/workflows/main-php-matrix.yml
vendored
10
.github/workflows/main-php-matrix.yml
vendored
@ -15,7 +15,7 @@ on:
|
||||
type: number
|
||||
image:
|
||||
description: 'Runner image to use'
|
||||
default: 'ubuntu-22.04'
|
||||
default: 'ubuntu-20.04'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
@ -30,7 +30,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.2.0
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
@ -62,7 +62,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.2.0
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
@ -96,7 +96,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.2.0
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
@ -128,7 +128,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: pmmp/setup-php-action@3.2.0
|
||||
uses: pmmp/setup-php-action@3.1.0
|
||||
with:
|
||||
php-version: ${{ inputs.php }}
|
||||
install-path: "./bin"
|
||||
|
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
||||
|
||||
codestyle:
|
||||
name: Code Style checks
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@ -28,7 +28,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP and tools
|
||||
uses: shivammathur/setup-php@2.32.0
|
||||
uses: shivammathur/setup-php@2.31.1
|
||||
with:
|
||||
php-version: 8.2
|
||||
tools: php-cs-fixer:3.49
|
||||
@ -40,7 +40,7 @@ jobs:
|
||||
|
||||
shellcheck:
|
||||
name: ShellCheck
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
|
33
.github/workflows/pr-remove-waiting-label.yml
vendored
33
.github/workflows/pr-remove-waiting-label.yml
vendored
@ -1,33 +0,0 @@
|
||||
name: Remove waiting label from PRs
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: synchronize
|
||||
|
||||
jobs:
|
||||
delabel:
|
||||
name: Remove label
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Remove label
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
script: |
|
||||
const [owner, repo] = context.payload.repository.full_name.split('/');
|
||||
try {
|
||||
await github.rest.issues.removeLabel({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
issue_number: context.payload.number,
|
||||
name: "Status: Waiting on Author",
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.status === 404) {
|
||||
//probably label wasn't set on the issue
|
||||
console.log('Failed to remove label (probably label isn\'t on the PR): ' + error.message);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
29
.github/workflows/pr-stale.yml
vendored
29
.github/workflows/pr-stale.yml
vendored
@ -1,29 +0,0 @@
|
||||
name: 'Clean up stale PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-issue-stale: -1
|
||||
days-before-issue-close: -1
|
||||
stale-pr-message: |
|
||||
This PR has been marked as "Waiting on Author", but we haven't seen any activity in 7 days.
|
||||
|
||||
If there is no further activity, it will be closed in 28 days.
|
||||
|
||||
Note for maintainers: Adding an assignee to the PR will prevent it from being marked as stale.
|
||||
|
||||
close-pr-message: |
|
||||
As this PR hasn't been updated for a while, unfortunately we'll have to close it.
|
||||
|
||||
days-before-pr-stale: 7
|
||||
days-before-pr-close: 28
|
||||
only-labels: "Status: Waiting on Author"
|
||||
close-pr-label: "Resolution: Abandoned"
|
||||
exempt-all-assignees: true
|
||||
|
5
.github/workflows/support.yml
vendored
5
.github/workflows/support.yml
vendored
@ -20,7 +20,10 @@ jobs:
|
||||
|
||||
- Check our [Documentation](https://doc.pmmp.io) to see if you can find answers there
|
||||
|
||||
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG)
|
||||
- Ask the community on our [Discord server](https://discord.gg/bmSAZBG) or our [Forums](https://forums.pmmp.io)
|
||||
|
||||
|
||||
[Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io)
|
||||
|
||||
close-issue: true
|
||||
lock-issue: false
|
||||
|
38
.github/workflows/team-pr-auto-approve.yml
vendored
38
.github/workflows/team-pr-auto-approve.yml
vendored
@ -9,30 +9,34 @@ on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- ready_for_review
|
||||
- synchronize
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
dispatch:
|
||||
name: Request approval
|
||||
approve:
|
||||
name: Auto approve
|
||||
runs-on: ubuntu-latest
|
||||
if: '! github.event.pull_request.draft'
|
||||
|
||||
steps:
|
||||
- name: Generate access token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
- name: Check if PR author has write access
|
||||
id: check-permission
|
||||
uses: actions-cool/check-user-permission@v2
|
||||
with:
|
||||
app-id: ${{ vars.RESTRICTED_ACTIONS_DISPATCH_ID }}
|
||||
private-key: ${{ secrets.RESTRICTED_ACTIONS_DISPATCH_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repositories: RestrictedActions
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
require: write
|
||||
username: ${{ github.event.pull_request.user.login }}
|
||||
#technically this would be fine for dependabot but generally bots don't count as team members
|
||||
check-bot: true
|
||||
|
||||
- name: Dispatch restricted action
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
#TODO: Some way to avoid unnecessary repeated reviews would be nice here
|
||||
|
||||
- name: Approve PR if authorized
|
||||
if: steps.check-permission.outputs.require-result == 'true' && steps.check-permission.outputs.check-result == 'false'
|
||||
uses: juliangruber/approve-pull-request-action@v2
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
repository: ${{ github.repository_owner }}/RestrictedActions
|
||||
event-type: auto_approve_collaborator_pr
|
||||
client-payload: '{"repo": "${{ github.repository }}", "pull_request_id": "${{ github.event.pull_request.number }}", "reviewer_id": "0" }'
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
number: ${{ github.event.pull_request.number }}
|
||||
|
@ -123,7 +123,7 @@ The following are required as a minimum for pull requests. PRs that don't meet t
|
||||
- Remember, PRs with small diffs are much easier to review. Small PRs are generally reviewed and merged much faster than large ones.
|
||||
- **Start small.** Try fixing minor bugs or doing something isolated (e.g. adding a new block or item) before attempting larger changes.
|
||||
- This helps you get familiar with the codebase, the contribution process, and the expectations of maintainers.
|
||||
- Check out ["Easy task" issues](https://github.com/pmmp/PocketMine-MP/issues?q=is%3Aissue+is%3Aopen+label%3A%22Easy+task%22) on the issues page for something that you could tackle without too much effort.
|
||||
- Check out the [issues page]() for something that you could tackle without too much effort.
|
||||
- **Do not copy-paste other people's code**. Many PRs involve discussion about the changes, and changes are often requested by reviewers. If you don't understand the code you're copy-pasting, your PR is likely to fail.
|
||||
- **Do not edit code directly on github.com.** We recommend learning how to use [`git`](https://git-scm.com). `git` allows you to "clone" a repository onto your computer, so that you can make changes using an IDE.
|
||||
- **Use an IDE, not a text editor.** We recommend PhpStorm or VSCode.
|
||||
|
@ -65,8 +65,6 @@ PocketMine-MP accepts community contributions! The following resources will be u
|
||||
* [Building and running PocketMine-MP from source](BUILDING.md)
|
||||
* [Contributing Guidelines](CONTRIBUTING.md)
|
||||
|
||||
New here? Check out [issues with the "Easy task" label](https://github.com/pmmp/PocketMine-MP/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22Easy%20task%22) for things you could work to familiarise yourself with the codebase.
|
||||
|
||||
## Donate
|
||||
PocketMine-MP is free, but it requires a lot of time and effort from unpaid volunteers to develop. Donations enable us to keep delivering support for new versions and adding features your players love.
|
||||
|
||||
|
@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use pocketmine\network\mcpe\protocol\ProtocolInfo;
|
||||
use pocketmine\VersionInfo;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
/*
|
||||
* Dumps version info in a machine-readable format for use in GitHub Actions workflows
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var string[]|\Closure[] $options
|
||||
* @phpstan-var array<string, string|\Closure() : string> $options
|
||||
*/
|
||||
$options = [
|
||||
"base_version" => VersionInfo::BASE_VERSION,
|
||||
"major_version" => fn() => explode(".", VersionInfo::BASE_VERSION, limit: 2)[0],
|
||||
"mcpe_version" => ProtocolInfo::MINECRAFT_VERSION_NETWORK,
|
||||
"is_dev" => VersionInfo::IS_DEVELOPMENT_BUILD,
|
||||
"changelog_file_name" => function() : string{
|
||||
$version = VersionInfo::VERSION();
|
||||
$result = $version->getMajor() . "." . $version->getMinor();
|
||||
$suffix = $version->getSuffix();
|
||||
if($suffix !== ""){
|
||||
if(preg_match('/^([A-Za-z]+)(\d+)$/', $suffix, $matches) !== 1){
|
||||
fwrite(STDERR, "error: invalid current version suffix \"$suffix\"; aborting" . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
$baseSuffix = $matches[1];
|
||||
$result .= "-" . strtolower($baseSuffix);
|
||||
}
|
||||
return $result . ".md";
|
||||
},
|
||||
"changelog_md_header" => fn() : string => str_replace(".", "", VersionInfo::BASE_VERSION),
|
||||
"prerelease" => fn() : bool => VersionInfo::VERSION()->getSuffix() !== "",
|
||||
"channel" => VersionInfo::BUILD_CHANNEL,
|
||||
"suffix_valid" => function() : bool{
|
||||
//TODO: maybe this should be put into its own script?
|
||||
$suffix = VersionInfo::VERSION()->getSuffix();
|
||||
if(VersionInfo::BUILD_CHANNEL === "stable"){
|
||||
//stable builds may not have suffixes
|
||||
return $suffix === "";
|
||||
}
|
||||
if(VersionInfo::BUILD_CHANNEL === "alpha" || VersionInfo::BUILD_CHANNEL === "beta"){
|
||||
$upperChannel = strtoupper(VersionInfo::BUILD_CHANNEL);
|
||||
$upperSuffix = strtoupper($suffix);
|
||||
return str_starts_with($upperSuffix, $upperChannel) && is_numeric(substr($upperSuffix, strlen($upperChannel)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
];
|
||||
if(count($argv) !== 2 || !isset($options[$argv[1]])){
|
||||
fwrite(STDERR, "Please provide an option (one of: " . implode(", ", array_keys($options)) . PHP_EOL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$result = $options[$argv[1]];
|
||||
if($result instanceof Closure){
|
||||
$result = $result();
|
||||
}
|
||||
if(is_bool($result)){
|
||||
echo $result ? "true" : "false";
|
||||
}else{
|
||||
echo $result;
|
||||
}
|
@ -28,7 +28,6 @@ use function dirname;
|
||||
use function fclose;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function is_dir;
|
||||
use function is_file;
|
||||
use function scandir;
|
||||
use function str_replace;
|
||||
@ -60,7 +59,7 @@ foreach($files as $file){
|
||||
continue;
|
||||
}
|
||||
$path = Path::join(BEDROCK_DATA_PATH, $file);
|
||||
if(!is_file($path) && !is_dir($path)){
|
||||
if(!is_file($path)){
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -68,7 +67,6 @@ foreach($files as $file){
|
||||
'README.md',
|
||||
'LICENSE',
|
||||
'composer.json',
|
||||
'.github'
|
||||
] as $ignored){
|
||||
if($file === $ignored){
|
||||
continue 2;
|
||||
|
@ -122,7 +122,7 @@ if(!is_array($ids)){
|
||||
throw new \RuntimeException("Invalid biome ID map, expected array for root JSON object");
|
||||
}
|
||||
$cleanedIds = [];
|
||||
foreach(Utils::promoteKeys($ids) as $name => $id){
|
||||
foreach($ids as $name => $id){
|
||||
if(!is_string($name) || !is_int($id)){
|
||||
throw new \RuntimeException("Invalid biome ID map, expected string => int map");
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ $constants = [];
|
||||
* @phpstan-param-out array<string, string> $constants
|
||||
*/
|
||||
function collectProperties(string $prefix, array $properties, array &$constants) : void{
|
||||
foreach(Utils::promoteKeys($properties) as $propertyName => $property){
|
||||
foreach($properties as $propertyName => $property){
|
||||
$fullPropertyName = ($prefix !== "" ? $prefix . "." : "") . $propertyName;
|
||||
|
||||
$constName = str_replace([".", "-"], "_", strtoupper($fullPropertyName));
|
||||
|
@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\update_registry_annotations;
|
||||
|
||||
use pocketmine\utils\Utils;
|
||||
use function basename;
|
||||
use function class_exists;
|
||||
use function count;
|
||||
@ -49,7 +48,6 @@ if(count($argv) !== 2){
|
||||
|
||||
/**
|
||||
* @param object[] $members
|
||||
* @phpstan-param array<string, object> $members
|
||||
*/
|
||||
function generateMethodAnnotations(string $namespaceName, array $members) : string{
|
||||
$selfName = basename(__FILE__);
|
||||
@ -62,7 +60,7 @@ function generateMethodAnnotations(string $namespaceName, array $members) : stri
|
||||
|
||||
static $lineTmpl = " * @method static %2\$s %s()";
|
||||
$memberLines = [];
|
||||
foreach(Utils::stringifyKeys($members) as $name => $member){
|
||||
foreach($members as $name => $member){
|
||||
$reflect = new \ReflectionClass($member);
|
||||
while($reflect !== false && $reflect->isAnonymous()){
|
||||
$reflect = $reflect->getParentClass();
|
||||
|
164
build/make-release.php
Normal file
164
build/make-release.php
Normal file
@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\build\make_release;
|
||||
|
||||
use pocketmine\utils\Filesystem;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\utils\VersionString;
|
||||
use pocketmine\VersionInfo;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function dirname;
|
||||
use function fgets;
|
||||
use function file_put_contents;
|
||||
use function fwrite;
|
||||
use function getopt;
|
||||
use function is_string;
|
||||
use function max;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function sprintf;
|
||||
use function str_pad;
|
||||
use function strlen;
|
||||
use function strtolower;
|
||||
use function system;
|
||||
use const STDERR;
|
||||
use const STDIN;
|
||||
use const STDOUT;
|
||||
use const STR_PAD_LEFT;
|
||||
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
function replaceVersion(string $versionInfoPath, string $newVersion, bool $isDev, string $channel) : void{
|
||||
$versionInfo = Filesystem::fileGetContents($versionInfoPath);
|
||||
$versionInfo = preg_replace(
|
||||
$pattern = '/^([\t ]*public )?const BASE_VERSION = "(\d+)\.(\d+)\.(\d+)(?:-(.*))?";$/m',
|
||||
'$1const BASE_VERSION = "' . $newVersion . '";',
|
||||
$versionInfo
|
||||
);
|
||||
$versionInfo = preg_replace(
|
||||
'/^([\t ]*public )?const IS_DEVELOPMENT_BUILD = (?:true|false);$/m',
|
||||
'$1const IS_DEVELOPMENT_BUILD = ' . ($isDev ? 'true' : 'false') . ';',
|
||||
$versionInfo
|
||||
);
|
||||
$versionInfo = preg_replace(
|
||||
'/^([\t ]*public )?const BUILD_CHANNEL = ".*";$/m',
|
||||
'$1const BUILD_CHANNEL = "' . $channel . '";',
|
||||
$versionInfo
|
||||
);
|
||||
file_put_contents($versionInfoPath, $versionInfo);
|
||||
}
|
||||
|
||||
const ACCEPTED_OPTS = [
|
||||
"current" => "Version to insert and tag",
|
||||
"next" => "Version to put in the file after tagging",
|
||||
"channel" => "Release channel to post this build into"
|
||||
];
|
||||
|
||||
function systemWrapper(string $command, string $errorMessage) : void{
|
||||
system($command, $result);
|
||||
if($result !== 0){
|
||||
echo "error: $errorMessage; aborting\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function main() : void{
|
||||
$filteredOpts = [];
|
||||
foreach(Utils::stringifyKeys(getopt("", ["current:", "next:", "channel:", "help"])) as $optName => $optValue){
|
||||
if($optName === "help"){
|
||||
fwrite(STDOUT, "Options:\n");
|
||||
|
||||
$maxLength = max(array_map(fn(string $str) => strlen($str), array_keys(ACCEPTED_OPTS)));
|
||||
foreach(ACCEPTED_OPTS as $acceptedName => $description){
|
||||
fwrite(STDOUT, str_pad("--$acceptedName", $maxLength + 4, " ", STR_PAD_LEFT) . ": $description\n");
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
if(!is_string($optValue)){
|
||||
fwrite(STDERR, "--$optName expects exactly 1 value\n");
|
||||
exit(1);
|
||||
}
|
||||
$filteredOpts[$optName] = $optValue;
|
||||
}
|
||||
|
||||
$channel = $filteredOpts["channel"] ?? null;
|
||||
if(isset($filteredOpts["current"])){
|
||||
$currentVer = new VersionString($filteredOpts["current"]);
|
||||
}else{
|
||||
$currentVer = new VersionString(VersionInfo::BASE_VERSION);
|
||||
}
|
||||
|
||||
$nextVer = isset($filteredOpts["next"]) ? new VersionString($filteredOpts["next"]) : null;
|
||||
|
||||
$suffix = $currentVer->getSuffix();
|
||||
if($suffix !== ""){
|
||||
if($channel === "stable"){
|
||||
fwrite(STDERR, "error: cannot release a suffixed build into the stable channel\n");
|
||||
exit(1);
|
||||
}
|
||||
if(preg_match('/^([A-Za-z]+)(\d+)$/', $suffix, $matches) !== 1){
|
||||
echo "error: invalid current version suffix \"$suffix\"; aborting\n";
|
||||
exit(1);
|
||||
}
|
||||
$nextVer ??= new VersionString(sprintf(
|
||||
"%u.%u.%u-%s%u",
|
||||
$currentVer->getMajor(),
|
||||
$currentVer->getMinor(),
|
||||
$currentVer->getPatch(),
|
||||
$matches[1],
|
||||
((int) $matches[2]) + 1
|
||||
));
|
||||
$channel ??= strtolower($matches[1]);
|
||||
}else{
|
||||
$nextVer ??= new VersionString(sprintf(
|
||||
"%u.%u.%u",
|
||||
$currentVer->getMajor(),
|
||||
$currentVer->getMinor(),
|
||||
$currentVer->getPatch() + 1
|
||||
));
|
||||
$channel ??= "stable";
|
||||
}
|
||||
|
||||
echo "About to tag version $currentVer. Next version will be $nextVer.\n";
|
||||
echo "$currentVer will be published on release channel \"$channel\".\n";
|
||||
echo "please add appropriate notes to the changelog and press enter...";
|
||||
fgets(STDIN);
|
||||
systemWrapper('git add "' . dirname(__DIR__) . '/changelogs"', "failed to stage changelog changes");
|
||||
system('git diff --cached --quiet "' . dirname(__DIR__) . '/changelogs"', $result);
|
||||
if($result === 0){
|
||||
echo "error: no changelog changes detected; aborting\n";
|
||||
exit(1);
|
||||
}
|
||||
$versionInfoPath = dirname(__DIR__) . '/src/VersionInfo.php';
|
||||
replaceVersion($versionInfoPath, $currentVer->getBaseVersion(), false, $channel);
|
||||
systemWrapper('git commit -m "Release ' . $currentVer->getBaseVersion() . '" --include "' . $versionInfoPath . '"', "failed to create release commit");
|
||||
systemWrapper('git tag ' . $currentVer->getBaseVersion(), "failed to create release tag");
|
||||
|
||||
replaceVersion($versionInfoPath, $nextVer->getBaseVersion(), true, $channel);
|
||||
systemWrapper('git add "' . $versionInfoPath . '"', "failed to stage changes for post-release commit");
|
||||
systemWrapper('git commit -m "' . $nextVer->getBaseVersion() . ' is next" --include "' . $versionInfoPath . '"', "failed to create post-release commit");
|
||||
}
|
||||
|
||||
main();
|
@ -1 +1 @@
|
||||
Subproject commit 15494337976e645499e2e3e8c8b491227522be91
|
||||
Subproject commit 084822aa9e381ca05591e902a2613fe971dff3fd
|
@ -25,7 +25,6 @@ namespace pocketmine\server_phar_stub;
|
||||
|
||||
use function clearstatcache;
|
||||
use function copy;
|
||||
use function define;
|
||||
use function fclose;
|
||||
use function fflush;
|
||||
use function flock;
|
||||
@ -166,5 +165,4 @@ $start = hrtime(true);
|
||||
$cacheName = preparePharCache($tmpDir, __FILE__);
|
||||
echo "Cache ready at $cacheName in " . number_format((hrtime(true) - $start) / 1e9, 2) . "s\n";
|
||||
|
||||
define('pocketmine\ORIGINAL_PHAR_PATH', __FILE__);
|
||||
require 'phar://' . str_replace(DIRECTORY_SEPARATOR, '/', $cacheName) . '/src/PocketMine.php';
|
||||
|
@ -129,7 +129,7 @@ function buildPhar(string $pharPath, string $basePath, array $includedPaths, arr
|
||||
}
|
||||
|
||||
function main() : void{
|
||||
if(ini_get("phar.readonly") === "1"){
|
||||
if(ini_get("phar.readonly") == 1){
|
||||
echo "Set phar.readonly to 0 with -dphar.readonly=0" . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
|
||||
- Use `VISIBLE_MOB_EFFECTS` actor metadata property to send effect bubbles, this fixes effect bubbles not showing
|
||||
|
||||
# 5.18.1
|
||||
Released 3rd September 2024.
|
||||
Released 2nd September 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed shift-crafting.
|
||||
|
@ -1,16 +0,0 @@
|
||||
# 5.19.0
|
||||
Released 21st September 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.21.30**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.30.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.30.
|
||||
- Removed support for earlier versions.
|
@ -1,25 +0,0 @@
|
||||
# 5.20.0
|
||||
Released 26th October 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.21.40**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.40.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.40.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
## Fixes
|
||||
- Fixed a bug in `tools/generate-blockstate-upgrade-schema.php` that caused it to fail on 1.21.40 with the new mushroom block changes.
|
||||
|
||||
# 5.20.1
|
||||
Released 31st October 2024.
|
||||
|
||||
## Fixes
|
||||
- Workaround old mob heads in world saves not being upgraded correctly and causing crashes.
|
@ -1,128 +0,0 @@
|
||||
# 5.21.0
|
||||
Released 3rd November 2024.
|
||||
|
||||
This is a minor feature release, including gameplay features and minor internals improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Gameplay
|
||||
- Added the following new blocks:
|
||||
- Campfire
|
||||
- Chiseled Copper
|
||||
- Chiseled Tuff
|
||||
- Chiseled Tuff Bricks
|
||||
- Copper Bulb
|
||||
- Copper Door
|
||||
- Copper Grate
|
||||
- Copper Trapdoor
|
||||
- Polished Tuff, Slabs, Stairs and Walls
|
||||
- Soul Campfire
|
||||
- Tuff Bricks, Slabs, Stairs and Walls
|
||||
- Tuff Slab, Stairs and Walls
|
||||
- Added the following new types of painting:
|
||||
- backyard
|
||||
- baroque
|
||||
- bouquet
|
||||
- cavebird
|
||||
- changing
|
||||
- cotan
|
||||
- endboss
|
||||
- fern
|
||||
- finding
|
||||
- humble
|
||||
- lowmist
|
||||
- meditative
|
||||
- orb
|
||||
- owlemons
|
||||
- passage
|
||||
- pond
|
||||
- prairie_ride
|
||||
- sunflowers
|
||||
- tides
|
||||
- unpacked
|
||||
- Armor slots are now properly restricted (on the server side) to only contain the appropriate type of armor or headwear.
|
||||
- Implemented Aqua Affinity enchantment. Since the server doesn't currently enforce any movement restrictions in water, this enchantment works based on client-side behaviour only.
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following new API methods have been added:
|
||||
- `public ChiseledBookshelf->getLastInteractedSlot() : ?ChiseledBookshelfSlot`
|
||||
- `public ChiseledBookshelf->setLastInteractedSlot(?ChiseledBookshelfSlot $lastInteractedSlot) : $this`
|
||||
- The following new classes have been added:
|
||||
- `utils\CopperMaterial` - interface implemented by all copper-like blocks with oxidation and waxed properties
|
||||
- `CopperBulb`
|
||||
- `CopperDoor`
|
||||
- `CopperGrate`
|
||||
- `CopperTrapdoor`
|
||||
- `SoulCampfire`
|
||||
- `Campfire`
|
||||
- The following enums have new cases:
|
||||
- `utils\BannerPatternType` has new cases `FLOW` and `GUSTER`
|
||||
|
||||
### `pocketmine\crafting`
|
||||
- The following enums have new cases:
|
||||
- `FurnaceType` has new cases `CAMPFIRE` and `SOUL_CAMPFIRE`
|
||||
|
||||
### `pocketmine\event`
|
||||
- The following new classes have been added:
|
||||
- `block\CampfireCookEvent` - called when a campfire finishes cooking an item
|
||||
|
||||
### `pocketmine\inventory`
|
||||
- Added support for slot validators, which permit restricting the types of items a player can put into an inventory slot.
|
||||
- The following new classes have been added:
|
||||
- `transaction\action\SlotValidator` - interface
|
||||
- `transaction\action\CallbackSlotValidator` - class allowing a closure to be used for slot content validation
|
||||
- `SlotValidatedInventory` - implemented by inventories which support the use of slot validators
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new API methods have been added:
|
||||
- `public Item->getCooldownTag() : ?string` - returns the cooldown group this item belongs to, used for ensuring that, for example, different types of goat horns all respect a general horn cooldown
|
||||
- The following new classes have been added:
|
||||
- `ItemCooldownTags` - list of cooldown group tags used by PocketMine-MP
|
||||
|
||||
### `pocketmine\world\sound`
|
||||
- The following new classes have been added
|
||||
- `CampfireSound` - sound made by campfires while lit
|
||||
|
||||
## Tools
|
||||
- `tools/blockstate-upgrade-schema-utils.php` (formerly `generate-blockstate-upgrade-schema.php`) has several improvements:
|
||||
- Support for generating `flattenedProperties` rules as per [BedrockBlockUpgradeSchema 5.0.0](https://github.com/pmmp/BedrockBlockUpgradeSchema/releases/tag/5.0.0)
|
||||
- Improved criteria for flattened property selection to minimize the amount of rules required
|
||||
- Several subcommands are now available:
|
||||
- `generate` - generates a schema from provided data
|
||||
- `update` - regenerates an existing schema in a newer format
|
||||
- `update-all` - regenerates a folder of existing schemas in a newer format (useful for updating `BedrockBlockUpgradeSchema` en masse)
|
||||
- `test` - verifies that a schema produces the results expected by provided data
|
||||
|
||||
## Internals
|
||||
- Fixed incorrect visibility of `createEntity` in spawn eggs.
|
||||
- Added support for newer `BedrockBlockUpgradeSchema` in `BlockStateUpgrader`.
|
||||
|
||||
# 5.21.1
|
||||
Released 12th November 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed server crash when applying a cooldown to an item with 1 count.
|
||||
- Fixed garbage collector cycle count increase on player disconnect.
|
||||
- Fixed weakness effect being applied to all attack types, causing damage splash potions to become weaker.
|
||||
- Fixed Enchanted Golden Apple regeneration effect amplifier to match vanilla.
|
||||
|
||||
# 5.21.2
|
||||
Released 29th November 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed blocks destroyable by water being able to be placed inside water.
|
||||
- Fixed deprecation warnings about nullable typehints on PHP 8.4.
|
||||
- Fixed `Utils::getNiceClosureName()` not working correctly on PHP 8.4.
|
||||
- Fixed incorrect break animations when breaking the block behind an instantly-breakable block like a torch.
|
||||
- Fixed candle extinguish logic.
|
||||
- Fixed various documentation issues around array key types.
|
||||
- Introduced a new PHPStan rule along with `Utils::promoteKeys()` to improve PHPStan error reporting around unspecified array key types. Previously, some errors were missed due to PHPStan's BenevolentUnionType.
|
||||
|
||||
## DevOps
|
||||
- `pmmp/server-developers` team is now automatically requested for review on any new PR.
|
||||
- `Status: Waiting on Author` label is now automatically removed from PRs when they are updated.
|
@ -1,16 +0,0 @@
|
||||
# 5.22.0
|
||||
Released 4th December 2024.
|
||||
|
||||
**For Minecraft: Bedrock Edition 1.21.50**
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.50.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.50.
|
||||
- Removed support for earlier versions.
|
@ -1,139 +0,0 @@
|
||||
# 5.23.0
|
||||
Released 5th December 2024.
|
||||
|
||||
This is a minor feature release, including new gameplay features, internals improvements, API additions and
|
||||
deprecations, and improvements to timings.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- `/timings` now supports collecting timings from async task workers. These new timings will be shown alongside `Full Server Tick` timings, but will not be counted in total load.
|
||||
- Added `/xp` command.
|
||||
- `start.sh` will now emit warnings when the server process exits with an unusual exit code. This helps to detect unexpected segmentation faults and other kinds of native errors.
|
||||
|
||||
## Gameplay
|
||||
- Added the following new items:
|
||||
- End Crystal
|
||||
- Goat Horn (all variants)
|
||||
- Ice Bomb (from Education Edition)
|
||||
- Recovery Compass
|
||||
- Added the following enchantments:
|
||||
- Frost Walker
|
||||
- Sugarcane now self-destructs when there is no water adjacent to the base block.
|
||||
- Added basic support for middle-clicking on entities to get their spawn eggs.
|
||||
- Added sounds when drinking potions.
|
||||
- Eating food is now allowed in creative mode and in peaceful difficulty.
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- Extracted `MultiAnyFacingTrait` and `MultiAnySupportTrait` from `GlowLichen` to enable reuse in other blocks.
|
||||
- The following API methods have been deprecated:
|
||||
- `Campfire->getInventory()` - this was added by mistake and can't be well-supported given the way that blocks work
|
||||
|
||||
### `pocketmine\command`
|
||||
- The following classes have been added:
|
||||
- `ClosureCommand` - allows registering a closure to execute a command
|
||||
|
||||
### `pocketmine\event`
|
||||
- Added APIs to `PlayerInteractEvent` to allow toggling item and block interactions.
|
||||
- This allows various customisations, such as allowing interactions when sneaking, selectively disabling item or block reactions, etc.
|
||||
- If both item and block interactions are disabled, the event is **not** cancelled (blocks can still be placed).
|
||||
- The following API methods have been added:
|
||||
- `public PlayerInteractEvent->setUseBlock(bool $useBlock) : void`
|
||||
- `public PlayerInteractEvent->setUseItem(bool $useItem) : void`
|
||||
- `public PlayerInteractEvent->useBlock() : bool` - returns whether the block can respond to the interaction (toggling levers, opening/closing doors, etc).
|
||||
- `public PlayerInteractEvent->useItem() : bool` - returns whether the item can respond to the interaction (spawn eggs, flint & steel, etc).
|
||||
- The following new classes have been added:
|
||||
- `player\PlayerEntityPickEvent` - called when a player middle-clicks on an entity
|
||||
|
||||
### `pocketmine\inventory\transaction`
|
||||
- The following API methods have been deprecated:
|
||||
- `InventoryAction->onAddToTransaction()`
|
||||
|
||||
### `pocketmine\permission`
|
||||
- The following API methods have been deprecated:
|
||||
- `PermissionManager->getPermissionSubscriptions()`
|
||||
- `PermissionManager->subscribeToPermission()`
|
||||
- `PermissionManager->unsubscribeFromAllPermissions()`
|
||||
- `PermissionManager->unsubscribeFromPermission()`
|
||||
|
||||
### `pocketmine\plugin`
|
||||
- The following classes have been deprecated:
|
||||
- `DiskResourceProvider`
|
||||
- `ResourceProvider`
|
||||
|
||||
### `pocketmine\promise`
|
||||
- `Promise::all()` now accepts zero promises. This will return an already-resolved promise with an empty array.
|
||||
|
||||
### `pocketmine\scheduler`
|
||||
- Added PHPStan generic types to `TaskHandler` and related APIs in `TaskScheduler` and `Task`.
|
||||
- The following API methods have been deprecated
|
||||
- `AsyncTask->publishProgress()`
|
||||
- `AsyncTask->onProgressUpdate()`
|
||||
|
||||
### `pocketmine\timings`
|
||||
- Timings can now notify other code when timings are enabled/disabled, reloaded, or collected.
|
||||
- The intent of this is to facilitate timings usage on other threads, and have the results collected into a single timings report.
|
||||
- Timings cannot directly control timings on other threads, so these callbacks allow plugins to use custom mechanisms to toggle, reset and collect timings.
|
||||
- PocketMine-MP currently uses this to collect timings from async task workers. More internal threads may be supported in the future.
|
||||
- The following API methods have been added:
|
||||
- `public static TimingsHandler::getCollectCallbacks() : ObjectSet<\Closure() : list<Promise<list<string>>>` - callbacks for (asynchronously) collecting timings (typically from other threads). The returned promises should be resolved with the result of `TimingsHandler::printCurrentThreadRecords()`.
|
||||
- `public static TimingsHandler::getReloadCallbacks() : ObjectSet<\Closure() : void>` - callbacks called when timings are reset
|
||||
- `public static TimingsHandler::getToggleCallbacks() : ObjectSet<\Closure(bool $enable) : void>` - callbacks called when timings are enabled/disabled
|
||||
- `public static TimingsHandler::requestPrintTimings() : Promise<list<string>>` - asynchronously collects timing results from all threads and assembles them into a single report
|
||||
- The following API methods have been deprecated:
|
||||
- `TimingsHandler::printTimings()` - this function cannot support async timings collection. Use `TimingsHandler::requestPrintTimings()` instead.
|
||||
- `Timings::getAsyncTaskErrorTimings()` - internal method that is no longer needed
|
||||
- The following constants have been deprecated:
|
||||
- `Timings::GROUP_BREAKDOWN` - no longer used
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following API methods have been added:
|
||||
- `public static Utils::getRandomFloat() : float` - returns a random float between 0 and 1. Drop-in replacement for `lcg_value()` in PHP 8.4.
|
||||
|
||||
## Internals
|
||||
- Blocks are now always synced with the client during a right-click-block interaction. This clears mispredictions on the client in case the new `PlayerInteractEvent` flags were customized by plugins.
|
||||
- `VanillaBlocks` and `VanillaItems` now use reflection to lookup TypeId constants by registration name, instead of requiring TypeIds to be manually specified.
|
||||
- While this is obviously a hack, it prevents incorrect constants from being used when adding new blocks, and guarantees that the names of constants in `BlockTypeIds` and `ItemTypeIds` will match their corresponding entries in `VanillaBlocks` and `VanillaItems` respectively.
|
||||
- It also significantly improves readability of `VanillaBlocks` and `VanillaItems`, as well as eliminating ugly code like `WoodLikeBlockIdHelper`.
|
||||
- In PM6, the team is exploring options to redesign `VanillaBlocks` and `VanillaItems` to eliminate the need for defining separate TypeIds entirely.
|
||||
- `ConsoleReader` now uses socket support in `proc_open()` to transmit IPC messages to the server process. Previously, a temporary socket server was used, which was unreliable in some conditions.
|
||||
- Event handler tests have been converted to PHPUnit tests by mocking `Server` and `Plugin` instances. Previously, these required integration tests for these dependencies.
|
||||
- Fixed various deprecation warnings in PHP 8.4.
|
||||
- `netresearch/jsonmapper` is now used at `5.0.0`. The PMMP fork of this library has been removed, as it is no longer needed.
|
||||
|
||||
# 5.23.1
|
||||
Released 5th December 2024.
|
||||
|
||||
## Fixes
|
||||
- Fixed signs not creating a tile when placed.
|
||||
|
||||
## Internals
|
||||
- Improved blockstate consistency check to detect tiles disappearing during refactors.
|
||||
|
||||
# 5.23.2
|
||||
Released 9th December 2024.
|
||||
|
||||
## General
|
||||
- Updated translations for Russian and Korean.
|
||||
|
||||
## Fixes
|
||||
- Fixed server build number.
|
||||
- Fixed some crashes being misreported as plugin-involved.
|
||||
|
||||
## Internals
|
||||
- Removed legacy `build/make-release.php` script. This script is no longer used, as all releases should now follow the PR workflow.
|
||||
|
||||
# 5.23.3
|
||||
Released 22nd January 2025.
|
||||
|
||||
## Fixes
|
||||
- Fixed crashes with PHP internal stack frames being flagged as plugin crashes.
|
||||
- Fixed note block instrument sounds in 1.21.50.
|
||||
|
||||
## Internals
|
||||
- Updated GitHub issue templates to use issue forms.
|
@ -1,108 +0,0 @@
|
||||
# 5.24.0
|
||||
Released 22nd January 2025.
|
||||
|
||||
This is a minor feature release, including new gameplay features, performance improvements, and minor API additions.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Performance
|
||||
- PHP garbage collection is now managed by the server, instead of being automatically triggered by PHP.
|
||||
- The mechanism for GC triggering is designed to mimic PHP's to avoid behavioural changes. Only the place it's triggered from should be significantly different.
|
||||
- This change also avoids unnecessary GCs during object-heavy operations, such as encoding `CraftingDataPacket`. As such, performance during server join should see an improvement.
|
||||
- Timings is now able to directly measure the impact of GC. Previously, GC would show up as random spikes under random timers, skewing timing results.
|
||||
- `ChunkCache` now uses `string` for completed caches directly instead of keeping them wrapped in `CompressBatchPromise`s. This reduces memory usage, improves performance, and reduces GC workload.
|
||||
|
||||
## Configuration
|
||||
- The following settings have been removed from `pocketmine.yml` and will no longer have any effect:
|
||||
- `memory.garbage-collection.collect-async-worker` (now always `true`)
|
||||
- `memory.garbage-collection.low-memory-trigger` (now always `true`)
|
||||
- `memory.max-chunks.trigger-chunk-collect` (now always `true`)
|
||||
- `memory.world-caches.disable-chunk-cache` (now always `true`)
|
||||
- `memory.world-caches.low-memory-trigger` (now always `true`)
|
||||
|
||||
## Gameplay
|
||||
- Added the following new blocks:
|
||||
- All types of pale oak wood, and leaves
|
||||
- Resin
|
||||
- Resin Bricks, Slabs, Stairs, and Walls
|
||||
- Resin Clump
|
||||
- Chiseled Resin Bricks
|
||||
- Some blocks have had their tool tier requirements adjusted to match latest Bedrock updates.
|
||||
- Added the following new items:
|
||||
- Resin Brick
|
||||
- Music Disc - Creator
|
||||
- Music Disc - Creator (Music Box)
|
||||
- Music Disc - Precipice
|
||||
- Music Disc - Relic
|
||||
|
||||
## API
|
||||
### General
|
||||
- Many places had their PHPDoc improved to address issues highlighted by PHPStan 2.x. This may cause new, previously unreported issues to be reported in plugins using PHPStan.
|
||||
|
||||
### `pocketmine`
|
||||
- The following methods have been deprecated:
|
||||
- `MemoryManager->canUseChunkCache()`
|
||||
- `MemoryManager::dumpMemory()` - relocated to `MemoryDump` class
|
||||
|
||||
### `pocketmine\item`
|
||||
- The following new enum cases have been added:
|
||||
- `RecordType::DISK_CREATOR`
|
||||
- `RecordType::DISK_CREATOR_MUSIC_BOX`
|
||||
- `RecordType::DISK_PRECIPICE`
|
||||
- `RecordType::DISK_RELIC`
|
||||
|
||||
### `pocketmine\player`
|
||||
- The following new methods have been added:
|
||||
- `public Player->getFlightSpeedMultiplier() : float` - a base multiplier for player's flight speed
|
||||
- `public Player->setFlightSpeedMultiplier(float $flightSpeedMultiplier) : void` - sets the player's flight speed multiplier
|
||||
- The following new constants have been added:
|
||||
- `Player::DEFAULT_FLIGHT_SPEED_MULTIPLIER`
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following new methods have been added:
|
||||
- `public static TextFormat::javaToBedrock(string $string) : string` - removes unsupported Java Edition format codes to prevent them being incorrectly displayed on Bedrock
|
||||
- The following methods have behavioural changes:
|
||||
- `TextFormat::toHTML()` now converts `§m` to redstone red (instead of strikethrough), and `§n` to copper orange (instead of underline). This is because the codes previously used for `STRIKETHROUGH` and `UNDERLINE` conflict with the new material codes introduced by Minecraft Bedrock.
|
||||
- `Terminal::toANSI()` now converts `§m` to redstone red (instead of strikethrough), and `§n` to copper orange (instead of underline), as above. However, underline and strikethrough can still be used on the terminal using `Terminal::$FORMAT_UNDERLINE` and `Terminal::$FORMAT_STRIKETHROUGH` respectively.
|
||||
- The following new constants have been added:
|
||||
- `TextFormat::MATERIAL_QUARTZ`
|
||||
- `TextFormat::MATERIAL_IRON`
|
||||
- `TextFormat::MATERIAL_NETHERITE`
|
||||
- `TextFormat::MATERIAL_REDSTONE`
|
||||
- `TextFormat::MATERIAL_COPPER`
|
||||
- `TextFormat::MATERIAL_GOLD`
|
||||
- `TextFormat::MATERIAL_EMERALD`
|
||||
- `TextFormat::MATERIAL_DIAMOND`
|
||||
- `TextFormat::MATERIAL_LAPIS`
|
||||
- `TextFormat::MATERIAL_AMETHYST`
|
||||
- The following constants have been deprecated:
|
||||
- `TextFormat::STRIKETHROUGH`
|
||||
- `TextFormat::UNDERLINE`
|
||||
- The following static properties have been added:
|
||||
- `Terminal::$COLOR_MATERIAL_QUARTZ`
|
||||
- `Terminal::$COLOR_MATERIAL_IRON`
|
||||
- `Terminal::$COLOR_MATERIAL_NETHERITE`
|
||||
- `Terminal::$COLOR_MATERIAL_REDSTONE`
|
||||
- `Terminal::$COLOR_MATERIAL_COPPER`
|
||||
- `Terminal::$COLOR_MATERIAL_GOLD`
|
||||
- `Terminal::$COLOR_MATERIAL_EMERALD`
|
||||
- `Terminal::$COLOR_MATERIAL_DIAMOND`
|
||||
- `Terminal::$COLOR_MATERIAL_LAPIS`
|
||||
- `Terminal::$COLOR_MATERIAL_AMETHYST`
|
||||
|
||||
## Tools
|
||||
- Fixed some UI issues in `tools/convert-world.php`
|
||||
|
||||
## Internals
|
||||
- Block cache in `World` is now size-limited. This prevents memory exhaustion when plugins call `getBlock()` many thousands of times with cache misses.
|
||||
- `RakLibServer` now disables PHP GC. As RakLib doesn't generate any unmanaged cycles, GC is just a waste of CPU time in this context.
|
||||
- `MemoryManager` now has the responsibility for triggering cycle GC. It's checked every tick, but GC won't take place unless the GC threshold is exceeded, similar to PHP.
|
||||
- This mechanism could probably do with alterations to better suit PocketMine-MP, but it was chosen to mimic PHP's own GC to minimize behavioural changes for now.
|
||||
- `AsyncTask` now triggers cycle GC after `onRun()` completes. As with `MemoryManager`, this is based on a threshold designed to mimic PHP's own behaviour.
|
||||
- `FormatConverter` now performs world provider GC periodically. This is not needed with current active providers, but was found to be a problem while developing custom providers.
|
||||
- Various internal adjustments were made to avoid returning incorrectly-keyed arrays in the code. These changes shouldn't affect anything as the arrays should have been properly ordered anyway.
|
||||
- Many places that previously used `==` and `!=` have been updated to use strict variants. This kind of change needs to be done carefully to avoid breaking `int|float` comparisons.
|
@ -1,52 +0,0 @@
|
||||
# 5.25.0
|
||||
Released 16th February 2025.
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.60. It also includes some minor API additions supporting new features in this version.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## General
|
||||
- Added support for Minecraft: Bedrock Edition 1.21.60.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
## Documentation
|
||||
- Fixed the documentation of `Utils::getOS()`. It now refers to the `Utils::OS_*` constants instead of a list of hardcoded strings.
|
||||
|
||||
## API
|
||||
### `pocketmine\inventory`
|
||||
This release allows plugins to decide which creative tab they want to add their new items to.
|
||||
It also allows creating new collapsible groups of items, and modifying or removing existing ones.
|
||||
|
||||
- The following new methods have been added:
|
||||
- `public CreativeInventory->getAllEntries() : list<CreativeInventoryEntry>` - returns an array of objects, each containing a creative item and information about its category and collapsible group (if applicable).
|
||||
- `public CreativeInventory->getEntry(int $index) : ?CreativeInventoryEntry` - returns the creative item with the specified identifier, or `null` if not found
|
||||
- The following methods have signature changes:
|
||||
- `CreativeInventory->add()` now accepts two additional optional parameters: `CreativeCategory $category, ?CreativeGroup $group`. If not specified, the item will be added to the Items tab without a group.
|
||||
- The following new classes have been added:
|
||||
- `CreativeCategory` - enum of possible creative inventory categories (each has its own tab on the GUI)
|
||||
- `CreativeGroup` - contains information about a collapsible group of creative items, including tooltip text and icon
|
||||
- `CreativeInventoryEntry` - contains information about a creative inventory item, including its category and collapsible group (if applicable)
|
||||
|
||||
## Internals
|
||||
- `CreativeContentPacket` is no longer fully cached due to the requirement for translation context during construction. The individual items are still cached (which is the most expensive part), but the packet itself is now constructed on demand, and group entries are constructed on the fly. This may affect performance, but this has not been investigated.
|
||||
- `BedrockDataFiles` now includes constants for folders at the top level of `BedrockData` as well as files.
|
||||
- The structure of creative data in `BedrockData` was changed to accommodate item category and grouping information. `creativeitems.json` has been replaced by `creative/*.json`, which contain information about item grouping and also segregates item lists per category.
|
||||
- New information was added to `required_item_list.json` in `BedrockData`, as the server is now required to send item component NBT data in some cases.
|
||||
|
||||
# 5.25.1
|
||||
Released 26th February 2025.
|
||||
|
||||
## Fixes
|
||||
- Fixed confusing exception message when a block-breaking tool has an efficiency value of zero.
|
||||
- Fixed incorrect facing of doors since 1.21.60 (resulted in mismatched AABBs between client & server, rendering glitches etc.)
|
||||
- Resource pack UUIDs are now validated on load. Previously, invalid UUIDs would be accepted, and potentially cause a server crash on player join.
|
||||
|
||||
# 5.25.2
|
||||
Released 4th March 2025.
|
||||
|
||||
## Fixes
|
||||
- Added limits to various `explode()` calls.
|
@ -1,71 +0,0 @@
|
||||
# 5.26.0
|
||||
Released 22nd March 2025.
|
||||
|
||||
This is a minor feature release focused on performance improvements.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Performance
|
||||
- Significantly improved performance of entity movement. Load testing with item entities showed a 3x increase in the number of entities supported without lag.
|
||||
- Significantly improved performance of on-ground checks for player movement. This still needs further work, but optimisations implemented in this version should improve performance substantially.
|
||||
- Updated `pocketmine/nbt` dependency with performance improvements to `TAG_Compound` and `TAG_List` comparison. This should improve performance of inventory-related actions.
|
||||
- `InventoryTransaction` now avoids useless item clones when processing transactions, which should improve performance of inventory-related actions.
|
||||
|
||||
## Dependencies
|
||||
- `pocketmine/bedrock-protocol` has been updated to `36.2.0`, which adds new functions to access some packet fields.
|
||||
- `pocketmine/nbt` has been updated to `1.1.0`, which improves performance when comparing NBT object trees.
|
||||
|
||||
## Gameplay
|
||||
- Block breaking animation speed now takes into account the following: jumping, being in water, haste, mining fatigue
|
||||
|
||||
## Tools
|
||||
- `blockstate-upgrade-schema-utils.php` now has a new `dump-table` command, which turns a `.bin` palette table file into human-readable text for debugging.
|
||||
|
||||
## API
|
||||
### `pocketmine\block`
|
||||
- The following methods have been added:
|
||||
- `public RuntimeBlockStateRegistry->hasStateId(int $stateId) : bool` - checks whether the given state ID is registered
|
||||
|
||||
### `pocketmine\crafting`
|
||||
- The following methods have been deprecated:
|
||||
- `CraftingManager::sort()` - this was implicitly internal anyway
|
||||
|
||||
### `pocketmine\utils`
|
||||
- The following constants have been added:
|
||||
- `TextFormat::MATERIAL_RESIN`
|
||||
- The following static properties have been added:
|
||||
- `Terminal::$COLOR_MATERIAL_RESIN`
|
||||
|
||||
### `pocketmine\data\bedrock\block`
|
||||
- `BlockStateToObjectDeserializer` now permits overriding **deserializers** for Bedrock IDs. This may be useful to implement custom state handling, or to implement missing block variants (such as snow cauldron).
|
||||
- This was originally prohibited since 5.0.0. However, there is no technical reason to disallow overriding **deserializers**.
|
||||
- Overriding **serializers** is still **not permitted**. Reusing type IDs doesn't make any sense and would break internal design contracts.
|
||||
- If you want to make a custom version of a vanilla block, create a custom type ID for it, exactly as you would for a regular custom block.
|
||||
- The following methods have been added:
|
||||
- `public BlockStateToObjectDeserializer->getDeserializerForId(string $id) : ?(\Closure(BlockStateReader) : Block)`
|
||||
|
||||
### `pocketmine\data\bedrock\item`
|
||||
- `ItemDeserializer` now permits overriding **deserializers** for Bedrock IDs. As above, this may be useful to implement custom data handling, or to implement missing variants of existing items.
|
||||
- This was originally prohibited since 5.0.0. However, there is no technical reason to disallow overriding **deserializers**.
|
||||
- Overriding **serializers** is still **not permitted**. Reusing type IDs doesn't make any sense and would break internal design contracts.
|
||||
- As above, if you want to make a custom version of a vanilla item, create a custom type ID for it, exactly as you would for a regular custom item.
|
||||
- The following methods have been added:
|
||||
- `public ItemDeserializer->getDeserializerForId(string $id) : ?(\Closure(SavedItemData) : Item)`
|
||||
|
||||
## Internals
|
||||
- `new $class` is now banned on new internals code by a PHPStan rule. Closures or factory objects should be used instead for greater flexibility and better static analysis.
|
||||
- `CraftingManager` now uses a more stable hash function for recipe output filtering.
|
||||
- `ChunkCache` now accepts `int $dimensionId` in the constructor. This may be useful for plugins which implement the nether.
|
||||
- `RuntimeBlockStateRegistry` now precomputes basic collision info about known states for fast paths.
|
||||
- This permits specialization for common shapes like cubes and collisionless blocks, which allows skipping complex logic in entity movement calculation. This vastly improves performance.
|
||||
- Any block whose class overrides `readStateFromWorld()` or `getModelPositionOffset()` will *not* be optimised.
|
||||
- `Block->recalculateCollisionBoxes()` now has a hard requirement not to depend on anything other than available properties. It must not use `World` or its position.
|
||||
- This change was problematic for `ChorusPlant`, which used nearby blocks to calculate its collision boxes.
|
||||
- Blocks which need nearby blocks should override `readStateFromWorld()` and set dynamic state properties, similar to fences.
|
||||
- This design flaw will be corrected with a major change to `Block` internals currently in planning for a future major version.
|
||||
- `Block->getCollisionBoxes()` may not be called at all during gameplay for blocks with shapes determined to be simple, like cubes and collisionless blocks.
|
||||
- `BlockStateToObjectDeserializer` now checks if the returned blockstate is registered in `RuntimeBlockStateRegistry` to promote earlier error detection (instead of crashing in random code paths).
|
@ -1,24 +0,0 @@
|
||||
# 5.27.0
|
||||
Released 27th March 2025.
|
||||
|
||||
This is a support release for Minecraft: Bedrock Edition 1.21.70.
|
||||
|
||||
**Plugin compatibility:** Plugins for previous 5.x versions will run unchanged on this release, unless they use internal APIs, reflection, or packages like the `pocketmine\network\mcpe` or `pocketmine\data` namespace.
|
||||
Do not update plugin minimum API versions unless you need new features added in this release.
|
||||
|
||||
**WARNING: If your plugin uses the `pocketmine\network\mcpe` namespace, you're not shielded by API change constraints.**
|
||||
Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you're using packets directly.
|
||||
|
||||
## Interim releases
|
||||
If you're upgrading from 5.25.x directly to 5.27.0, please also read the following changelogs, as the interim releases contain important changes:
|
||||
- [5.26.0](https://github.com/pmmp/PocketMine-MP/blob/5.26.0/changelogs/5.26.md#5260) - Performance improvements and other internal improvements
|
||||
|
||||
## General
|
||||
- Aded support for Minecraft: Bedrock Edition 1.21.70.
|
||||
- Removed support for earlier versions.
|
||||
|
||||
# 5.27.1
|
||||
Released 6th April 2025.
|
||||
|
||||
## Fixes
|
||||
- Updated RakLib to get ping timestamp handling fixes.
|
@ -32,29 +32,29 @@
|
||||
"ext-zlib": ">=1.2.11",
|
||||
"composer-runtime-api": "^2.0",
|
||||
"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": "~4.1.0+bedrock-1.21.70",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
|
||||
"pocketmine/bedrock-protocol": "~37.0.0+bedrock-1.21.70",
|
||||
"pocketmine/netresearch-jsonmapper": "~v4.4.999",
|
||||
"pocketmine/bedrock-block-upgrade-schema": "~4.3.0+bedrock-1.21.20",
|
||||
"pocketmine/bedrock-data": "~2.12.0+bedrock-1.21.20",
|
||||
"pocketmine/bedrock-item-upgrade-schema": "~1.11.0+bedrock-1.21.20",
|
||||
"pocketmine/bedrock-protocol": "~33.0.0+bedrock-1.21.20",
|
||||
"pocketmine/binaryutils": "^0.2.1",
|
||||
"pocketmine/callback-validator": "^1.0.2",
|
||||
"pocketmine/color": "^0.3.0",
|
||||
"pocketmine/errorhandler": "^0.7.0",
|
||||
"pocketmine/locale-data": "~2.24.0",
|
||||
"pocketmine/locale-data": "~2.19.0",
|
||||
"pocketmine/log": "^0.4.0",
|
||||
"pocketmine/math": "~1.0.0",
|
||||
"pocketmine/nbt": "~1.1.0",
|
||||
"pocketmine/raklib": "~1.1.2",
|
||||
"pocketmine/nbt": "~1.0.0",
|
||||
"pocketmine/raklib": "~1.1.0",
|
||||
"pocketmine/raklib-ipc": "~1.0.0",
|
||||
"pocketmine/snooze": "^0.5.0",
|
||||
"ramsey/uuid": "~4.7.0",
|
||||
"symfony/filesystem": "~6.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "2.1.11",
|
||||
"phpstan/phpstan-phpunit": "^2.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0.0",
|
||||
"phpstan/phpstan": "1.11.11",
|
||||
"phpstan/phpstan-phpunit": "^1.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.2.0",
|
||||
"phpunit/phpunit": "^10.5.24"
|
||||
},
|
||||
"autoload": {
|
||||
|
506
composer.lock
generated
506
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "818c679a25da8e6b466bc454ad48dec3",
|
||||
"content-hash": "85c407770e0f2a1bda7c8e23faf2026e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/json-comment",
|
||||
@ -67,16 +67,16 @@
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.12.3",
|
||||
"version": "0.12.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/brick/math.git",
|
||||
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
|
||||
"reference": "f510c0a40911935b77b86859eb5223d58d660df1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
|
||||
"reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
|
||||
"url": "https://api.github.com/repos/brick/math/zipball/f510c0a40911935b77b86859eb5223d58d660df1",
|
||||
"reference": "f510c0a40911935b77b86859eb5223d58d660df1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -85,7 +85,7 @@
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "^2.2",
|
||||
"phpunit/phpunit": "^10.1",
|
||||
"vimeo/psalm": "6.8.8"
|
||||
"vimeo/psalm": "5.16.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -115,7 +115,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/brick/math/issues",
|
||||
"source": "https://github.com/brick/math/tree/0.12.3"
|
||||
"source": "https://github.com/brick/math/tree/0.12.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -123,71 +123,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-28T13:11:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "netresearch/jsonmapper",
|
||||
"version": "v5.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cweiske/jsonmapper.git",
|
||||
"reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c",
|
||||
"reference": "8c64d8d444a5d764c641ebe97e0e3bc72b25bf6c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-reflection": "*",
|
||||
"ext-spl": "*",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
|
||||
"squizlabs/php_codesniffer": "~3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"JsonMapper": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"OSL-3.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Weiske",
|
||||
"email": "cweiske@cweiske.de",
|
||||
"homepage": "http://github.com/cweiske/jsonmapper/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Map nested JSON structures onto PHP classes",
|
||||
"support": {
|
||||
"email": "cweiske@cweiske.de",
|
||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||
"source": "https://github.com/cweiske/jsonmapper/tree/v5.0.0"
|
||||
},
|
||||
"time": "2024-09-08T10:20:00+00:00"
|
||||
"time": "2023-11-29T23:19:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-block-upgrade-schema",
|
||||
"version": "5.1.0",
|
||||
"version": "4.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockBlockUpgradeSchema.git",
|
||||
"reference": "2218512e4b91f5bfd09ef55f7a4c4b04e169e41a"
|
||||
"reference": "53d3a41c37ce90d58b33130cdadad08e442d7c47"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/2218512e4b91f5bfd09ef55f7a4c4b04e169e41a",
|
||||
"reference": "2218512e4b91f5bfd09ef55f7a4c4b04e169e41a",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockBlockUpgradeSchema/zipball/53d3a41c37ce90d58b33130cdadad08e442d7c47",
|
||||
"reference": "53d3a41c37ce90d58b33130cdadad08e442d7c47",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -198,22 +147,22 @@
|
||||
"description": "Schemas describing how to upgrade saved block data in older Minecraft: Bedrock Edition world saves",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockBlockUpgradeSchema/issues",
|
||||
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/5.1.0"
|
||||
"source": "https://github.com/pmmp/BedrockBlockUpgradeSchema/tree/4.3.0"
|
||||
},
|
||||
"time": "2025-02-11T17:41:44+00:00"
|
||||
"time": "2024-08-13T18:04:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-data",
|
||||
"version": "4.1.0+bedrock-1.21.70",
|
||||
"version": "2.12.0+bedrock-1.21.20",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockData.git",
|
||||
"reference": "d53fe98cb3b596ac016e275df5bd5e89b04a4817"
|
||||
"reference": "d4ee3d08964fa16fbbdd04af1fb52bbde540b665"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/d53fe98cb3b596ac016e275df5bd5e89b04a4817",
|
||||
"reference": "d53fe98cb3b596ac016e275df5bd5e89b04a4817",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockData/zipball/d4ee3d08964fa16fbbdd04af1fb52bbde540b665",
|
||||
"reference": "d4ee3d08964fa16fbbdd04af1fb52bbde540b665",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -224,22 +173,22 @@
|
||||
"description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockData/issues",
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.70"
|
||||
"source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.21.20"
|
||||
},
|
||||
"time": "2025-03-25T19:43:31+00:00"
|
||||
"time": "2024-08-15T12:50:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-item-upgrade-schema",
|
||||
"version": "1.14.0",
|
||||
"version": "1.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockItemUpgradeSchema.git",
|
||||
"reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb"
|
||||
"reference": "35c18d093fc2b12da8737b2edb2c3ad6a14a53dd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/9fc7c9bbb558a017395c1cb7dd819c033ee971bb",
|
||||
"reference": "9fc7c9bbb558a017395c1cb7dd819c033ee971bb",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockItemUpgradeSchema/zipball/35c18d093fc2b12da8737b2edb2c3ad6a14a53dd",
|
||||
"reference": "35c18d093fc2b12da8737b2edb2c3ad6a14a53dd",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -250,22 +199,22 @@
|
||||
"description": "JSON schemas for upgrading items found in older Minecraft: Bedrock world saves",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockItemUpgradeSchema/issues",
|
||||
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.14.0"
|
||||
"source": "https://github.com/pmmp/BedrockItemUpgradeSchema/tree/1.11.0"
|
||||
},
|
||||
"time": "2024-12-04T12:22:49+00:00"
|
||||
"time": "2024-08-13T18:06:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/bedrock-protocol",
|
||||
"version": "37.0.0+bedrock-1.21.70",
|
||||
"version": "33.0.0+bedrock-1.21.20",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/BedrockProtocol.git",
|
||||
"reference": "7091dad2c12ed4a4106432df21fc698960c6be9e"
|
||||
"reference": "e2264137c5cd0522de2c6ee4921a3a803818ea32"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/7091dad2c12ed4a4106432df21fc698960c6be9e",
|
||||
"reference": "7091dad2c12ed4a4106432df21fc698960c6be9e",
|
||||
"url": "https://api.github.com/repos/pmmp/BedrockProtocol/zipball/e2264137c5cd0522de2c6ee4921a3a803818ea32",
|
||||
"reference": "e2264137c5cd0522de2c6ee4921a3a803818ea32",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -278,10 +227,10 @@
|
||||
"ramsey/uuid": "^4.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "2.1.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0.0",
|
||||
"phpunit/phpunit": "^9.5 || ^10.0 || ^11.0"
|
||||
"phpstan/phpstan": "1.11.2",
|
||||
"phpstan/phpstan-phpunit": "^1.0.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0.0",
|
||||
"phpunit/phpunit": "^9.5 || ^10.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -296,9 +245,9 @@
|
||||
"description": "An implementation of the Minecraft: Bedrock Edition protocol in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/BedrockProtocol/issues",
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/37.0.0+bedrock-1.21.70"
|
||||
"source": "https://github.com/pmmp/BedrockProtocol/tree/32.2.0+bedrock-1.21.2"
|
||||
},
|
||||
"time": "2025-03-27T15:19:36+00:00"
|
||||
"time": "2024-08-10T19:23:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/binaryutils",
|
||||
@ -471,16 +420,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/locale-data",
|
||||
"version": "2.24.2",
|
||||
"version": "2.19.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/Language.git",
|
||||
"reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b"
|
||||
"reference": "93e473e20e7f4515ecf45c5ef0f9155b9247a86e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/2a00c44c52bce98e7a43aa31517df78cbb2ba23b",
|
||||
"reference": "2a00c44c52bce98e7a43aa31517df78cbb2ba23b",
|
||||
"url": "https://api.github.com/repos/pmmp/Language/zipball/93e473e20e7f4515ecf45c5ef0f9155b9247a86e",
|
||||
"reference": "93e473e20e7f4515ecf45c5ef0f9155b9247a86e",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
@ -488,9 +437,9 @@
|
||||
"description": "Language resources used by PocketMine-MP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/Language/issues",
|
||||
"source": "https://github.com/pmmp/Language/tree/2.24.2"
|
||||
"source": "https://github.com/pmmp/Language/tree/2.19.6"
|
||||
},
|
||||
"time": "2025-04-03T01:23:27+00:00"
|
||||
"time": "2023-08-08T16:53:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/log",
|
||||
@ -576,16 +525,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/nbt",
|
||||
"version": "1.1.1",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/NBT.git",
|
||||
"reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1"
|
||||
"reference": "20540271cb59e04672cb163dca73366f207974f1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/c3c7b0a7295daeaf7873d90fed5c5d10381d12e1",
|
||||
"reference": "c3c7b0a7295daeaf7873d90fed5c5d10381d12e1",
|
||||
"url": "https://api.github.com/repos/pmmp/NBT/zipball/20540271cb59e04672cb163dca73366f207974f1",
|
||||
"reference": "20540271cb59e04672cb163dca73366f207974f1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -595,8 +544,8 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "2.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpstan/phpstan": "1.10.25",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"type": "library",
|
||||
@ -612,22 +561,76 @@
|
||||
"description": "PHP library for working with Named Binary Tags",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/NBT/issues",
|
||||
"source": "https://github.com/pmmp/NBT/tree/1.1.1"
|
||||
"source": "https://github.com/pmmp/NBT/tree/1.0.0"
|
||||
},
|
||||
"time": "2025-03-09T01:46:03+00:00"
|
||||
"time": "2023-07-14T13:01:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib",
|
||||
"version": "1.1.2",
|
||||
"name": "pocketmine/netresearch-jsonmapper",
|
||||
"version": "v4.4.999",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/RakLib.git",
|
||||
"reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f"
|
||||
"url": "https://github.com/pmmp/netresearch-jsonmapper.git",
|
||||
"reference": "9a6610033d56e358e86a3e4fd5f87063c7318833"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/4145a31cd812fe8931c3c9c691fcd2ded2f47e7f",
|
||||
"reference": "4145a31cd812fe8931c3c9c691fcd2ded2f47e7f",
|
||||
"url": "https://api.github.com/repos/pmmp/netresearch-jsonmapper/zipball/9a6610033d56e358e86a3e4fd5f87063c7318833",
|
||||
"reference": "9a6610033d56e358e86a3e4fd5f87063c7318833",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-reflection": "*",
|
||||
"ext-spl": "*",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"replace": {
|
||||
"netresearch/jsonmapper": "~4.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0",
|
||||
"squizlabs/php_codesniffer": "~3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"JsonMapper": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"OSL-3.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Weiske",
|
||||
"email": "cweiske@cweiske.de",
|
||||
"homepage": "http://github.com/cweiske/jsonmapper/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Fork of netresearch/jsonmapper with security fixes needed by pocketmine/pocketmine-mp",
|
||||
"support": {
|
||||
"email": "cweiske@cweiske.de",
|
||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
||||
"source": "https://github.com/pmmp/netresearch-jsonmapper/tree/v4.4.999"
|
||||
},
|
||||
"time": "2024-02-23T13:17:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pmmp/RakLib.git",
|
||||
"reference": "be2783be516bf6e2872ff5c81fb9048596617b97"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pmmp/RakLib/zipball/be2783be516bf6e2872ff5c81fb9048596617b97",
|
||||
"reference": "be2783be516bf6e2872ff5c81fb9048596617b97",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -639,8 +642,8 @@
|
||||
"pocketmine/log": "^0.3.0 || ^0.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "2.1.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0"
|
||||
"phpstan/phpstan": "1.10.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -655,9 +658,9 @@
|
||||
"description": "A RakNet server implementation written in PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/pmmp/RakLib/issues",
|
||||
"source": "https://github.com/pmmp/RakLib/tree/1.1.2"
|
||||
"source": "https://github.com/pmmp/RakLib/tree/1.1.1"
|
||||
},
|
||||
"time": "2025-04-06T03:38:21+00:00"
|
||||
"time": "2024-03-04T14:02:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pocketmine/raklib-ipc",
|
||||
@ -742,16 +745,16 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/collection",
|
||||
"version": "2.1.1",
|
||||
"version": "2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/collection.git",
|
||||
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2"
|
||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2",
|
||||
"reference": "344572933ad0181accbf4ba763e85a0306a8c5e2",
|
||||
"url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
||||
"reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -759,22 +762,25 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"captainhook/plugin-composer": "^5.3",
|
||||
"ergebnis/composer-normalize": "^2.45",
|
||||
"fakerphp/faker": "^1.24",
|
||||
"ergebnis/composer-normalize": "^2.28.3",
|
||||
"fakerphp/faker": "^1.21",
|
||||
"hamcrest/hamcrest-php": "^2.0",
|
||||
"jangregor/phpstan-prophecy": "^2.1",
|
||||
"mockery/mockery": "^1.6",
|
||||
"jangregor/phpstan-prophecy": "^1.0",
|
||||
"mockery/mockery": "^1.5",
|
||||
"php-parallel-lint/php-console-highlighter": "^1.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4",
|
||||
"phpspec/prophecy-phpunit": "^2.3",
|
||||
"phpstan/extension-installer": "^1.4",
|
||||
"phpstan/phpstan": "^2.1",
|
||||
"phpstan/phpstan-mockery": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"ramsey/coding-standard": "^2.3",
|
||||
"ramsey/conventional-commits": "^1.6",
|
||||
"roave/security-advisories": "dev-latest"
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||
"phpcsstandards/phpcsutils": "^1.0.0-rc1",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpstan/extension-installer": "^1.2",
|
||||
"phpstan/phpstan": "^1.9",
|
||||
"phpstan/phpstan-mockery": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psalm/plugin-mockery": "^1.1",
|
||||
"psalm/plugin-phpunit": "^0.18.4",
|
||||
"ramsey/coding-standard": "^2.0.3",
|
||||
"ramsey/conventional-commits": "^1.3",
|
||||
"vimeo/psalm": "^5.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -812,9 +818,19 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/collection/issues",
|
||||
"source": "https://github.com/ramsey/collection/tree/2.1.1"
|
||||
"source": "https://github.com/ramsey/collection/tree/2.0.0"
|
||||
},
|
||||
"time": "2025-03-22T05:38:12+00:00"
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/ramsey",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/ramsey/collection",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-31T21:50:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
@ -910,16 +926,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v6.4.13",
|
||||
"version": "v6.4.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3"
|
||||
"reference": "b51ef8059159330b74a4d52f68e671033c0fe463"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3",
|
||||
"reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/b51ef8059159330b74a4d52f68e671033c0fe463",
|
||||
"reference": "b51ef8059159330b74a4d52f68e671033c0fe463",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -956,7 +972,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v6.4.13"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v6.4.9"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -972,24 +988,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-25T15:07:50+00:00"
|
||||
"time": "2024-06-28T09:49:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.31.0",
|
||||
"version": "v1.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
|
||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540",
|
||||
"reference": "0424dff1c58f028c451efff2045f5d92410bd540",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"provide": {
|
||||
"ext-ctype": "*"
|
||||
@ -1000,8 +1016,8 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -1035,7 +1051,7 @@
|
||||
"portable"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
|
||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1051,24 +1067,24 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
"time": "2024-05-31T15:07:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.31.0",
|
||||
"version": "v1.30.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
||||
"reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
@ -1079,8 +1095,8 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -1115,7 +1131,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1131,22 +1147,22 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
"time": "2024-06-19T12:30:46+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.13.0",
|
||||
"version": "1.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
|
||||
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||
"reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1185,7 +1201,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/myclabs/DeepCopy/issues",
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1193,20 +1209,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-12T12:17:51+00:00"
|
||||
"time": "2024-06-12T14:39:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.4.0",
|
||||
"version": "v5.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "447a020a1f875a434d62f2a401f53b82a396e494"
|
||||
"reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
|
||||
"reference": "447a020a1f875a434d62f2a401f53b82a396e494",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13",
|
||||
"reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1217,7 +1233,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"ircmaxell/php-yacc": "^0.0.7",
|
||||
"phpunit/phpunit": "^9.0"
|
||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/php-parse"
|
||||
@ -1249,9 +1265,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2"
|
||||
},
|
||||
"time": "2024-12-30T11:07:19+00:00"
|
||||
"time": "2024-03-05T20:51:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
@ -1373,20 +1389,20 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.11",
|
||||
"version": "1.11.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30"
|
||||
"reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/8ca5f79a8f63c49b2359065832a654e1ec70ac30",
|
||||
"reference": "8ca5f79a8f63c49b2359065832a654e1ec70ac30",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/707c2aed5d8d0075666e673a5e71440c1d01a5a3",
|
||||
"reference": "707c2aed5d8d0075666e673a5e71440c1d01a5a3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4|^8.0"
|
||||
"php": "^7.2|^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan-shim": "*"
|
||||
@ -1427,35 +1443,34 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-03-24T13:45:00+00:00"
|
||||
"time": "2024-08-19T14:37:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
"version": "2.0.6",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-phpunit.git",
|
||||
"reference": "6b92469f8a7995e626da3aa487099617b8dfa260"
|
||||
"reference": "f3ea021866f4263f07ca3636bf22c64be9610c11"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/6b92469f8a7995e626da3aa487099617b8dfa260",
|
||||
"reference": "6b92469f8a7995e626da3aa487099617b8dfa260",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/f3ea021866f4263f07ca3636bf22c64be9610c11",
|
||||
"reference": "f3ea021866f4263f07ca3636bf22c64be9610c11",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"phpstan/phpstan": "^2.0.4"
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpstan": "^1.11"
|
||||
},
|
||||
"conflict": {
|
||||
"phpunit/phpunit": "<7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^5",
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/phpstan-deprecation-rules": "^2.0",
|
||||
"phpstan/phpstan-strict-rules": "^2.0",
|
||||
"phpunit/phpunit": "^9.6"
|
||||
"phpstan/phpstan-strict-rules": "^1.5.1",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"type": "phpstan-extension",
|
||||
"extra": {
|
||||
@ -1478,33 +1493,34 @@
|
||||
"description": "PHPUnit extensions and rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-phpunit/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/2.0.6"
|
||||
"source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.0"
|
||||
},
|
||||
"time": "2025-03-26T12:47:06+00:00"
|
||||
"time": "2024-04-20T06:39:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-strict-rules",
|
||||
"version": "2.0.4",
|
||||
"version": "1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
|
||||
"reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a"
|
||||
"reference": "363f921dd8441777d4fc137deb99beb486c77df1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
|
||||
"reference": "3e139cbe67fafa3588e1dbe27ca50f31fdb6236a",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/363f921dd8441777d4fc137deb99beb486c77df1",
|
||||
"reference": "363f921dd8441777d4fc137deb99beb486c77df1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"phpstan/phpstan": "^2.0.4"
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpstan/phpstan": "^1.11"
|
||||
},
|
||||
"require-dev": {
|
||||
"nikic/php-parser": "^4.13.0",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2",
|
||||
"phpstan/phpstan-deprecation-rules": "^2.0",
|
||||
"phpstan/phpstan-phpunit": "^2.0",
|
||||
"phpunit/phpunit": "^9.6"
|
||||
"phpstan/phpstan-deprecation-rules": "^1.1",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"type": "phpstan-extension",
|
||||
"extra": {
|
||||
@ -1526,38 +1542,38 @@
|
||||
"description": "Extra strict and opinionated rules for PHPStan",
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.4"
|
||||
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.0"
|
||||
},
|
||||
"time": "2025-03-18T11:42:40+00:00"
|
||||
"time": "2024-04-20T06:37:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "10.1.16",
|
||||
"version": "10.1.15",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "7e308268858ed6baedc8704a304727d20bc07c77"
|
||||
"reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77",
|
||||
"reference": "7e308268858ed6baedc8704a304727d20bc07c77",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae",
|
||||
"reference": "5da8b1728acd1e6ffdf2ff32ffbdfd04307f26ae",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^4.19.1 || ^5.1.0",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=8.1",
|
||||
"phpunit/php-file-iterator": "^4.1.0",
|
||||
"phpunit/php-text-template": "^3.0.1",
|
||||
"sebastian/code-unit-reverse-lookup": "^3.0.0",
|
||||
"sebastian/complexity": "^3.2.0",
|
||||
"sebastian/environment": "^6.1.0",
|
||||
"sebastian/lines-of-code": "^2.0.2",
|
||||
"sebastian/version": "^4.0.1",
|
||||
"theseer/tokenizer": "^1.2.3"
|
||||
"phpunit/php-file-iterator": "^4.0",
|
||||
"phpunit/php-text-template": "^3.0",
|
||||
"sebastian/code-unit-reverse-lookup": "^3.0",
|
||||
"sebastian/complexity": "^3.0",
|
||||
"sebastian/environment": "^6.0",
|
||||
"sebastian/lines-of-code": "^2.0",
|
||||
"sebastian/version": "^4.0",
|
||||
"theseer/tokenizer": "^1.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.1"
|
||||
@ -1569,7 +1585,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "10.1.x-dev"
|
||||
"dev-main": "10.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -1598,7 +1614,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.15"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1606,7 +1622,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-08-22T04:31:57+00:00"
|
||||
"time": "2024-06-29T08:25:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
@ -1853,16 +1869,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "10.5.45",
|
||||
"version": "10.5.24",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "bd68a781d8e30348bc297449f5234b3458267ae8"
|
||||
"reference": "5f124e3e3e561006047b532fd0431bf5bb6b9015"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8",
|
||||
"reference": "bd68a781d8e30348bc297449f5234b3458267ae8",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5f124e3e3e561006047b532fd0431bf5bb6b9015",
|
||||
"reference": "5f124e3e3e561006047b532fd0431bf5bb6b9015",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1872,26 +1888,26 @@
|
||||
"ext-mbstring": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"myclabs/deep-copy": "^1.12.1",
|
||||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"myclabs/deep-copy": "^1.10.1",
|
||||
"phar-io/manifest": "^2.0.3",
|
||||
"phar-io/version": "^3.0.2",
|
||||
"php": ">=8.1",
|
||||
"phpunit/php-code-coverage": "^10.1.16",
|
||||
"phpunit/php-file-iterator": "^4.1.0",
|
||||
"phpunit/php-invoker": "^4.0.0",
|
||||
"phpunit/php-text-template": "^3.0.1",
|
||||
"phpunit/php-timer": "^6.0.0",
|
||||
"sebastian/cli-parser": "^2.0.1",
|
||||
"sebastian/code-unit": "^2.0.0",
|
||||
"sebastian/comparator": "^5.0.3",
|
||||
"sebastian/diff": "^5.1.1",
|
||||
"sebastian/environment": "^6.1.0",
|
||||
"sebastian/exporter": "^5.1.2",
|
||||
"sebastian/global-state": "^6.0.2",
|
||||
"sebastian/object-enumerator": "^5.0.0",
|
||||
"sebastian/recursion-context": "^5.0.0",
|
||||
"sebastian/type": "^4.0.0",
|
||||
"sebastian/version": "^4.0.1"
|
||||
"phpunit/php-code-coverage": "^10.1.5",
|
||||
"phpunit/php-file-iterator": "^4.0",
|
||||
"phpunit/php-invoker": "^4.0",
|
||||
"phpunit/php-text-template": "^3.0",
|
||||
"phpunit/php-timer": "^6.0",
|
||||
"sebastian/cli-parser": "^2.0",
|
||||
"sebastian/code-unit": "^2.0",
|
||||
"sebastian/comparator": "^5.0",
|
||||
"sebastian/diff": "^5.0",
|
||||
"sebastian/environment": "^6.0",
|
||||
"sebastian/exporter": "^5.1",
|
||||
"sebastian/global-state": "^6.0.1",
|
||||
"sebastian/object-enumerator": "^5.0",
|
||||
"sebastian/recursion-context": "^5.0",
|
||||
"sebastian/type": "^4.0",
|
||||
"sebastian/version": "^4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-soap": "To be able to generate mocks based on WSDL files"
|
||||
@ -1934,7 +1950,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.24"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -1950,7 +1966,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-06T16:08:12+00:00"
|
||||
"time": "2024-06-20T13:09:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@ -2122,16 +2138,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "5.0.3",
|
||||
"version": "5.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e"
|
||||
"reference": "2db5010a484d53ebf536087a70b4a5423c102372"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
|
||||
"reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372",
|
||||
"reference": "2db5010a484d53ebf536087a70b4a5423c102372",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -2142,7 +2158,7 @@
|
||||
"sebastian/exporter": "^5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.5"
|
||||
"phpunit/phpunit": "^10.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@ -2187,7 +2203,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/comparator/issues",
|
||||
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3"
|
||||
"source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -2195,7 +2211,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-18T14:56:07+00:00"
|
||||
"time": "2023-08-14T13:18:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
|
@ -11,17 +11,14 @@ includes:
|
||||
|
||||
rules:
|
||||
- pocketmine\phpstan\rules\DeprecatedLegacyEnumAccessRule
|
||||
- pocketmine\phpstan\rules\DisallowDynamicNewRule
|
||||
- pocketmine\phpstan\rules\DisallowEnumComparisonRule
|
||||
- pocketmine\phpstan\rules\DisallowForeachByReferenceRule
|
||||
- pocketmine\phpstan\rules\ExplodeLimitRule
|
||||
- pocketmine\phpstan\rules\UnsafeForeachArrayOfStringRule
|
||||
# - pocketmine\phpstan\rules\ThreadedSupportedTypesRule
|
||||
|
||||
parameters:
|
||||
level: 9
|
||||
checkMissingCallableSignature: true
|
||||
rememberPossiblyImpureFunctionValues: false #risky to remember these, better for performance to avoid repeated calls anyway
|
||||
treatPhpDocTypesAsCertain: false
|
||||
bootstrapFiles:
|
||||
- tests/phpstan/bootstrap.php
|
||||
@ -34,7 +31,6 @@ parameters:
|
||||
paths:
|
||||
- build
|
||||
- src
|
||||
- tests/phpstan/DummyPluginOwned.php
|
||||
- tests/phpstan/rules
|
||||
- tests/phpunit
|
||||
- tests/plugins/TesterPlugin
|
||||
@ -44,15 +40,15 @@ parameters:
|
||||
- build/php
|
||||
dynamicConstantNames:
|
||||
- pocketmine\VersionInfo::IS_DEVELOPMENT_BUILD
|
||||
- pocketmine\VersionInfo::BUILD_CHANNEL
|
||||
- pocketmine\DEBUG
|
||||
- pocketmine\IS_DEVELOPMENT_BUILD
|
||||
stubFiles:
|
||||
- tests/phpstan/stubs/chunkutils2.stub
|
||||
- tests/phpstan/stubs/JsonMapper.stub
|
||||
- tests/phpstan/stubs/leveldb.stub
|
||||
- tests/phpstan/stubs/pmmpthread.stub
|
||||
reportUnmatchedIgnoredErrors: false #no other way to silence platform-specific non-warnings
|
||||
staticReflectionClassNamePatterns:
|
||||
- "#^COM$#"
|
||||
typeAliases:
|
||||
#variadics don't work for this - mixed probably shouldn't work either, but for now it does
|
||||
#what we actually need is something that accepts an infinite number of parameters, but in the absence of that,
|
||||
|
@ -54,6 +54,12 @@ memory:
|
||||
#This only affects the main thread. Other threads should fire their own collections
|
||||
period: 36000
|
||||
|
||||
#Fire asynchronous tasks to collect garbage from workers
|
||||
collect-async-worker: true
|
||||
|
||||
#Trigger on low memory
|
||||
low-memory-trigger: true
|
||||
|
||||
#Settings controlling memory dump handling.
|
||||
memory-dump:
|
||||
#Dump memory from async workers as well as the main thread. If you have issues with segfaults when dumping memory, disable this setting.
|
||||
@ -63,6 +69,16 @@ memory:
|
||||
#Cap maximum render distance per player when low memory is triggered. Set to 0 to disable cap.
|
||||
chunk-radius: 4
|
||||
|
||||
#Do chunk garbage collection on trigger
|
||||
trigger-chunk-collect: true
|
||||
|
||||
world-caches:
|
||||
#Disallow adding to world chunk-packet caches when memory is low
|
||||
disable-chunk-cache: true
|
||||
#Clear world caches when memory is low
|
||||
low-memory-trigger: true
|
||||
|
||||
|
||||
network:
|
||||
#Threshold for batching packets, in bytes. Only these packets will be compressed
|
||||
#Set to 0 to compress everything, -1 to disable.
|
||||
|
@ -1,114 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\timings\TimingsHandler;
|
||||
use function gc_collect_cycles;
|
||||
use function gc_disable;
|
||||
use function gc_status;
|
||||
use function hrtime;
|
||||
use function max;
|
||||
use function min;
|
||||
use function number_format;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* Allows threads to manually trigger the cyclic garbage collector using a threshold like PHP's own garbage collector,
|
||||
* but triggered at a time that suits the thread instead of in random code pathways.
|
||||
*
|
||||
* The GC trigger behaviour in this class was adapted from Zend/zend_gc.c as of PHP 8.3.14.
|
||||
*/
|
||||
final class GarbageCollectorManager{
|
||||
//TODO: These values could be adjusted to better suit PM, but for now we just want to mirror PHP GC to minimize
|
||||
//behavioural changes.
|
||||
private const GC_THRESHOLD_TRIGGER = 100;
|
||||
private const GC_THRESHOLD_MAX = 1_000_000_000;
|
||||
private const GC_THRESHOLD_DEFAULT = 10_001;
|
||||
private const GC_THRESHOLD_STEP = 10_000;
|
||||
|
||||
private int $threshold = self::GC_THRESHOLD_DEFAULT;
|
||||
private int $collectionTimeTotalNs = 0;
|
||||
private int $runs = 0;
|
||||
|
||||
private \Logger $logger;
|
||||
private TimingsHandler $timings;
|
||||
|
||||
public function __construct(
|
||||
\Logger $logger,
|
||||
?TimingsHandler $parentTimings,
|
||||
){
|
||||
gc_disable();
|
||||
$this->logger = new \PrefixedLogger($logger, "Cyclic Garbage Collector");
|
||||
$this->timings = new TimingsHandler("Cyclic Garbage Collector", $parentTimings);
|
||||
}
|
||||
|
||||
private function adjustGcThreshold(int $cyclesCollected, int $rootsAfterGC) : void{
|
||||
//TODO Very simple heuristic for dynamic GC buffer resizing:
|
||||
//If there are "too few" collections, increase the collection threshold
|
||||
//by a fixed step
|
||||
//Adapted from zend_gc.c/gc_adjust_threshold() as of PHP 8.3.14
|
||||
if($cyclesCollected < self::GC_THRESHOLD_TRIGGER || $rootsAfterGC >= $this->threshold){
|
||||
$this->threshold = min(self::GC_THRESHOLD_MAX, $this->threshold + self::GC_THRESHOLD_STEP);
|
||||
}elseif($this->threshold > self::GC_THRESHOLD_DEFAULT){
|
||||
$this->threshold = max(self::GC_THRESHOLD_DEFAULT, $this->threshold - self::GC_THRESHOLD_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
public function getThreshold() : int{ return $this->threshold; }
|
||||
|
||||
public function getCollectionTimeTotalNs() : int{ return $this->collectionTimeTotalNs; }
|
||||
|
||||
public function maybeCollectCycles() : int{
|
||||
$rootsBefore = gc_status()["roots"];
|
||||
if($rootsBefore < $this->threshold){
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->timings->startTiming();
|
||||
|
||||
$start = hrtime(true);
|
||||
$cycles = gc_collect_cycles();
|
||||
$end = hrtime(true);
|
||||
|
||||
$rootsAfter = gc_status()["roots"];
|
||||
$this->adjustGcThreshold($cycles, $rootsAfter);
|
||||
|
||||
$this->timings->stopTiming();
|
||||
|
||||
$time = $end - $start;
|
||||
$this->collectionTimeTotalNs += $time;
|
||||
$this->runs++;
|
||||
$this->logger->info(sprintf(
|
||||
"Run #%d took %s ms (%s -> %s roots, %s cycles collected) - cumulative GC time: %s ms",
|
||||
$this->runs,
|
||||
number_format($time / 1_000_000, 2),
|
||||
$rootsBefore,
|
||||
$rootsAfter,
|
||||
$cycles,
|
||||
number_format($this->collectionTimeTotalNs / 1_000_000, 2)
|
||||
));
|
||||
|
||||
return $cycles;
|
||||
}
|
||||
}
|
@ -1,305 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine;
|
||||
|
||||
use pocketmine\utils\Utils;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function arsort;
|
||||
use function count;
|
||||
use function fclose;
|
||||
use function file_exists;
|
||||
use function file_put_contents;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function gc_disable;
|
||||
use function gc_enable;
|
||||
use function gc_enabled;
|
||||
use function get_class;
|
||||
use function get_declared_classes;
|
||||
use function get_defined_functions;
|
||||
use function ini_get;
|
||||
use function ini_set;
|
||||
use function is_array;
|
||||
use function is_float;
|
||||
use function is_object;
|
||||
use function is_resource;
|
||||
use function is_string;
|
||||
use function json_encode;
|
||||
use function mkdir;
|
||||
use function print_r;
|
||||
use function spl_object_hash;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use const JSON_PRETTY_PRINT;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
final class MemoryDump{
|
||||
|
||||
private function __construct(){
|
||||
//NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Static memory dumper accessible from any thread.
|
||||
*/
|
||||
public static function dumpMemory(mixed $startingObject, string $outputFolder, int $maxNesting, int $maxStringSize, \Logger $logger) : void{
|
||||
$hardLimit = Utils::assumeNotFalse(ini_get('memory_limit'), "memory_limit INI directive should always exist");
|
||||
ini_set('memory_limit', '-1');
|
||||
$gcEnabled = gc_enabled();
|
||||
gc_disable();
|
||||
|
||||
if(!file_exists($outputFolder)){
|
||||
mkdir($outputFolder, 0777, true);
|
||||
}
|
||||
|
||||
$obData = Utils::assumeNotFalse(fopen(Path::join($outputFolder, "objects.js"), "wb+"));
|
||||
|
||||
$objects = [];
|
||||
|
||||
$refCounts = [];
|
||||
|
||||
$instanceCounts = [];
|
||||
|
||||
$staticProperties = [];
|
||||
$staticCount = 0;
|
||||
|
||||
$functionStaticVars = [];
|
||||
$functionStaticVarsCount = 0;
|
||||
|
||||
foreach(get_declared_classes() as $className){
|
||||
$reflection = new \ReflectionClass($className);
|
||||
$staticProperties[$className] = [];
|
||||
foreach($reflection->getProperties() as $property){
|
||||
if(!$property->isStatic() || $property->getDeclaringClass()->getName() !== $className){
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!$property->isInitialized()){
|
||||
continue;
|
||||
}
|
||||
|
||||
$staticCount++;
|
||||
$staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
if(count($staticProperties[$className]) === 0){
|
||||
unset($staticProperties[$className]);
|
||||
}
|
||||
|
||||
foreach($reflection->getMethods() as $method){
|
||||
if($method->getDeclaringClass()->getName() !== $reflection->getName()){
|
||||
continue;
|
||||
}
|
||||
$methodStatics = [];
|
||||
foreach(Utils::promoteKeys($method->getStaticVariables()) as $name => $variable){
|
||||
$methodStatics[$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
if(count($methodStatics) > 0){
|
||||
$functionStaticVars[$className . "::" . $method->getName()] = $methodStatics;
|
||||
$functionStaticVarsCount += count($functionStaticVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
$logger->info("Wrote $staticCount static properties");
|
||||
|
||||
$globalVariables = [];
|
||||
$globalCount = 0;
|
||||
|
||||
$ignoredGlobals = [
|
||||
'GLOBALS' => true,
|
||||
'_SERVER' => true,
|
||||
'_REQUEST' => true,
|
||||
'_POST' => true,
|
||||
'_GET' => true,
|
||||
'_FILES' => true,
|
||||
'_ENV' => true,
|
||||
'_COOKIE' => true,
|
||||
'_SESSION' => true
|
||||
];
|
||||
|
||||
foreach(Utils::promoteKeys($GLOBALS) as $varName => $value){
|
||||
if(isset($ignoredGlobals[$varName])){
|
||||
continue;
|
||||
}
|
||||
|
||||
$globalCount++;
|
||||
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
$logger->info("Wrote $globalCount global variables");
|
||||
|
||||
foreach(get_defined_functions()["user"] as $function){
|
||||
$reflect = new \ReflectionFunction($function);
|
||||
|
||||
$vars = [];
|
||||
foreach(Utils::promoteKeys($reflect->getStaticVariables()) as $varName => $variable){
|
||||
$vars[$varName] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
if(count($vars) > 0){
|
||||
$functionStaticVars[$function] = $vars;
|
||||
$functionStaticVarsCount += count($vars);
|
||||
}
|
||||
}
|
||||
file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
$logger->info("Wrote $functionStaticVarsCount function static variables");
|
||||
|
||||
$data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
|
||||
do{
|
||||
$continue = false;
|
||||
foreach(Utils::stringifyKeys($objects) as $hash => $object){
|
||||
if(!is_object($object)){
|
||||
continue;
|
||||
}
|
||||
$continue = true;
|
||||
|
||||
$className = get_class($object);
|
||||
if(!isset($instanceCounts[$className])){
|
||||
$instanceCounts[$className] = 1;
|
||||
}else{
|
||||
$instanceCounts[$className]++;
|
||||
}
|
||||
|
||||
$objects[$hash] = true;
|
||||
$info = [
|
||||
"information" => "$hash@$className",
|
||||
];
|
||||
if($object instanceof \Closure){
|
||||
$info["definition"] = Utils::getNiceClosureName($object);
|
||||
$info["referencedVars"] = [];
|
||||
$reflect = new \ReflectionFunction($object);
|
||||
if(($closureThis = $reflect->getClosureThis()) !== null){
|
||||
$info["this"] = self::continueDump($closureThis, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
foreach(Utils::promoteKeys($reflect->getStaticVariables()) as $name => $variable){
|
||||
$info["referencedVars"][$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
}else{
|
||||
$reflection = new \ReflectionObject($object);
|
||||
|
||||
$info["properties"] = [];
|
||||
|
||||
for($original = $reflection; $reflection !== false; $reflection = $reflection->getParentClass()){
|
||||
foreach($reflection->getProperties() as $property){
|
||||
if($property->isStatic()){
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $property->getName();
|
||||
if($reflection !== $original){
|
||||
if($property->isPrivate()){
|
||||
$name = $reflection->getName() . ":" . $name;
|
||||
}else{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(!$property->isInitialized($object)){
|
||||
continue;
|
||||
}
|
||||
|
||||
$info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n");
|
||||
}
|
||||
|
||||
}while($continue);
|
||||
|
||||
$logger->info("Wrote " . count($objects) . " objects");
|
||||
|
||||
fclose($obData);
|
||||
|
||||
file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
|
||||
arsort($instanceCounts, SORT_NUMERIC);
|
||||
file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
|
||||
$logger->info("Finished!");
|
||||
|
||||
ini_set('memory_limit', $hardLimit);
|
||||
if($gcEnabled){
|
||||
gc_enable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object[]|true[] $objects reference parameter
|
||||
* @param int[] $refCounts reference parameter
|
||||
*
|
||||
* @phpstan-param array<string, object|true> $objects
|
||||
* @phpstan-param array<string, int> $refCounts
|
||||
* @phpstan-param-out array<string, object|true> $objects
|
||||
* @phpstan-param-out array<string, int> $refCounts
|
||||
*/
|
||||
private static function continueDump(mixed $from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : mixed{
|
||||
if($maxNesting <= 0){
|
||||
return "(error) NESTING LIMIT REACHED";
|
||||
}
|
||||
|
||||
--$maxNesting;
|
||||
|
||||
if(is_object($from)){
|
||||
if(!isset($objects[$hash = spl_object_hash($from)])){
|
||||
$objects[$hash] = $from;
|
||||
$refCounts[$hash] = 0;
|
||||
}
|
||||
|
||||
++$refCounts[$hash];
|
||||
|
||||
$data = "(object) $hash";
|
||||
}elseif(is_array($from)){
|
||||
if($recursion >= 5){
|
||||
return "(error) ARRAY RECURSION LIMIT REACHED";
|
||||
}
|
||||
$data = [];
|
||||
$numeric = 0;
|
||||
foreach(Utils::promoteKeys($from) as $key => $value){
|
||||
$data[$numeric] = [
|
||||
"k" => self::continueDump($key, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
|
||||
"v" => self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
|
||||
];
|
||||
$numeric++;
|
||||
}
|
||||
}elseif(is_string($from)){
|
||||
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||
}elseif(is_resource($from)){
|
||||
$data = "(resource) " . print_r($from, true);
|
||||
}elseif(is_float($from)){
|
||||
$data = "(float) $from";
|
||||
}else{
|
||||
$data = $from;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@ -29,24 +29,52 @@ use pocketmine\scheduler\DumpWorkerMemoryTask;
|
||||
use pocketmine\scheduler\GarbageCollectionTask;
|
||||
use pocketmine\timings\Timings;
|
||||
use pocketmine\utils\Process;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\YmlServerProperties as Yml;
|
||||
use Symfony\Component\Filesystem\Path;
|
||||
use function arsort;
|
||||
use function count;
|
||||
use function fclose;
|
||||
use function file_exists;
|
||||
use function file_put_contents;
|
||||
use function fopen;
|
||||
use function fwrite;
|
||||
use function gc_collect_cycles;
|
||||
use function gc_disable;
|
||||
use function gc_enable;
|
||||
use function gc_mem_caches;
|
||||
use function get_class;
|
||||
use function get_declared_classes;
|
||||
use function get_defined_functions;
|
||||
use function ini_get;
|
||||
use function ini_set;
|
||||
use function intdiv;
|
||||
use function is_array;
|
||||
use function is_float;
|
||||
use function is_object;
|
||||
use function is_resource;
|
||||
use function is_string;
|
||||
use function json_encode;
|
||||
use function mb_strtoupper;
|
||||
use function min;
|
||||
use function mkdir;
|
||||
use function preg_match;
|
||||
use function print_r;
|
||||
use function round;
|
||||
use function spl_object_hash;
|
||||
use function sprintf;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
use const JSON_PRETTY_PRINT;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
use const SORT_NUMERIC;
|
||||
|
||||
class MemoryManager{
|
||||
private const DEFAULT_CHECK_RATE = Server::TARGET_TICKS_PER_SECOND;
|
||||
private const DEFAULT_CONTINUOUS_TRIGGER_RATE = Server::TARGET_TICKS_PER_SECOND * 2;
|
||||
private const DEFAULT_TICKS_PER_GC = 30 * 60 * Server::TARGET_TICKS_PER_SECOND;
|
||||
|
||||
private GarbageCollectorManager $cycleGcManager;
|
||||
|
||||
private int $memoryLimit;
|
||||
private int $globalMemoryLimit;
|
||||
private int $checkRate;
|
||||
@ -60,8 +88,14 @@ class MemoryManager{
|
||||
|
||||
private int $garbageCollectionPeriod;
|
||||
private int $garbageCollectionTicker = 0;
|
||||
private bool $garbageCollectionTrigger;
|
||||
private bool $garbageCollectionAsync;
|
||||
|
||||
private int $lowMemChunkRadiusOverride;
|
||||
private bool $lowMemChunkGC;
|
||||
|
||||
private bool $lowMemDisableChunkCache;
|
||||
private bool $lowMemClearWorldCache;
|
||||
|
||||
private bool $dumpWorkers = true;
|
||||
|
||||
@ -71,7 +105,6 @@ class MemoryManager{
|
||||
private Server $server
|
||||
){
|
||||
$this->logger = new \PrefixedLogger($server->getLogger(), "Memory Manager");
|
||||
$this->cycleGcManager = new GarbageCollectorManager($this->logger, Timings::$memoryManager);
|
||||
|
||||
$this->init($server->getConfigGroup());
|
||||
}
|
||||
@ -109,10 +142,17 @@ class MemoryManager{
|
||||
$this->continuousTriggerRate = $config->getPropertyInt(Yml::MEMORY_CONTINUOUS_TRIGGER_RATE, self::DEFAULT_CONTINUOUS_TRIGGER_RATE);
|
||||
|
||||
$this->garbageCollectionPeriod = $config->getPropertyInt(Yml::MEMORY_GARBAGE_COLLECTION_PERIOD, self::DEFAULT_TICKS_PER_GC);
|
||||
$this->garbageCollectionTrigger = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER, true);
|
||||
$this->garbageCollectionAsync = $config->getPropertyBool(Yml::MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER, true);
|
||||
|
||||
$this->lowMemChunkRadiusOverride = $config->getPropertyInt(Yml::MEMORY_MAX_CHUNKS_CHUNK_RADIUS, 4);
|
||||
$this->lowMemChunkGC = $config->getPropertyBool(Yml::MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT, true);
|
||||
|
||||
$this->lowMemDisableChunkCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE, true);
|
||||
$this->lowMemClearWorldCache = $config->getPropertyBool(Yml::MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER, true);
|
||||
|
||||
$this->dumpWorkers = $config->getPropertyBool(Yml::MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER, true);
|
||||
gc_enable();
|
||||
}
|
||||
|
||||
public function isLowMemory() : bool{
|
||||
@ -123,11 +163,8 @@ class MemoryManager{
|
||||
return $this->globalMemoryLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public function canUseChunkCache() : bool{
|
||||
return !$this->lowMemory;
|
||||
return !$this->lowMemory || !$this->lowMemDisableChunkCache;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,19 +180,26 @@ class MemoryManager{
|
||||
public function trigger(int $memory, int $limit, bool $global = false, int $triggerCount = 0) : void{
|
||||
$this->logger->debug(sprintf("%sLow memory triggered, limit %gMB, using %gMB",
|
||||
$global ? "Global " : "", round(($limit / 1024) / 1024, 2), round(($memory / 1024) / 1024, 2)));
|
||||
if($this->lowMemClearWorldCache){
|
||||
foreach($this->server->getWorldManager()->getWorlds() as $world){
|
||||
$world->clearCache(true);
|
||||
}
|
||||
ChunkCache::pruneCaches();
|
||||
}
|
||||
|
||||
if($this->lowMemChunkGC){
|
||||
foreach($this->server->getWorldManager()->getWorlds() as $world){
|
||||
$world->doChunkGarbageCollection();
|
||||
}
|
||||
}
|
||||
|
||||
$ev = new LowMemoryEvent($memory, $limit, $global, $triggerCount);
|
||||
$ev->call();
|
||||
|
||||
$cycles = 0;
|
||||
if($this->garbageCollectionTrigger){
|
||||
$cycles = $this->triggerGarbageCollector();
|
||||
}
|
||||
|
||||
$this->logger->debug(sprintf("Freed %gMB, $cycles cycles", round(($ev->getMemoryFreed() / 1024) / 1024, 2)));
|
||||
}
|
||||
@ -195,8 +239,6 @@ class MemoryManager{
|
||||
if($this->garbageCollectionPeriod > 0 && ++$this->garbageCollectionTicker >= $this->garbageCollectionPeriod){
|
||||
$this->garbageCollectionTicker = 0;
|
||||
$this->triggerGarbageCollector();
|
||||
}else{
|
||||
$this->cycleGcManager->maybeCollectCycles();
|
||||
}
|
||||
|
||||
Timings::$memoryManager->stopTiming();
|
||||
@ -205,6 +247,7 @@ class MemoryManager{
|
||||
public function triggerGarbageCollector() : int{
|
||||
Timings::$garbageCollector->startTiming();
|
||||
|
||||
if($this->garbageCollectionAsync){
|
||||
$pool = $this->server->getAsyncPool();
|
||||
if(($w = $pool->shutdownUnusedWorkers()) > 0){
|
||||
$this->logger->debug("Shut down $w idle async pool workers");
|
||||
@ -212,6 +255,7 @@ class MemoryManager{
|
||||
foreach($pool->getRunningWorkers() as $i){
|
||||
$pool->submitTaskToWorker(new GarbageCollectionTask(), $i);
|
||||
}
|
||||
}
|
||||
|
||||
$cycles = gc_collect_cycles();
|
||||
gc_mem_caches();
|
||||
@ -227,7 +271,7 @@ class MemoryManager{
|
||||
public function dumpServerMemory(string $outputFolder, int $maxNesting, int $maxStringSize) : void{
|
||||
$logger = new \PrefixedLogger($this->server->getLogger(), "Memory Dump");
|
||||
$logger->notice("After the memory dump is done, the server might crash");
|
||||
MemoryDump::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize, $logger);
|
||||
self::dumpMemory($this->server, $outputFolder, $maxNesting, $maxStringSize, $logger);
|
||||
|
||||
if($this->dumpWorkers){
|
||||
$pool = $this->server->getAsyncPool();
|
||||
@ -239,10 +283,239 @@ 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);
|
||||
$hardLimit = Utils::assumeNotFalse(ini_get('memory_limit'), "memory_limit INI directive should always exist");
|
||||
ini_set('memory_limit', '-1');
|
||||
gc_disable();
|
||||
|
||||
if(!file_exists($outputFolder)){
|
||||
mkdir($outputFolder, 0777, true);
|
||||
}
|
||||
|
||||
$obData = Utils::assumeNotFalse(fopen(Path::join($outputFolder, "objects.js"), "wb+"));
|
||||
|
||||
$objects = [];
|
||||
|
||||
$refCounts = [];
|
||||
|
||||
$instanceCounts = [];
|
||||
|
||||
$staticProperties = [];
|
||||
$staticCount = 0;
|
||||
|
||||
$functionStaticVars = [];
|
||||
$functionStaticVarsCount = 0;
|
||||
|
||||
foreach(get_declared_classes() as $className){
|
||||
$reflection = new \ReflectionClass($className);
|
||||
$staticProperties[$className] = [];
|
||||
foreach($reflection->getProperties() as $property){
|
||||
if(!$property->isStatic() || $property->getDeclaringClass()->getName() !== $className){
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!$property->isInitialized()){
|
||||
continue;
|
||||
}
|
||||
|
||||
$staticCount++;
|
||||
$staticProperties[$className][$property->getName()] = self::continueDump($property->getValue(), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
if(count($staticProperties[$className]) === 0){
|
||||
unset($staticProperties[$className]);
|
||||
}
|
||||
|
||||
foreach($reflection->getMethods() as $method){
|
||||
if($method->getDeclaringClass()->getName() !== $reflection->getName()){
|
||||
continue;
|
||||
}
|
||||
$methodStatics = [];
|
||||
foreach($method->getStaticVariables() as $name => $variable){
|
||||
$methodStatics[$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
if(count($methodStatics) > 0){
|
||||
$functionStaticVars[$className . "::" . $method->getName()] = $methodStatics;
|
||||
$functionStaticVarsCount += count($functionStaticVars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents(Path::join($outputFolder, "staticProperties.js"), json_encode($staticProperties, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
$logger->info("Wrote $staticCount static properties");
|
||||
|
||||
$globalVariables = [];
|
||||
$globalCount = 0;
|
||||
|
||||
$ignoredGlobals = [
|
||||
'GLOBALS' => true,
|
||||
'_SERVER' => true,
|
||||
'_REQUEST' => true,
|
||||
'_POST' => true,
|
||||
'_GET' => true,
|
||||
'_FILES' => true,
|
||||
'_ENV' => true,
|
||||
'_COOKIE' => true,
|
||||
'_SESSION' => true
|
||||
];
|
||||
|
||||
foreach($GLOBALS as $varName => $value){
|
||||
if(isset($ignoredGlobals[$varName])){
|
||||
continue;
|
||||
}
|
||||
|
||||
$globalCount++;
|
||||
$globalVariables[$varName] = self::continueDump($value, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
file_put_contents(Path::join($outputFolder, "globalVariables.js"), json_encode($globalVariables, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
$logger->info("Wrote $globalCount global variables");
|
||||
|
||||
foreach(get_defined_functions()["user"] as $function){
|
||||
$reflect = new \ReflectionFunction($function);
|
||||
|
||||
$vars = [];
|
||||
foreach($reflect->getStaticVariables() as $varName => $variable){
|
||||
$vars[$varName] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
if(count($vars) > 0){
|
||||
$functionStaticVars[$function] = $vars;
|
||||
$functionStaticVarsCount += count($vars);
|
||||
}
|
||||
}
|
||||
file_put_contents(Path::join($outputFolder, 'functionStaticVars.js'), json_encode($functionStaticVars, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
$logger->info("Wrote $functionStaticVarsCount function static variables");
|
||||
|
||||
$data = self::continueDump($startingObject, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
|
||||
do{
|
||||
$continue = false;
|
||||
foreach(Utils::stringifyKeys($objects) as $hash => $object){
|
||||
if(!is_object($object)){
|
||||
continue;
|
||||
}
|
||||
$continue = true;
|
||||
|
||||
$className = get_class($object);
|
||||
if(!isset($instanceCounts[$className])){
|
||||
$instanceCounts[$className] = 1;
|
||||
}else{
|
||||
$instanceCounts[$className]++;
|
||||
}
|
||||
|
||||
$objects[$hash] = true;
|
||||
$info = [
|
||||
"information" => "$hash@$className",
|
||||
];
|
||||
if($object instanceof \Closure){
|
||||
$info["definition"] = Utils::getNiceClosureName($object);
|
||||
$info["referencedVars"] = [];
|
||||
$reflect = new \ReflectionFunction($object);
|
||||
if(($closureThis = $reflect->getClosureThis()) !== null){
|
||||
$info["this"] = self::continueDump($closureThis, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
|
||||
foreach($reflect->getStaticVariables() as $name => $variable){
|
||||
$info["referencedVars"][$name] = self::continueDump($variable, $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
}else{
|
||||
$reflection = new \ReflectionObject($object);
|
||||
|
||||
$info["properties"] = [];
|
||||
|
||||
for($original = $reflection; $reflection !== false; $reflection = $reflection->getParentClass()){
|
||||
foreach($reflection->getProperties() as $property){
|
||||
if($property->isStatic()){
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $property->getName();
|
||||
if($reflection !== $original){
|
||||
if($property->isPrivate()){
|
||||
$name = $reflection->getName() . ":" . $name;
|
||||
}else{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(!$property->isInitialized($object)){
|
||||
continue;
|
||||
}
|
||||
|
||||
$info["properties"][$name] = self::continueDump($property->getValue($object), $objects, $refCounts, 0, $maxNesting, $maxStringSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fwrite($obData, json_encode($info, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n");
|
||||
}
|
||||
|
||||
}while($continue);
|
||||
|
||||
$logger->info("Wrote " . count($objects) . " objects");
|
||||
|
||||
fclose($obData);
|
||||
|
||||
file_put_contents(Path::join($outputFolder, "serverEntry.js"), json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
file_put_contents(Path::join($outputFolder, "referenceCounts.js"), json_encode($refCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
|
||||
arsort($instanceCounts, SORT_NUMERIC);
|
||||
file_put_contents(Path::join($outputFolder, "instanceCounts.js"), json_encode($instanceCounts, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
|
||||
$logger->info("Finished!");
|
||||
|
||||
ini_set('memory_limit', $hardLimit);
|
||||
gc_enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object[] $objects reference parameter
|
||||
* @param int[] $refCounts reference parameter
|
||||
*
|
||||
* @phpstan-param array<string, object> $objects
|
||||
* @phpstan-param array<string, int> $refCounts
|
||||
* @phpstan-param-out array<string, object> $objects
|
||||
* @phpstan-param-out array<string, int> $refCounts
|
||||
*/
|
||||
private static function continueDump(mixed $from, array &$objects, array &$refCounts, int $recursion, int $maxNesting, int $maxStringSize) : mixed{
|
||||
if($maxNesting <= 0){
|
||||
return "(error) NESTING LIMIT REACHED";
|
||||
}
|
||||
|
||||
--$maxNesting;
|
||||
|
||||
if(is_object($from)){
|
||||
if(!isset($objects[$hash = spl_object_hash($from)])){
|
||||
$objects[$hash] = $from;
|
||||
$refCounts[$hash] = 0;
|
||||
}
|
||||
|
||||
++$refCounts[$hash];
|
||||
|
||||
$data = "(object) $hash";
|
||||
}elseif(is_array($from)){
|
||||
if($recursion >= 5){
|
||||
return "(error) ARRAY RECURSION LIMIT REACHED";
|
||||
}
|
||||
$data = [];
|
||||
$numeric = 0;
|
||||
foreach($from as $key => $value){
|
||||
$data[$numeric] = [
|
||||
"k" => self::continueDump($key, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
|
||||
"v" => self::continueDump($value, $objects, $refCounts, $recursion + 1, $maxNesting, $maxStringSize),
|
||||
];
|
||||
$numeric++;
|
||||
}
|
||||
}elseif(is_string($from)){
|
||||
$data = "(string) len(" . strlen($from) . ") " . substr(Utils::printable($from), 0, $maxStringSize);
|
||||
}elseif(is_resource($from)){
|
||||
$data = "(resource) " . print_r($from, true);
|
||||
}elseif(is_float($from)){
|
||||
$data = "(float) $from";
|
||||
}else{
|
||||
$data = $from;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ JIT_WARNING
|
||||
$composerGitHash = InstalledVersions::getReference('pocketmine/pocketmine-mp');
|
||||
if($composerGitHash !== null){
|
||||
//we can't verify dependency versions if we were installed without using git
|
||||
$currentGitHash = explode("-", VersionInfo::GIT_HASH(), 2)[0];
|
||||
$currentGitHash = explode("-", VersionInfo::GIT_HASH())[0];
|
||||
if($currentGitHash !== $composerGitHash){
|
||||
critical_error("Composer dependencies and/or autoloader are out of sync.");
|
||||
critical_error("- Current revision is $currentGitHash");
|
||||
@ -282,11 +282,6 @@ JIT_WARNING
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(defined('pocketmine\ORIGINAL_PHAR_PATH')){
|
||||
//if we're inside a phar cache, \pocketmine\PATH will not include the original phar
|
||||
Filesystem::addCleanedPath(ORIGINAL_PHAR_PATH, Filesystem::CLEAN_PATH_SRC_PREFIX);
|
||||
}
|
||||
|
||||
$cwd = Utils::assumeNotFalse(realpath(Utils::assumeNotFalse(getcwd())));
|
||||
$dataPath = getopt_string(BootstrapOptions::DATA) ?? $cwd;
|
||||
$pluginPath = getopt_string(BootstrapOptions::PLUGINS) ?? $cwd . DIRECTORY_SEPARATOR . "plugins";
|
||||
|
@ -36,7 +36,6 @@ use pocketmine\crafting\CraftingManager;
|
||||
use pocketmine\crafting\CraftingManagerFromDataHelper;
|
||||
use pocketmine\crash\CrashDump;
|
||||
use pocketmine\crash\CrashDumpRenderer;
|
||||
use pocketmine\data\bedrock\BedrockDataFiles;
|
||||
use pocketmine\entity\EntityDataHelper;
|
||||
use pocketmine\entity\Location;
|
||||
use pocketmine\event\HandlerListManager;
|
||||
@ -90,8 +89,6 @@ use pocketmine\promise\Promise;
|
||||
use pocketmine\promise\PromiseResolver;
|
||||
use pocketmine\resourcepacks\ResourcePackManager;
|
||||
use pocketmine\scheduler\AsyncPool;
|
||||
use pocketmine\scheduler\TimingsCollectionTask;
|
||||
use pocketmine\scheduler\TimingsControlTask;
|
||||
use pocketmine\snooze\SleeperHandler;
|
||||
use pocketmine\stats\SendUsageTask;
|
||||
use pocketmine\thread\log\AttachableThreadSafeLogger;
|
||||
@ -139,7 +136,6 @@ use function file_put_contents;
|
||||
use function filemtime;
|
||||
use function fopen;
|
||||
use function get_class;
|
||||
use function gettype;
|
||||
use function ini_set;
|
||||
use function is_array;
|
||||
use function is_dir;
|
||||
@ -699,7 +695,7 @@ class Server{
|
||||
|
||||
public function removeOp(string $name) : void{
|
||||
$lowercaseName = strtolower($name);
|
||||
foreach(Utils::promoteKeys($this->operators->getAll()) as $operatorName => $_){
|
||||
foreach($this->operators->getAll() as $operatorName => $_){
|
||||
$operatorName = (string) $operatorName;
|
||||
if($lowercaseName === strtolower($operatorName)){
|
||||
$this->operators->remove($operatorName);
|
||||
@ -740,15 +736,12 @@ class Server{
|
||||
|
||||
/**
|
||||
* @return string[][]
|
||||
* @phpstan-return array<string, list<string>>
|
||||
*/
|
||||
public function getCommandAliases() : array{
|
||||
$section = $this->configGroup->getProperty(Yml::ALIASES);
|
||||
$result = [];
|
||||
if(is_array($section)){
|
||||
foreach(Utils::promoteKeys($section) as $key => $value){
|
||||
//TODO: more validation needed here
|
||||
//key might not be a string, value might not be list<string>
|
||||
foreach($section as $key => $value){
|
||||
$commands = [];
|
||||
if(is_array($value)){
|
||||
$commands = $value;
|
||||
@ -756,7 +749,7 @@ class Server{
|
||||
$commands[] = (string) $value;
|
||||
}
|
||||
|
||||
$result[(string) $key] = $commands;
|
||||
$result[$key] = $commands;
|
||||
}
|
||||
}
|
||||
|
||||
@ -898,37 +891,7 @@ class Server{
|
||||
$poolSize = max(1, (int) $poolSize);
|
||||
}
|
||||
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
|
||||
|
||||
$this->asyncPool = new AsyncPool($poolSize, max(-1, $this->configGroup->getPropertyInt(Yml::MEMORY_ASYNC_WORKER_HARD_LIMIT, 256)), $this->autoloader, $this->logger, $this->tickSleeper);
|
||||
$this->asyncPool->addWorkerStartHook(function(int $i) : void{
|
||||
if(TimingsHandler::isEnabled()){
|
||||
$this->asyncPool->submitTaskToWorker(TimingsControlTask::setEnabled(true), $i);
|
||||
}
|
||||
});
|
||||
TimingsHandler::getToggleCallbacks()->add(function(bool $enable) : void{
|
||||
foreach($this->asyncPool->getRunningWorkers() as $workerId){
|
||||
$this->asyncPool->submitTaskToWorker(TimingsControlTask::setEnabled($enable), $workerId);
|
||||
}
|
||||
});
|
||||
TimingsHandler::getReloadCallbacks()->add(function() : void{
|
||||
foreach($this->asyncPool->getRunningWorkers() as $workerId){
|
||||
$this->asyncPool->submitTaskToWorker(TimingsControlTask::reload(), $workerId);
|
||||
}
|
||||
});
|
||||
TimingsHandler::getCollectCallbacks()->add(function() : array{
|
||||
$promises = [];
|
||||
foreach($this->asyncPool->getRunningWorkers() as $workerId){
|
||||
/** @phpstan-var PromiseResolver<list<string>> $resolver */
|
||||
$resolver = new PromiseResolver();
|
||||
$this->asyncPool->submitTaskToWorker(new TimingsCollectionTask($resolver), $workerId);
|
||||
|
||||
$promises[] = $resolver->getPromise();
|
||||
}
|
||||
|
||||
return $promises;
|
||||
});
|
||||
|
||||
$netCompressionThreshold = -1;
|
||||
if($this->configGroup->getPropertyInt(Yml::NETWORK_BATCH_THRESHOLD, 256) >= 0){
|
||||
@ -1002,11 +965,14 @@ class Server{
|
||||
)));
|
||||
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_license($this->getName())));
|
||||
|
||||
TimingsHandler::setEnabled($this->configGroup->getPropertyBool(Yml::SETTINGS_ENABLE_PROFILING, false));
|
||||
$this->profilingTickRate = $this->configGroup->getPropertyInt(Yml::SETTINGS_PROFILE_REPORT_TRIGGER, self::TARGET_TICKS_PER_SECOND);
|
||||
|
||||
DefaultPermissions::registerCorePermissions();
|
||||
|
||||
$this->commandMap = new SimpleCommandMap($this);
|
||||
|
||||
$this->craftingManager = CraftingManagerFromDataHelper::make(BedrockDataFiles::RECIPES);
|
||||
$this->craftingManager = CraftingManagerFromDataHelper::make(Path::join(\pocketmine\BEDROCK_DATA_PATH, "recipes"));
|
||||
|
||||
$this->resourceManager = new ResourcePackManager(Path::join($this->dataPath, "resource_packs"), $this->logger);
|
||||
|
||||
@ -1016,11 +982,7 @@ class Server{
|
||||
copy(Path::join(\pocketmine\RESOURCE_PATH, 'plugin_list.yml'), $graylistFile);
|
||||
}
|
||||
try{
|
||||
$array = yaml_parse(Filesystem::fileGetContents($graylistFile));
|
||||
if(!is_array($array)){
|
||||
throw new \InvalidArgumentException("Expected array for root, but have " . gettype($array));
|
||||
}
|
||||
$pluginGraylist = PluginGraylist::fromArray($array);
|
||||
$pluginGraylist = PluginGraylist::fromArray(yaml_parse(Filesystem::fileGetContents($graylistFile)));
|
||||
}catch(\InvalidArgumentException $e){
|
||||
$this->logger->emergency("Failed to load $graylistFile: " . $e->getMessage());
|
||||
$this->forceShutdownExit();
|
||||
@ -1132,11 +1094,7 @@ class Server{
|
||||
|
||||
$anyWorldFailedToLoad = false;
|
||||
|
||||
foreach(Utils::promoteKeys((array) $this->configGroup->getProperty(Yml::WORLDS, [])) as $name => $options){
|
||||
if(!is_string($name)){
|
||||
//TODO: this probably should be an error
|
||||
continue;
|
||||
}
|
||||
foreach((array) $this->configGroup->getProperty(Yml::WORLDS, []) as $name => $options){
|
||||
if($options === null){
|
||||
$options = [];
|
||||
}elseif(!is_array($options)){
|
||||
@ -1181,7 +1139,7 @@ class Server{
|
||||
|
||||
if($this->worldManager->getDefaultWorld() === null){
|
||||
$default = $this->configGroup->getConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
if(trim($default) === ""){
|
||||
if(trim($default) == ""){
|
||||
$this->logger->warning("level-name cannot be null, using default");
|
||||
$default = "world";
|
||||
$this->configGroup->setConfigString(ServerProperties::DEFAULT_WORLD_NAME, "world");
|
||||
|
@ -31,8 +31,8 @@ use function str_repeat;
|
||||
|
||||
final class VersionInfo{
|
||||
public const NAME = "PocketMine-MP";
|
||||
public const BASE_VERSION = "5.27.2";
|
||||
public const IS_DEVELOPMENT_BUILD = true;
|
||||
public const BASE_VERSION = "5.18.1";
|
||||
public const IS_DEVELOPMENT_BUILD = false;
|
||||
public const BUILD_CHANNEL = "stable";
|
||||
|
||||
/**
|
||||
|
@ -75,14 +75,20 @@ final class YmlServerProperties{
|
||||
public const MEMORY_CONTINUOUS_TRIGGER = 'memory.continuous-trigger';
|
||||
public const MEMORY_CONTINUOUS_TRIGGER_RATE = 'memory.continuous-trigger-rate';
|
||||
public const MEMORY_GARBAGE_COLLECTION = 'memory.garbage-collection';
|
||||
public const MEMORY_GARBAGE_COLLECTION_COLLECT_ASYNC_WORKER = 'memory.garbage-collection.collect-async-worker';
|
||||
public const MEMORY_GARBAGE_COLLECTION_LOW_MEMORY_TRIGGER = 'memory.garbage-collection.low-memory-trigger';
|
||||
public const MEMORY_GARBAGE_COLLECTION_PERIOD = 'memory.garbage-collection.period';
|
||||
public const MEMORY_GLOBAL_LIMIT = 'memory.global-limit';
|
||||
public const MEMORY_MAIN_HARD_LIMIT = 'memory.main-hard-limit';
|
||||
public const MEMORY_MAIN_LIMIT = 'memory.main-limit';
|
||||
public const MEMORY_MAX_CHUNKS = 'memory.max-chunks';
|
||||
public const MEMORY_MAX_CHUNKS_CHUNK_RADIUS = 'memory.max-chunks.chunk-radius';
|
||||
public const MEMORY_MAX_CHUNKS_TRIGGER_CHUNK_COLLECT = 'memory.max-chunks.trigger-chunk-collect';
|
||||
public const MEMORY_MEMORY_DUMP = 'memory.memory-dump';
|
||||
public const MEMORY_MEMORY_DUMP_DUMP_ASYNC_WORKER = 'memory.memory-dump.dump-async-worker';
|
||||
public const MEMORY_WORLD_CACHES = 'memory.world-caches';
|
||||
public const MEMORY_WORLD_CACHES_DISABLE_CHUNK_CACHE = 'memory.world-caches.disable-chunk-cache';
|
||||
public const MEMORY_WORLD_CACHES_LOW_MEMORY_TRIGGER = 'memory.world-caches.low-memory-trigger';
|
||||
public const NETWORK = 'network';
|
||||
public const NETWORK_ASYNC_COMPRESSION = 'network.async-compression';
|
||||
public const NETWORK_ASYNC_COMPRESSION_THRESHOLD = 'network.async-compression-threshold';
|
||||
|
@ -35,10 +35,10 @@ use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\AnvilFallSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
use function lcg_value;
|
||||
use function round;
|
||||
|
||||
class Anvil extends Transparent implements Fallable{
|
||||
@ -70,6 +70,9 @@ class Anvil extends Transparent implements Fallable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->squash(Facing::axis(Facing::rotateY($this->facing, false)), 1 / 8)];
|
||||
}
|
||||
@ -94,7 +97,7 @@ class Anvil extends Transparent implements Fallable{
|
||||
}
|
||||
|
||||
public function onHitGround(FallingBlock $blockEntity) : bool{
|
||||
if(Utils::getRandomFloat() < 0.05 + (round($blockEntity->getFallDistance()) - 1) * 0.05){
|
||||
if(lcg_value() < 0.05 + (round($blockEntity->getFallDistance()) - 1) * 0.05){
|
||||
if($this->damage !== self::VERY_DAMAGED){
|
||||
$this->damage = $this->damage + 1;
|
||||
}else{
|
||||
|
@ -87,6 +87,9 @@ class Bamboo extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//this places the BB at the northwest corner, not the center
|
||||
$inset = 1 - (($this->thick ? 3 : 2) / 16);
|
||||
|
@ -30,6 +30,7 @@ use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\item\Banner as ItemBanner;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
@ -96,6 +97,9 @@ abstract class BaseBanner extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ use pocketmine\event\block\SignChangeEvent;
|
||||
use pocketmine\item\Dye;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\TextFormat;
|
||||
@ -94,6 +95,9 @@ abstract class BaseSign extends Transparent{
|
||||
return 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
@ -76,6 +76,9 @@ class Bed extends Transparent{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 16)];
|
||||
}
|
||||
|
@ -75,10 +75,7 @@ class Block{
|
||||
protected BlockTypeInfo $typeInfo;
|
||||
protected Position $position;
|
||||
|
||||
/**
|
||||
* @var AxisAlignedBB[]|null
|
||||
* @phpstan-var list<AxisAlignedBB>|null
|
||||
*/
|
||||
/** @var AxisAlignedBB[]|null */
|
||||
protected ?array $collisionBoxes = null;
|
||||
|
||||
private int $requiredBlockItemStateDataBits;
|
||||
@ -365,8 +362,6 @@ class Block{
|
||||
*
|
||||
* A replacement block may be returned. This is useful if the block type changed due to reading of world data (e.g.
|
||||
* data from a block entity).
|
||||
*
|
||||
* @phpstan-impure
|
||||
*/
|
||||
public function readStateFromWorld() : Block{
|
||||
return $this;
|
||||
@ -910,7 +905,6 @@ class Block{
|
||||
* - anti-cheat checks in plugins
|
||||
*
|
||||
* @return AxisAlignedBB[]
|
||||
* @phpstan-return list<AxisAlignedBB>
|
||||
*/
|
||||
final public function getCollisionBoxes() : array{
|
||||
if($this->collisionBoxes === null){
|
||||
@ -935,7 +929,6 @@ class Block{
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
* @phpstan-return list<AxisAlignedBB>
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()];
|
||||
|
@ -95,7 +95,7 @@ class BlockBreakInfo{
|
||||
* Returns whether this block can be instantly broken.
|
||||
*/
|
||||
public function breaksInstantly() : bool{
|
||||
return $this->hardness === 0.0;
|
||||
return $this->hardness == 0.0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,7 +154,7 @@ class BlockBreakInfo{
|
||||
|
||||
$efficiency = $item->getMiningEfficiency(($this->toolType & $item->getBlockToolType()) !== 0);
|
||||
if($efficiency <= 0){
|
||||
throw new \InvalidArgumentException(get_class($item) . " must have a positive mining efficiency, but got $efficiency");
|
||||
throw new \InvalidArgumentException(get_class($item) . " has invalid mining efficiency: expected >= 0, got $efficiency");
|
||||
}
|
||||
|
||||
$base /= $efficiency;
|
||||
|
@ -745,49 +745,8 @@ final class BlockTypeIds{
|
||||
public const PITCHER_PLANT = 10715;
|
||||
public const PITCHER_CROP = 10716;
|
||||
public const DOUBLE_PITCHER_CROP = 10717;
|
||||
public const CAMPFIRE = 10718;
|
||||
public const SOUL_CAMPFIRE = 10719;
|
||||
public const TUFF_SLAB = 10720;
|
||||
public const TUFF_STAIRS = 10721;
|
||||
public const TUFF_WALL = 10722;
|
||||
public const CHISELED_TUFF = 10723;
|
||||
public const TUFF_BRICKS = 10724;
|
||||
public const TUFF_BRICK_SLAB = 10725;
|
||||
public const TUFF_BRICK_STAIRS = 10726;
|
||||
public const TUFF_BRICK_WALL = 10727;
|
||||
public const CHISELED_TUFF_BRICKS = 10728;
|
||||
public const POLISHED_TUFF = 10729;
|
||||
public const POLISHED_TUFF_SLAB = 10730;
|
||||
public const POLISHED_TUFF_STAIRS = 10731;
|
||||
public const POLISHED_TUFF_WALL = 10732;
|
||||
public const COPPER_BULB = 10733;
|
||||
public const COPPER_DOOR = 10734;
|
||||
public const COPPER_TRAPDOOR = 10735;
|
||||
public const CHISELED_COPPER = 10736;
|
||||
public const COPPER_GRATE = 10737;
|
||||
public const PALE_OAK_BUTTON = 10738;
|
||||
public const PALE_OAK_DOOR = 10739;
|
||||
public const PALE_OAK_FENCE = 10740;
|
||||
public const PALE_OAK_FENCE_GATE = 10741;
|
||||
public const PALE_OAK_LEAVES = 10742;
|
||||
public const PALE_OAK_LOG = 10743;
|
||||
public const PALE_OAK_PLANKS = 10744;
|
||||
public const PALE_OAK_PRESSURE_PLATE = 10745;
|
||||
public const PALE_OAK_SIGN = 10746;
|
||||
public const PALE_OAK_SLAB = 10747;
|
||||
public const PALE_OAK_STAIRS = 10748;
|
||||
public const PALE_OAK_TRAPDOOR = 10749;
|
||||
public const PALE_OAK_WALL_SIGN = 10750;
|
||||
public const PALE_OAK_WOOD = 10751;
|
||||
public const RESIN = 10752;
|
||||
public const RESIN_BRICK_SLAB = 10753;
|
||||
public const RESIN_BRICK_STAIRS = 10754;
|
||||
public const RESIN_BRICK_WALL = 10755;
|
||||
public const RESIN_BRICKS = 10756;
|
||||
public const RESIN_CLUMP = 10757;
|
||||
public const CHISELED_RESIN_BRICKS = 10758;
|
||||
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10759;
|
||||
public const FIRST_UNUSED_BLOCK_ID = 10718;
|
||||
|
||||
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;
|
||||
|
||||
|
@ -43,6 +43,9 @@ class Cactus extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$shrinkSize = 1 / 16;
|
||||
return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)];
|
||||
|
@ -40,6 +40,9 @@ class Cake extends BaseCake{
|
||||
$w->boundedIntAuto(0, self::MAX_BITES, $this->bites);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
|
@ -36,6 +36,9 @@ class CakeWithCandle extends BaseCake{
|
||||
onInteract as onInteractCandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
@ -49,9 +52,6 @@ class CakeWithCandle extends BaseCake{
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($this->lit && $face !== Facing::UP){
|
||||
return true;
|
||||
}
|
||||
if($this->onInteractCandle($item, $face, $clickVector, $player, $returnedItems)){
|
||||
return true;
|
||||
}
|
||||
|
@ -1,285 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\inventory\CampfireInventory;
|
||||
use pocketmine\block\tile\Campfire as TileCampfire;
|
||||
use pocketmine\block\utils\HorizontalFacingTrait;
|
||||
use pocketmine\block\utils\LightableTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\crafting\FurnaceRecipe;
|
||||
use pocketmine\crafting\FurnaceType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
use pocketmine\entity\projectile\Projectile;
|
||||
use pocketmine\entity\projectile\SplashPotion;
|
||||
use pocketmine\event\block\CampfireCookEvent;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\item\Durable;
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\ItemTypeIds;
|
||||
use pocketmine\item\PotionType;
|
||||
use pocketmine\item\Shovel;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\RayTraceResult;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\BlazeShootSound;
|
||||
use pocketmine\world\sound\FireExtinguishSound;
|
||||
use pocketmine\world\sound\FlintSteelSound;
|
||||
use pocketmine\world\sound\ItemFrameAddItemSound;
|
||||
use function count;
|
||||
use function min;
|
||||
use function mt_rand;
|
||||
|
||||
class Campfire extends Transparent{
|
||||
use HorizontalFacingTrait{
|
||||
HorizontalFacingTrait::describeBlockOnlyState as encodeFacingState;
|
||||
}
|
||||
use LightableTrait{
|
||||
LightableTrait::describeBlockOnlyState as encodeLitState;
|
||||
}
|
||||
|
||||
private const UPDATE_INTERVAL_TICKS = 10;
|
||||
|
||||
/**
|
||||
* @deprecated This was added by mistake. It can't be relied on as the inventory won't be initialized if this block
|
||||
* has never been set in the world.
|
||||
*/
|
||||
protected CampfireInventory $inventory;
|
||||
|
||||
/**
|
||||
* @var int[] slot => ticks
|
||||
* @phpstan-var array<int, int>
|
||||
*/
|
||||
protected array $cookingTimes = [];
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$this->encodeFacingState($w);
|
||||
$this->encodeLitState($w);
|
||||
}
|
||||
|
||||
public function readStateFromWorld() : Block{
|
||||
parent::readStateFromWorld();
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if($tile instanceof TileCampfire){
|
||||
$this->inventory = $tile->getInventory();
|
||||
$this->cookingTimes = $tile->getCookingTimes();
|
||||
}else{
|
||||
$this->inventory = new CampfireInventory($this->position);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function writeStateToWorld() : void{
|
||||
parent::writeStateToWorld();
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if($tile instanceof TileCampfire){
|
||||
$tile->setCookingTimes($this->cookingTimes);
|
||||
}
|
||||
}
|
||||
|
||||
public function hasEntityCollision() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return $this->lit ? 15 : 0;
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::CHARCOAL()->setCount(2)
|
||||
];
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 9 / 16)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This was added by mistake. It can't be relied on as the inventory won't be initialized if this block
|
||||
* has never been set in the world.
|
||||
*/
|
||||
public function getInventory() : CampfireInventory{
|
||||
return $this->inventory;
|
||||
}
|
||||
|
||||
protected function getFurnaceType() : FurnaceType{
|
||||
return FurnaceType::CAMPFIRE;
|
||||
}
|
||||
|
||||
protected function getEntityCollisionDamage() : int{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of ticks during the item in the given slot has been cooked.
|
||||
*/
|
||||
public function setCookingTime(int $slot, int $time) : void{
|
||||
if($slot < 0 || $slot > 3){
|
||||
throw new \InvalidArgumentException("Slot must be in range 0-3");
|
||||
}
|
||||
if($time < 0 || $time > $this->getFurnaceType()->getCookDurationTicks()){
|
||||
throw new \InvalidArgumentException("CookingTime must be in range 0-" . $this->getFurnaceType()->getCookDurationTicks());
|
||||
}
|
||||
$this->cookingTimes[$slot] = $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of ticks during the item in the given slot has been cooked.
|
||||
*/
|
||||
public function getCookingTime(int $slot) : int{
|
||||
return $this->cookingTimes[$slot] ?? 0;
|
||||
}
|
||||
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
if($this->getSide(Facing::DOWN) instanceof Campfire){
|
||||
return false;
|
||||
}
|
||||
if($player !== null){
|
||||
$this->facing = $player->getHorizontalFacing();
|
||||
}
|
||||
$this->lit = true;
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if(!$this->lit){
|
||||
if($item->getTypeId() === ItemTypeIds::FIRE_CHARGE){
|
||||
$item->pop();
|
||||
$this->ignite();
|
||||
$this->position->getWorld()->addSound($this->position, new BlazeShootSound());
|
||||
return true;
|
||||
}elseif($item->getTypeId() === ItemTypeIds::FLINT_AND_STEEL || $item->hasEnchantment(VanillaEnchantments::FIRE_ASPECT())){
|
||||
if($item instanceof Durable){
|
||||
$item->applyDamage(1);
|
||||
}
|
||||
$this->ignite();
|
||||
return true;
|
||||
}
|
||||
}elseif($item instanceof Shovel){
|
||||
$item->applyDamage(1);
|
||||
$this->extinguish();
|
||||
return true;
|
||||
}
|
||||
|
||||
if($this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($this->getFurnaceType())->match($item) !== null){
|
||||
$ingredient = clone $item;
|
||||
$ingredient->setCount(1);
|
||||
if(count($this->inventory->addItem($ingredient)) === 0){
|
||||
$item->pop();
|
||||
$this->position->getWorld()->addSound($this->position, new ItemFrameAddItemSound());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
if($this->lit && $this->getSide(Facing::UP)->getTypeId() === BlockTypeIds::WATER){
|
||||
$this->extinguish();
|
||||
//TODO: Waterlogging
|
||||
}
|
||||
}
|
||||
|
||||
public function onEntityInside(Entity $entity) : bool{
|
||||
if(!$this->lit){
|
||||
if($entity->isOnFire()){
|
||||
$this->ignite();
|
||||
return false;
|
||||
}
|
||||
}elseif($entity instanceof Living){
|
||||
$entity->attack(new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, $this->getEntityCollisionDamage()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onProjectileHit(Projectile $projectile, RayTraceResult $hitResult) : void{
|
||||
if($this->lit && $projectile instanceof SplashPotion && $projectile->getPotionType() === PotionType::WATER){
|
||||
$this->extinguish();
|
||||
}
|
||||
}
|
||||
|
||||
public function onScheduledUpdate() : void{
|
||||
if($this->lit){
|
||||
$items = $this->inventory->getContents();
|
||||
$furnaceType = $this->getFurnaceType();
|
||||
$maxCookDuration = $furnaceType->getCookDurationTicks();
|
||||
foreach($items as $slot => $item){
|
||||
$this->setCookingTime($slot, min($maxCookDuration, $this->getCookingTime($slot) + self::UPDATE_INTERVAL_TICKS));
|
||||
if($this->getCookingTime($slot) >= $maxCookDuration){
|
||||
$result =
|
||||
($recipe = $this->position->getWorld()->getServer()->getCraftingManager()->getFurnaceRecipeManager($furnaceType)->match($item)) instanceof FurnaceRecipe ?
|
||||
$recipe->getResult() :
|
||||
VanillaItems::AIR();
|
||||
|
||||
$ev = new CampfireCookEvent($this, $slot, $item, $result);
|
||||
$ev->call();
|
||||
|
||||
if ($ev->isCancelled()){
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->inventory->setItem($slot, VanillaItems::AIR());
|
||||
$this->setCookingTime($slot, 0);
|
||||
$this->position->getWorld()->dropItem($this->position->add(0.5, 1, 0.5), $ev->getResult());
|
||||
}
|
||||
}
|
||||
if(count($items) > 0){
|
||||
$this->position->getWorld()->setBlock($this->position, $this);
|
||||
}
|
||||
if(mt_rand(1, 6) === 1){
|
||||
$this->position->getWorld()->addSound($this->position, $furnaceType->getCookSound());
|
||||
}
|
||||
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS);
|
||||
}
|
||||
}
|
||||
|
||||
private function extinguish() : void{
|
||||
$this->position->getWorld()->addSound($this->position, new FireExtinguishSound());
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setLit(false));
|
||||
}
|
||||
|
||||
private function ignite() : void{
|
||||
$this->position->getWorld()->addSound($this->position, new FlintSteelSound());
|
||||
$this->position->getWorld()->setBlock($this->position, $this->setLit(true));
|
||||
$this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS);
|
||||
}
|
||||
}
|
@ -36,6 +36,9 @@ class Carpet extends Flowable{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 15 / 16)];
|
||||
}
|
||||
|
@ -36,6 +36,9 @@ use pocketmine\player\Player;
|
||||
class Chest extends Transparent{
|
||||
use FacesOppositePlacingPlayerTrait;
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//these are slightly bigger than in PC
|
||||
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];
|
||||
|
@ -48,32 +48,11 @@ class ChiseledBookshelf extends Opaque{
|
||||
*/
|
||||
private array $slots = [];
|
||||
|
||||
private ?ChiseledBookshelfSlot $lastInteractedSlot = null;
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->horizontalFacing($this->facing);
|
||||
$w->enumSet($this->slots, ChiseledBookshelfSlot::cases());
|
||||
}
|
||||
|
||||
public function readStateFromWorld() : Block{
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if($tile instanceof TileChiseledBookshelf){
|
||||
$this->lastInteractedSlot = $tile->getLastInteractedSlot();
|
||||
}else{
|
||||
$this->lastInteractedSlot = null;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function writeStateToWorld() : void{
|
||||
parent::writeStateToWorld();
|
||||
|
||||
$tile = $this->position->getWorld()->getTile($this->position);
|
||||
if($tile instanceof TileChiseledBookshelf){
|
||||
$tile->setLastInteractedSlot($this->lastInteractedSlot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given slot is displayed as occupied.
|
||||
* This doesn't guarantee that there is or isn't a book in the bookshelf's inventory.
|
||||
@ -113,23 +92,6 @@ class ChiseledBookshelf extends Opaque{
|
||||
return $this->slots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last slot interacted by a player or null if no slot has been interacted with yet.
|
||||
*/
|
||||
public function getLastInteractedSlot() : ?ChiseledBookshelfSlot{
|
||||
return $this->lastInteractedSlot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last slot interacted by a player.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setLastInteractedSlot(?ChiseledBookshelfSlot $lastInteractedSlot) : self{
|
||||
$this->lastInteractedSlot = $lastInteractedSlot;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if($face !== $this->facing){
|
||||
return false;
|
||||
@ -150,12 +112,10 @@ class ChiseledBookshelf extends Opaque{
|
||||
$returnedItems[] = $inventory->getItem($slot->value);
|
||||
$inventory->clear($slot->value);
|
||||
$this->setSlot($slot, false);
|
||||
$this->lastInteractedSlot = $slot;
|
||||
}elseif($item instanceof WritableBookBase || $item instanceof Book || $item instanceof EnchantedBook){
|
||||
//TODO: type tags like blocks would be better for this
|
||||
$inventory->setItem($slot->value, $item->pop());
|
||||
$this->setSlot($slot, true);
|
||||
$this->lastInteractedSlot = $slot;
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
|
@ -34,16 +34,11 @@ use function mt_rand;
|
||||
final class ChorusPlant extends Flowable{
|
||||
use StaticSupportTrait;
|
||||
|
||||
/**
|
||||
* @var true[]
|
||||
* @phpstan-var array<int, true>
|
||||
*/
|
||||
protected array $connections = [];
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$bb = AxisAlignedBB::one();
|
||||
foreach(Facing::ALL as $facing){
|
||||
if(!isset($this->connections[$facing])){
|
||||
foreach($this->getAllSides() as $facing => $block){
|
||||
$id = $block->getTypeId();
|
||||
if($id !== BlockTypeIds::END_STONE && $id !== BlockTypeIds::CHORUS_FLOWER && !$block->hasSameTypeId($this)){
|
||||
$bb->trim($facing, 2 / 16);
|
||||
}
|
||||
}
|
||||
@ -51,26 +46,6 @@ final class ChorusPlant extends Flowable{
|
||||
return [$bb];
|
||||
}
|
||||
|
||||
public function readStateFromWorld() : Block{
|
||||
parent::readStateFromWorld();
|
||||
|
||||
$this->collisionBoxes = null;
|
||||
|
||||
foreach(Facing::ALL as $facing){
|
||||
$block = $this->getSide($facing);
|
||||
if(match($block->getTypeId()){
|
||||
BlockTypeIds::END_STONE, BlockTypeIds::CHORUS_FLOWER, $this->getTypeId() => true,
|
||||
default => false
|
||||
}){
|
||||
$this->connections[$facing] = true;
|
||||
}else{
|
||||
unset($this->connections[$facing]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function canBeSupportedBy(Block $block) : bool{
|
||||
return $block->hasSameTypeId($this) || $block->getTypeId() === BlockTypeIds::END_STONE;
|
||||
}
|
||||
|
@ -50,6 +50,9 @@ class CocoaBlock extends Flowable{
|
||||
$w->boundedIntAuto(0, self::MAX_AGE, $this->age);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
|
@ -23,9 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CopperMaterial;
|
||||
use pocketmine\block\utils\CopperTrait;
|
||||
|
||||
class Copper extends Opaque implements CopperMaterial{
|
||||
class Copper extends Opaque{
|
||||
use CopperTrait;
|
||||
}
|
||||
|
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CopperMaterial;
|
||||
use pocketmine\block\utils\CopperOxidation;
|
||||
use pocketmine\block\utils\CopperTrait;
|
||||
use pocketmine\block\utils\LightableTrait;
|
||||
use pocketmine\block\utils\PoweredByRedstoneTrait;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
|
||||
class CopperBulb extends Opaque implements CopperMaterial{
|
||||
use CopperTrait;
|
||||
use PoweredByRedstoneTrait;
|
||||
use LightableTrait{
|
||||
describeBlockOnlyState as encodeLitState;
|
||||
}
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$this->encodeLitState($w);
|
||||
$w->bool($this->powered);
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function togglePowered(bool $powered) : self{
|
||||
if($powered === $this->powered){
|
||||
return $this;
|
||||
}
|
||||
if ($powered) {
|
||||
$this->setLit(!$this->lit);
|
||||
}
|
||||
$this->setPowered($powered);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
if ($this->lit) {
|
||||
return match($this->oxidation){
|
||||
CopperOxidation::NONE => 15,
|
||||
CopperOxidation::EXPOSED => 12,
|
||||
CopperOxidation::WEATHERED => 8,
|
||||
CopperOxidation::OXIDIZED => 4,
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CopperMaterial;
|
||||
use pocketmine\block\utils\CopperTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class CopperDoor extends Door implements CopperMaterial{
|
||||
use CopperTrait{
|
||||
onInteract as onInteractCopper;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if ($player !== null && $player->isSneaking() && $this->onInteractCopper($item, $face, $clickVector, $player, $returnedItems)) {
|
||||
//copy copper properties to other half
|
||||
$other = $this->getSide($this->top ? Facing::DOWN : Facing::UP);
|
||||
$world = $this->position->getWorld();
|
||||
if ($other instanceof CopperDoor) {
|
||||
$other->setOxidation($this->oxidation);
|
||||
$other->setWaxed($this->waxed);
|
||||
$world->setBlock($other->position, $other);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::onInteract($item, $face, $clickVector, $player, $returnedItems);
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CopperMaterial;
|
||||
use pocketmine\block\utils\CopperTrait;
|
||||
|
||||
class CopperGrate extends Transparent implements CopperMaterial{
|
||||
use CopperTrait;
|
||||
|
||||
//TODO: waterlogging!
|
||||
}
|
@ -23,9 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CopperMaterial;
|
||||
use pocketmine\block\utils\CopperTrait;
|
||||
|
||||
class CopperSlab extends Slab implements CopperMaterial{
|
||||
class CopperSlab extends Slab{
|
||||
use CopperTrait;
|
||||
}
|
||||
|
@ -23,9 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CopperMaterial;
|
||||
use pocketmine\block\utils\CopperTrait;
|
||||
|
||||
class CopperStairs extends Stair implements CopperMaterial{
|
||||
class CopperStairs extends Stair{
|
||||
use CopperTrait;
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\CopperMaterial;
|
||||
use pocketmine\block\utils\CopperTrait;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
|
||||
class CopperTrapdoor extends Trapdoor implements CopperMaterial{
|
||||
use CopperTrait{
|
||||
onInteract as onInteractCopper;
|
||||
}
|
||||
|
||||
public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{
|
||||
if ($player !== null && $player->isSneaking() && $this->onInteractCopper($item, $face, $clickVector, $player, $returnedItems)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::onInteract($item, $face, $clickVector, $player, $returnedItems);
|
||||
}
|
||||
}
|
@ -62,6 +62,9 @@ class DaylightSensor extends Transparent{
|
||||
return 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 10 / 16)];
|
||||
}
|
||||
|
@ -95,6 +95,9 @@ class Door extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//TODO: doors are 0.1825 blocks thick, instead of 0.1875 like JE (https://bugs.mojang.com/browse/MCPE-19214)
|
||||
return [AxisAlignedBB::one()->trim($this->open ? Facing::rotateY($this->facing, !$this->hingeRight) : $this->facing, 327 / 400)];
|
||||
|
@ -33,6 +33,9 @@ use pocketmine\player\Player;
|
||||
|
||||
class EnchantingTable extends Transparent{
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 0.25)];
|
||||
}
|
||||
|
@ -50,6 +50,9 @@ class EndPortalFrame extends Opaque{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 3 / 16)];
|
||||
}
|
||||
|
@ -52,6 +52,9 @@ class EndRod extends Flowable{
|
||||
return 14;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$myAxis = Facing::axis($this->facing);
|
||||
|
||||
|
@ -40,6 +40,9 @@ class EnderChest extends Transparent{
|
||||
return 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//these are slightly bigger than in PC
|
||||
return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)];
|
||||
|
@ -31,8 +31,8 @@ use pocketmine\event\entity\EntityTrampleFarmlandEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\utils\Utils;
|
||||
use function intdiv;
|
||||
use function lcg_value;
|
||||
|
||||
class Farmland extends Transparent{
|
||||
public const MAX_WETNESS = 7;
|
||||
@ -94,6 +94,9 @@ class Farmland extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
|
||||
}
|
||||
@ -145,7 +148,7 @@ class Farmland extends Transparent{
|
||||
}
|
||||
|
||||
public function onEntityLand(Entity $entity) : ?float{
|
||||
if($entity instanceof Living && Utils::getRandomFloat() < $entity->getFallDistance() - 0.5){
|
||||
if($entity instanceof Living && lcg_value() < $entity->getFallDistance() - 0.5){
|
||||
$ev = new EntityTrampleFarmlandEvent($entity, $this);
|
||||
$ev->call();
|
||||
if(!$ev->isCancelled()){
|
||||
|
@ -54,9 +54,13 @@ class Fence extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$inset = 0.5 - $this->getThickness() / 2;
|
||||
|
||||
/** @var AxisAlignedBB[] $bbs */
|
||||
$bbs = [];
|
||||
|
||||
$connectWest = isset($this->connections[Facing::WEST]);
|
||||
|
@ -64,6 +64,9 @@ class FenceGate extends Transparent{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return $this->open ? [] : [AxisAlignedBB::one()->extend(Facing::UP, 0.5)->squash(Facing::axis($this->facing), 6 / 16)];
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
/**
|
||||
* "Flowable" blocks are destroyed if water flows into the same space as the block. These blocks usually don't have any
|
||||
@ -40,11 +40,9 @@ abstract class Flowable extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{
|
||||
return (!$this->canBeFlowedInto() || !$blockReplace instanceof Liquid) &&
|
||||
parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
@ -83,6 +83,9 @@ class FlowerPot extends Flowable{
|
||||
return $block->hasTypeTag(BlockTypeTags::POTTABLE_PLANTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->contract(3 / 16, 0, 3 / 16)->trim(Facing::UP, 5 / 8)];
|
||||
}
|
||||
|
@ -24,19 +24,60 @@ declare(strict_types=1);
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\BlockEventHelper;
|
||||
use pocketmine\block\utils\MultiAnySupportTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Fertilizer;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\World;
|
||||
use function array_key_first;
|
||||
use function count;
|
||||
use function shuffle;
|
||||
|
||||
class GlowLichen extends Transparent{
|
||||
use MultiAnySupportTrait;
|
||||
|
||||
/** @var int[] */
|
||||
protected array $faces = [];
|
||||
|
||||
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
|
||||
$w->facingFlags($this->faces);
|
||||
}
|
||||
|
||||
/** @return int[] */
|
||||
public function getFaces() : array{ return $this->faces; }
|
||||
|
||||
public function hasFace(int $face) : bool{
|
||||
return isset($this->faces[$face]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $faces
|
||||
* @return $this
|
||||
*/
|
||||
public function setFaces(array $faces) : self{
|
||||
$uniqueFaces = [];
|
||||
foreach($faces as $face){
|
||||
Facing::validate($face);
|
||||
$uniqueFaces[$face] = $face;
|
||||
}
|
||||
$this->faces = $uniqueFaces;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** @return $this */
|
||||
public function setFace(int $face, bool $value) : self{
|
||||
Facing::validate($face);
|
||||
if($value){
|
||||
$this->faces[$face] = $face;
|
||||
}else{
|
||||
unset($this->faces[$face]);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLightLevel() : int{
|
||||
return 7;
|
||||
@ -46,6 +87,9 @@ class GlowLichen extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
@ -58,11 +102,39 @@ class GlowLichen extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
protected function getInitialPlaceFaces(Block $blockReplace) : array{
|
||||
return $blockReplace instanceof GlowLichen ? $blockReplace->faces : [];
|
||||
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
|
||||
$this->faces = $blockReplace instanceof GlowLichen ? $blockReplace->faces : [];
|
||||
$availableFaces = $this->getAvailableFaces();
|
||||
|
||||
if(count($availableFaces) === 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
$opposite = Facing::opposite($face);
|
||||
$placedFace = isset($availableFaces[$opposite]) ? $opposite : array_key_first($availableFaces);
|
||||
$this->faces[$placedFace] = $placedFace;
|
||||
|
||||
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$changed = false;
|
||||
|
||||
foreach($this->faces as $face){
|
||||
if($this->getAdjacentSupportType($face) !== SupportType::FULL){
|
||||
unset($this->faces[$face]);
|
||||
$changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if($changed){
|
||||
$world = $this->position->getWorld();
|
||||
if(count($this->faces) === 0){
|
||||
$world->useBreakOn($this->position);
|
||||
}else{
|
||||
$world->setBlock($this->position, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getSpreadBlock(Block $replace, int $spreadFace) : ?Block{
|
||||
@ -189,4 +261,17 @@ class GlowLichen extends Transparent{
|
||||
public function getFlammability() : int{
|
||||
return 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, int> $faces
|
||||
*/
|
||||
private function getAvailableFaces() : array{
|
||||
$faces = [];
|
||||
foreach(Facing::ALL as $face){
|
||||
if(!$this->hasFace($face) && $this->getAdjacentSupportType($face) === SupportType::FULL){
|
||||
$faces[$face] = $face;
|
||||
}
|
||||
}
|
||||
return $faces;
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,9 @@ use pocketmine\math\Facing;
|
||||
|
||||
class GrassPath extends Transparent{
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 1 / 16)];
|
||||
}
|
||||
|
@ -31,13 +31,13 @@ use pocketmine\item\Item;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\sound\ItemFrameAddItemSound;
|
||||
use pocketmine\world\sound\ItemFrameRemoveItemSound;
|
||||
use pocketmine\world\sound\ItemFrameRotateItemSound;
|
||||
use function is_infinite;
|
||||
use function is_nan;
|
||||
use function lcg_value;
|
||||
|
||||
class ItemFrame extends Flowable{
|
||||
use AnyFacingTrait;
|
||||
@ -154,7 +154,7 @@ class ItemFrame extends Flowable{
|
||||
return false;
|
||||
}
|
||||
$world = $this->position->getWorld();
|
||||
if(Utils::getRandomFloat() <= $this->itemDropChance){
|
||||
if(lcg_value() <= $this->itemDropChance){
|
||||
$world->dropItem($this->position->add(0.5, 0.5, 0.5), clone $this->framedItem);
|
||||
$world->addSound($this->position, new ItemFrameRemoveItemSound());
|
||||
}
|
||||
@ -185,7 +185,7 @@ class ItemFrame extends Flowable{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
$drops = parent::getDropsForCompatibleTool($item);
|
||||
if($this->framedItem !== null && Utils::getRandomFloat() <= $this->itemDropChance){
|
||||
if($this->framedItem !== null && lcg_value() <= $this->itemDropChance){
|
||||
$drops[] = clone $this->framedItem;
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,9 @@ class Ladder extends Transparent{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim($this->facing, 13 / 16)];
|
||||
}
|
||||
|
@ -59,6 +59,9 @@ class Lantern extends Transparent{
|
||||
return $this->lightLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [
|
||||
AxisAlignedBB::one()
|
||||
|
@ -157,7 +157,6 @@ class Leaves extends Transparent{
|
||||
LeavesType::MANGROVE, //TODO: mangrove propagule
|
||||
LeavesType::AZALEA, LeavesType::FLOWERING_AZALEA => null, //TODO: azalea
|
||||
LeavesType::CHERRY => null, //TODO: cherry
|
||||
LeavesType::PALE_OAK => null, //TODO: pale oak
|
||||
})?->asItem();
|
||||
if($sapling !== null){
|
||||
$drops[] = $sapling;
|
||||
|
@ -30,11 +30,12 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\event\block\BlockSpreadEvent;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\sound\FizzSound;
|
||||
use pocketmine\world\sound\Sound;
|
||||
use function lcg_value;
|
||||
|
||||
abstract class Liquid extends Transparent{
|
||||
public const MAX_DECAY = 7;
|
||||
@ -88,6 +89,9 @@ abstract class Liquid extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
@ -364,7 +368,7 @@ abstract class Liquid extends Transparent{
|
||||
|
||||
protected function liquidCollide(Block $cause, Block $result) : bool{
|
||||
if(BlockEventHelper::form($this, $result, $cause)){
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new FizzSound(2.6 + (Utils::getRandomFloat() - Utils::getRandomFloat()) * 0.8));
|
||||
$this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new FizzSound(2.6 + (lcg_value() - lcg_value()) * 0.8));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ class Magma extends Opaque{
|
||||
}
|
||||
|
||||
public function onEntityInside(Entity $entity) : bool{
|
||||
if($entity instanceof Living && !$entity->isSneaking() && $entity->getFrostWalkerLevel() === 0){
|
||||
if($entity instanceof Living && !$entity->isSneaking()){
|
||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||
$entity->attack($ev);
|
||||
}
|
||||
|
@ -104,6 +104,9 @@ class MobHead extends Flowable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
$collisionBox = AxisAlignedBB::one()
|
||||
->contract(0.25, 0, 0.25)
|
||||
|
@ -28,6 +28,7 @@ use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\math\Axis;
|
||||
use pocketmine\math\AxisAlignedBB;
|
||||
|
||||
class NetherPortal extends Transparent{
|
||||
|
||||
@ -61,6 +62,9 @@ class NetherPortal extends Transparent{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
|
@ -79,6 +79,9 @@ class RedstoneComparator extends Flowable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 8)];
|
||||
}
|
||||
|
@ -62,6 +62,9 @@ class RedstoneRepeater extends Flowable{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AxisAlignedBB[]
|
||||
*/
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 8)];
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\MultiAnySupportTrait;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
|
||||
final class ResinClump extends Transparent{
|
||||
use MultiAnySupportTrait;
|
||||
|
||||
public function isSolid() : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getSupportType(int $facing) : SupportType{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
public function canBeReplaced() : bool{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
protected function getInitialPlaceFaces(Block $blockReplace) : array{
|
||||
return $blockReplace instanceof ResinClump ? $blockReplace->faces : [];
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
return [];
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user